| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182 |
- #pragma once
- // GDEY0213Z98, SSD1680 controller, 128x250 RAM window (122 columns visible),
- // black + red. Derived from third_party/GxEPD2/src/epd3c/GxEPD2_213_Z98c.{h,cpp}.
- #include "epd_command.h"
- namespace esphome::gxepd2 {
- // _InitDisplay(): SWRESET (0x12) bracketed by fixed 10ms delays (not a
- // busy-pin wait), driver output control, data entry mode, border waveform,
- // temp sensor, and display update control (0x21). The trailing
- // _setPartialRamArea() is dropped - CycleEngine's SET_WINDOW covers it.
- 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_BORDER_WAVEFORM[] = {0x05};
- inline const uint8_t PANEL_213_Z98C_TEMP_SENSOR[] = {0x80};
- inline const uint8_t PANEL_213_Z98C_DISPLAY_UPDATE_CONTROL[] = {0x00, 0x80};
- inline const EpdCommand PANEL_213_Z98C_INIT[] = {
- {0x12, nullptr, 0, /*delay_before_ms=*/10, /*delay_after_ms=*/10, /*wait_busy_after=*/false}, // SWRESET
- {0x01, PANEL_213_Z98C_DRIVER_OUTPUT_CONTROL, 3},
- {0x11, PANEL_213_Z98C_DATA_ENTRY_MODE, 1},
- {0x3C, PANEL_213_Z98C_BORDER_WAVEFORM, 1},
- {0x18, PANEL_213_Z98C_TEMP_SENSOR, 1},
- {0x21, PANEL_213_Z98C_DISPLAY_UPDATE_CONTROL, 2},
- };
- // _Update_Full(): a single combined trigger (0x22 update control + 0x20) that
- // handles power internally.
- inline const uint8_t PANEL_213_Z98C_UPDATE_MODE[] = {0xF7};
- inline const EpdCommand PANEL_213_Z98C_REFRESH[] = {
- {0x22, PANEL_213_Z98C_UPDATE_MODE, 1},
- {0x20, nullptr, 0, /*delay_before_ms=*/0, /*delay_after_ms=*/0, /*wait_busy_after=*/true},
- };
- // _setPartialRamArea(0, 0, WIDTH, HEIGHT): SSD1680 byte-column X addressing
- // (0x44's operands are RAM byte columns, not raw pixels), no Y-reversal.
- inline const uint8_t PANEL_213_Z98C_WINDOW_X[] = {0x00, 0x0F}; // xe/8 = 127/8
- inline const uint8_t PANEL_213_Z98C_WINDOW_Y[] = {0x00, 0x00, 0xF9, 0x00}; // ye = 249
- inline const uint8_t PANEL_213_Z98C_WINDOW_XC[] = {0x00};
- inline const uint8_t PANEL_213_Z98C_WINDOW_YC[] = {0x00, 0x00};
- inline const EpdCommand PANEL_213_Z98C_WINDOW[] = {
- {0x44, PANEL_213_Z98C_WINDOW_X, 2},
- {0x45, PANEL_213_Z98C_WINDOW_Y, 4},
- {0x4E, PANEL_213_Z98C_WINDOW_XC, 1},
- {0x4F, PANEL_213_Z98C_WINDOW_YC, 2},
- };
- inline const uint8_t PANEL_213_Z98C_HIBERNATE_0_10[] = {0x01};
- inline const EpdCommand PANEL_213_Z98C_HIBERNATE[] = {
- {0x10, PANEL_213_Z98C_HIBERNATE_0_10, 1},
- };
- // Vendor full_refresh_time is 15000ms; used as the ceiling for every busy
- // wait (erring long only delays reporting a genuine timeout).
- inline const EpdPanelDescriptor PANEL_213_Z98C = {
- .width = 128, // RAM window width (addressing works in this, not WIDTH_VISIBLE=122)
- .height = 250,
- .busy_active_level = true, // GxEPD2_EPD(..., /*busy_level=*/HIGH, ...)
- .busy_timeout_ms = 30000,
- .init_sequence = PANEL_213_Z98C_INIT,
- .init_sequence_len = sizeof(PANEL_213_Z98C_INIT) / sizeof(PANEL_213_Z98C_INIT[0]),
- .window_sequence = {PANEL_213_Z98C_WINDOW, nullptr},
- .window_sequence_len = {sizeof(PANEL_213_Z98C_WINDOW) / sizeof(PANEL_213_Z98C_WINDOW[0]), 0},
- .plane_count = 2,
- .plane_write_cmd = {0x24, 0x26},
- // Color-plane wire convention: vendor writeImage() does _writeData(~data)
- // with a 0xFF "blank" default, so wire 0x00 = not-red; our buffer's 1=red
- // bit matches that, so no inversion. (DISPLAY_UPDATE_CONTROL={0x00,0x80}
- // above sets the matching plane polarity.) Bench-confirmed.
- .plane_invert = {false, false},
- .refresh_sequence = PANEL_213_Z98C_REFRESH,
- .refresh_sequence_len = sizeof(PANEL_213_Z98C_REFRESH) / sizeof(PANEL_213_Z98C_REFRESH[0]),
- .hibernate_sequence = PANEL_213_Z98C_HIBERNATE,
- .hibernate_sequence_len = sizeof(PANEL_213_Z98C_HIBERNATE) / sizeof(PANEL_213_Z98C_HIBERNATE[0]),
- };
- } // namespace esphome::gxepd2
|