panel_426_gdeq0426t82.h 4.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. #pragma once
  2. // Hand-derived from third_party/GxEPD2/src/gdeq/GxEPD2_426_GDEQ0426T82.{h,cpp}
  3. // (GDEQ0426T82, SSD1677 controller, 800x480, monochrome). First panel with
  4. // a genuine current/previous differential RAM (0x24/0x26) - the vendor
  5. // driver's writeImageAgain()/writeImageForFullRefresh() keep both buffers
  6. // in sync purely so a *future* fast-partial update diffs correctly; this
  7. // engine never does partial refresh (see gxepd2_extraction_next_steps in
  8. // project memory for that scope decision), so only the current-buffer
  9. // command (0x24) is ever written here - 0x26 is dropped entirely, same as
  10. // GxEPD2's own _initial_write priming pass (a dummy full-buffer clear
  11. // before the real content write) is dropped, since this engine always
  12. // writes real content directly and re-initializes fully every cycle. The
  13. // 0x26 write is still recorded below, in plane_write_cmd_for_full_refresh,
  14. // so a future partial-refresh engine has it without a second capture pass.
  15. //
  16. // Also the first panel whose RAM-window-set (_setPartialRamArea) layout
  17. // differs from GxEPD2_213_Z98c's: SSD1677 addresses 0x44/0x45 in raw
  18. // pixels (not byte columns), reverses Y, and re-issues the entry-mode
  19. // command (0x11) on every window set - see window_sequence below.
  20. #include "epd_command.h"
  21. namespace esphome::gxepd2 {
  22. inline const uint8_t PANEL_426_GDEQ0426T82_TEMP_SENSOR[] = {0x80};
  23. inline const uint8_t PANEL_426_GDEQ0426T82_ANALOG_BLOCK[] = {0xAE, 0xC7, 0xC3, 0xC0, 0x80};
  24. // Driver output control: (HEIGHT-1) low/high byte, then SM=0x02 (interlaced).
  25. inline const uint8_t PANEL_426_GDEQ0426T82_DRIVER_OUTPUT_CONTROL[] = {0xDF, 0x01, 0x02};
  26. inline const uint8_t PANEL_426_GDEQ0426T82_BORDER_WAVEFORM[] = {0x01};
  27. inline const EpdCommand PANEL_426_GDEQ0426T82_INIT[] = {
  28. {0x12, nullptr, 0, /*delay_before_ms=*/10, /*delay_after_ms=*/10, /*wait_busy_after=*/false}, // SWRESET
  29. {0x18, PANEL_426_GDEQ0426T82_TEMP_SENSOR, 1},
  30. {0x0C, PANEL_426_GDEQ0426T82_ANALOG_BLOCK, 5},
  31. {0x01, PANEL_426_GDEQ0426T82_DRIVER_OUTPUT_CONTROL, 3},
  32. {0x3C, PANEL_426_GDEQ0426T82_BORDER_WAVEFORM, 1},
  33. };
  34. // _setPartialRamArea(0, 0, 800, 480). y is stored as HEIGHT-y-h, which is
  35. // 0 for a full-height window regardless of the reversal - only matters for
  36. // a real partial window, which this engine never does.
  37. inline const uint8_t PANEL_426_GDEQ0426T82_ENTRY_MODE[] = {0x01};
  38. inline const uint8_t PANEL_426_GDEQ0426T82_WINDOW_X[] = {0x00, 0x00, 0x1F, 0x03}; // xs=0, xe=799
  39. inline const uint8_t PANEL_426_GDEQ0426T82_WINDOW_Y[] = {0xDF, 0x01, 0x00, 0x00}; // ye=479, ys=0
  40. inline const uint8_t PANEL_426_GDEQ0426T82_WINDOW_XC[] = {0x00, 0x00};
  41. inline const uint8_t PANEL_426_GDEQ0426T82_WINDOW_YC[] = {0xDF, 0x01};
  42. inline const EpdCommand PANEL_426_GDEQ0426T82_WINDOW[] = {
  43. {0x11, PANEL_426_GDEQ0426T82_ENTRY_MODE, 1},
  44. {0x44, PANEL_426_GDEQ0426T82_WINDOW_X, 4},
  45. {0x45, PANEL_426_GDEQ0426T82_WINDOW_Y, 4},
  46. {0x4E, PANEL_426_GDEQ0426T82_WINDOW_XC, 2},
  47. {0x4F, PANEL_426_GDEQ0426T82_WINDOW_YC, 2},
  48. };
  49. // _Update_Full(), useFastFullUpdate=true path (this panel's vendor default).
  50. inline const uint8_t PANEL_426_GDEQ0426T82_DISPLAY_UPDATE_CONTROL[] = {0x40, 0x00}; // bypass RED as 0, single chip
  51. inline const uint8_t PANEL_426_GDEQ0426T82_TEMP_REGISTER[] = {0x5A};
  52. inline const uint8_t PANEL_426_GDEQ0426T82_UPDATE_MODE[] = {0xD7};
  53. inline const EpdCommand PANEL_426_GDEQ0426T82_REFRESH[] = {
  54. {0x21, PANEL_426_GDEQ0426T82_DISPLAY_UPDATE_CONTROL, 2},
  55. {0x1A, PANEL_426_GDEQ0426T82_TEMP_REGISTER, 1},
  56. {0x22, PANEL_426_GDEQ0426T82_UPDATE_MODE, 1},
  57. {0x20, nullptr, 0, /*delay_before_ms=*/0, /*delay_after_ms=*/0, /*wait_busy_after=*/true},
  58. };
  59. inline const uint8_t PANEL_426_GDEQ0426T82_HIBERNATE_0_10[] = {0x01};
  60. inline const EpdCommand PANEL_426_GDEQ0426T82_HIBERNATE[] = {
  61. {0x10, PANEL_426_GDEQ0426T82_HIBERNATE_0_10, 1},
  62. };
  63. inline const EpdPanelDescriptor PANEL_426_GDEQ0426T82 = {
  64. .width = 800,
  65. .height = 480,
  66. .busy_active_level = true, // GxEPD2_EPD(..., /*busy_level=*/HIGH, ...)
  67. .busy_timeout_ms = 20000, // full_refresh_time is 1600ms; generous ceiling, matches PANEL_213_Z98C's style
  68. .init_sequence = PANEL_426_GDEQ0426T82_INIT,
  69. .init_sequence_len = sizeof(PANEL_426_GDEQ0426T82_INIT) / sizeof(PANEL_426_GDEQ0426T82_INIT[0]),
  70. .window_sequence = {PANEL_426_GDEQ0426T82_WINDOW, nullptr},
  71. .window_sequence_len = {sizeof(PANEL_426_GDEQ0426T82_WINDOW) / sizeof(PANEL_426_GDEQ0426T82_WINDOW[0]), 0},
  72. .plane_count = 1,
  73. .plane_write_cmd = {0x24, 0x00},
  74. .plane_write_cmd_for_full_refresh = {0x26, 0x00}, // see file header
  75. .plane_invert = {false, false},
  76. .refresh_sequence = PANEL_426_GDEQ0426T82_REFRESH,
  77. .refresh_sequence_len = sizeof(PANEL_426_GDEQ0426T82_REFRESH) / sizeof(PANEL_426_GDEQ0426T82_REFRESH[0]),
  78. .hibernate_sequence = PANEL_426_GDEQ0426T82_HIBERNATE,
  79. .hibernate_sequence_len = sizeof(PANEL_426_GDEQ0426T82_HIBERNATE) / sizeof(PANEL_426_GDEQ0426T82_HIBERNATE[0]),
  80. };
  81. } // namespace esphome::gxepd2