From 93bb0deba1cc98a20081909ddd31aafe5d5b52fc Mon Sep 17 00:00:00 2001 From: raw-designs Date: Tue, 1 Sep 2026 02:56:23 +0200 Subject: [PATCH] =?UTF-8?q?feat(P4):=20Waveshare=20ESP32-P4-Pico=20mit=207?= =?UTF-8?q?inch=20DSI=20LCD=20(H)=20unterst=C3=BCtzen=20(1.6.0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dieselbe P4-Firmware läuft jetzt zusätzlich auf einem Waveshare ESP32-P4-Pico mit dem Waveshare 7inch DSI LCD (H) (1280x720). Auswahl über JC_PANEL_TYPE in config.h (neu: WS_PANEL_7H, ab jetzt Vorgabe); JC_PANEL_43 und JC_PANEL_70 bleiben unverändert. - board_bringup.c: DSI-Bus, DBI-Kommandokanal und DPI-Panel werden ohne Hersteller-Panel-Treiber direkt angelegt (PLL_F20M, 2 Lanes zu 1250 Mbit/s, 80 MHz DPI, Austastlücken 64/64/64, RGB888). Panel-Freigabe und Helligkeit über die Bridge auf I2C 0x45; Licht erst nach dem Start der DSI-Ausgabe. - lv_conf.h leitet LV_COLOR_DEPTH aus JC_PANEL_TYPE ab (24 Bit für das Waveshare-Panel, 16 Bit für die JC-Panels) und liest dafür config.h. display_hal.cpp sichert das mit static_assert ab. - Touch GT9271 (I2C 0x14) über den GT911-Treiber; Achsentausch und Begrenzung auf die Bildfläche im process_coordinates-Hook. - pins_config.h: Auflösung, DSI-Zeitbasis und Touch-Umrechnung als WS7_*-Werte. - README und Changelog ergänzt. Die UART-Pins zum S3 stehen für das Waveshare-Board noch auf den JC-Werten (GPIO33/31) und müssen nach dem Header-Aufdruck gesetzt werden. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01DxAvqVnrY6YSoGFrNGeRTi --- JC_Display_Firmware/Changelog.txt | 29 +++++ JC_Display_Firmware/README.md | 81 +++++++++---- JC_Display_Firmware/board_bringup.c | 179 ++++++++++++++++++++++++++-- JC_Display_Firmware/config.h | 58 ++++++--- JC_Display_Firmware/display_hal.cpp | 13 +- JC_Display_Firmware/display_hal.h | 7 +- JC_Display_Firmware/lv_conf.h | 13 ++ JC_Display_Firmware/pins_config.h | 45 ++++++- 8 files changed, 371 insertions(+), 54 deletions(-) diff --git a/JC_Display_Firmware/Changelog.txt b/JC_Display_Firmware/Changelog.txt index a96b11f..2d7724d 100644 --- a/JC_Display_Firmware/Changelog.txt +++ b/JC_Display_Firmware/Changelog.txt @@ -1,3 +1,32 @@ +Version 1.6.0: +- Neu: Dieselbe Firmware läuft jetzt auch auf einem Waveshare ESP32-P4-Pico mit dem + Waveshare 7inch DSI LCD (H) (1280x720). Umgeschaltet wird über „JC_PANEL_TYPE" in + config.h; WS_PANEL_7H ist ab dieser Version die Vorgabe, JC_PANEL_43 und JC_PANEL_70 + bleiben unverändert verfügbar. +- Das Waveshare-Panel hängt hinter einer Bridge, die ausschließlich RGB888 annimmt. LVGL + rechnet für dieses Panel deshalb mit 24 statt 16 Bit Farbtiefe. lv_conf.h liest dazu + JC_PANEL_TYPE aus config.h, damit Sketch und LVGL-Bibliothek garantiert dieselbe + Farbtiefe benutzen; display_hal.cpp bricht den Build ab, falls sie auseinanderlaufen. + Der Panelwechsel muss aus diesem Grund in config.h erfolgen und nicht per Compiler-Flag. +- Bringup ohne Hersteller-Panel-Treiber: DSI-Bus, Kommandokanal und DPI-Panel werden direkt + angelegt. Entscheidend ist die Legacy-Referenztaktquelle PLL_F20M - mit der Standardquelle + bleibt der Bildschirm auf ESP32-P4 Rev. 1.3 / ECO2 schwarz. Die Zeitbasis (2 Lanes zu + 1250 Mbit/s, 80 MHz DPI-Takt, Austastlücken 64/64/64, rund 60 Hz) steht als WS7_*-Werte + in pins_config.h und ist dort anpassbar, falls das Bild reißt. +- Panel-Freigabe und Helligkeit laufen beim Waveshare nicht über einen PWM-Pin, sondern über + Register der Bridge auf I2C-Adresse 0x45. Die Hintergrundbeleuchtung wird bewusst erst + eingeschaltet, wenn die DSI-Ausgabe steht - sonst blitzt beim Start Bildrauschen auf. + Standby-Abdunklung und „Uhrzeit im Standby" funktionieren wie bei den JC-Panels. +- Touch: Der GT9271 des Waveshare-Panels benutzt dieselbe Registerbelegung wie der GT911, + liegt aber auf I2C-Adresse 0x14 und meldet im Hochformat. X und Y werden deshalb getauscht + und auf die Bildfläche begrenzt; Ausreißer des Controllers landen nicht mehr als Klick am + Bildrand. Sollte die Bedienung spiegelverkehrt reagieren, lässt sich das mit + WS7_TOUCH_MIRROR_RAW_X / _Y in pins_config.h umdrehen. +- Der Framebuffer wächst auf 3 x 2,8 MB (rund 8,3 MB PSRAM). Auf dem P4-Pico mit 32 MB + PSRAM ist das unkritisch. +- Die UART-Pins zur Hauptplatine sind für das Waveshare-Board getrennt einstellbar, weil + dessen 40-poliger Header eine andere Belegung hat als die JC-Panels. + Version 1.5.0: - Neu: Dieselbe Firmware unterstützt jetzt auch das 7-Zoll-Display Guition JC1060P470C-I-W (JD9165, 1024x600) zusätzlich zum bisherigen 4,3-Zöller JC4880P443C-I-W (ST7701, 480x800). diff --git a/JC_Display_Firmware/README.md b/JC_Display_Firmware/README.md index 6dcd863..306d5c9 100644 --- a/JC_Display_Firmware/README.md +++ b/JC_Display_Firmware/README.md @@ -1,9 +1,14 @@ -# JC-Touch-Display-Firmware (ESP32-P4) +# Touch-Display-Firmware (ESP32-P4) -Client-Firmware für die Guition-Smart-Displays **JC4880P443C-I-W (4,3")** und -**JC1060P470C-I-W (7,0")**, die als UART-Touch-Bedienung für die -Dual-PID-Siebträgersteuerung dienen. Beide Panels teilen sich denselben Sketch; das -Zielpanel wird über **`JC_PANEL_TYPE`** in [`config.h`](config.h) gewählt. +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`](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 @@ -15,31 +20,52 @@ Zustand und sendet Bedienkommandos. Protokoll: siehe In [`config.h`](config.h): ```c -#define JC_PANEL_TYPE JC_PANEL_43 // 4,3" JC4880P443C-I-W (Vorgabe) +#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 ``` -Alternativ ohne Quelltextänderung per Compiler-Flag `-DJC_PANEL_TYPE=70`. Der Schalter -steuert Panel-Treiber, Auflösung, Rotation, LCD-Reset-Pin und die Touch-Skalierung; UI, -Protokoll und Pinbelegung des UART bleiben identisch. +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`](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 | -|---|---|---| -| Haupt-MCU (UI) | ESP32-P4 | ESP32-P4 | -| WLAN/BT (hier ungenutzt) | ESP32-C6 | ESP32-C6 | -| Display | ST7701, 480×800 IPS, MIPI-DSI | JD9165, 1024×600 IPS, MIPI-DSI | -| LVGL-Ausrichtung | Rotation **270°** (PPA) → 800×480 | **keine** Rotation, nativ 1024×600 | -| Touch | GT911, I²C SDA=GPIO7 / SCL=GPIO8 | GT911, I²C SDA=GPIO7 / SCL=GPIO8 | -| Touch-Rohkoordinaten | 480×800 (= Panelraster) | **800×480** → wird auf 1024×600 skaliert | -| LCD-Reset | GPIO5 | **GPIO27** | -| Backlight | GPIO23 (LEDC-PWM) | GPIO23 (LEDC-PWM) | -| Framebuffer (3×, RGB565) | 3 × 750 KB ≈ 2,3 MB PSRAM | 3 × 1,2 MB ≈ 3,6 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 | +| 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 | **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×) | 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) | + +### 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`](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. > 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 @@ -47,8 +73,10 @@ Vendor-Pakete: 4,3" im Ordner `JC4880P443C_I_W/`, 7,0" im Repo-Ordner ## Verkabelung zur Hauptplatine (UART, gekreuzt) -Für **beide** Panels dieselben P4-Pins (4,3": Header JP1, Schaltplan -`JC4880P443C_I_W/5-Schematic/4_USB&IO.png` · 7,0": FPC-Buchse FPC4): +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). Beim Waveshare-Board +werden die beiden Pins in [`config.h`](config.h) nach dem Aufdruck des eigenen Headers +gesetzt: ``` S3 GPIO43 (TX) ----> P4 GPIO31 (RX) (DISPLAY_UART_RX_PIN) @@ -74,9 +102,10 @@ Für **beide** Panels dieselben P4-Pins (4,3": Header JP1, Schaltplan - **Arduino-ESP32** ≥ 3.1 (mit ESP32-P4-Support), Board: *ESP32P4 Dev Module*, **PSRAM aktiviert**. -- **LVGL** 9.x + `lv_conf.h`. Tipp: die `lv_conf.h` aus dem Vendor-Beispiel - (`JC4880P443C_I_W/1-Demo/arduino_examples/lvgl_v9_sw_rotation/lv_conf.h`) übernehmen - und `LV_FONT_MONTSERRAT_40` aktivieren (große Temperaturanzeige). +- **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`) diff --git a/JC_Display_Firmware/board_bringup.c b/JC_Display_Firmware/board_bringup.c index 53329c4..97dfb94 100644 --- a/JC_Display_Firmware/board_bringup.c +++ b/JC_Display_Firmware/board_bringup.c @@ -1,7 +1,8 @@ // ===================================================================================== -// board_bringup.c - ESP32-P4 / GT911 Hardware-Bringup -// JC_PANEL_43 = JC4880P443C-I-W (ST7701, 480x800) -// JC_PANEL_70 = JC1060P470C-I-W (JD9165, 1024x600) +// board_bringup.c - ESP32-P4 Hardware-Bringup +// JC_PANEL_43 = JC4880P443C-I-W (ST7701, 480x800, GT911) +// JC_PANEL_70 = JC1060P470C-I-W (JD9165, 1024x600, GT911) +// WS_PANEL_7H = Waveshare ESP32-P4-Pico + 7inch DSI LCD (H) (1280x720, GT9271) // ===================================================================================== // BEWUSST eine .c-Datei (wird als C kompiliert): die esp_lcd-Init-Makros nutzen // Compound-Literals und Out-of-Order-Designated-Initializer, die in C++ (Arduino .cpp) @@ -30,7 +31,11 @@ #include "esp_lcd_panel_ops.h" #include "esp_lcd_mipi_dsi.h" #include "src/touch/esp_lcd_touch_gt911.h" -#if JC_PANEL_TYPE == JC_PANEL_70 +#if JC_PANEL_TYPE == WS_PANEL_7H +// Das Waveshare-Panel braucht keinen Hersteller-Panel-Treiber: es wird direkt als +// DPI-Panel angelegt und mit den drei Standard-DCS-Befehlen geweckt. +#include "hal/mipi_dsi_types.h" +#elif JC_PANEL_TYPE == JC_PANEL_70 #include "src/lcd/esp_lcd_jd9165.h" #else #include "src/lcd/esp_lcd_st7701.h" @@ -51,8 +56,71 @@ #define BSP_LCD_BACKLIGHT ((gpio_num_t)LCD_LED) #define LCD_LEDC_CH LEDC_CHANNEL_0 +// Bytes je Pixel im Framebuffer. Das Waveshare-Panel laeuft in RGB888 (LVGL ebenfalls, +// siehe lv_conf.h), die JC-Panels in RGB565. +#if JC_PANEL_TYPE == WS_PANEL_7H +#define BSP_LCD_FB_BYTES_PER_PX (3) +#else +#define BSP_LCD_FB_BYTES_PER_PX (2) +#endif + static i2c_master_bus_handle_t s_i2c_handle = NULL; +// ===================================================================================== +#if JC_PANEL_TYPE == WS_PANEL_7H +// ===================================================================================== +// Waveshare 7inch DSI LCD (H): Panel-Freigabe und Helligkeit haengen an einer Bridge +// auf I2C-Adresse 0x45 - es gibt weder einen Reset- noch einen Backlight-GPIO. +// Registerfolge wie im Linux-Treiber: +// Grundinitialisierung: C0=01, C2=01, AC=01 (vor dem DSI-Bringup) +// Freigabe/Helligkeit: AD=01, AB=255-Helligkeit, AA=01 (ERST wenn DSI laeuft, +// sonst bleibt das Bild dunkel bzw. flackert beim Start) +// ===================================================================================== +static i2c_master_dev_handle_t s_bridge_handle = NULL; + +static void ws7_bridge_write(uint8_t reg, uint8_t value) +{ + if (s_bridge_handle == NULL) return; + uint8_t buf[2] = { reg, value }; + i2c_master_transmit(s_bridge_handle, buf, sizeof(buf), 100); +} + +// Bridge am I2C-Bus anmelden und Grundinitialisierung schreiben. Muss VOR dem +// DSI-Bringup laufen; die Hintergrundbeleuchtung bleibt dabei noch aus. +static void ws7_bridge_pre_init(void) +{ + i2c_device_config_t dev_cfg = { + .dev_addr_length = I2C_ADDR_BIT_LEN_7, + .device_address = WS7_BRIDGE_I2C_ADDR, + .scl_speed_hz = 100000, + }; + if (i2c_master_bus_add_device(s_i2c_handle, &dev_cfg, &s_bridge_handle) != ESP_OK) { + s_bridge_handle = NULL; + return; + } + ws7_bridge_write(0xC0, 0x01); + ws7_bridge_write(0xC2, 0x01); + ws7_bridge_write(0xAC, 0x01); +} + +void jc_backlight_init(void) +{ + // Nichts zu tun - die Bridge uebernimmt das, siehe ws7_bridge_pre_init(). +} + +void jc_backlight_set(int percent) +{ + if (percent > 100) percent = 100; + if (percent < 0) percent = 0; + uint8_t brightness = (uint8_t)((255 * percent) / 100); + ws7_bridge_write(0xAD, 0x01); // Panel-/Backlight-Freigabe + ws7_bridge_write(0xAB, (uint8_t)(255 - brightness)); + ws7_bridge_write(0xAA, 0x01); // Helligkeit uebernehmen +} + +// ===================================================================================== +#else // JC-Panels: Hintergrundbeleuchtung als LEDC-PWM an einem GPIO +// ===================================================================================== void jc_backlight_init(void) { const ledc_channel_config_t ch = { @@ -83,6 +151,7 @@ void jc_backlight_set(int percent) ledc_set_duty(LEDC_LOW_SPEED_MODE, LCD_LEDC_CH, duty); ledc_update_duty(LEDC_LOW_SPEED_MODE, LCD_LEDC_CH); } +#endif // JC_PANEL_TYPE == WS_PANEL_7H IRAM_ATTR static bool on_vsync(esp_lcd_panel_handle_t panel, esp_lcd_dpi_panel_event_data_t *edata, void *ctx) @@ -90,6 +159,34 @@ IRAM_ATTR static bool on_vsync(esp_lcd_panel_handle_t panel, return lvgl_port_notify_lcd_vsync(); } +#if JC_PANEL_TYPE == WS_PANEL_7H +// Der GT9271 des Waveshare-Panels meldet im Hochformat (Roh-X 0..720, Roh-Y 0..1280), +// das Bild laeuft aber im Querformat 1280x720. Achsentausch (und bei Bedarf Spiegelung) +// deshalb ueber den process_coordinates-Hook, der VOR den swap/mirror-Flags von +// esp_lcd_touch greift - deren Flags rechnen mit x_max/y_max des BILDES und wuerden auf +// den Rohwerten falsche Ergebnisse liefern. +static void ws7_touch_map(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y, + uint16_t *strength, uint8_t *point_num, uint8_t max_point_num) +{ + (void)tp; (void)strength; (void)max_point_num; + if (point_num == NULL) return; + for (uint8_t i = 0; i < *point_num; i++) { + uint16_t raw_x = x[i]; + uint16_t raw_y = y[i]; +#if WS7_TOUCH_MIRROR_RAW_X + raw_x = (raw_x > WS7_TOUCH_RAW_X_MAX) ? 0 : (uint16_t)(WS7_TOUCH_RAW_X_MAX - raw_x); +#endif +#if WS7_TOUCH_MIRROR_RAW_Y + raw_y = (raw_y > WS7_TOUCH_RAW_Y_MAX) ? 0 : (uint16_t)(WS7_TOUCH_RAW_Y_MAX - raw_y); +#endif + // Achsentausch + Begrenzung auf die Bildflaeche (der GT9271 liefert vereinzelt + // Ausreisser, die sonst als Klick am Rand ankaemen). + x[i] = (raw_y >= LCD_H_RES) ? (LCD_H_RES - 1) : raw_y; + y[i] = (raw_x >= LCD_V_RES) ? (LCD_V_RES - 1) : raw_x; + } +} +#endif + #if JC_PANEL_TYPE == JC_PANEL_70 // Der GT911 des 7,0"-Panels liefert Rohkoordinaten im Raster 800x480 (nicht 1024x600). // Ohne Umrechnung waere nur das linke obere Rechteck erreichbar. Das Hersteller-Beispiel @@ -123,6 +220,11 @@ void jc_board_bringup(void) }; i2c_new_master_bus(&i2c_bus_conf, &s_i2c_handle); +#if JC_PANEL_TYPE == WS_PANEL_7H + // Bridge des Waveshare-Panels vorbereiten (noch ohne Hintergrundbeleuchtung). + ws7_bridge_pre_init(); +#endif + static esp_ldo_channel_handle_t phy_pwr_chan = NULL; esp_ldo_channel_config_t ldo_cfg = { .chan_id = BSP_MIPI_DSI_PHY_PWR_LDO_CHAN, @@ -134,7 +236,61 @@ void jc_board_bringup(void) esp_lcd_panel_io_handle_t io = NULL; esp_lcd_panel_handle_t disp_panel = NULL; -#if JC_PANEL_TYPE == JC_PANEL_70 +#if JC_PANEL_TYPE == WS_PANEL_7H + // ---------------- Waveshare 7inch DSI LCD (H) (1280x720) ---------------- + // Kein Hersteller-Panel-Treiber: DSI-Bus, DBI-Kommandokanal und DPI-Panel werden + // direkt angelegt. Entscheidend ist die Referenztaktquelle PLL_F20M - mit der + // Standardquelle bleibt das Bild auf ESP32-P4 Rev. 1.3 / ECO2 schwarz. + esp_lcd_dsi_bus_config_t bus_config = { + .bus_id = 0, + .num_data_lanes = WS7_DSI_LANES, + .phy_clk_src = MIPI_DSI_PHY_PLLREF_CLK_SRC_PLL_F20M, + .lane_bit_rate_mbps = WS7_DSI_LANE_MBPS, + }; + esp_lcd_new_dsi_bus(&bus_config, &mipi_dsi_bus); + + esp_lcd_dbi_io_config_t dbi_config = { + .virtual_channel = 0, + .lcd_cmd_bits = 8, + .lcd_param_bits = 8, + }; + esp_lcd_new_panel_io_dbi(mipi_dsi_bus, &dbi_config, &io); + + esp_lcd_dpi_panel_config_t dpi_config = { + .virtual_channel = 0, + .dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT, + .dpi_clock_freq_mhz = WS7_DPI_CLOCK_MHZ, + .pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB888, + .num_fbs = LVGL_PORT_LCD_BUFFER_NUMS, + .video_timing = { + .h_size = BSP_LCD_H_RES, + .v_size = BSP_LCD_V_RES, + .hsync_back_porch = WS7_HSYNC_BACK, + .hsync_pulse_width = WS7_HSYNC_PULSE, + .hsync_front_porch = WS7_HSYNC_FRONT, + .vsync_back_porch = WS7_VSYNC_BACK, + .vsync_pulse_width = WS7_VSYNC_PULSE, + .vsync_front_porch = WS7_VSYNC_FRONT, + }, + .flags = { + .use_dma2d = true, + }, + }; + esp_lcd_new_panel_dpi(mipi_dsi_bus, &dpi_config, &disp_panel); + + // Panel wecken (MADCTL / Sleep Out / Display On). Ein Reset gibt es hier nicht: + // ein reines DPI-Panel kennt keine reset-Funktion, esp_lcd_panel_reset() wuerde + // ins Leere greifen. + { + uint8_t zero = 0x00; + esp_lcd_panel_io_tx_param(io, 0x36, &zero, 1); // MADCTL + esp_lcd_panel_io_tx_param(io, 0x11, &zero, 1); // Sleep Out + vTaskDelay(pdMS_TO_TICKS(120)); + esp_lcd_panel_io_tx_param(io, 0x29, &zero, 1); // Display On + vTaskDelay(pdMS_TO_TICKS(20)); + } + esp_lcd_panel_init(disp_panel); // DPI-Videoausgabe starten +#elif JC_PANEL_TYPE == JC_PANEL_70 // ---------------- 7,0" JD9165 (1024x600) ---------------- esp_lcd_dsi_bus_config_t bus_config = JD9165_PANEL_BUS_DSI_2CH_CONFIG(); esp_lcd_new_dsi_bus(&bus_config, &mipi_dsi_bus); @@ -186,8 +342,10 @@ void jc_board_bringup(void) }; esp_lcd_new_panel_st7701(io, &lcd_dev_config, &disp_panel); #endif +#if JC_PANEL_TYPE != WS_PANEL_7H esp_lcd_panel_reset(disp_panel); esp_lcd_panel_init(disp_panel); +#endif // Alle Framebuffer einmal auf Schwarz loeschen. Im Avoid-Tear-Direct-Mode (mehrere // Buffer) kopiert LVGL pro Frame nur die geaenderten Bereiche in den naechsten Buffer; @@ -196,7 +354,7 @@ void jc_board_bringup(void) // nicht auf. Cache-Writeback noetig, da die Buffer im PSRAM liegen und der DMA liest. { void *fbs[3] = { NULL, NULL, NULL }; - size_t fb_size = (size_t)BSP_LCD_H_RES * BSP_LCD_V_RES * 2; // RGB565 = 2 Byte/Pixel + size_t fb_size = (size_t)BSP_LCD_H_RES * BSP_LCD_V_RES * BSP_LCD_FB_BYTES_PER_PX; #if LVGL_PORT_LCD_BUFFER_NUMS >= 3 esp_lcd_dpi_panel_get_frame_buffer(disp_panel, 3, &fbs[0], &fbs[1], &fbs[2]); #elif LVGL_PORT_LCD_BUFFER_NUMS == 2 @@ -225,6 +383,11 @@ void jc_board_bringup(void) esp_lcd_touch_handle_t tp_handle; esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_GT911_CONFIG(); tp_io_config.scl_speed_hz = 100000; +#if JC_PANEL_TYPE == WS_PANEL_7H + // GT9271 des Waveshare-Panels: gleiche Registerbelegung wie der GT911, aber + // andere I2C-Adresse. + tp_io_config.dev_addr = WS7_TOUCH_I2C_ADDR; +#endif esp_lcd_new_panel_io_i2c(s_i2c_handle, &tp_io_config, &tp_io_handle); const esp_lcd_touch_config_t tp_cfg = { .x_max = BSP_LCD_H_RES, @@ -240,7 +403,9 @@ void jc_board_bringup(void) .mirror_x = 0, .mirror_y = 0, }, -#if JC_PANEL_TYPE == JC_PANEL_70 +#if JC_PANEL_TYPE == WS_PANEL_7H + .process_coordinates = ws7_touch_map, +#elif JC_PANEL_TYPE == JC_PANEL_70 .process_coordinates = jc_touch_scale, #endif }; diff --git a/JC_Display_Firmware/config.h b/JC_Display_Firmware/config.h index 2271939..445e3f1 100644 --- a/JC_Display_Firmware/config.h +++ b/JC_Display_Firmware/config.h @@ -18,8 +18,19 @@ // 800x480 und wird in board_bringup.c auf 1024x600 hochskaliert // - LCD-Reset GPIO27, Backlight GPIO23 (LEDC-PWM) // -// Gemeinsam: ESP32-C6 (hier NICHT genutzt - WLAN/Webinterface laufen auf der -// Hauptplatine), 16 MB Flash, PSRAM aktiviert, Audio ES8311 (optional). +// WS_PANEL_7H - Waveshare ESP32-P4-Pico + Waveshare 7inch DSI LCD (H) +// - MCU: ESP32-P4 (Rev. 1.3 / ECO2), 32 MB PSRAM, 32 MB Flash, KEIN ESP32-C6 +// - Display: 1280 x 720 IPS, MIPI-DSI (2 Lanes), nativ Querformat, keine Rotation. +// Das Panel haengt hinter einer Waveshare-Bridge und akzeptiert NUR +// RGB888 -> LVGL laeuft bei diesem Panel mit 24 Bit Farbtiefe +// (siehe lv_conf.h). Kein LCD-Reset-Pin. +// - Touch: GT9271 (kapazitiv, I2C SDA=7 / SCL=8, Adresse 0x14); liefert +// Rohkoordinaten im Hochformat -> X/Y werden getauscht +// - Backlight: kein PWM-Pin, sondern Register der Bridge auf I2C-Adresse 0x45 +// +// Gemeinsam: 16 MB Flash (Waveshare: 32 MB), PSRAM aktiviert, Audio ES8311 (optional). +// Bei den JC-Panels ist zusaetzlich ein ESP32-C6 bestueckt, der hier NICHT genutzt wird - +// WLAN/Webinterface laufen auf der Hauptplatine. // // Diese Firmware ist ein reiner UART-Client. Quelle der Wahrheit ist die Hauptplatine // (ESP32-S3, Dual_PID_FastHeatUp.ino). Siehe Doku/JC-Display_UART-Protokoll.md. @@ -37,20 +48,25 @@ #endif // ------------------------------------------------------------------------------------- -// Panel-Typ (C-sicher hier definiert, da auch board_bringup.c und pins_config.h ihn lesen) -// JC_PANEL_43 = Guition JC4880P443C-I-W : 4,3", ST7701, 480x800 (per Rotation 800x480) -// JC_PANEL_70 = Guition JC1060P470C-I-W : 7,0", JD9165, 1024x600 (nativ Querformat) -// Umschalten entweder hier oder per Compiler-Flag -DJC_PANEL_TYPE=JC_PANEL_70. +// Panel-Typ (C-sicher hier definiert, da auch board_bringup.c, pins_config.h und +// lv_conf.h ihn lesen) +// JC_PANEL_43 = Guition JC4880P443C-I-W : 4,3", ST7701, 480x800 (per Rotation 800x480) +// JC_PANEL_70 = Guition JC1060P470C-I-W : 7,0", JD9165, 1024x600 (nativ Querformat) +// WS_PANEL_7H = Waveshare ESP32-P4-Pico + Waveshare 7inch DSI LCD (H) : 1280x720 +// HIER umschalten. Ein Compiler-Flag reicht NICHT sicher aus, weil lv_conf.h die +// Farbtiefe aus diesem Wert ableitet und auch die LVGL-Bibliothek damit uebersetzt +// werden muss. // ------------------------------------------------------------------------------------- #define JC_PANEL_43 43 #define JC_PANEL_70 70 +#define WS_PANEL_7H 77 #ifndef JC_PANEL_TYPE -#define JC_PANEL_TYPE JC_PANEL_43 +#define JC_PANEL_TYPE WS_PANEL_7H #endif -#if (JC_PANEL_TYPE != JC_PANEL_43) && (JC_PANEL_TYPE != JC_PANEL_70) -#error "JC_PANEL_TYPE muss JC_PANEL_43 oder JC_PANEL_70 sein" +#if (JC_PANEL_TYPE != JC_PANEL_43) && (JC_PANEL_TYPE != JC_PANEL_70) && (JC_PANEL_TYPE != WS_PANEL_7H) +#error "JC_PANEL_TYPE muss JC_PANEL_43, JC_PANEL_70 oder WS_PANEL_7H sein" #endif // ------------------------------------------------------------------------------------- @@ -86,19 +102,29 @@ // Schaltplan "5-Schematic/4_CONN.png" - kein Stiftleisten-Header, Adapterkabel noetig. // FPC4 fuehrt GPIO 34/33/32/31/30/29/28 heraus, FPC3 zusaetzlich 48/47/46/45/5/4/3/2. // -// Beide Panels: gleiche Pinwahl P4-TX = GPIO33, P4-RX = GPIO31. +// Beide JC-Panels: gleiche Pinwahl P4-TX = GPIO33, P4-RX = GPIO31. // GPIO33 (P4 TX) ----> S3 GPIO44 (RX) // GPIO31 (P4 RX) <---- S3 GPIO43 (TX) // GND ---- S3 GND +// +// Waveshare ESP32-P4-Pico (WS_PANEL_7H): 40-poliger Header im Raspberry-Pi-Pico-Format. +// Belegt sind dort u.a. I2C (7/8), TF-Karte (9/10/11/12/13/53) und der Debug-UART0 +// (37/38); diese Pins duerfen NICHT genommen werden. Die beiden Werte unten nach dem +// Aufdruck des eigenen Boards setzen. #define DISPLAY_UART_PORT Serial1 #define DISPLAY_UART_BAUDRATE 230400 +#if JC_PANEL_TYPE == WS_PANEL_7H +#define DISPLAY_UART_TX_PIN 33 // TODO: freien GPIO des Pico-Headers eintragen +#define DISPLAY_UART_RX_PIN 31 // TODO: freien GPIO des Pico-Headers eintragen +#else #define DISPLAY_UART_TX_PIN 33 #define DISPLAY_UART_RX_PIN 31 +#endif // ------------------------------------------------------------------------------------- // Firmware // ------------------------------------------------------------------------------------- -#define DISPLAY_FW_VERSION "1.5.0" // Firmware-Stand der P4-Display-Steuerung (Info-Seite) +#define DISPLAY_FW_VERSION "1.6.0" // Firmware-Stand der P4-Display-Steuerung (Info-Seite) // ------------------------------------------------------------------------------------- // Protokoll @@ -115,9 +141,13 @@ // ------------------------------------------------------------------------------------- // Display / LVGL // ------------------------------------------------------------------------------------- -// Querformat. 4,3": Panel ist physisch 480x800, per Rotation 270 (pins_config.h) -> 800x480. -// 7,0": Panel ist nativ 1024x600, keine Rotation noetig. -#if JC_PANEL_TYPE == JC_PANEL_70 +// Querformat. 4,3": Panel ist physisch 480x800, per Rotation 270 (pins_config.h) -> 800x480. +// 7,0": Panel ist nativ 1024x600, keine Rotation noetig. +// 7" WS: Panel ist nativ 1280x720, keine Rotation noetig. +#if JC_PANEL_TYPE == WS_PANEL_7H +#define DISP_HOR_RES 1280 +#define DISP_VER_RES 720 +#elif JC_PANEL_TYPE == JC_PANEL_70 #define DISP_HOR_RES 1024 #define DISP_VER_RES 600 #else diff --git a/JC_Display_Firmware/display_hal.cpp b/JC_Display_Firmware/display_hal.cpp index b814fd7..637c1a9 100644 --- a/JC_Display_Firmware/display_hal.cpp +++ b/JC_Display_Firmware/display_hal.cpp @@ -1,5 +1,5 @@ // ===================================================================================== -// display_hal.cpp - LVGL-Glue fuer das JC4880P443C-I-W +// display_hal.cpp - LVGL-Glue fuer JC4880P443C-I-W / JC1060P470C-I-W / Waveshare 7" (H) // ===================================================================================== // Realer Modus: nutzt die Hersteller-Portierung. Der eigentliche esp_lcd-Bringup liegt // bewusst in board_bringup.c (C). Hier nur die LVGL-/UI-Verdrahtung. @@ -11,6 +11,15 @@ #include "ui.h" #include "config.h" +// LVGL muss mit derselben Farbtiefe uebersetzt sein wie das Panel erwartet. Zieht der +// Build versehentlich eine fremde lv_conf.h (z.B. eine alte Datei neben dem lvgl-Ordner), +// faellt das hier auf - sonst erst am schwarzen oder farbverfaelschten Bild. +#if JC_PANEL_TYPE == WS_PANEL_7H +static_assert(LV_COLOR_DEPTH == 24, "Waveshare 7\" (H) braucht RGB888 - falsche lv_conf.h?"); +#else +static_assert(LV_COLOR_DEPTH == 16, "JC-Panels brauchen RGB565 - falsche lv_conf.h?"); +#endif + static ProtocolClient* g_client = nullptr; // ===================================================================================== @@ -46,7 +55,7 @@ void hal_backlight(int percent) { jc_backlight_set(percent); } // STUB-MODUS - minimales LVGL ohne Panel/Touch (zum Testen von Protokoll/Logik). // ===================================================================================== #define HAL_BUF_LINES 40 -#define HAL_BYTES_PER_PX 2 +#define HAL_BYTES_PER_PX (LV_COLOR_DEPTH / 8) static uint8_t s_buf1[DISP_HOR_RES * HAL_BUF_LINES * HAL_BYTES_PER_PX]; static lv_display_t* s_disp = nullptr; diff --git a/JC_Display_Firmware/display_hal.h b/JC_Display_Firmware/display_hal.h index a63a540..50ab102 100644 --- a/JC_Display_Firmware/display_hal.h +++ b/JC_Display_Firmware/display_hal.h @@ -1,10 +1,11 @@ // ===================================================================================== -// display_hal.h - Board-/Panel-/Touch-Anbindung (ST7701 bzw. JD9165 + GT911) + LVGL-Glue +// display_hal.h - Board-/Panel-/Touch-Anbindung (ST7701 / JD9165 / Waveshare-DSI) + LVGL-Glue // ===================================================================================== // Einziger board-spezifischer Teil. Baut auf der HERSTELLER-LVGL-PORTIERUNG des // JC4880P443C-I-W auf (1-Demo/arduino_examples/lvgl_v9_sw_rotation): -// - MIPI-DSI ST7701 (480x800) bzw. JD9165 (1024x600) - Auswahl ueber JC_PANEL_TYPE -// - GT911-Touch (I2C SDA=7/SCL=8), Backlight GPIO23 +// - MIPI-DSI ST7701 (480x800), JD9165 (1024x600) oder Waveshare 7" (H) (1280x720) +// - Auswahl ueber JC_PANEL_TYPE +// - GT911- bzw. GT9271-Touch (I2C SDA=7/SCL=8); Backlight GPIO23 bzw. Bridge-Register // - LVGL laeuft in einem EIGENEN FreeRTOS-Task -> UI-Zugriffe von aussen muessen // mit hal_lock()/hal_unlock() (= lvgl_port_lock/unlock) geschuetzt werden. // diff --git a/JC_Display_Firmware/lv_conf.h b/JC_Display_Firmware/lv_conf.h index 0e47eca..1b90379 100644 --- a/JC_Display_Firmware/lv_conf.h +++ b/JC_Display_Firmware/lv_conf.h @@ -26,8 +26,21 @@ COLOR SETTINGS *====================*/ +/* Panel-Typ des Projekts. Liegt im selben Ordner wie diese Datei, ein Include mit + * Anfuehrungszeichen findet also immer genau diese config.h - auch dann, wenn die + * LVGL-Bibliothek uebersetzt wird. Nur so bekommen Sketch UND Bibliothek dieselbe + * Farbtiefe; ein Compiler-Flag allein wuerde die Bibliothek nicht erreichen. */ +#include "config.h" + /*Color depth: 1 (I1), 8 (L8), 16 (RGB565), 24 (RGB888), 32 (XRGB8888)*/ +/* Waveshare 7inch DSI LCD (H): Die Bridge des Panels nimmt ausschliesslich RGB888 + * entgegen, deshalb muss auch LVGL in 24 Bit rechnen. Die JC-Panels laufen wie + * bisher mit RGB565. */ +#if JC_PANEL_TYPE == WS_PANEL_7H +#define LV_COLOR_DEPTH 24 +#else #define LV_COLOR_DEPTH 16 +#endif /*========================= STDLIB WRAPPER SETTINGS diff --git a/JC_Display_Firmware/pins_config.h b/JC_Display_Firmware/pins_config.h index bf2c368..7fd94ab 100644 --- a/JC_Display_Firmware/pins_config.h +++ b/JC_Display_Firmware/pins_config.h @@ -18,7 +18,11 @@ // Bei Rotation 90 nutzen beide Modi ohnehin 3 Framebuffer -> kein Mehrverbrauch. #define EXAMPLE_LVGL_PORT_AVOID_TEAR_MODE 2 //range 1 to 3 -#if JC_PANEL_TYPE == JC_PANEL_70 +#if JC_PANEL_TYPE == WS_PANEL_7H +// Waveshare 7" (H): Panel ist nativ 1280x720 Querformat -> keine Rotation, kein PPA noetig. +#define EXAMPLE_LVGL_PORT_ROTATION_DEGREE_ 0 // 0,90,180,270 +#define EXAMPLE_LVGL_PORT_PPA_ROTATION_ENABLE 0 +#elif JC_PANEL_TYPE == JC_PANEL_70 // 7,0" JD9165: Panel ist nativ 1024x600 Querformat -> keine Rotation, kein PPA noetig. #define EXAMPLE_LVGL_PORT_ROTATION_DEGREE_ 0 // 0,90,180,270 #define EXAMPLE_LVGL_PORT_PPA_ROTATION_ENABLE 0 @@ -31,7 +35,44 @@ // LCD_H_RES/LCD_V_RES = NATIVE Panel-Aufloesung (vor der LVGL-Rotation). -#if JC_PANEL_TYPE == JC_PANEL_70 +#if JC_PANEL_TYPE == WS_PANEL_7H + +#define LCD_H_RES 1280 +#define LCD_V_RES 720 + +// Das Waveshare-Panel hat weder einen Reset-Pin noch eine PWM-Hintergrundbeleuchtung: +// Reset macht die Bridge selbst, die Helligkeit laeuft ueber deren I2C-Register. +#define LCD_RST (-1) +#define LCD_LED (-1) + +// ---- MIPI-DSI-Parameter des Waveshare 7inch DSI LCD (H) ----------------------------- +// Uebernommen aus dem funktionierenden Funktionstest-Sketch. Wichtig ist die Legacy- +// Referenztaktquelle PLL_F20M: nur damit liefert der ESP32-P4 Rev. 1.3 / ECO2 ein Bild. +// Das Panel akzeptiert nur RGB888 (24 Bit) - deshalb rechnet LVGL bei diesem Panel +// ebenfalls mit 24 Bit (lv_conf.h). +#define WS7_DSI_LANES 2 +#define WS7_DSI_LANE_MBPS 1250 +#define WS7_DPI_CLOCK_MHZ 80 // 1472 x 912 Gesamtraster -> ca. 60 Hz +#define WS7_HSYNC_BACK 64 +#define WS7_HSYNC_PULSE 64 +#define WS7_HSYNC_FRONT 64 +#define WS7_VSYNC_BACK 64 +#define WS7_VSYNC_PULSE 64 +#define WS7_VSYNC_FRONT 64 + +// Bridge (Helligkeit/Panel-Freigabe) und Touch-Controller am selben I2C-Bus wie GT911. +#define WS7_BRIDGE_I2C_ADDR 0x45 +#define WS7_TOUCH_I2C_ADDR 0x14 // GT9271 + +// Der GT9271 meldet im Hochformat: Roh-X 0..720, Roh-Y 0..1280. Fuer das Querformat +// werden die Achsen getauscht. Zeigt der Cursor spiegelverkehrt, hier die passende +// Achse auf 1 setzen (die Spiegelung geschieht VOR dem Tausch, auf den Rohwerten). +#define WS7_TOUCH_RAW_X_MAX 720 +#define WS7_TOUCH_RAW_Y_MAX 1280 +#define WS7_TOUCH_MIRROR_RAW_X 0 +#define WS7_TOUCH_MIRROR_RAW_Y 0 + +#elif JC_PANEL_TYPE == JC_PANEL_70 #define LCD_H_RES 1024 #define LCD_V_RES 600