diff --git a/firmware/platformio.ini b/firmware/platformio.ini index 560cbd3..1c25ca8 100644 --- a/firmware/platformio.ini +++ b/firmware/platformio.ini @@ -170,7 +170,7 @@ build_flags = -DLV_USE_SNAPSHOT=0 lib_deps = - ; 1.6.4+ required for Arduino_SH8601 (this board uses SH8601, not CO5300) + ; this board uses the CO5300 (same controller as the S3 2.16); Arduino_CO5300 moononournation/GFX Library for Arduino@^1.6.4 lewisxhe/SensorLib@^0.2.6 lewisxhe/XPowersLib@^0.2.7 diff --git a/firmware/src/boards/waveshare_amoled_216_c6/board.h b/firmware/src/boards/waveshare_amoled_216_c6/board.h index 2a94676..2fc5750 100644 --- a/firmware/src/boards/waveshare_amoled_216_c6/board.h +++ b/firmware/src/boards/waveshare_amoled_216_c6/board.h @@ -3,9 +3,9 @@ // Waveshare ESP32-C6-Touch-AMOLED-2.16. // // Despite the matching "2.16" model number, this board is hardware- -// distinct from the S3 AMOLED-2.16: it uses an SH8601 panel (same driver -// family as the AMOLED-1.8), a CST9217 touch controller, and the C6 SoC's -// own GPIO map. There is no PSRAM. AXP2101 PMU and QMI8658 IMU carry over. +// distinct from the S3 AMOLED-2.16: it shares the CO5300 panel controller +// but uses a CST9217 touch controller and the C6 SoC's own GPIO map. There +// is no PSRAM. AXP2101 PMU and QMI8658 IMU carry over. // // Pin assignments verified against the official Waveshare XiaoZhi BSP at // waveshareteam/ESP32-C6-Touch-AMOLED-2.16 (XiaoZhi config.h) and the @@ -16,14 +16,14 @@ #define LCD_WIDTH 480 #define LCD_HEIGHT 480 -// ---- QSPI display pins (SH8601) ---- +// ---- QSPI display pins (CO5300) ---- #define LCD_CS 15 #define LCD_SCLK 0 #define LCD_SDIO0 1 #define LCD_SDIO1 2 #define LCD_SDIO2 3 #define LCD_SDIO3 4 -// LCD reset is not wired to a MCU GPIO on this board — the SH8601 relies +// LCD reset is not wired to a MCU GPIO on this board — the CO5300 relies // on its internal power-on reset. The Arduino_GFX driver gets // GFX_NOT_DEFINED for reset. diff --git a/firmware/src/boards/waveshare_amoled_216_c6/display.cpp b/firmware/src/boards/waveshare_amoled_216_c6/display.cpp index dfdc9ee..f2c3e53 100644 --- a/firmware/src/boards/waveshare_amoled_216_c6/display.cpp +++ b/firmware/src/boards/waveshare_amoled_216_c6/display.cpp @@ -3,49 +3,52 @@ #include #include -// C6 AMOLED-2.16 uses an SH8601 panel — same driver family as the -// AMOLED-1.8 port. LCD reset is not wired to any MCU GPIO; the SH8601 -// boots from its internal POR. Rotation is disabled (no PSRAM headroom -// for the strip buffer). +// C6 AMOLED-2.16 uses a CO5300 AMOLED panel (per the Waveshare +// ESP32-C6-Touch-AMOLED-2.16 spec) — the same controller as the S3 +// AMOLED-2.16 sibling, so we drive it with Arduino_CO5300 and reuse that +// class's vendor-correct init rather than the SH8601 class + a hand-patched +// sequence. LCD reset is not wired to any MCU GPIO; the panel boots from its +// internal power-on reset (rst = GFX_NOT_DEFINED). Rotation is disabled (no +// PSRAM headroom for a rotation strip). static Arduino_DataBus* bus = nullptr; -static Arduino_SH8601* gfx = nullptr; +static Arduino_CO5300* gfx = nullptr; void display_hal_init(void) { bus = new Arduino_ESP32QSPI( LCD_CS, LCD_SCLK, LCD_SDIO0, LCD_SDIO1, LCD_SDIO2, LCD_SDIO3); - gfx = new Arduino_SH8601( - bus, GFX_NOT_DEFINED, 0, LCD_WIDTH, LCD_HEIGHT); + // CO5300 constructor: (bus, rst, rotation, w, h, col_off1..2, row_off1..2). + // No reset GPIO on this board; the 480-wide panel is full-width so all + // offsets are 0 — matches the S3 AMOLED-2.16 instantiation. + gfx = new Arduino_CO5300( + bus, GFX_NOT_DEFINED, 0 /* rotation disabled */, + LCD_WIDTH, LCD_HEIGHT, 0, 0, 0, 0); } -// Vendor-specific init commands from the Waveshare C6-2.16 BSP -// (02_Example/Arduino-v3.3.3/09_LVGL_V9_Test/bsp_lvgl_port.cpp in the -// waveshareteam/ESP32-C6-Touch-AMOLED-2.16 repo). The stock Arduino_GFX -// SH8601 init does SLPOUT + NORON + INVOFF + PIXFMT + DISPON + brightness, -// which is enough for the AMOLED-1.8 panel but leaves this 2.16 panel -// dark. The page-switch sequence (0xFE 0x20 ... 0xFE 0x00) writes two -// panel-specific manufacturer registers (0x19 and 0x1C) that gate the -// driving voltages — without them the panel stays black even with the -// rails up and the reset pulse applied. -static void send_vendor_init(Arduino_DataBus* b) { +// Arduino_CO5300::begin() already issues SLPOUT, SPI-mode control, pixel +// format, brightness-control, DISPON and a default MADCTL. The ONLY thing it +// does not set is this panel's manufacturer page-0x20 driving-voltage +// registers (0x19/0x1C) — without them the panel stays black even with the +// rails up. Set just those; everything else the SH8601-era hack also wrote +// (0xC4/0x36/0x53/0x51/0x63/0x29) is now covered by the class init. +// +// Note: we deliberately do NOT restore the old MADCTL 0x30 (MV transpose). +// The CO5300 class default (rotation-0, MADCTL 0x00) orients the panel with +// the USB port on the side, which is the preferred desk orientation for this +// board. +static void send_panel_driving_init(Arduino_DataBus* b) { b->beginWrite(); b->writeC8D8(0xFE, 0x20); // enter manufacturer command page 0x20 - b->writeC8D8(0x19, 0x10); // panel driving - b->writeC8D8(0x1C, 0xA0); // panel driving + b->writeC8D8(0x19, 0x10); // panel driving voltage + b->writeC8D8(0x1C, 0xA0); // panel driving voltage b->writeC8D8(0xFE, 0x00); // back to user command page - b->writeC8D8(0xC4, 0x80); // SPI mode control - b->writeC8D8(0x36, 0x30); // MADCTL (BSP value) - b->writeC8D8(0x53, 0x20); // CTRL display 1 (brightness control on) - b->writeC8D8(0x51, 0xFF); // brightness = max - b->writeC8D8(0x63, 0xFF); // HBM brightness = max - b->writeCommand(0x29); // DISPON (idempotent — stock init already did this) b->endWrite(); delay(20); } void display_hal_begin(void) { gfx->begin(); - send_vendor_init(bus); // patch up panel-specific regs the stock init misses + send_panel_driving_init(bus); // panel-specific regs the class init omits gfx->fillScreen(0x0000); gfx->setBrightness(200); } @@ -67,8 +70,7 @@ void display_hal_tick(void) { // No rotation cycle on this board. } -// Mirrors the CO5300/SH8601 even-alignment pattern from the other ports. -// Harmless on SH8601, kept for consistency. +// CO5300 requires even-aligned flush regions. void display_hal_round_area(int32_t* x1, int32_t* y1, int32_t* x2, int32_t* y2) { *x1 = *x1 & ~1; *y1 = *y1 & ~1; diff --git a/firmware/src/boards/waveshare_amoled_216_c6/touch.cpp b/firmware/src/boards/waveshare_amoled_216_c6/touch.cpp index 8fdeef2..02efd22 100644 --- a/firmware/src/boards/waveshare_amoled_216_c6/touch.cpp +++ b/firmware/src/boards/waveshare_amoled_216_c6/touch.cpp @@ -22,11 +22,16 @@ void touch_hal_init(void) { return; } touch.setMaxCoordinates(LCD_WIDTH, LCD_HEIGHT); - // C6 2.16 panel mapping (verified empirically): the CST9217's raw - // axes are swapped relative to the SH8601 raster AND X is mirrored. - // Matches the Waveshare BSP, which reads y = raw_byte1, x = W - raw_byte2. - touch.setSwapXY(true); - touch.setMirrorXY(true, false); + // C6 2.16 panel mapping. The original values (swap=true, mirrorX=true) + // were calibrated to the old display orientation that force-wrote MADCTL + // 0x30 (MV transpose + ML). The display now runs at the CO5300 class + // default (MADCTL 0x00 — USB-port-on-the-side orientation), so the touch + // mapping is re-derived to match. SensorLib applies swap then mirror + // (TouchDrvInterface::updateXY); tap-tested on C6 hardware, the raw + // CST9217 coordinates map straight through in this orientation — no swap, + // no mirror. + touch.setSwapXY(false); + touch.setMirrorXY(false, false); pinMode(TP_INT, INPUT_PULLUP); attachInterrupt(TP_INT, touch_isr, FALLING); Serial.println("Touch init OK");