Das Panel ist auf dem Kopf eingebaut. WS7_ROTATE_180 in pins_config.h dreht Bild und Touch gemeinsam; Vorgabe ist gedreht. Die Drehung übernimmt der PPA-Grafikbeschleuniger (EXAMPLE_LVGL_PORT_PPA_ ROTATION_ENABLE), weil die Software-Rotation des LVGL-Ports nur RGB565 verarbeitet und für dieses RGB888-Panel nicht in Frage kommt. Der Touch wird im process_coordinates-Hook mitgedreht, sonst läge die Bedienung spiegelbildlich zum Bild. MADCTL ist als WS7_MADCTL herausgezogen, falls die Bridge es doch auswertet. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018QoLDQeUh1dCQz7yYZVb4Y
Touch-Display-Firmware (ESP32-P4)
Client-Firmware für die Touch-Displays, die als UART-Bedienung für die Dual-PID-Siebträgersteuerung dienen:
- Guition JC4880P443C-I-W (4,3", ST7701, 480×800)
- Guition JC1060P470C-I-W (7,0", JD9165, 1024×600)
- Waveshare ESP32-P4-Pico + Waveshare 7inch DSI LCD (H) (1280×720)
Alle drei teilen sich denselben Sketch; das Zielpanel wird über JC_PANEL_TYPE in
config.h gewählt.
Die Hauptplatine (ESP32-S3, Dual_PID_FastHeatUp.ino) bleibt die Steuerzentrale
inkl. WLAN/Webinterface. Dieses Display ist ein reiner UART-Client: es empfängt den
Zustand und sendet Bedienkommandos. Protokoll: siehe
../Doku/JC-Display_UART-Protokoll.md.
Panel-Auswahl
In config.h:
#define JC_PANEL_TYPE WS_PANEL_7H // Waveshare P4-Pico + 7inch DSI LCD (H) (Vorgabe)
#define JC_PANEL_TYPE JC_PANEL_43 // 4,3" JC4880P443C-I-W
#define JC_PANEL_TYPE JC_PANEL_70 // 7,0" JC1060P470C-I-W
Der Schalter steuert Panel-Treiber, Auflösung, Rotation, Reset-/Backlight-Ansteuerung, die Touch-Umrechnung und die Farbtiefe von LVGL; UI und Protokoll bleiben identisch.
Nur hier umschalten, nicht per Compiler-Flag.
lv_conf.hliestJC_PANEL_TYPEausconfig.h, weil das Waveshare-Panel RGB888 verlangt und LVGL deshalb mit 24 statt 16 Bit übersetzt werden muss. Ein-D-Flag der IDE erreicht die LVGL-Bibliothek nicht — Sketch und Bibliothek liefen dann mit verschiedenen Farbtiefen.display_hal.cppbricht den Build mit einerstatic_assertab, falls das doch passiert.
Hardware
Vendor-Pakete: 4,3" im Ordner JC4880P443C_I_W/, 7,0" im Repo-Ordner
../JC_Display_Firmware_7zoll/.
| Komponente | 4,3" JC4880P443C-I-W | 7,0" JC1060P470C-I-W | Waveshare P4-Pico + 7" DSI (H) |
|---|---|---|---|
| Haupt-MCU (UI) | ESP32-P4 | ESP32-P4 | ESP32-P4 (32 MB PSRAM, 32 MB Flash) |
| WLAN/BT (hier ungenutzt) | ESP32-C6 | ESP32-C6 | — (kein Funkmodul) |
| Display | ST7701, 480×800 IPS, MIPI-DSI | JD9165, 1024×600 IPS, MIPI-DSI | 1280×720 IPS, MIPI-DSI 2 Lanes über Waveshare-Bridge |
| Farbformat | RGB565 | RGB565 | RGB888 (Bridge nimmt nichts anderes) |
| LVGL-Ausrichtung | Rotation 270° (PPA) → 800×480 | keine Rotation, nativ 1024×600 | nativ 1280×720, bei Einbau auf dem Kopf 180° (PPA) |
| Touch | GT911, I²C SDA=GPIO7 / SCL=GPIO8 | GT911, I²C SDA=GPIO7 / SCL=GPIO8 | GT9271 (I²C-Adresse 0x14), SDA=GPIO7 / SCL=GPIO8 |
| Touch-Rohkoordinaten | 480×800 (= Panelraster) | 800×480 → wird auf 1024×600 skaliert | 720×1280 (Hochformat) → X/Y werden getauscht |
| LCD-Reset | GPIO5 | GPIO27 | kein Reset-Pin (macht die Bridge) |
| Backlight | GPIO23 (LEDC-PWM) | GPIO23 (LEDC-PWM) | Bridge-Register auf I²C 0x45 (AD/AB/AA) |
| Framebuffer (3×) | 3 × 750 KB ≈ 2,3 MB PSRAM | 3 × 1,2 MB ≈ 3,6 MB PSRAM | 3 × 2,8 MB ≈ 8,3 MB PSRAM |
| Freie Expansion-IO | Stiftleiste JP1: GPIO 52/51/50/49/35/34/33/32/31/30/29/28 | FPC 1,0 mm 16-pol. FPC4: GPIO 34/33/32/31/30/29/28 · FPC3: 48/47/46/45/5/4/3/2 | 40-poliger Header im Raspberry-Pi-Pico-Format; belegt sind I²C (7/8), TF-Karte (9/10/11/12/13/53) und Debug-UART0 (37/38) |
| UART zur Hauptplatine | TX GPIO33 / RX GPIO31 | TX GPIO33 / RX GPIO31 | TX GPIO17 / RX GPIO18 |
Waveshare 7" (H) — Besonderheiten des Bringups
Das Panel hängt hinter einer Waveshare-Bridge und braucht keinen Hersteller-Panel-Treiber;
board_bringup.c legt DSI-Bus, DBI-Kommandokanal und DPI-Panel direkt an:
- Referenztakt der D-PHY =
PLL_F20M(Legacy). Mit der Standardquelle bleibt das Bild auf ESP32-P4 Rev. 1.3 / ECO2 schwarz. - 2 Lanes à 1250 Mbit/s, DPI-Takt 80 MHz, Austastlücken 64/64/64 (≈ 60 Hz).
Alle Werte stehen in
pins_config.h(WS7_*) und lassen sich dort ändern, falls das Bild reißt oder flimmert — 1280×720 in RGB888 belastet den PSRAM spürbar. - Reihenfolge: Bridge-Grundinitialisierung (
C0/C2/AC) → DSI → DCSMADCTL/Sleep Out/Display On→ DPI-Start → erst dann Hintergrundbeleuchtung. Wird das Licht früher eingeschaltet, blitzt beim Start Bildrauschen auf. - Einbaulage:
WS7_ROTATE_180inpins_config.hdreht Bild und Touch um 180°, wenn das Panel auf dem Kopf montiert ist (Vorgabe: gedreht). Die Drehung macht der PPA-Grafikbeschleuniger; die Software-Rotation des LVGL-Ports beherrscht nur RGB565 und käme für dieses Panel nicht in Frage.
Beim 7-Zöller ist die Expansion-IO kein Stiftleisten-Header, sondern eine FPC-Buchse (1,0 mm Raster, 16-polig) — für die UART-Verdrahtung wird ein FPC-Breakout/Adapterkabel gebraucht. Schaltplan:
../JC_Display_Firmware_7zoll/5-Schematic/4_CONN.png.
Verkabelung zur Hauptplatine (UART, gekreuzt)
Für beide JC-Panels dieselben P4-Pins (4,3": Header JP1, Schaltplan
JC4880P443C_I_W/5-Schematic/4_USB&IO.png · 7,0": FPC-Buchse FPC4):
S3 GPIO43 (TX) ----> P4 GPIO31 (RX) (DISPLAY_UART_RX_PIN)
S3 GPIO44 (RX) <---- P4 GPIO33 (TX) (DISPLAY_UART_TX_PIN)
S3 GND ------ P4 GND
Waveshare ESP32-P4-Pico (40-poliger Header):
S3 GPIO43 (TX) ----> P4 GPIO18 (RX) (DISPLAY_UART_RX_PIN)
S3 GPIO44 (RX) <---- P4 GPIO17 (TX) (DISPLAY_UART_TX_PIN)
S3 GND ------ P4 GND
Die rechte JP1-Spalte (
C6_U01TXD/C6_I10RXD/…) gehört zum ESP32-C6 — nicht verwenden. 3,3-V-Logik beidseitig → keine Pegelwandlung nötig.
Projektstruktur (eigener Code)
| Datei | Zweck |
|---|---|
JC_Display_Firmware.ino |
setup()/loop(), verdrahtet die Module |
config.h |
Pins, UART, Protokoll-Parameter |
machine_state.h |
Spiegel des state-Objekts der S3 |
protocol_client.h/.cpp |
UART-Protokoll: hello/state/ack/profiles/… + Heartbeat |
ui.h/.cpp |
LVGL-Dashboard (hardwareunabhängig) |
display_hal.h/.cpp |
LVGL-/UI-Verdrahtung + Lock-Wrapper |
board_bringup.c |
esp_lcd-Hardware-Bringup (C; nur bei JC_USE_REAL_PANEL=1) |
Abhängigkeiten
- Arduino-ESP32 ≥ 3.1 (mit ESP32-P4-Support), Board: ESP32P4 Dev Module, PSRAM aktiviert.
- LVGL 9.x. Die
lv_conf.him Sketch-Ordner ist die maßgebliche; sie wird über den Include-Pfad des Sketches gefunden und leitetLV_COLOR_DEPTHausJC_PANEL_TYPEab. Liegt zusätzlich eine altelv_conf.hneben demlvgl-Ordner der Bibliotheken, wird sie nicht benutzt — sie darf dort aber auch nicht stören. - ArduinoJson 7.x.
Zwei Betriebsmodi (JC_USE_REAL_PANEL in display_hal.h)
0 = Stub-Modus (Standard)
Kompiliert ohne Display-Treiber (eigenes Minimal-LVGL, rendert ins Leere). Ideal, um
Protokoll/UART/Logik am Schreibtisch zu testen (Debug über USB-CDC Serial). Läuft auf
jedem ESP32 mit LVGL+ArduinoJson.
1 = echte Hardware (Hersteller-BSP)
display_hal.cpp baut auf der erprobten Hersteller-Portierung auf. Dazu folgende
Dateien aus JC4880P443C_I_W/1-Demo/arduino_examples/lvgl_v9_sw_rotation/ in diesen
Sketch-Ordner kopieren:
pins_config.h
lvgl_port_v9.h
lvgl_port_v9.c
src/lcd/ (esp_lcd_st7701*.c/.h + st7701_lcd.* sowie esp_lcd_jd9165.c/.h)
src/touch/ (komplett: esp_lcd_touch*.c/.h, gt911_touch.*)
Diese Dateien liegen bereits im Sketch. esp_lcd_jd9165.* stammt aus dem
7-Zoll-Vendor-Paket
(../JC_Display_Firmware_7zoll/1-Demo/Demo_Arduino/1_2_Lvgl_V9/.../src/lcd/); je nach
JC_PANEL_TYPE wird nur einer der beiden Panel-Treiber eingebunden.
Der Init-Ablauf (MIPI-DSI-PHY-LDO, ST7701 bzw. JD9165, GT911, LEDC-Backlight,
lvgl_port_init) ist 1:1 aus dem Vendor-Beispiel lvgl_sw_rotation.c übernommen — nur
der Demo-Aufruf (lv_demo_widgets()) wurde durch ui_init() ersetzt.
Die Touch-Skalierung des 7-Zöllers hängt in board_bringup.c am
process_coordinates-Hook von esp_lcd_touch, damit die Vendor-Datei
esp_lcd_touch_gt911.c unverändert bleibt (im Vendor-Demo ist die Umrechnung direkt in
den Treiber gepatcht).
Wichtig: Im realen Modus läuft LVGL in einem eigenen FreeRTOS-Task. UI-Zugriffe aus
der Arduino-loop() (z. B. ui_update bei jedem state-Push) sind daher in
hal_lock()/hal_unlock() (= lvgl_port_lock/unlock) gekapselt — ist in der .ino
bereits umgesetzt.
Ausrichtung
Das Dashboard ist Querformat. Beim 4,3-Zöller (physisch 480×800) wird das per
LVGL-Rotation 270° mit PPA-Beschleunigung erreicht → 800×480. Der 7-Zöller ist nativ
1024×600, dort steht die Rotation auf 0 und PPA ist abgeschaltet. Beides setzt
pins_config.h automatisch anhand von JC_PANEL_TYPE.
Das Layout arbeitet fast durchgehend mit LV_PCT/LV_SIZE_CONTENT und skaliert
deshalb mit. Feste Pixelmaße (Rundinstrumente, Thermometer, Buttons) bleiben gleich groß
— auf dem 7-Zöller entsteht dadurch mehr Luft. Die Schriftgrößen bleiben ebenfalls
unverändert: 4,3" ≈ 213 dpi, 7,0" ≈ 170 dpi, gleiche Pixelhöhe wirkt dort physisch
größer.
Status
Fertig & hardwareunabhängig:
- Vollständiger UART-Protokoll-Client (v2): hello-Handshake, state-Parsing, ack/error, Profile, Heartbeat, Link-Timeout.
- Dashboard: Live-Temperaturen Wasser/Dampf (ist/soll), Duty-Balken, Status-Banner
(Farbe nach
statusKey), Verbindungs- & WLAN-Anzeige, Bezugs-Timer, Bedien-Buttons. - Senden für
setPid,startAutotune/stopAutotune,getProfileDetailsvorhanden.
Board-Bringup: auf die konkreten JC-Pins/Treiber gesetzt (ST7701 bzw. JD9165, GT911,
Backlight, I²C) — sobald die BSP-Dateien kopiert und JC_USE_REAL_PANEL=1 gesetzt ist,
lauffähig.
Noch offen (UI-Ausbau): weitere Screens — Einstellungen (Brew/Service/Sensor), Profil-Auswahl/-Editor, PID/AutoTune-Bedienung.
Inbetriebnahme / Fehlersuche (Lessons learned)
- Stromversorgung: Jedes Board eigene Versorgung. Zwischen P4 und S3 nur GND + TX + RX — kein 3V3/5V! Den S3 nicht über den 3V3-Header des Displays speisen (reicht nicht / Regler-Rückspeisung).
- Pins nach Silkscreen: Die UART-Pads am Board nach Aufdruck
GPIO50/GPIO51identifizieren, nicht nach Header-Pin-Nummern. - S3-Seite: muss mit
TOUCH_UART_ENABLED 1geflasht sein und laufen. DaSerial(Debug) und der Touch-UART beide auf GPIO43/44 liegen, ggf. „USB CDC On Boot: Enabled" verwenden, damit der Debug-Port nicht die UART-Pins blockiert.
Diagnose-Schalter (in config.h)
SHOW_DEBUG_OVERLAY 1→ blendet unten ein grünes Panel ein: gesendetehello, empfangene Bytes/Zeilen, Parse-Fehler, letzte Rohzeile, Link-Status.UART_SELFTEST_INTERNAL_LOOPBACK 1→ legt TX chip-intern auf RX (ohne Draht/Pins). Läuft „RX byte" hoch, sind Firmware+UART ok → Problem liegt an Pins/Verkabelung. Nach dem Test wieder auf 0!