Files
planar-EL512.256-H/docs/README.md
T
mangavalkandClaude Opus 5.5 ab3e6ad0ac Project check against the datasheet; fix column parity
The datasheet numbers columns from 1 (Fig. 3: "row 1", "Last pixel
(512 / 256)") and puts odd columns on TVID, so x = 0 (column 1) now
goes to TVID and x = 1 to VID; the encoder had them swapped.

README wiring now lists the J1/J2 pins and power rails from Table 1,
the 5 V buffer, and a pull-down on ENABLE so the panel stays off while
the ESP32 boots without VCLK. encodeRow() documents its T4/T5 margins.
docs/README.md open items are regrouped into done, hardware checks and
software work. main.cpp counts seconds, not frames.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 21:17:29 +02:00

88 lines
4.4 KiB
Markdown

# 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. Each DMA byte
is one VCLK period:
| 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` 32, `tx_bck_div_num` 1 -> 5 MHz, one byte
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 clock c at `c ^ 2`.
- Stream bits 0..3 -> `I2S0O_DATA_OUT16_IDX` + n; BCK -> VCLK (`INVERT_VCLK` flips it).
- 18 descriptors of up to 15 lines (4080 bytes) 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, 5 MHz from PLL_D2 / 32,
GPIO matrix routing, circular `lldesc_t` chain).
- [x] Handle the 8-bit LCD-mode byte-pair swap in `encodeRow()` (clock c at `c ^ 2`).
- [x] Map x = 0 (datasheet column 1, odd) to TVID, not VID.
Hardware checks (need the panel and a scope or logic analyser):
- [ ] Self test first (Table 3): remove PS1 jumper 1, power up; all pixels except the
first half of the top row should light. Refit jumper 1, remove jumper 2.
- [ ] Scope: VCLK 5 MHz on GPIO 18; HS 256 clocks high / 16 low (54.4 µs, T6-T8);
VS one line high per 14.2 ms frame (70.4 Hz); data changing on the falling VCLK
edge with >= 8 ns setup/hold (Table 6); T1 220.8 µs, T4/T5 as in `encodeRow()`.
If data changes on the rising edge, set `INVERT_VCLK`.
- [ ] Confirm the I2S0 data signal base (`I2S0O_DATA_OUT16_IDX`): if GPIO 19/21/22/23
stay idle, try `I2S0O_DATA_OUT8_IDX`.
- [ ] 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 in `main.cpp` must look identical to
the framebuffer, 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 71 KB stream is one contiguous DMA allocation; with Wi-Fi on it may not fit.
Fallback: per-line buffers or a line ring refilled from the EOF interrupt.