diff --git a/Client/AgentDoc/epd_reference_driver.md b/Client/AgentDoc/epd_reference_driver.md index 63b6b16..924e49b 100644 --- a/Client/AgentDoc/epd_reference_driver.md +++ b/Client/AgentDoc/epd_reference_driver.md @@ -1,62 +1,71 @@ -# EPD Reference Driver — GDEY075T7 (UC8179) +# EPD Implementation Reference — GDEY075T7 (UC8179) -## Source - -**Repository:** [ekosboard/firmware](https://github.com/ekosboard/firmware) -**File:** [`src/components/EPD/driver/epd_GDEY075T7.c`](https://github.com/ekosboard/firmware/blob/main/src/components/EPD/driver/epd_GDEY075T7.c) +This document describes the current working state of the UC8179 E-Paper driver as implemented in `components/EPD/epd.cpp`. ## Panel Info -- **Controller:** UC8179 -- **Panel:** GDEY075T7 (Good Display 7.5" B/W, 800×480) -- **Platform:** ESP-IDF (native SPI) -- **Grayscale:** 4-level support present but marked as "NOT TESTED" +- **Controller:** UC8179 (Good Display) +- **Panel:** GDEY075T7 (7.5" B/W, 800×480) +- **Platform:** ESP-IDF (Native SPI2 Host) +- **Status:** **Fully Operational** (B/W and 4-Level Grayscale) + +## Hardware Interface + +### BUSY Pin Polarity +- **Logic:** LOW = Busy, HIGH = Idle +- **Wait loop:** `while (gpio_get_level(BUSY) == 0) { vTaskDelay(5); }` + +### SPI Configuration +- **Host:** `SPI2_HOST` +- **Clock:** `SPI_FREQUENCY` (2MHz typically for EPD) +- **Mode:** SPI Mode 0 +- **Transfer Size:** Chunked into 4096-byte buffers to avoid DMA limits and task watchdogs. ## Key Implementation Details -### BUSY Pin Polarity -- **Reference driver:** HIGH = Busy, LOW = Idle -- **⚠️ Our board is INVERTED:** LOW = Busy, HIGH = Idle -- Wait loop polls `gpio_get_level(BUSY) == 0` to detect idle (reference) -- Our code uses `== 0` to wait while busy (opposite meaning, same code pattern) +### Data Polarity & VCOM (0x50) +We use `0x29` for VCOM and Data Interval: +- **VBD:** `00` (Floating/Black border?) +- **N2OCP:** `1` (Auto-copy NEW data to OLD data after refresh) +- **DDX:** `01` (Data Polarity: 0=Black, 1=White) +- **Note:** In our 4-gray unpacking, we send `~output_byte`, effectively inverting the logic to match the panel's expectation for the LUTs used by the UC8179. -### Clear Screen (White) -- Writes `0xFF` to **both** old (0x10) and new (0x13) data layers -- `0xFF` = White, `0x00` = Black +### Refresh Management +The driver tracks refresh history to prevent ghosting or panel damage: +- **Full Refresh:** Required every 5 fast refreshes or after 24 hours. +- **Fast Refresh (B/W):** Optimized waveforms via `0xE5` -> `0x5A`. +- **4-Gray Refresh:** Optimized waveforms via `0xE5` -> `0x5F`. -### Display Image -- Writes `0x00` to old data layer (0x10) — assumes previous state was black -- Writes actual image data to new data layer (0x13) +## Grayscale Mapping (4-Level) + +The input is a packed 2bpp bitmap (4 pixels per byte). We unpack this into two sequential data layers: **Old (0x10)** and **New (0x13)**. + +| Gray Level | Input Bits (2bpp) | Old Layer (0x10) | New Layer (0x13) | Final Value (Inverted) | +| :--- | :--- | :--- | :--- | :--- | +| **White** | `11` | 1 | 1 | `00` (Low) | +| **Gray 1** | `10` | 0 | 1 | `10` | +| **Gray 2** | `01` | 1 | 0 | `01` | +| **Black** | `00` | 0 | 0 | `11` (High) | + +*Note: The hardware logic for 4-gray on UC8179 drives the pixels based on the difference between the Old and New layers over multiple sub-frames.* + +## Driver State Machine + +### Initialization (Full) +1. **Hardware Reset:** RST Low (10ms), RST High (10ms). +2. **Power Setting (0x01):** `0x07, 0x07, 0x3f, 0x3f`. +3. **Booster Soft Start (0x06):** `0x17, 0x17, 0x28, 0x17`. +4. **Power On (0x04):** Wait 100ms + Busy Idle. +5. **Panel Setting (0x00):** `0x1F` (800x480, KW Mode). +6. **Resolution (0x61):** `800×480`. +7. **VCOM (0x50):** `0x29, 0x07`. + +### Fast Mode Adjustments +- **Booster (0x06):** `0x27, 0x27, 0x18, 0x17` (Stronger drive for fast transitions). +- **Fast Mode Enable (0xE0):** `0x02`. +- **Timing (0xE5):** `0x5A` (B/W) or `0x5F` (4-Gray). ### Sleep Sequence -1. `0x50` with `0xF7` — VCOM and data interval setting before sleep -2. `0x02` — Power Off -3. Wait for BUSY idle -4. `0x07` + `0xA5` — Deep Sleep - -### Init Sequence (Full Refresh) -1. Hardware reset (RST low 10ms, high 10ms) -2. `0x01` — Power Setting: VGH=20V, VGL=-20V, VDH=15V, VDL=-15V, VDHR=4.2V -3. `0x06` — Booster Soft Start: 0x17, 0x17, 0x28, 0x17 -4. `0x04` — Power On + 100ms delay + wait busy -5. `0x00` — Panel Setting: `0x1F` (KW B/W mode) -6. `0x61` — Resolution: 800×480 -7. `0x15` — DUSPI disabled -8. `0x50` — VCOM: 0x10, 0x07 -9. `0x60` — TCON: 0x22 -10. `0xE3` — PWS: 0x22 - -### Fast Refresh -- `0xE0` → `0x02` (enable fast mode) -- `0xE5` → `0x5A` (fast refresh timing) - -### Partial Update -- Uses `0x91` (partial in) / `0x92` (partial out) + `0x90` (resolution setting) -- Writes `~data` (inverted) to old layer to force transitions -- Sets `0x50` → `0x21` (N2OCP disabled) for partial mode - -### 4-Level Grayscale -- Requires different booster settings: `0x27, 0x27, 0x18, 0x17` -- `0xE5` → `0x5F` for grayscale timing -- Data encoding: 2 bits per pixel (0xC0=white, 0x00=black, 0x80=gray1, 0x40=gray2) -- Old layer and new layer encode different bit planes, both inverted (`~temp3`) +1. **VCOM pre-sleep (0x50):** `0xF7`. +2. **Power Off (0x02):** Wait for Busy Idle. +3. **Deep Sleep (0x07):** `0xA5` (Check code).