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

Roll back to stock GxEPD2 protocol values, keeping the real fix

Now that the actual bug (display.py never wiring the lambda to
set_writer()) is fixed and confirmed correct on real hardware, testing
whether this panel genuinely needs epaper_spi's deviations from GxEPD2's
vendor source, or whether the stock protocol was fine all along:

- SPI clock: 20MHz (was dropped to 10MHz)
- Display update control (0x21): {0x00, 0x80} (was {0x80, 0x80})
- Refresh sequence: single combined trigger 0x22/0xF7 + 0x20 (was
  bracketed with explicit power-on/off)

Keeping the red-plane bit-convention fix and the busy-pin polarity as-is -
those are per-panel/wiring facts GxEPD2's model doesn't track at all
(same category as busy_pin inversion), not protocol deviations to test.
ZiB 1 месяц назад
Родитель
Сommit
682235efa8
2 измененных файлов с 22 добавлено и 43 удалено
  1. 7 10
      components/gxepd2/cycle_engine.h
  2. 15 33
      components/gxepd2/panel_213_z98c.h

+ 7 - 10
components/gxepd2/cycle_engine.h

@@ -11,17 +11,14 @@
 
 
 namespace esphome::gxepd2 {
 namespace esphome::gxepd2 {
 
 
-// GxEPD2's vendor source specifies 20MHz for this panel, but the
-// known-working epaper_spi driver for this exact physical unit/wiring
-// (waveshare-2.13in-bv4) deliberately runs at 10MHz. Busy consistently
-// engaging and clearing at a normal duration while content still comes out
-// wrong (solid black, then solid red, now solid black again) is consistent
-// with signal integrity problems at too aggressive a clock corrupting what
-// actually lands in RAM, even though the controller still completes some
-// waveform. Matching the proven-working clock instead of GxEPD2's generic
-// spec value.
+// Stock GxEPD2 vendor value (20MHz) for this panel. Was dropped to 10MHz
+// (matching epaper_spi) while chasing the solid-black/solid-red symptom,
+// which turned out to be unrelated - display.py never wired the configured
+// lambda to set_writer() at all, so nothing but auto_clear's default fill
+// ever rendered, regardless of SPI clock. Rolled back to test the stock
+// GxEPD2 clock now that the real bug is fixed.
 using EpdSPIDevice = spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, spi::CLOCK_PHASE_LEADING,
 using EpdSPIDevice = spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, spi::CLOCK_PHASE_LEADING,
-                                     spi::DATA_RATE_10MHZ>;
+                                     spi::DATA_RATE_20MHZ>;
 
 
 // Mechanically replicates one GxEPD2 driver's refresh cycle - reset pulse,
 // Mechanically replicates one GxEPD2 driver's refresh cycle - reset pulse,
 // init command table, RAM-window set, per-plane byte burst, refresh
 // init command table, RAM-window set, per-plane byte burst, refresh

+ 15 - 33
components/gxepd2/panel_213_z98c.h

@@ -21,15 +21,14 @@ inline const uint8_t PANEL_213_Z98C_DRIVER_OUTPUT_CONTROL[] = {0xF9, 0x00, 0x00}
 inline const uint8_t PANEL_213_Z98C_DATA_ENTRY_MODE[] = {0x03};
 inline const uint8_t PANEL_213_Z98C_DATA_ENTRY_MODE[] = {0x03};
 inline const uint8_t PANEL_213_Z98C_BORDER_WAVEFORM[] = {0x05};
 inline const uint8_t PANEL_213_Z98C_BORDER_WAVEFORM[] = {0x05};
 inline const uint8_t PANEL_213_Z98C_TEMP_SENSOR[] = {0x80};
 inline const uint8_t PANEL_213_Z98C_TEMP_SENSOR[] = {0x80};
-// GxEPD2's vendor source sends {0x00, 0x80} here, but the whole panel came
-// out solid black regardless of RAM content with that value on real
-// hardware. The known-working epaper_spi driver on this exact same panel/
-// wiring (waveshare-2.13in-bv4, see device/epaper-nametag.yaml) sends
-// {0x80, 0x80} instead - this register controls per-plane RAM bypass
-// options, so a wrong bypass bit here would force a plane to a constant
-// value irrespective of what's actually written to it, matching the
-// symptom exactly.
-inline const uint8_t PANEL_213_Z98C_DISPLAY_UPDATE_CONTROL[] = {0x80, 0x80};
+// Stock GxEPD2 vendor value. Was swapped to {0x80, 0x80} (matching the
+// epaper_spi reference) while chasing the solid-black/solid-red hardware
+// symptom - that turned out to be an unrelated bug (display.py never
+// wired the configured lambda to set_writer() at all, so nothing but
+// auto_clear's default fill ever rendered). Rolled back now that the real
+// cause is fixed, to test whether the stock GxEPD2 protocol works as-is
+// on this panel or genuinely needs epaper_spi's deviations.
+inline const uint8_t PANEL_213_Z98C_DISPLAY_UPDATE_CONTROL[] = {0x00, 0x80};
 
 
 inline const EpdCommand PANEL_213_Z98C_INIT[] = {
 inline const EpdCommand PANEL_213_Z98C_INIT[] = {
     {0x12, nullptr, 0, /*delay_before_ms=*/10, /*delay_after_ms=*/10, /*wait_busy_after=*/false},  // SWRESET
     {0x12, nullptr, 0, /*delay_before_ms=*/10, /*delay_after_ms=*/10, /*wait_busy_after=*/false},  // SWRESET
@@ -40,35 +39,18 @@ inline const EpdCommand PANEL_213_Z98C_INIT[] = {
     {0x21, PANEL_213_Z98C_DISPLAY_UPDATE_CONTROL, 2},
     {0x21, PANEL_213_Z98C_DISPLAY_UPDATE_CONTROL, 2},
 };
 };
 
 
-// GxEPD2_213_Z98c::_Update_Full()/_Update_Part() fire a single combined
-// trigger (0x22/0xF7 + 0x20) and assume it handles power internally. That
-// matched neither hardware symptom we saw (solid black, then solid red) -
-// busy genuinely engaged and cleared each time, consistent with a waveform
-// that ran without properly stabilized power, not a hang. The known-working
-// epaper_spi driver for this exact panel instead brackets the refresh with
-// explicit power-on/off triggers, each with its own busy-wait, and resets
-// the RAM counters again immediately before the refresh trigger itself:
-//   POWER_ON (0x22/0xF8 + 0x20, wait busy)
-//   reset RAM counters (0x4E/0x4F back to 0,0)
-//   REFRESH  (0x22/0xF7 + 0x20, wait busy)
-//   POWER_OFF (0x22/0x83 + 0x20, wait busy)
-// Mirroring that sequence here since GxEPD2's shortcut is what's unproven
-// on this specific panel/FPC revision.
-inline const uint8_t PANEL_213_Z98C_POWER_ON_MODE[] = {0xF8};
+// GxEPD2_213_Z98c::_Update_Full()/_Update_Part() - stock vendor sequence,
+// a single combined trigger that assumes it handles power internally.
+// Bracketed this with explicit power-on/off (matching epaper_spi) while
+// chasing the solid-black/solid-red symptom, which turned out to be
+// unrelated (see PANEL_213_Z98C_DISPLAY_UPDATE_CONTROL's comment). Rolled
+// back to the stock single-trigger sequence to test it now that the real
+// bug is fixed.
 inline const uint8_t PANEL_213_Z98C_UPDATE_MODE[] = {0xF7};
 inline const uint8_t PANEL_213_Z98C_UPDATE_MODE[] = {0xF7};
-inline const uint8_t PANEL_213_Z98C_POWER_OFF_MODE[] = {0x83};
-inline const uint8_t PANEL_213_Z98C_RESET_X_COUNTER[] = {0x00};
-inline const uint8_t PANEL_213_Z98C_RESET_Y_COUNTER[] = {0x00, 0x00};
 
 
 inline const EpdCommand PANEL_213_Z98C_REFRESH[] = {
 inline const EpdCommand PANEL_213_Z98C_REFRESH[] = {
-    {0x22, PANEL_213_Z98C_POWER_ON_MODE, 1},
-    {0x20, nullptr, 0, /*delay_before_ms=*/0, /*delay_after_ms=*/0, /*wait_busy_after=*/true},
-    {0x4E, PANEL_213_Z98C_RESET_X_COUNTER, 1},
-    {0x4F, PANEL_213_Z98C_RESET_Y_COUNTER, 2},
     {0x22, PANEL_213_Z98C_UPDATE_MODE, 1},
     {0x22, PANEL_213_Z98C_UPDATE_MODE, 1},
     {0x20, nullptr, 0, /*delay_before_ms=*/0, /*delay_after_ms=*/0, /*wait_busy_after=*/true},
     {0x20, nullptr, 0, /*delay_before_ms=*/0, /*delay_after_ms=*/0, /*wait_busy_after=*/true},
-    {0x22, PANEL_213_Z98C_POWER_OFF_MODE, 1},
-    {0x20, nullptr, 0, /*delay_before_ms=*/0, /*delay_after_ms=*/0, /*wait_busy_after=*/true},
 };
 };
 
 
 // full_refresh_time/partial_refresh_time from the vendor header are both
 // full_refresh_time/partial_refresh_time from the vendor header are both