# Hardware reference — CrowPanel 2.1" HMI Rotary Display Everything below was taken from Elecrow's own source for **this** board and cross-checked against a second independent source, as PRD section 8.1 requires. Nothing here is from wiki prose or a search summary. **Sources** 1. `Elecrow-RD/CrowPanel-2.1inch-HMI-ESP32-Rotary-Display-480-480-IPS-Round-Touch-Knob-Screen` — `example/RotaryScreen_2_1/RotaryScreen_2_1.ino`, the vendor's shipping Arduino example, plus the bundled `GFX_Library_for_Arduino`. 2. The same repo's `example/esphome/esphome2.1.yaml` — an ESP-IDF-framework config for the same board, written independently of the Arduino example. The two agree on every pin. Where they disagree on anything else, it is called out below. **Not yet verified on hardware.** The board was not connected when this was written. Section "First bring-up" at the end is the order to check things in. --- ## Corrections to the PRD The PRD's section 2.2 was close but incomplete in three ways that matter: | PRD said | Actually | Why it matters | |---|---|---| | Touch is **CST816** | Touch is **CST826**, I2C `0x15` | Different chip ID register value (`0xAA` reads `0x11`, not `0xB4`). A CST816 driver's probe fails and the PRD's own phase-1 sanity check would look like a hardware fault. | | `CS 16` listed alone | The panel needs a **3-wire SPI** bus: **CS 16, SCK 2, MOSI/SDA 1** | The ~30-command ST7701S init sequence goes over this bus. Without SCK and MOSI there is no way to send it, and the panel stays black — exactly the failure mode section 8.1 warns about. | | No backlight mentioned | **Backlight is GPIO6**, PWM | Panel can be fully initialised and still appear dead with the backlight off. | Two smaller additions: there is a **breathing LED on GPIO43**, and expander **P3 ("LCD power") is driven HIGH during init and LOW at the end** of the vendor's setup — see the note under PCF8574 below. The PRD's claim that expander **P1, P6 and P7 are free is correct** — the vendor example configures P0, P2, P3, P4, P5 and never touches the other three. P1 is what this project uses for the relay. --- ## Pinout ### RGB panel (matches the PRD exactly) | Signal | GPIO | |---|---| | DE | 40 | | HSYNC | 15 | | VSYNC | 7 | | PCLK | 41 | | R0–R4 | 46, 3, 8, 18, 17 | | G0–G5 | 14, 13, 12, 11, 10, 9 | | B0–B4 | 5, 45, 48, 47, 21 | ### Panel control SPI (missing from the PRD) | Signal | GPIO | |---|---| | CS | 16 | | SCK | 2 | | SDA (MOSI) | 1 | 9-bit writes, MSB first, **SPI mode 0**. Arduino_GFX's `Arduino_SWSPI::begin()` drives SCK low at init and shifts on the rising edge, which is mode 0. Elecrow's ESPHome config says `spi_mode: MODE3` — that config also carries the comment that its colours are wrong, so mode 0 is the one to trust. If the panel is black, `ST7701_SPI_MODE` in `drivers/display/display.c` is a one-line change. ### Other | Signal | GPIO | |---|---| | I2C SDA / SCL | 38 / 39 | | Backlight (LEDC PWM) | 6 | | Encoder A / B | 42 / 4 | | Breathing LED | 43 | PCLK **18 MHz**, and `pclk_inverted` (negative edge) per the ESPHome config. ### Panel timings The two sources disagree, which is normal — these have slack. | | hsync fp / pw / bp | vsync fp / pw / bp | |---|---|---| | Arduino example (**used here**) | 10 / 4 / 20 | 10 / 4 / 20 | | ESPHome example | 20 / 10 / 10 | 8 / 10 / 10 | The Arduino numbers are from the vendor's shipping firmware, so those are the defaults in `display.c`. Either set should work; swap if the image rolls or shears. --- ## I2C bus (SDA 38 / SCL 39, 400 kHz) | Address | Device | |---|---| | `0x21` | PCF8574 I/O expander | | `0x15` | CST826 capacitive touch | Finding both in the boot scan proves the board is alive and the I2C pins are right, independently of the display. That is the cheapest first check. ### PCF8574 allocation | Pin | Use | Direction | |---|---|---| | P0 | Touch reset | out | | P1 | **Relay — heat call** (this project) | out, active low | | P2 | Touch interrupt | out (driven high by vendor init) | | P3 | LCD power | out | | P4 | LCD reset | out | | P5 | Encoder button | in, pull-up | | P6 | free | — | | P7 | free | — | Two things about this part that are easy to get wrong: **Power-on state is all-high.** A PCF8574's quasi-bidirectional pins come up weakly pulled high. With an active-low relay module that means the relay is **off** at power-on, which is what we want. The driver keeps a shadow byte initialised to `0xFF` so a read-modify-write on any other pin can never accidentally pull P1 low. **The expander does not reset when the ESP32 does.** A software reset, panic reboot or `esp_restart()` leaves the PCF8574's output latch exactly as it was. If P1 was low (heat on) when the firmware crashed, the relay stays closed until firmware comes back and clears it. `app_main()` therefore de-asserts P1 before doing anything else — before WiFi, before the display — which bounds that window to roughly a second. This is documented in `hvac/relay.h` too. A true hardware fail-safe would need an external watchdog or an RC on the relay coil; this firmware does not have one, and the honest statement is that a crash gives you about one second of unwanted heat call, not zero. **P3 is driven HIGH before the LCD reset pulse and LOW at the end of setup** in the vendor example, after the backlight PWM is running. Despite the "LCD power" label the sequence only makes sense as a blanking control — it hides init garbage. `display.c` reproduces the vendor's ordering exactly rather than reasoning about what the net is really called. --- ## ST7701S initialisation `drivers/display/st7701_init.h` carries the sequence verbatim from `st7701_type5_init_operations` in the bundled `Arduino_GFX` (`display/Arduino_ST7701_RGBPanel.h`), which is what the vendor example passes to the panel constructor. The ESPHome config's `init_sequence` is the same sequence with three commands missing from bank `0x10` — `0xC0 3B 00`, `0xC1 0B 02` (VBP) and `0xC2 00 02` — and an extra leading `0x01` software reset. Since that same file admits its colours are wrong, the Arduino/type5 version is the one reproduced here, with the software reset added at the front because it is harmless and makes the state deterministic. Pixel format is set to **RGB666** (`0x3A 0x60`) by the sequence, with `0x36 0x00`. The Arduino example additionally passes `bgr = true` to the panel constructor; that is reflected here by setting the RGB panel's BGR flag. If red and blue are swapped on first light, that flag is the thing to toggle. --- ## Furnace side **Confirmed by the user, and it differs from the PRD:** the system is **2-wire, R and W only**. Existing thermostat is set to Gas/Oil Warm Air, **5 CPH**. Consequences: - **There is no C wire and no third wire to repurpose.** The PRD's section 2.4 discussion of moving `G` to `C` does not apply. The board must run from its own **5V USB supply**. Do not attempt power stealing — this board needs ~5W and power stealing supplies roughly a tenth of that. - **5 CPH is a real constraint, not a display preference.** Five cycles per hour means at most one heat-call *start* every 12 minutes. A minimum off-time alone does not enforce that, because a short call followed by a 5-minute gap would give 8 CPH. `hvac/relay.c` enforces a minimum period between successive heat-call starts (720 s) in addition to the minimum off-time. Wiring: ``` PCF8574 P1 ──► relay module IN (active low) R (24VAC) ──► relay COM W (heat) ◄── relay NO closes to call for heat ``` Opto-isolated relay module with a separate JD-VCC jumper, normally open. The PCF8574 sinks ~25 mA but barely sources, which is why the module must be active-low triggered. **Never connect R to C** — dead short across the transformer, blows the fuse on the furnace control board. On this 2-wire system there is no C at the thermostat anyway. --- ## First bring-up In this order, because each step's failure mode is unambiguous only if the previous one passed: 1. **I2C scan.** Expect `0x21` and `0x15`. If the bus looks empty, stop and re-check SDA 38 / SCL 39 before touching anything else. 2. **Backlight.** GPIO6 PWM up. Screen should glow even with no image. 3. **Panel.** Colour bars. If black: check SPI mode, then the init sequence, then re-verify the pinout — in that order, and re-verify the pinout before writing any new software hypothesis. 4. **Touch.** Chip ID register `0xAA` should read `0x11`. 5. **Encoder.** Detents count in both directions; button on P5 reads low when pressed. 6. **Relay — on the bench, with an LED or a spare relay module, not the furnace.** Exercise every interlock in PRD section 5 before the unit goes anywhere near 24VAC.