Merge pull request 'feat(P4): Waveshare ESP32-P4-Pico mit 7inch DSI LCD (H) unterstützen (1.6.0)' (#27) from feat/waveshare-p4-pico-7zoll-dsi into main

This commit was merged in pull request #27.
This commit is contained in:
2026-09-01 03:05:49 +02:00
8 changed files with 380 additions and 53 deletions
+30
View File
@@ -1,3 +1,33 @@
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 eingestellt, weil
dessen 40-poliger Header eine andere Belegung hat als die JC-Panels: TX = GPIO17,
RX = GPIO18 (JC-Panels unverändert TX = GPIO33, RX = GPIO31).
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).
+61 -25
View File
@@ -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,53 @@ 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) |
| 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`](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,7 +74,7 @@ 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
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):
```
@@ -55,6 +82,14 @@ Für **beide** Panels dieselben P4-Pins (4,3": Header JP1, Schaltplan
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.
@@ -74,9 +109,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`)
+172 -7
View File
@@ -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
};
+42 -10
View File
@@ -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)
// 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)
// Umschalten entweder hier oder per Compiler-Flag -DJC_PANEL_TYPE=JC_PANEL_70.
// 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,31 @@
// 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. Genutzt werden GPIO17/GPIO18:
// GPIO17 (P4 TX) ----> S3 GPIO44 (RX)
// GPIO18 (P4 RX) <---- S3 GPIO43 (TX)
// GND ---- S3 GND
#define DISPLAY_UART_PORT Serial1
#define DISPLAY_UART_BAUDRATE 230400
#if JC_PANEL_TYPE == WS_PANEL_7H
#define DISPLAY_UART_TX_PIN 17
#define DISPLAY_UART_RX_PIN 18
#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
@@ -117,7 +145,11 @@
// -------------------------------------------------------------------------------------
// 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
// 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
+11 -2
View File
@@ -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;
+4 -3
View File
@@ -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.
//
+13
View File
@@ -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
+43 -2
View File
@@ -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