# Notes - Plan: https://claude.ai/code/artifact/3b9eda11-a87e-4eea-bbb9-e6454e558991 - Datasheet: [datasheet/EL512.256-H3 FRB.pdf](datasheet/EL512.256-H3%20FRB.pdf) ## Approach I2S0 in 8-bit parallel (LCD) mode with a circular DMA descriptor chain. BCK rises once per two DMA bytes (measured with PCNT: 2.5 MHz BCK at a 5 MHz byte rate), so each VCLK period is two identical bytes: | Bit | Signal | |-----|--------| | 0 | VID (even columns) | | 1 | TVID (odd columns) | | 2 | HS | | 3 | VS | The I2S0 BCK output drives VCLK. ENABLE (GPIO 25) and _LOWPWR (GPIO 26) are plain GPIO. I2S0 setup (`EL512Panel::startI2S()`), following bitluni's ESP32Lib 8-bit mode: - Clock: PLL_D2_CLK 160 MHz / `clkm_div_num` 16, `tx_bck_div_num` 1 -> 10 MHz byte rate, 5 MHz BCK (two bytes per BCK period). - `lcd_en`, `lcd_tx_wrx2_en`, `tx_bits_mod` 8, `tx_fifo_mod` 1, `tx_chan_mod` 1, `tx_right_first`. With this setup each 32-bit DMA word goes out as bytes 2, 3, 0, 1, so `encodeRow()` stores stream byte i at `i ^ 2`. - Stream bits 0..3 -> `I2S0O_DATA_OUT16_IDX` + n; BCK -> VCLK (`INVERT_VCLK` flips it). - Stream: 261 lines × 544 bytes ≈ 142 KB, too big for one DMA block, so it is allocated as 38 chunks of up to 7 lines (3808 bytes), one descriptor each, looped; `eof` set once per frame. ## From the datasheet The datasheet is the source of truth for everything in this section and wins over any other doc, comment or the plan. - Two-bit parallel mode is selected by removing jumper 2 (DCONFIG) of pin strip PS1 (Table 3; factory default has jumpers 1 and 2 fitted). Even columns on VID, odd columns on TVID, numbered from the left as seen by the viewer; 256 VCLKs per row. The datasheet numbers from 1 (Fig. 3: "row 1", "Last pixel (512 / 256)"), so the leftmost pixel, x = 0 in the code, is column 1 and goes on TVID. - VCLK is active on the rising edge and should be kept running. - HS envelopes the pixels of a row: the visible pixels are the last 512 (two-bit mode: last 256 clocks) before HS falls. The number of VCLKs during HS high should be even. - The topmost row is the first HS high time ending after the rising edge of VS. Only the rising edge of VS is used; VS high/low time is at least 1 VCLK (T2). - Table 5: front porch T1 >= 100 µs, HS setup to VS T4 >= 1 VCLK, HS hold from VS T5 >= 3 µs, HS low T6 >= 4 VCLK, HS period T8 >= 50 µs, VS 70 Hz typ / 75 Hz max. - Figure 4 / Table 6: VID, TVID, HS and VS need 8 ns setup and 8 ns hold around the rising VCLK edge; VCLK period >= 33 ns (30 MHz max). - Inputs are HCT compatible with pull-ups (Table 4: high >= 2 V, low <= 0.8 V, abs. max Vcc1 + 0.5 V). ENABLE and _LOWPWR are on J2 and pulled high internally. ## Open items Done: - [x] Implement `EL512Panel::startI2S()` (I2S0 LCD mode, GPIO matrix routing, circular `lldesc_t` chain). - [x] Handle the 8-bit LCD-mode byte-pair swap in `encodeRow()` (byte i at `i ^ 2`). - [x] Map x = 0 (datasheet column 1, odd) to TVID, not VID. - [x] VCLK rate: PCNT showed BCK at half the byte rate (panel saw every other byte, image squeezed and repeated). Fixed with two bytes per VCLK at a 10 MHz byte rate; PCNT now reads VCLK 5.0 MHz, VS 70 Hz. - [x] I2S0 data signal base `I2S0O_DATA_OUT16_IDX`: GPIO 19/21/22/23 all toggle. - [x] Panel shows a correct image in two-bit mode. Hardware checks: - [ ] Self test (Table 3): remove PS1 jumper 1, power up; all pixels except the first half of the top row should light. Refit jumper 1. - [ ] HS reads ~18,030 Hz on PCNT where 5 MHz / 272 = 18,382 Hz is expected (~2% low) while VCLK reads 5.0 MHz. Frame rate is still ~70 Hz; cause unknown, check on a scope (HS 256 clocks high / 16 low, T6-T8). - [ ] Scope: data changing away from the rising VCLK edge with >= 8 ns setup/hold (Table 6); which BCK edge lines up with the byte-pair boundary is unverified. If pixels look shifted or noisy, set `INVERT_VCLK`. - [ ] Confirm the `^ 2` byte order. HS edges sit on word boundaries, so a wrong order does not show on HS; on the panel it shuffles pixels in groups of 8 (a 1-pixel line at x = 0 lands at x = 4). - [ ] Confirm the column parity: the "checkerboard" and "VID/TVID columns" test images in `main.cpp` must look as drawn, and the left border must sit on the panel's first column. - [ ] Add the 5 V buffer (74HCT245/74AHCT541) and a pull-down on ENABLE so the panel stays off while the ESP32 boots without VCLK (Table 1: ENABLE pulled high internally; Table 5 note 3: VCLK should be kept running). Software: - [ ] Tear-free updates: `show()` rewrites the stream while DMA reads it. Encode into a second buffer and swap descriptors at the per-frame EOF, or encode only during vertical blanking. - [ ] Unit test for `encodeRow()` (see `test/README`). - [ ] The ~142 KB stream (in 38 chunks) leaves ~190 KB heap; with Wi-Fi on it may not fit. Fallback: a line ring refilled from the EOF interrupt.