|
@@ -3,22 +3,28 @@
|
|
|
// GDEY0579F51 - HX8717 dual-chip, 792x272, 4-color, 2bpp packed (same
|
|
// GDEY0579F51 - HX8717 dual-chip, 792x272, 4-color, 2bpp packed (same
|
|
|
// JD79667-family packing as GDEY029F51, see panel_290c_gdey029f51.h).
|
|
// JD79667-family packing as GDEY029F51, see panel_290c_gdey029f51.h).
|
|
|
//
|
|
//
|
|
|
-// Captured from the STOCK vendored driver
|
|
|
|
|
-// (third_party/GxEPD2/src/epd4c/GxEPD2_579c_GDEY0579F51.{h,cpp}) and kept
|
|
|
|
|
-// byte-for-byte stock EXCEPT the PSR source-scan bytes (see PSR_MASTER/
|
|
|
|
|
-// PSR_SLAVE below) - those are swapped to Waveshare's orientation because
|
|
|
|
|
-// the stock values render this panel left-right mirrored on hardware.
|
|
|
|
|
|
|
+// Faithful replay of the STOCK vendored driver
|
|
|
|
|
+// (third_party/GxEPD2/src/epd4c/GxEPD2_579c_GDEY0579F51.{h,cpp}): init, PSR,
|
|
|
|
|
+// BTST, window, refresh, master/slave split and plane order all match
|
|
|
|
|
+// GxEPD2's own on-wire behaviour. The only non-default engine setting is
|
|
|
|
|
+// line_order = PAIRED_EDGES, which reproduces GxEPD2 writeNative's doubled,
|
|
|
|
|
+// both-edges-to-middle line emission (544 lines/region) - a general engine
|
|
|
|
|
+// mechanism, not a panel hack. The user confirmed GxEPD2 itself drives this
|
|
|
|
|
+// panel correctly when run natively, so a byte-faithful replay is correct by
|
|
|
|
|
+// construction.
|
|
|
//
|
|
//
|
|
|
-// History worth not repeating: an earlier revision carried a pile of
|
|
|
|
|
-// hand-"fixes" from Waveshare's epd5in79g.cpp - swapped PSR, power-on under
|
|
|
|
|
-// select=Both, a changed BTST - all introduced together to chase mirrored
|
|
|
|
|
-// text AND a slave region that never converged. The bench (2026-10-18)
|
|
|
|
|
-// separated the two: the non-convergence was DRIVE-CURRENT STARVATION on
|
|
|
|
|
-// the bench MCU (not a driver bug - the same panel + firmware renders on an
|
|
|
|
|
-// adequately-powered board), so power-on-select and BTST were red herrings
|
|
|
|
|
-// and are back to stock here; only the PSR scan-direction swap was doing
|
|
|
|
|
-// real work (fixing the mirror) and is kept. Window + refresh are the fresh
|
|
|
|
|
-// capture, unchanged.
|
|
|
|
|
|
|
+// History worth not repeating: an earlier revision carried hand-"fixes" from
|
|
|
|
|
+// Waveshare's epd5in79g.cpp (swapped PSR, power-on under select=Both, changed
|
|
|
|
|
+// BTST) plus, on 2026-10-18, a PSR scan-direction swap + window-order swap to
|
|
|
|
|
+// chase a left-right mirror and swapped halves. The bench showed those were
|
|
|
|
|
+// ALL compensating for two separate real issues, neither a driver bug:
|
|
|
|
|
+// - the "slave never converges" symptom was DRIVE-CURRENT STARVATION on the
|
|
|
|
|
+// bench MCU (same panel + firmware renders on an adequately-powered
|
|
|
|
|
+// board), so power-on-select and BTST are back to stock;
|
|
|
|
|
+// - the mirror + swapped halves were the engine sending ONE line per row
|
|
|
|
|
+// where GxEPD2 sends TWO (line_order below), so the PSR/window swaps are
|
|
|
|
|
+// gone too.
|
|
|
|
|
+// Only busy_timeout_ms is tuned (engine hard-aborts where GxEPD2 polls on).
|
|
|
//
|
|
//
|
|
|
// Dual-region layer assembled by hand from the driver source, per
|
|
// Dual-region layer assembled by hand from the driver source, per
|
|
|
// CONTRIBUTING.md "Limits - True dual-region command structure": the
|
|
// CONTRIBUTING.md "Limits - True dual-region command structure": the
|
|
@@ -42,16 +48,14 @@ namespace esphome::gxepd2 {
|
|
|
inline const uint8_t PANEL_579C_GDEY0579F51_SELECT_MASTER[] = {0x01};
|
|
inline const uint8_t PANEL_579C_GDEY0579F51_SELECT_MASTER[] = {0x01};
|
|
|
inline const uint8_t PANEL_579C_GDEY0579F51_SELECT_SLAVE[] = {0x02};
|
|
inline const uint8_t PANEL_579C_GDEY0579F51_SELECT_SLAVE[] = {0x02};
|
|
|
inline const uint8_t PANEL_579C_GDEY0579F51_SELECT_BOTH[] = {0x00};
|
|
inline const uint8_t PANEL_579C_GDEY0579F51_SELECT_BOTH[] = {0x00};
|
|
|
-// PSR source-scan (SHL) bytes are the ONE deviation from the stock driver:
|
|
|
|
|
-// stock is master {0x07,0x29} / slave {0x03,0x29}, which renders this panel
|
|
|
|
|
-// left-right MIRRORED (text backwards) on hardware. The two values differ
|
|
|
|
|
-// only in the source-scan-direction bit; swapping which half gets it (the
|
|
|
|
|
-// value Waveshare's epd5in79g.cpp uses) un-mirrors it - confirmed on the
|
|
|
|
|
-// bench 2026-10-18. This is a real per-panel orientation fix and is
|
|
|
|
|
-// unrelated to the drive-current issue that explained the old "slave won't
|
|
|
|
|
-// converge" symptom; everything else here stays stock.
|
|
|
|
|
-inline const uint8_t PANEL_579C_GDEY0579F51_PSR_MASTER[] = {0x03, 0x29};
|
|
|
|
|
-inline const uint8_t PANEL_579C_GDEY0579F51_PSR_SLAVE[] = {0x07, 0x29};
|
|
|
|
|
|
|
+// Stock PSR values, matching GxEPD2's _InitDisplay() exactly: master
|
|
|
|
|
+// {0x07,0x29}, slave {0x03,0x29}. (A brief detour on 2026-10-18 swapped
|
|
|
|
|
+// these to "fix" a left-right mirror, but the mirror was an artifact of the
|
|
|
|
|
+// engine sending one line per row instead of GxEPD2's two - see line_order
|
|
|
|
|
+// below. With the line order faithful, the stock PSR is correct and the
|
|
|
|
|
+// swap is gone.)
|
|
|
|
|
+inline const uint8_t PANEL_579C_GDEY0579F51_PSR_MASTER[] = {0x07, 0x29};
|
|
|
|
|
+inline const uint8_t PANEL_579C_GDEY0579F51_PSR_SLAVE[] = {0x03, 0x29};
|
|
|
inline const uint8_t PANEL_579C_GDEY0579F51_BTST[] = {0x32, 0x32, 0x32, 0x32};
|
|
inline const uint8_t PANEL_579C_GDEY0579F51_BTST[] = {0x32, 0x32, 0x32, 0x32};
|
|
|
inline const uint8_t PANEL_579C_GDEY0579F51_TRES[] = {0x01, 0x8C, 0x01, 0x10}; // 396x272 - one region
|
|
inline const uint8_t PANEL_579C_GDEY0579F51_TRES[] = {0x01, 0x8C, 0x01, 0x10}; // 396x272 - one region
|
|
|
inline const uint8_t PANEL_579C_GDEY0579F51_CDI_INIT[] = {0x97}; // border white
|
|
inline const uint8_t PANEL_579C_GDEY0579F51_CDI_INIT[] = {0x97}; // border white
|
|
@@ -119,22 +123,25 @@ inline const EpdPanelDescriptor PANEL_579C_GDEY0579F51 = {
|
|
|
// the engine hard-aborts
|
|
// the engine hard-aborts
|
|
|
.init_sequence = PANEL_579C_GDEY0579F51_INIT,
|
|
.init_sequence = PANEL_579C_GDEY0579F51_INIT,
|
|
|
.init_sequence_len = sizeof(PANEL_579C_GDEY0579F51_INIT) / sizeof(PANEL_579C_GDEY0579F51_INIT[0]),
|
|
.init_sequence_len = sizeof(PANEL_579C_GDEY0579F51_INIT) / sizeof(PANEL_579C_GDEY0579F51_INIT[0]),
|
|
|
- // plane 0 is the LEFT half of the canvas (draw_packed_ splits at
|
|
|
|
|
- // plane_width), plane 1 the RIGHT half. With the swapped PSR scan
|
|
|
|
|
- // direction, chip 0x02 (slave) drives the left of the glass and chip
|
|
|
|
|
- // 0x01 (master) the right, so route plane 0 -> slave-select window and
|
|
|
|
|
- // plane 1 -> master-select. Sending them in physical-chip order instead
|
|
|
|
|
- // put the left half on the right of the panel and vice versa
|
|
|
|
|
- // (bench-observed 2026-10-18).
|
|
|
|
|
- .window_sequence = {PANEL_579C_GDEY0579F51_WINDOW_SLAVE, PANEL_579C_GDEY0579F51_WINDOW_MASTER},
|
|
|
|
|
- .window_sequence_len = {sizeof(PANEL_579C_GDEY0579F51_WINDOW_SLAVE) / sizeof(PANEL_579C_GDEY0579F51_WINDOW_SLAVE[0]),
|
|
|
|
|
- sizeof(PANEL_579C_GDEY0579F51_WINDOW_MASTER) / sizeof(PANEL_579C_GDEY0579F51_WINDOW_MASTER[0])},
|
|
|
|
|
|
|
+ // plane 0 = LEFT canvas half -> master (chip 0x01), plane 1 = RIGHT half
|
|
|
|
|
+ // -> slave (chip 0x02), matching GxEPD2 writeNative's MasterSide/SlaveSide
|
|
|
|
|
+ // split (left<WIDTH/2 -> master). (The 2026-10-18 detour swapped this to
|
|
|
|
|
+ // compensate for the one-line-per-row bug; with line_order faithful it's
|
|
|
|
|
+ // back to GxEPD2's own order.)
|
|
|
|
|
+ .window_sequence = {PANEL_579C_GDEY0579F51_WINDOW_MASTER, PANEL_579C_GDEY0579F51_WINDOW_SLAVE},
|
|
|
|
|
+ .window_sequence_len = {sizeof(PANEL_579C_GDEY0579F51_WINDOW_MASTER) / sizeof(PANEL_579C_GDEY0579F51_WINDOW_MASTER[0]),
|
|
|
|
|
+ sizeof(PANEL_579C_GDEY0579F51_WINDOW_SLAVE) / sizeof(PANEL_579C_GDEY0579F51_WINDOW_SLAVE[0])},
|
|
|
.window_per_plane = true,
|
|
.window_per_plane = true,
|
|
|
- .plane_count = 2, // plane 0 = left half -> chip 0x02; plane 1 = right half -> chip 0x01
|
|
|
|
|
|
|
+ .plane_count = 2, // plane 0 = left half -> chip 0x01 (master); plane 1 = right half -> chip 0x02 (slave)
|
|
|
.plane_write_cmd = {0x10, 0x10},
|
|
.plane_write_cmd = {0x10, 0x10},
|
|
|
.plane_invert = {false, false},
|
|
.plane_invert = {false, false},
|
|
|
.plane_width = 396, // each region's own local width
|
|
.plane_width = 396, // each region's own local width
|
|
|
- .row_interleave = true,
|
|
|
|
|
|
|
+ // GxEPD2 writeNative sends each region as 544 lines (2x272) in paired
|
|
|
|
|
+ // top/bottom-from-edges order, filling a 2x-height RAM - reproduce that
|
|
|
|
|
+ // exactly rather than one line per row. This is what makes the stock PSR
|
|
|
|
|
+ // and window order render correctly; the earlier swaps were compensating
|
|
|
|
|
+ // for not doing it.
|
|
|
|
|
+ .line_order = LineOrder::PAIRED_EDGES,
|
|
|
.bits_per_pixel = 2,
|
|
.bits_per_pixel = 2,
|
|
|
.palette = GXEPD2_PALETTE_4C,
|
|
.palette = GXEPD2_PALETTE_4C,
|
|
|
.palette_len = GXEPD2_PALETTE_4C_LEN,
|
|
.palette_len = GXEPD2_PALETTE_4C_LEN,
|