Skip to content

Commit a9af494

Browse files
committed
i2c hacky output
need to refactor display model methods out, and i2c output methods in from i2c to display model, and driver files out of i2c drivers.
1 parent 68bfc88 commit a9af494

File tree

6 files changed

+190
-13
lines changed

6 files changed

+190
-13
lines changed

platformio.ini

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,14 @@ build_flags = -DARDUINO_METRO_ESP32S3 -DBOARD_HAS_PSRAM
277277
board_build.partitions = tinyuf2-partitions-16MB.csv
278278
extra_scripts = pre:rename_usb_config.py
279279

280+
; Adafruit Metro ESP32-S3
281+
[env:adafruit_metro_esp32s3_debug]
282+
extends = env:adafruit_metro_esp32s3
283+
build_type = debug
284+
; debug_tool = jlink
285+
; upload_protocol = jlink
286+
board_build.partitions = tinyuf2-partitions-16MB.csv
287+
280288
; Adafruit Qualia ESP32-S3 RGB666
281289
[env:adafruit_qualia_s3_rgb666]
282290
extends = common:esp32
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*!
2+
* @file src/components/display/drivers/dispDrvI2cAdapter.h
3+
*
4+
* Adapter that wraps I2C output drivers (drvOutputBase) behind the
5+
* dispDrvBase interface so the display controller can manage them.
6+
*
7+
* Adafruit invests time and resources providing this open source code,
8+
* please support Adafruit and open-source hardware by purchasing
9+
* products from Adafruit!
10+
*
11+
* Copyright (c) Tyeth Gundry 2025 for Adafruit Industries.
12+
*
13+
* BSD license, all text here must be included in any redistribution.
14+
*
15+
*/
16+
#ifndef WS_DISP_DRV_I2C_ADAPTER_H
17+
#define WS_DISP_DRV_I2C_ADAPTER_H
18+
19+
#include "dispDrvBase.h"
20+
#include "../../i2c/drivers/drvOutputBase.h"
21+
22+
/*!
23+
@brief Adapter that wraps an I2C output driver (drvOutputBase)
24+
behind the display driver interface (dispDrvBase).
25+
*/
26+
class dispDrvI2cAdapter : public dispDrvBase {
27+
public:
28+
/*!
29+
@brief Constructor — takes ownership of the I2C output driver.
30+
@param drv Pointer to an I2C output driver (will be deleted on
31+
destruction).
32+
*/
33+
dispDrvI2cAdapter(drvOutputBase *drv) : dispDrvBase(), _drv(drv) {}
34+
35+
~dispDrvI2cAdapter() {
36+
if (_drv) {
37+
delete _drv;
38+
_drv = nullptr;
39+
}
40+
}
41+
42+
bool begin() override {
43+
if (!_drv)
44+
return false;
45+
return _drv->begin();
46+
}
47+
48+
void writeMessage(const char *message, bool clear_first = true,
49+
int32_t cursor_x = 0, int32_t cursor_y = 0) override {
50+
if (!_drv)
51+
return;
52+
// I2C output drivers only support simple WriteMessage
53+
_drv->WriteMessage(message);
54+
}
55+
56+
private:
57+
drvOutputBase *_drv;
58+
};
59+
60+
#endif // WS_DISP_DRV_I2C_ADAPTER_H

src/components/display/drivers/dispDrvRgb666.h

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -63,36 +63,47 @@ class dispDrvRgb666 : public dispDrvBase {
6363
if (!_expander)
6464
return false;
6565

66-
_rgbpanel = new Arduino_ESP32RGBPanel(
67-
TFT_DE, TFT_VSYNC, TFT_HSYNC, TFT_PCLK, TFT_R1, TFT_R2, TFT_R3,
68-
TFT_R4, TFT_R5, TFT_G0, TFT_G1, TFT_G2, TFT_G3, TFT_G4, TFT_G5,
69-
TFT_B1, TFT_B2, TFT_B3, TFT_B4, TFT_B5,
70-
1 /* hsync_polarity */, 46 /* hsync_front_porch */,
71-
2 /* hsync_pulse_width */, 44 /* hsync_back_porch */,
72-
1 /* vsync_polarity */, 50 /* vsync_front_porch */,
73-
16 /* vsync_pulse_width */, 16 /* vsync_back_porch */);
74-
if (!_rgbpanel)
75-
return false;
76-
77-
// Select init operations based on panel string.
66+
// Select init operations and dotclock timings per panel.
67+
// Timings from CircuitPython dotclockframebuffer configs.
7868
// Accepts both panel part numbers and Adafruit PIDs.
7969
const uint8_t *init_ops = nullptr;
8070
size_t init_ops_len = 0;
71+
uint16_t h_fp, h_pw, h_bp, v_fp, v_pw, v_bp;
72+
uint16_t pclk_active_neg = 0;
73+
int32_t prefer_speed = 16000000;
8174

8275
if (strcmp(_panel, "TL021WVC02") == 0 ||
8376
strcmp(_panel, "adafruit-5792") == 0) {
77+
// 2.1" round 480x480
8478
init_ops = TL021WVC02_init_operations;
8579
init_ops_len = sizeof(TL021WVC02_init_operations);
80+
h_fp = 40; h_pw = 20; h_bp = 40;
81+
v_fp = 40; v_pw = 10; v_bp = 40;
82+
pclk_active_neg = 0; // pclk_active_high = True
8683
} else if (strcmp(_panel, "TL032FWV01") == 0 ||
8784
strcmp(_panel, "adafruit-5797") == 0) {
85+
// 3.2" bar 320x820
8886
init_ops = tl032fwv01_init_operations;
8987
init_ops_len = sizeof(tl032fwv01_init_operations);
88+
h_fp = 150; h_pw = 3; h_bp = 251;
89+
v_fp = 100; v_pw = 6; v_bp = 90;
90+
pclk_active_neg = 1; // pclk_active_high = False
9091
} else {
9192
WS_DEBUG_PRINT("[display] ERROR: Unknown RGB666 panel: ");
9293
WS_DEBUG_PRINTLN(_panel);
9394
return false;
9495
}
9596

97+
_rgbpanel = new Arduino_ESP32RGBPanel(
98+
TFT_DE, TFT_VSYNC, TFT_HSYNC, TFT_PCLK, TFT_R1, TFT_R2, TFT_R3,
99+
TFT_R4, TFT_R5, TFT_G0, TFT_G1, TFT_G2, TFT_G3, TFT_G4, TFT_G5,
100+
TFT_B1, TFT_B2, TFT_B3, TFT_B4, TFT_B5,
101+
1 /* hsync_polarity */, h_fp, h_pw, h_bp,
102+
1 /* vsync_polarity */, v_fp, v_pw, v_bp,
103+
pclk_active_neg, prefer_speed);
104+
if (!_rgbpanel)
105+
return false;
106+
96107
_display = new Arduino_RGB_Display(_width, _height, _rgbpanel,
97108
_rotation, true /* auto_flush */,
98109
_expander, GFX_NOT_DEFINED /* RST */,

src/components/display/hardware.cpp

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ bool DisplayHardware::begin(ws_display_Add *addMsg) {
5454
return beginSpiEpd(addMsg);
5555
case ws_display_Add_ttl_rgb666_tag:
5656
return beginTtlRgb666(addMsg);
57+
// DSI + i8080 todo
58+
case ws_display_Add_i2c_tag:
59+
return beginI2cDisplay(addMsg);
5760
default:
5861
WS_DEBUG_PRINTLN(
5962
"[display] ERROR: Unsupported display interface type!");
@@ -359,6 +362,94 @@ bool DisplayHardware::beginTtlRgb666(ws_display_Add *msg) {
359362
#endif
360363
}
361364

365+
// ---------------------------------------------------------------------------
366+
// I2C display initialization (OLED, CharLCD, LED backpack, etc.)
367+
// ---------------------------------------------------------------------------
368+
bool DisplayHardware::beginI2cDisplay(ws_display_Add *msg) {
369+
if (msg->which_interface_type != ws_display_Add_i2c_tag) {
370+
WS_DEBUG_PRINTLN("[display] ERROR: Expected I2C interface for I2C display!");
371+
return false;
372+
}
373+
ws_display_I2cDisplayConfig *i2c_cfg = &msg->interface_type.i2c;
374+
uint16_t addr = (uint16_t)i2c_cfg->device_address;
375+
376+
if (_drvDisp) {
377+
delete _drvDisp;
378+
_drvDisp = nullptr;
379+
}
380+
381+
WS_DEBUG_PRINT("[display] I2C driver: ");
382+
WS_DEBUG_PRINT(msg->driver);
383+
WS_DEBUG_PRINT(" addr: 0x");
384+
WS_DEBUG_PRINTLN(addr, HEX);
385+
386+
// Get the initialized I2C bus from the I2C controller
387+
if (!Ws._i2c_controller->IsBusStatusOK()) {
388+
WS_DEBUG_PRINTLN("[display] ERROR: I2C bus not initialized!");
389+
return false;
390+
}
391+
TwoWire *i2c = Ws._i2c_controller->GetI2cBus();
392+
393+
// Create the appropriate I2C output driver based on driver string
394+
drvOutputBase *drv = nullptr;
395+
if (strcasecmp(msg->driver, "SSD1306") == 0) {
396+
drv = new drvOutSsd1306(i2c, addr, 0, msg->driver);
397+
} else if (strcasecmp(msg->driver, "SH1107") == 0) {
398+
drv = new drvOutSh1107(i2c, addr, 0, msg->driver);
399+
} else if (strcasecmp(msg->driver, "charlcd") == 0) {
400+
drv = new drvOutCharLcd(i2c, addr, 0, msg->driver);
401+
} else if (strcasecmp(msg->driver, "7seg") == 0) {
402+
drv = new drvOut7Seg(i2c, addr, 0, msg->driver);
403+
} else if (strcasecmp(msg->driver, "quadalphanum") == 0) {
404+
drv = new drvOutQuadAlphaNum(i2c, addr, 0, msg->driver);
405+
} else {
406+
WS_DEBUG_PRINT("[display] ERROR: Unsupported I2C display driver: ");
407+
WS_DEBUG_PRINTLN(msg->driver);
408+
return false;
409+
}
410+
411+
// Configure based on config type
412+
pb_size_t config = msg->which_config;
413+
WS_DEBUG_PRINT("[display] I2C config tag: ");
414+
WS_DEBUG_PRINTLN(config);
415+
if (config == ws_display_Add_config_oled_tag) {
416+
ws_display_OledConfig *cfg = &msg->config.config_oled;
417+
WS_DEBUG_PRINT("[display] OLED config: ");
418+
WS_DEBUG_PRINT(cfg->width);
419+
WS_DEBUG_PRINT("x");
420+
WS_DEBUG_PRINTLN(cfg->height);
421+
drv->ConfigureSSD1306(cfg->width, cfg->height,
422+
cfg->font_size > 0 ? cfg->font_size : 1);
423+
} else if (config == ws_display_Add_config_char_lcd_tag) {
424+
ws_display_CharLcdConfig *cfg = &msg->config.config_char_lcd;
425+
drv->ConfigureCharLcd(cfg->rows, cfg->columns, true);
426+
} else if (config == ws_display_Add_config_led_tag) {
427+
ws_display_LedBackpackConfig *cfg = &msg->config.config_led;
428+
drv->ConfigureI2CBackpack(cfg->brightness, cfg->alignment);
429+
} else {
430+
// No matching config — for OLEDs, apply safe defaults to prevent
431+
// crash from uninitialized width/height in drvOutSsd1306::begin()
432+
WS_DEBUG_PRINTLN("[display] WARNING: No config for I2C display, "
433+
"applying defaults");
434+
if (strcasecmp(msg->driver, "SSD1306") == 0) {
435+
drv->ConfigureSSD1306(128, 32, 1);
436+
} else if (strcasecmp(msg->driver, "SH1107") == 0) {
437+
drv->ConfigureSSD1306(128, 64, 1);
438+
}
439+
}
440+
441+
WS_DEBUG_PRINTLN("[display] Calling I2C driver begin()...");
442+
if (!drv->begin()) {
443+
WS_DEBUG_PRINTLN("[display] ERROR: Failed to begin I2C display driver!");
444+
delete drv;
445+
return false;
446+
}
447+
448+
_drvDisp = new dispDrvI2cAdapter(drv);
449+
WS_DEBUG_PRINTLN("[display] I2C display initialized successfully!");
450+
return true;
451+
}
452+
362453
void DisplayHardware::showSplash() {
363454
if (_drvDisp)
364455
_drvDisp->showSplash();

src/components/display/hardware.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@
1717
#include "Wippersnapper.h"
1818
#include "drivers/dispDrvBase.h"
1919
#include "drivers/dispDrvSt7789.h"
20+
#include "drivers/dispDrvI2cAdapter.h"
21+
#include "../i2c/drivers/drvOut7Seg.h"
22+
#include "../i2c/drivers/drvOutCharLcd.h"
23+
#include "../i2c/drivers/drvOutQuadAlphaNum.h"
24+
#include "../i2c/drivers/drvOutSh1107.h"
25+
#include "../i2c/drivers/drvOutSsd1306.h"
2026
#ifdef ARDUINO_ADAFRUIT_QUALIA_S3_RGB666
2127
#include "drivers/dispDrvRgb666.h"
2228
#endif
@@ -53,6 +59,7 @@ class DisplayHardware {
5359
bool beginSpiTft(ws_display_Add *msg);
5460
bool beginSpiEpd(ws_display_Add *msg);
5561
bool beginTtlRgb666(ws_display_Add *msg);
62+
bool beginI2cDisplay(ws_display_Add *msg);
5663
int16_t parsePin(const char *pinStr);
5764

5865
// EPD auto-detection helpers

src/wippersnapper.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ class wippersnapper {
258258
AnalogIOController *analogio_controller =
259259
nullptr; ///< Instance of AnalogIO controller
260260
DisplayController *_display_controller =
261-
nullptr; ///< Instance of Display controller
261+
nullptr; ///< Instance of Display controller
262262
DS18X20Controller *_ds18x20_controller =
263263
nullptr; ///< Instance of DS18X20 controller
264264
GPSController *_gps_controller = nullptr; ///< Instance of GPS controller

0 commit comments

Comments
 (0)