Преглед изворни кода

Add GDEY075T7 (7.5" 800x480 mono, UC8179); define PROGMEM in the spy shim

GDEY075T7 is the 800x480 big brother of the GDEQ0583T31 - same UC8179
controller, captured clean from the stock GxEPD2_750_GDEY075T7 driver
(single region, 1bpp): identical 0x91/0x90/0x92 window bracketing, 0x13
plane write, and the UC8179 re-init-before-refresh quirk. busy_timeout_ms
set to 20000 (generous ceiling; vendor full_refresh_time is 1200ms), same
style as the 583. Wired into display.py PANELS (structural, pending bench)
and included by gxepd2_display.h. check_descriptors: MATCH.

Capturing it first needed a host-shim fix: the spy Arduino.h never defined
PROGMEM, so this driver's partial-refresh LUT tables
(`const unsigned char Cls::lut[] PROGMEM = {...}`) failed to compile. Define
PROGMEM as empty on the host - correct (no PROGMEM distinction off-AVR) and
unblocks capturing any driver that uses it on out-of-class array defs.
ZiB пре 3 недеља
родитељ
комит
f502ba3b63

+ 1 - 0
components/gxepd2/display.py

@@ -65,6 +65,7 @@ PANELS = {
     "GxEPD2_213c_GDEY0213F52": Panel("PANEL_213C_GDEY0213F52", "GDEY0213F52", "JD79676", "4-color", "verified"),
     "GxEPD2_426_GDEQ0426T82": Panel("PANEL_426_GDEQ0426T82", "GDEQ0426T82", "SSD1677", "mono", "verified"),
     "GxEPD2_583_GDEQ0583T31": Panel("PANEL_583_GDEQ0583T31", "GDEQ0583T31", "UC8179", "mono", "verified"),
+    "GxEPD2_750_GDEY075T7": Panel("PANEL_750_GDEY075T7", "GDEY075T7", "UC8179", "mono", "structural"),
     "GxEPD2_290c_GDEY029F51": Panel("PANEL_290C_GDEY029F51", "GDEY029F51", "JD79667", "4-color", "structural"),
     "GxEPD2_579c_GDEY0579F51": Panel("PANEL_579C_GDEY0579F51", "GDEY0579F51", "HX8717", "4-color", "verified"),
     # Diagnostic variant: the 396x272 master region as a self-contained panel.

+ 1 - 0
components/gxepd2/gxepd2_display.h

@@ -14,6 +14,7 @@
 #include "panel_579c_gdey0579f51.h"
 #include "panel_579c_gdey0579f51_master_only.h"
 #include "panel_583_gdeq0583t31.h"
+#include "panel_750_gdey075t7.h"
 
 namespace esphome::gxepd2 {
 

+ 97 - 0
components/gxepd2/panel_750_gdey075t7.h

@@ -0,0 +1,97 @@
+#pragma once
+
+// GDEY075T7 - 7.5" 800x480 mono, UC8179 (GD7965). Captured clean from the
+// stock GxEPD2_750_GDEY075T7 driver (single region, 1bpp, no hand-assembly).
+// Same controller family as GDEQ0583T31 (panel_583_gdeq0583t31.h), and it
+// shows: identical 0x90 window bracketed by 0x91 "partial in" / 0x92
+// "partial out", 0x13 plane write, and a full _InitDisplay() re-run before
+// the 0x12 refresh trigger on every cycle (the UC8179 "double-init" quirk) -
+// so 0x91+0x90 sit in window_sequence and 0x92 + the re-init + 0x12 make up
+// refresh_sequence, exactly as on the 583.
+
+#include "epd_command.h"
+
+namespace esphome::gxepd2 {
+
+inline const uint8_t PANEL_750_GDEY075T7_INIT_0_00[] = {0x1F};
+inline const uint8_t PANEL_750_GDEY075T7_INIT_1_01[] = {0x07, 0x07, 0x3F, 0x3F, 0x09};
+inline const uint8_t PANEL_750_GDEY075T7_INIT_2_06[] = {0x17, 0x17, 0x28, 0x17};
+inline const uint8_t PANEL_750_GDEY075T7_INIT_3_61[] = {0x03, 0x20, 0x01, 0xE0};  // TRES 800x480
+inline const uint8_t PANEL_750_GDEY075T7_INIT_4_15[] = {0x00};
+inline const uint8_t PANEL_750_GDEY075T7_INIT_5_50[] = {0x29, 0x07};
+inline const uint8_t PANEL_750_GDEY075T7_INIT_6_60[] = {0x22};
+inline const uint8_t PANEL_750_GDEY075T7_INIT_7_E3[] = {0x22};
+inline const uint8_t PANEL_750_GDEY075T7_INIT_8_E0[] = {0x02};
+inline const uint8_t PANEL_750_GDEY075T7_INIT_9_E5[] = {0x6E};
+
+inline const EpdCommand PANEL_750_GDEY075T7_INIT[] = {
+    {0x00, PANEL_750_GDEY075T7_INIT_0_00, 1},
+    {0x01, PANEL_750_GDEY075T7_INIT_1_01, 5},
+    {0x06, PANEL_750_GDEY075T7_INIT_2_06, 4},
+    {0x61, PANEL_750_GDEY075T7_INIT_3_61, 4},
+    {0x15, PANEL_750_GDEY075T7_INIT_4_15, 1},
+    {0x50, PANEL_750_GDEY075T7_INIT_5_50, 2},
+    {0x60, PANEL_750_GDEY075T7_INIT_6_60, 1},
+    {0xE3, PANEL_750_GDEY075T7_INIT_7_E3, 1},
+    {0xE0, PANEL_750_GDEY075T7_INIT_8_E0, 1},
+    {0xE5, PANEL_750_GDEY075T7_INIT_9_E5, 1},
+    {0x04, nullptr, 0, /*delay_before_ms=*/0, /*delay_after_ms=*/0, /*wait_busy_after=*/true},  // power on
+};
+
+// 0x91 "partial in" then 0x90 window (x 0..799, y 0..479, full frame).
+inline const uint8_t PANEL_750_GDEY075T7_WINDOW_REGION[] = {0x00, 0x00, 0x03, 0x1F, 0x00, 0x00, 0x01, 0xDF, 0x01};
+
+inline const EpdCommand PANEL_750_GDEY075T7_WINDOW[] = {
+    {0x91, nullptr, 0},
+    {0x90, PANEL_750_GDEY075T7_WINDOW_REGION, 9},
+};
+
+// 0x92 "partial out" closes the window the plane burst wrote, then the
+// driver re-runs its whole init (UC8179 double-init) with TSSET=0x5A before
+// the 0x12 refresh trigger.
+inline const uint8_t PANEL_750_GDEY075T7_REFRESH_1_00[] = {0x1F};
+inline const uint8_t PANEL_750_GDEY075T7_REFRESH_2_01[] = {0x07, 0x07, 0x3F, 0x3F, 0x09};
+inline const uint8_t PANEL_750_GDEY075T7_REFRESH_3_06[] = {0x17, 0x17, 0x28, 0x17};
+inline const uint8_t PANEL_750_GDEY075T7_REFRESH_4_61[] = {0x03, 0x20, 0x01, 0xE0};
+inline const uint8_t PANEL_750_GDEY075T7_REFRESH_5_15[] = {0x00};
+inline const uint8_t PANEL_750_GDEY075T7_REFRESH_6_50[] = {0x29, 0x07};
+inline const uint8_t PANEL_750_GDEY075T7_REFRESH_7_60[] = {0x22};
+inline const uint8_t PANEL_750_GDEY075T7_REFRESH_8_E3[] = {0x22};
+inline const uint8_t PANEL_750_GDEY075T7_REFRESH_9_00[] = {0x1F};
+inline const uint8_t PANEL_750_GDEY075T7_REFRESH_10_E0[] = {0x02};
+inline const uint8_t PANEL_750_GDEY075T7_REFRESH_11_E5[] = {0x5A};  // TSSET before refresh
+
+inline const EpdCommand PANEL_750_GDEY075T7_REFRESH[] = {
+    {0x92, nullptr, 0, /*delay_before_ms=*/0, /*delay_after_ms=*/1, /*wait_busy_after=*/false},
+    {0x00, PANEL_750_GDEY075T7_REFRESH_1_00, 1},
+    {0x01, PANEL_750_GDEY075T7_REFRESH_2_01, 5},
+    {0x06, PANEL_750_GDEY075T7_REFRESH_3_06, 4},
+    {0x61, PANEL_750_GDEY075T7_REFRESH_4_61, 4},
+    {0x15, PANEL_750_GDEY075T7_REFRESH_5_15, 1},
+    {0x50, PANEL_750_GDEY075T7_REFRESH_6_50, 2},
+    {0x60, PANEL_750_GDEY075T7_REFRESH_7_60, 1},
+    {0xE3, PANEL_750_GDEY075T7_REFRESH_8_E3, 1},
+    {0x00, PANEL_750_GDEY075T7_REFRESH_9_00, 1},
+    {0xE0, PANEL_750_GDEY075T7_REFRESH_10_E0, 1},
+    {0xE5, PANEL_750_GDEY075T7_REFRESH_11_E5, 1},
+    {0x12, nullptr, 0, /*delay_before_ms=*/0, /*delay_after_ms=*/0, /*wait_busy_after=*/true},  // display refresh
+};
+
+inline const EpdPanelDescriptor PANEL_750_GDEY075T7 = {
+    .width = 800,
+    .height = 480,
+    .busy_active_level = false,  // GxEPD2_EPD(..., /*busy_level=*/LOW, ...)
+    .busy_timeout_ms = 20000,    // full_refresh_time is 1200ms; generous ceiling, same style as the 583
+    .init_sequence = PANEL_750_GDEY075T7_INIT,
+    .init_sequence_len = sizeof(PANEL_750_GDEY075T7_INIT) / sizeof(PANEL_750_GDEY075T7_INIT[0]),
+    .window_sequence = {PANEL_750_GDEY075T7_WINDOW, nullptr},
+    .window_sequence_len = {sizeof(PANEL_750_GDEY075T7_WINDOW) / sizeof(PANEL_750_GDEY075T7_WINDOW[0]), 0},
+    .plane_count = 1,
+    .plane_write_cmd = {0x13, 0x00},
+    .plane_invert = {false, false},
+    .bits_per_pixel = 1,
+    .refresh_sequence = PANEL_750_GDEY075T7_REFRESH,
+    .refresh_sequence_len = sizeof(PANEL_750_GDEY075T7_REFRESH) / sizeof(PANEL_750_GDEY075T7_REFRESH[0]),
+};
+
+}  // namespace esphome::gxepd2

+ 6 - 0
tools/gxepd2_harness/spy/Arduino.h

@@ -42,6 +42,12 @@ inline void yield() {}
 
 #define pgm_read_byte(addr) (*reinterpret_cast<const uint8_t *>(addr))
 
+// No PROGMEM distinction on a dev machine - expands to nothing, so vendor
+// definitions like `const unsigned char Cls::lut[] PROGMEM = {...}` (used by
+// the partial-refresh LUT tables in several drivers, e.g. GDEY075T7) compile
+// host-side. Harmless for drivers that don't use it.
+#define PROGMEM
+
 // GxEPD2_EPD::_waitWhileBusy()'s diagnostic prints (opt-in, never enabled
 // here since the harness passes serial_diag_bitrate=0 to init()) and the
 // unconditional "Busy Timeout!" warning both go through this - harmless to