Просмотр исходного кода

Add GDEY0213F51 4-color panel descriptor

128x250 4-color (JD79661), hand-derived from the vendor driver. Shares the
Good Display 4-color command template with panel_290c_gdey029f51 (the init
sequence is identical except TRES), so it's the 290c descriptor retargeted
to 128x250 with the window Y-end adjusted. Wired into MODELS as
GxEPD2_213c_GDEY0213F51 (label 0213F51).

Note: bench hardware is marked GDEY0213F52 (a V2 revision on a different
controller); this F51 descriptor is a starting point for it, not confirmed
on that part yet.
ZiB 3 недель назад
Родитель
Сommit
d4134a202b

+ 1 - 0
components/gxepd2/display.py

@@ -60,6 +60,7 @@ GxEPD2Display = gxepd2_ns.class_("GxEPD2Display", display.DisplayBuffer)
 # GDEY0213Z98 - so the class name alone can't reconstruct what's on the tag.
 MODELS = {
     "GxEPD2_213_Z98C": ("PANEL_213_Z98C", "GDEY0213Z98"),
+    "GxEPD2_213c_GDEY0213F51": ("PANEL_213C_GDEY0213F51", "GDEY0213F51"),
     "GxEPD2_426_GDEQ0426T82": ("PANEL_426_GDEQ0426T82", "GDEQ0426T82"),
     "GxEPD2_583_GDEQ0583T31": ("PANEL_583_GDEQ0583T31", "GDEQ0583T31"),
     "GxEPD2_290c_GDEY029F51": ("PANEL_290C_GDEY029F51", "GDEY029F51"),

+ 1 - 0
components/gxepd2/gxepd2_display.h

@@ -6,6 +6,7 @@
 #include "esphome/components/spi/spi.h"
 #include "cycle_engine.h"
 #include "panel_213_z98c.h"
+#include "panel_213c_gdey0213f51.h"
 #include "panel_290c_gdey029f51.h"
 #include "panel_426_gdeq0426t82.h"
 #include "panel_579c_gdey0579f51.h"

+ 105 - 0
components/gxepd2/panel_213c_gdey0213f51.h

@@ -0,0 +1,105 @@
+#pragma once
+
+// Hand-derived from vendor/src/epd4c/GxEPD2_213c_GDEY0213F51.{h,cpp}
+// (GDEY0213F51, JD79661 controller, 128x250 buffer / 122x250 visible,
+// 4-color BWRY). Same Good Display 4-color command template as
+// panel_290c_gdey029f51.h (JD79667) - the _InitDisplay() command sequence is
+// byte-for-byte identical except TRES (0x61, the resolution), so this is the
+// 290c descriptor retargeted to 128x250. See panel_290c_gdey029f51.h for the
+// per-command rationale (0x00 PSR / 0x01 PWRR / 0x03 POFS / 0x06 BTST / 0x50
+// CDI / 0x60 TCON / 0x61 TRES / 0x83 window-set / refresh via 0x50+0x12), and
+// GxEPD2Display::draw_packed_ for the 2bpp/4-pixels-per-byte buffer side.
+//
+// Pixel codes black=0x00, white=0x01, yellow=0x02, red=0x03 (GXEPD2_PALETTE_4C,
+// per GxEPD2_4C.h color4()); the vendor's own white clear writes 0x55 (code
+// 0x01 x4), confirming white=0x01. JD79661 vs JD79667 could in principle order
+// yellow/red differently - the bit-depth-aware test pattern's color bars will
+// show it directly if so, and only the palette codes would need swapping.
+//
+// NOTE: bench hardware is marked GDEY0213F52 (a V2 revision); this descriptor
+// is the F51 vendor driver, tried on F52 as a starting point pending a
+// datasheet/product-page diff. Same label (0213F52 vs 0213F51) aside, if the
+// F52 needs init tweaks they go in a separate descriptor.
+
+#include "epd_command.h"
+
+namespace esphome::gxepd2 {
+
+inline const uint8_t PANEL_213C_GDEY0213F51_CMD_4D[] = {0x78};
+inline const uint8_t PANEL_213C_GDEY0213F51_PSR[] = {0x0F, 0x29};
+inline const uint8_t PANEL_213C_GDEY0213F51_PWRR[] = {0x07, 0x00};
+inline const uint8_t PANEL_213C_GDEY0213F51_POFS[] = {0x10, 0x54, 0x44};
+inline const uint8_t PANEL_213C_GDEY0213F51_BTST[] = {0x05, 0x00, 0x3F, 0x0A, 0x25, 0x12, 0x1A};
+inline const uint8_t PANEL_213C_GDEY0213F51_CDI[] = {0x37};
+inline const uint8_t PANEL_213C_GDEY0213F51_TCON[] = {0x02, 0x02};
+inline const uint8_t PANEL_213C_GDEY0213F51_TRES[] = {0x00, 0x80, 0x00, 0xFA};  // WIDTH=128, HEIGHT=250
+inline const uint8_t PANEL_213C_GDEY0213F51_E7[] = {0x1C};
+inline const uint8_t PANEL_213C_GDEY0213F51_PWS[] = {0x22};
+inline const uint8_t PANEL_213C_GDEY0213F51_LVD[] = {0xD0};
+inline const uint8_t PANEL_213C_GDEY0213F51_B5[] = {0x03};
+inline const uint8_t PANEL_213C_GDEY0213F51_E9[] = {0x01};
+inline const uint8_t PANEL_213C_GDEY0213F51_PLL[] = {0x08};
+
+inline const EpdCommand PANEL_213C_GDEY0213F51_INIT[] = {
+    {0x4D, PANEL_213C_GDEY0213F51_CMD_4D, 1},
+    {0x00, PANEL_213C_GDEY0213F51_PSR, 2},
+    {0x01, PANEL_213C_GDEY0213F51_PWRR, 2},
+    {0x03, PANEL_213C_GDEY0213F51_POFS, 3},
+    {0x06, PANEL_213C_GDEY0213F51_BTST, 7},
+    {0x50, PANEL_213C_GDEY0213F51_CDI, 1},
+    {0x60, PANEL_213C_GDEY0213F51_TCON, 2},
+    {0x61, PANEL_213C_GDEY0213F51_TRES, 4},
+    {0xE7, PANEL_213C_GDEY0213F51_E7, 1},
+    {0xE3, PANEL_213C_GDEY0213F51_PWS, 1},
+    {0xB4, PANEL_213C_GDEY0213F51_LVD, 1},
+    {0xB5, PANEL_213C_GDEY0213F51_B5, 1},
+    {0xE9, PANEL_213C_GDEY0213F51_E9, 1},
+    {0x30, PANEL_213C_GDEY0213F51_PLL, 1},
+    {0x04, nullptr, 0, /*delay_before_ms=*/0, /*delay_after_ms=*/0, /*wait_busy_after=*/true},  // power on
+};
+
+// _setPartialRamArea(0, 0, 128, 250), default partial_mode=true.
+inline const uint8_t PANEL_213C_GDEY0213F51_WINDOW[] = {
+    0x00, 0x00,  // x/256, x%256   = 0
+    0x00, 0x7F,  // xe/256, xe%256 = 127
+    0x00, 0x00,  // y/256, y%256   = 0
+    0x00, 0xF9,  // ye/256, ye%256 = 249
+    0x01,
+};
+
+inline const EpdCommand PANEL_213C_GDEY0213F51_WINDOW_SEQ[] = {
+    {0x83, PANEL_213C_GDEY0213F51_WINDOW, 9},
+};
+
+// _refresh(false): 0x50=0x37 (white/non-floating border), then 0x12+delay(1)+
+// _waitWhileBusy - collapsed into one wait_busy_after.
+inline const uint8_t PANEL_213C_GDEY0213F51_CDI_REFRESH[] = {0x37};
+inline const uint8_t PANEL_213C_GDEY0213F51_REFRESH_TRIGGER[] = {0x00};
+
+inline const EpdCommand PANEL_213C_GDEY0213F51_REFRESH[] = {
+    {0x50, PANEL_213C_GDEY0213F51_CDI_REFRESH, 1},
+    {0x12, PANEL_213C_GDEY0213F51_REFRESH_TRIGGER, 1, /*delay_before_ms=*/0, /*delay_after_ms=*/0,
+     /*wait_busy_after=*/true},
+};
+
+inline const EpdPanelDescriptor PANEL_213C_GDEY0213F51 = {
+    .width = 128,
+    .height = 250,
+    .busy_active_level = false,  // GxEPD2_EPD(..., /*busy_level=*/LOW, ...)
+    .busy_timeout_ms = 30000,    // full_refresh_time is 25000ms
+    .init_sequence = PANEL_213C_GDEY0213F51_INIT,
+    .init_sequence_len = sizeof(PANEL_213C_GDEY0213F51_INIT) / sizeof(PANEL_213C_GDEY0213F51_INIT[0]),
+    .window_sequence = {PANEL_213C_GDEY0213F51_WINDOW_SEQ, nullptr},
+    .window_sequence_len = {sizeof(PANEL_213C_GDEY0213F51_WINDOW_SEQ) / sizeof(PANEL_213C_GDEY0213F51_WINDOW_SEQ[0]), 0},
+    .plane_count = 1,
+    .plane_write_cmd = {0x10, 0x00},
+    .plane_invert = {false, false},
+    .bits_per_pixel = 2,
+    .palette = GXEPD2_PALETTE_4C,
+    .palette_len = GXEPD2_PALETTE_4C_LEN,
+    .blank_code = 0x01,
+    .refresh_sequence = PANEL_213C_GDEY0213F51_REFRESH,
+    .refresh_sequence_len = sizeof(PANEL_213C_GDEY0213F51_REFRESH) / sizeof(PANEL_213C_GDEY0213F51_REFRESH[0]),
+};
+
+}  // namespace esphome::gxepd2