Files
raw-designsandClaude Opus 5 a4ed0197e7 fix(P4): Punkt am Kurvenende sichtbar, weiche Linienfuehrung (1.11.1)
Das Diagramm beschnitt seine Kinder an der eigenen Kante: Der Punkt am
rechten Ende war angeschnitten, und vom Schein war nichts zu sehen -
damit blieb auch das Pulsieren unsichtbar. Punkt und Schein duerfen jetzt
darueber hinausreichen; der Schein ist kraeftiger, der Punkt etwas
groesser.

Die Kurven verlaufen jetzt weich statt kantig. Gemessen wird weiterhin
einmal je Sekunde, gezeichnet viermal so fein: Zwischen zwei Messwerten
liegen vier Stuetzpunkte auf einem Kosinusbogen, der an den Messpunkten
waagerecht beginnt und endet. Linienenden und -ecken sind abgerundet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wx7wu7uXXgRzp1zHUhtUa6
2026-09-04 12:06:24 +02:00
..

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/P4-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.h liest JC_PANEL_TYPE aus config.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.cpp bricht den Build mit einer static_assert ab, 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 — die Bridge nimmt kein RGB565 (geprüft)
LVGL-Ausrichtung Rotation 270° (PPA) → 800×480 keine Rotation, nativ 1024×600 keine Rotation, nativ 1280×720
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 × 750 KB ≈ 2,3 MB PSRAM 3 × 1,2 MB ≈ 3,6 MB PSRAM 1 × 2,8 MB — mehr verträgt das Panel beim Start nicht
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 GPIO20 / RX GPIO21

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 → DCS MADCTL/Sleep Out/ Display On → DPI-Start → erst dann Hintergrundbeleuchtung. Wird das Licht früher eingeschaltet, blitzt beim Start Bildrauschen auf.
  • Einbaulage: WS7_ROTATE_180 in pins_config.h dreht Bild und Touch um 180°, falls das Panel auf dem Kopf montiert wird. Vorgabe ist 0 — in der jetzigen Einbaulage steht das Bild richtig herum. Die Drehung macht der PPA-Grafikbeschleuniger; die Software-Rotation des LVGL-Ports beherrscht nur RGB565.
  • Touch-Spiegelung: Der Digitizer sitzt gegenüber dem Bild um die Hochachse gedreht. WS7_TOUCH_MIRROR_RAW_X steht deshalb auf 1 (dreht oben/unten), unabhängig von der Bilddrehung.

Waveshare 7" (H) — Tempo-Schalter

1280×720 bedeutet 2,4-mal so viele Pixel wie beim 4,3-Zöller. Drei Schalter in pins_config.h halten die Bedienung flüssig; jeder ist einzeln zurückstellbar, falls er Ärger macht:

Schalter Vorgabe Wirkung Stand am Gerät
WS7_COLOR_BITS 24 16 (RGB565) würde die Datenmenge je Bild halbieren. Geht an diesem Panel nicht — die Bridge nimmt nur RGB888
WS7_PARTIAL_REFRESH 0 1 zeichnet nur geänderte Bereiche neu (LVGL-Direct-Mode, zwei wechselnde Puffer). Wäre der größte Gewinn. Geht so nicht — der halbtransparente Menü-Vorhang landet nur in einem der beiden Puffer und ist sofort wieder weg
WS7_PARALLEL_RENDER 1 LVGL zeichnet mit zwei Threads auf beiden Prozessorkernen. Aktiv

Damit WS7_PARTIAL_REFRESH nutzbar würde, müsste der LVGL-Port die geänderten Bereiche zwischen beiden Puffern abgleichen. Die Maschinerie dafür liegt in lvgl_port_v9.c, wird aber nur bei gedrehter Ausgabe übersetzt.

Die Farbtiefe muss für Sketch und LVGL-Bibliothek dieselbe sein; lv_conf.h liest WS7_COLOR_BITS deshalb direkt aus pins_config.h.

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 GPIO21 (RX)     (DISPLAY_UART_RX_PIN)
  S3 GPIO44 (RX) <---- P4 GPIO20 (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
P4_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.h im Sketch-Ordner ist die maßgebliche; sie wird über den Include-Pfad des Sketches gefunden und leitet LV_COLOR_DEPTH aus JC_PANEL_TYPE ab. Liegt zusätzlich eine alte lv_conf.h neben dem lvgl-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, getProfileDetails vorhanden.

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 + RXkein 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/GPIO51 identifizieren, nicht nach Header-Pin-Nummern.
  • S3-Seite: muss mit TOUCH_UART_ENABLED 1 geflasht sein und laufen. Da Serial (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: gesendete hello, 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!