SSD1306 tiny I2C display driver

* TEST

* t1

* faster

* Update drv_ssd1306.c

* mk

* Update drv_ssd1306.c

* test

* Update drv_ssd1306.c

* Update drv_ssd1306.c

* Update drv_ssd1306.c

* fx

* test

* Update drv_ssd1306.c

* cmds

* fx

* q

* goto

* Update drv_ssd1306.c

* finish

* rev
This commit is contained in:
openshwprojects
2026-01-29 01:12:04 +01:00
committed by GitHub
parent f0c275a03c
commit 43e3540518
6 changed files with 334 additions and 0 deletions

View File

@@ -129,6 +129,7 @@ set(OBKM_SRC
${OBK_SRCS}driver/drv_spi_flash.c
${OBK_SRCS}driver/drv_spidma.c
${OBK_SRCS}driver/drv_ssdp.c
${OBK_SRCS}driver/drv_ssd1306.c
${OBK_SRCS}driver/drv_tasmotaDeviceGroups.c
${OBK_SRCS}driver/drv_tca9554.c
${OBK_SRCS}driver/drv_tclAC.c

View File

@@ -148,6 +148,7 @@ OBKM_SRC += $(OBK_SRCS)driver/drv_spiLED.c
OBKM_SRC += $(OBK_SRCS)driver/drv_spi_flash.c
OBKM_SRC += $(OBK_SRCS)driver/drv_spidma.c
OBKM_SRC += $(OBK_SRCS)driver/drv_ssdp.c
OBKM_SRC += $(OBK_SRCS)driver/drv_ssd1306.c
OBKM_SRC += $(OBK_SRCS)driver/drv_tasmotaDeviceGroups.c
OBKM_SRC += $(OBK_SRCS)driver/drv_tclAC.c
OBKM_SRC += $(OBK_SRCS)driver/drv_test.c

View File

@@ -29,6 +29,9 @@ void DRV_MAX72XX_Clock_OnEverySecond();
void DRV_MAX72XX_Clock_RunFrame();
void DRV_MAX72XX_Clock_Init();
void SSD1306_Init();
void SSD1306_OnEverySecond();
void DRV_ADCButton_Init();
void DRV_ADCButton_RunFrame();

View File

@@ -1007,6 +1007,22 @@ static driver_t g_drivers[] = {
false, // loaded
},
#endif
#if ENABLE_DRIVER_SSD1306
//drvdetail:{"name":"SSD1306",
//drvdetail:"title":"TODO",
//drvdetail:"descr":"SSD1306SSD1306SSD1306SSD1306SSD1306SSD1306e.",
//drvdetail:"requires":""}
{ "SSD1306", // Driver Name
SSD1306_Init, // Init
SSD1306_OnEverySecond, // onEverySecond
NULL, // appendInformationToHTTPIndexPage
NULL, // runQuickTick
NULL, // stopFunction
NULL, // onChannelChanged
NULL, // onHassDiscovery
false, // loaded
},
#endif
#if ENABLE_DRIVER_BMP280
//drvdetail:{"name":"BMP280",
//drvdetail:"title":"TODO",

311
src/driver/drv_ssd1306.c Normal file
View File

@@ -0,0 +1,311 @@
#include "../new_common.h"
#include "../new_pins.h"
#include "../new_cfg.h"
// Commands register, execution API and cmd tokenizer
#include "../cmnds/cmd_public.h"
#include "../mqtt/new_mqtt.h"
#include "../logging/logging.h"
#include "drv_local.h"
#include "drv_uart.h"
#include "../httpserver/new_http.h"
#include "../hal/hal_pins.h"
static softI2C_t g_softI2C;
static int ssd1306_addr = 0x3C;
#define SSD1306_CMD 0x00
#define SSD1306_DATA 0x40
static void SSD1306_WriteCmd(byte c) {
Soft_I2C_Start(&g_softI2C, ssd1306_addr << 1);
Soft_I2C_WriteByte(&g_softI2C, SSD1306_CMD);
Soft_I2C_WriteByte(&g_softI2C, c);
Soft_I2C_Stop(&g_softI2C);
}
static void SSD1306_WriteData(byte d) {
Soft_I2C_Start(&g_softI2C, ssd1306_addr << 1);
Soft_I2C_WriteByte(&g_softI2C, SSD1306_DATA);
Soft_I2C_WriteByte(&g_softI2C, d);
Soft_I2C_Stop(&g_softI2C);
}
void SSD1306_Fill(byte v) {
int i;
SSD1306_WriteCmd(0x21); // Set column range
SSD1306_WriteCmd(0x00);
SSD1306_WriteCmd(0x7F);
SSD1306_WriteCmd(0x22); // Set page range (for 128x32: 0-3)
SSD1306_WriteCmd(0x00);
SSD1306_WriteCmd(0x03);
for (i = 0; i < 512; i++)
SSD1306_WriteData(v);
}
void SSD1306_SetOn(bool b) {
if (b) {
SSD1306_WriteCmd(0xAF);
}
else {
SSD1306_WriteCmd(0xAE);
}
}
void SSD1306_SetPos(byte x, byte page) {
SSD1306_WriteCmd(0xB0 | page);
SSD1306_WriteCmd(0x00 | (x & 0x0F));
SSD1306_WriteCmd(0x10 | (x >> 4));
}
void SSD1306_DrawRect(byte x, byte y, byte w, byte h, byte fill) {
byte px, py;
byte page_start = y >> 3;
byte page_end = (y + h - 1) >> 3;
for (py = page_start; py <= page_end; py++) {
SSD1306_SetPos(x, py);
for (px = 0; px < w; px++) {
byte mask = 0x00;
if (fill) {
mask = 0xFF;
}
else {
if (py == page_start || py == page_end)
mask = 0xFF;
else if (px == 0 || px == w - 1)
mask = 0xFF;
}
SSD1306_WriteData(mask);
}
}
}
// Standard 5x7 ASCII font
static const byte font5x7[][5] = {
{0x00, 0x00, 0x00, 0x00, 0x00}, // space
{0x00, 0x00, 0x5F, 0x00, 0x00}, // !
{0x00, 0x07, 0x00, 0x07, 0x00}, // "
{0x14, 0x7F, 0x14, 0x7F, 0x14}, // #
{0x24, 0x2A, 0x7F, 0x2A, 0x12}, // $
{0x23, 0x13, 0x08, 0x64, 0x62}, // %
{0x36, 0x49, 0x55, 0x22, 0x50}, // &
{0x00, 0x05, 0x03, 0x00, 0x00}, // '
{0x00, 0x1C, 0x22, 0x41, 0x00}, // (
{0x00, 0x41, 0x22, 0x1C, 0x00}, // )
{0x14, 0x08, 0x3E, 0x08, 0x14}, // *
{0x08, 0x08, 0x3E, 0x08, 0x08}, // +
{0x00, 0x50, 0x60, 0x00, 0x00}, // ,
{0x08, 0x08, 0x08, 0x08, 0x08}, // -
{0x00, 0x60, 0x60, 0x00, 0x00}, // .
{0x20, 0x10, 0x08, 0x04, 0x02}, // /
{0x3E, 0x51, 0x49, 0x45, 0x3E}, // 0
{0x00, 0x42, 0x7F, 0x40, 0x00}, // 1
{0x42, 0x61, 0x51, 0x49, 0x46}, // 2
{0x21, 0x41, 0x45, 0x4B, 0x31}, // 3
{0x18, 0x14, 0x12, 0x7F, 0x10}, // 4
{0x27, 0x45, 0x45, 0x45, 0x39}, // 5
{0x3C, 0x4A, 0x49, 0x49, 0x30}, // 6
{0x01, 0x71, 0x09, 0x05, 0x03}, // 7
{0x36, 0x49, 0x49, 0x49, 0x36}, // 8
{0x06, 0x49, 0x49, 0x29, 0x1E}, // 9
{0x00, 0x36, 0x36, 0x00, 0x00}, // :
{0x00, 0x56, 0x36, 0x00, 0x00}, // ;
{0x08, 0x14, 0x22, 0x41, 0x00}, // <
{0x14, 0x14, 0x14, 0x14, 0x14}, // =
{0x00, 0x41, 0x22, 0x14, 0x08}, // >
{0x02, 0x01, 0x51, 0x09, 0x06}, // ?
{0x32, 0x49, 0x79, 0x41, 0x3E}, // @
{0x7E, 0x11, 0x11, 0x11, 0x7E}, // A
{0x7F, 0x49, 0x49, 0x49, 0x36}, // B
{0x3E, 0x41, 0x41, 0x41, 0x22}, // C
{0x7F, 0x41, 0x41, 0x22, 0x1C}, // D
{0x7F, 0x49, 0x49, 0x49, 0x41}, // E
{0x7F, 0x09, 0x09, 0x09, 0x01}, // F
{0x3E, 0x41, 0x49, 0x49, 0x7A}, // G
{0x7F, 0x08, 0x08, 0x08, 0x7F}, // H
{0x00, 0x41, 0x7F, 0x41, 0x00}, // I
{0x20, 0x40, 0x41, 0x3F, 0x01}, // J
{0x7F, 0x08, 0x14, 0x22, 0x41}, // K
{0x7F, 0x40, 0x40, 0x40, 0x40}, // L
{0x7F, 0x02, 0x0C, 0x02, 0x7F}, // M
{0x7F, 0x04, 0x08, 0x10, 0x7F}, // N
{0x3E, 0x41, 0x41, 0x41, 0x3E}, // O
{0x7F, 0x09, 0x09, 0x09, 0x06}, // P
{0x3E, 0x41, 0x51, 0x21, 0x5E}, // Q
{0x7F, 0x09, 0x19, 0x29, 0x46}, // R
{0x46, 0x49, 0x49, 0x49, 0x31}, // S
{0x01, 0x01, 0x7F, 0x01, 0x01}, // T
{0x3F, 0x40, 0x40, 0x40, 0x3F}, // U
{0x1F, 0x20, 0x40, 0x20, 0x1F}, // V
{0x3F, 0x40, 0x38, 0x40, 0x3F}, // W
{0x63, 0x14, 0x08, 0x14, 0x63}, // X
{0x07, 0x08, 0x70, 0x08, 0x07}, // Y
{0x61, 0x51, 0x49, 0x45, 0x43}, // Z
};
void SSD1306_WriteChar(char c) {
// Convert lowercase to uppercase
if (c >= 'a' && c <= 'z') {
c = c - 'a' + 'A';
}
if (c < 32 || c > 90) c = 32; // Basic bounds check, map unknown to space
c -= 32; // Offset to match array index
Soft_I2C_Start(&g_softI2C, ssd1306_addr << 1);
Soft_I2C_WriteByte(&g_softI2C, SSD1306_DATA);
for (int i = 0; i < 5; i++) {
Soft_I2C_WriteByte(&g_softI2C, font5x7[(uint8_t)c][i]);
}
Soft_I2C_WriteByte(&g_softI2C, 0x00); // 1px spacing between chars
Soft_I2C_Stop(&g_softI2C);
}
void SSD1306_String(const char *str) {
while (*str) {
SSD1306_WriteChar(*str++);
}
}
//int x = 1000;
void SSD1306_OnEverySecond() {
//SSD1306_SetOn(true);
//x++;
//char tmp[8];
//sprintf(tmp, "%i", x);
//SSD1306_SetPos(0, 0);
//SSD1306_String(tmp);
}
commandResult_t SSD1306_Cmd_Print(const void* context, const char* cmd, const char* args, int cmdFlags) {
Tokenizer_TokenizeString(args, TOKENIZER_ALLOW_QUOTES);
// following check must be done after 'Tokenizer_TokenizeString',
// so we know arguments count in Tokenizer. 'cmd' argument is
// only for warning display
if (Tokenizer_CheckArgsCountAndPrintWarning(cmd, 1)) {
return CMD_RES_NOT_ENOUGH_ARGUMENTS;
}
const char *s = Tokenizer_GetArg(0);
SSD1306_String(s);
return CMD_RES_OK;
}
commandResult_t SSD1306_Cmd_GoTo(const void* context, const char* cmd, const char* args, int cmdFlags) {
Tokenizer_TokenizeString(args, TOKENIZER_ALLOW_QUOTES);
// following check must be done after 'Tokenizer_TokenizeString',
// so we know arguments count in Tokenizer. 'cmd' argument is
// only for warning display
if (Tokenizer_CheckArgsCountAndPrintWarning(cmd, 2)) {
return CMD_RES_NOT_ENOUGH_ARGUMENTS;
}
int x = Tokenizer_GetArgInteger(0);
int y = Tokenizer_GetArgInteger(1);
SSD1306_SetPos(x, y);
return CMD_RES_OK;
}
commandResult_t SSD1306_Cmd_On(const void* context, const char* cmd, const char* args, int cmdFlags) {
Tokenizer_TokenizeString(args, 0);
// following check must be done after 'Tokenizer_TokenizeString',
// so we know arguments count in Tokenizer. 'cmd' argument is
// only for warning display
if (Tokenizer_CheckArgsCountAndPrintWarning(cmd, 1)) {
return CMD_RES_NOT_ENOUGH_ARGUMENTS;
}
int bOn = Tokenizer_GetArgInteger(0);
SSD1306_SetOn(bOn);
return CMD_RES_OK;
}
commandResult_t SSD1306_Cmd_Clear(const void* context, const char* cmd, const char* args, int cmdFlags) {
Tokenizer_TokenizeString(args, 0);
// following check must be done after 'Tokenizer_TokenizeString',
// so we know arguments count in Tokenizer. 'cmd' argument is
// only for warning display
if (Tokenizer_CheckArgsCountAndPrintWarning(cmd, 1)) {
return CMD_RES_NOT_ENOUGH_ARGUMENTS;
}
int val = Tokenizer_GetArgInteger(0);
SSD1306_Fill(val);
return CMD_RES_OK;
}
void SSD1306_Cmd_Rect(const void* context, const char* cmd, const char* args, int cmdFlags) {
Tokenizer_TokenizeString(args, 0);
// following check must be done after 'Tokenizer_TokenizeString',
// so we know arguments count in Tokenizer. 'cmd' argument is
// only for warning display
if (Tokenizer_CheckArgsCountAndPrintWarning(cmd, 4)) {
return CMD_RES_NOT_ENOUGH_ARGUMENTS;
}
int x = Tokenizer_GetArgInteger(0);
int y = Tokenizer_GetArgInteger(1);
int w = Tokenizer_GetArgInteger(2);
int h = Tokenizer_GetArgInteger(3);
int fill = Tokenizer_GetArgIntegerDefault(4, 0xff);
SSD1306_DrawRect(x, y, w, h, fill);
return CMD_RES_OK;
}
// startDriver SSD1306 16 20 0x3C
// backlog stopdriver SSD1306 ; startDriver SSD1306 16 20 0x3C
/*
backlog stopdriver SSD1306 ; startDriver SSD1306 16 20 0x3C
ssd1306_clear 0
ssd1306_on 1
setChannel 12 0
again:
delay_s 1
ssd1306_goto 0 0
ssd1306_print "Hello "
ssd1306_print $CH12
addChannel 12 1
goto again
*/
void SSD1306_Init() {
g_softI2C.pin_clk = Tokenizer_GetPin(1, 16);
g_softI2C.pin_data = Tokenizer_GetPin(2, 20);
ssd1306_addr = Tokenizer_GetArgIntegerDefault(3, 0x3C);
CMD_RegisterCommand("ssd1306_clear", SSD1306_Cmd_Clear, NULL);
CMD_RegisterCommand("ssd1306_on", SSD1306_Cmd_On, NULL);
CMD_RegisterCommand("ssd1306_print", SSD1306_Cmd_Print, NULL);
CMD_RegisterCommand("ssd1306_rect", SSD1306_Cmd_Rect, NULL);
CMD_RegisterCommand("ssd1306_goto", SSD1306_Cmd_GoTo, NULL);
Soft_I2C_PreInit(&g_softI2C);
SSD1306_WriteCmd(0xAE);
SSD1306_WriteCmd(0xD5);
SSD1306_WriteCmd(0x80);
SSD1306_WriteCmd(0xA8);
SSD1306_WriteCmd(0x1F);
SSD1306_WriteCmd(0xD3);
SSD1306_WriteCmd(0x00);
SSD1306_WriteCmd(0x40);
SSD1306_WriteCmd(0x8D);
SSD1306_WriteCmd(0x14);
SSD1306_WriteCmd(0x20);
SSD1306_WriteCmd(0x00);
SSD1306_WriteCmd(0xA1);
SSD1306_WriteCmd(0xC8);
SSD1306_WriteCmd(0xDA);
SSD1306_WriteCmd(0x02);
SSD1306_WriteCmd(0x81);
SSD1306_WriteCmd(0x8F);
SSD1306_WriteCmd(0xD9);
SSD1306_WriteCmd(0xF1);
SSD1306_WriteCmd(0xDB);
SSD1306_WriteCmd(0x40);
SSD1306_WriteCmd(0xA4);
SSD1306_WriteCmd(0xA6);
SSD1306_WriteCmd(0xAF);
SSD1306_Fill(0x00);
}

View File

@@ -242,6 +242,8 @@
//#define ENABLE_DRIVER_UART_TCP 1
//#define ENABLE_DRIVER_SSD1306 1
// #define ENABLE_DRIVER_PIR 1
//#define ENABLE_DRIVER_BKPARTITIONS 1
#define ENABLE_HA_DISCOVERY 1