fix(P4): DSI-Strecke beim Hochlauf einmal neu aufbauen (1.6.21)

Der Hochlauf lief zuletzt vollständig fehlerfrei durch - Bridge zweimal
eingestellt, Panel zweimal geweckt, alle I2C-Bausteine erreichbar - und
trotzdem kam beim ersten Einschalten kein Bild. Erst ein Reset half, und
der zuverlässig.

Es fehlte also kein Befehl mehr, sondern der Vorgang selbst: Ein Reset
unterscheidet sich an dieser Stelle in genau einem Punkt von unserem
Ablauf - die DSI-Verbindung geht einmal weg und neu auf, während Bridge
und Panel bereits versorgt und eingestellt sind. Die Wiederholungen aus
1.6.19/1.6.20 liefen dagegen über eine durchgehend bestehende Verbindung.

- Der DSI-Aufbau (Bus, Kommandokanal, Bildausgabe, Weckbefehle) steckt
  jetzt in ws7_dsi_bringup() und ist damit wiederholbar.
- Nach dem ersten Durchlauf werden esp_lcd_panel_del(),
  esp_lcd_panel_io_del() und esp_lcd_del_dsi_bus() aufgerufen und die
  Strecke neu angelegt. Schalter WS7_DSI_RESTART, Pause
  WS7_DSI_RESTART_MS.

Beide Panel-Varianten mit arduino-cli gegengebaut.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P7JsiDJ1QbNFLDz5chf8Jt
This commit is contained in:
raw-designs
2026-09-02 02:26:24 +02:00
co-authored by Claude Opus 5
parent 6d7d544ac7
commit c2a8b21917
3 changed files with 125 additions and 54 deletions
+101 -54
View File
@@ -422,6 +422,84 @@ static void ws7_panel_wake(esp_lcd_panel_io_handle_t io, const char *wann)
}
#endif
#if JC_PANEL_TYPE == WS_PANEL_7H
// Baut die komplette DSI-Strecke auf: Bus, Kommandokanal, Bildausgabe, und weckt das
// Panel. Bewusst als eigene Funktion, damit der ganze Vorgang wiederholbar ist.
static bool ws7_dsi_bringup(esp_lcd_dsi_bus_handle_t *out_bus,
esp_lcd_panel_io_handle_t *out_io,
esp_lcd_panel_handle_t *out_panel,
esp_lcd_dpi_panel_config_t *out_dpi_config)
{
esp_lcd_dsi_bus_handle_t mipi_dsi_bus = NULL;
esp_lcd_panel_io_handle_t io = NULL;
esp_lcd_panel_handle_t disp_panel = NULL;
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,
};
BSP_STEP(esp_lcd_new_dsi_bus(&bus_config, &mipi_dsi_bus), "MIPI-DSI-Bus");
esp_lcd_dbi_io_config_t dbi_config = {
.virtual_channel = 0,
.lcd_cmd_bits = 8,
.lcd_param_bits = 8,
};
BSP_STEP(esp_lcd_new_panel_io_dbi(mipi_dsi_bus, &dbi_config, &io), "DBI-Kommandokanal");
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,
#if WS7_COLOR_BITS == 24
.pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB888,
#else
.pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565,
#endif
.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,
},
};
BSP_STEP(esp_lcd_new_panel_dpi(mipi_dsi_bus, &dpi_config, &disp_panel),
"DPI-Panel (Framebuffer im PSRAM)");
if (disp_panel == NULL) {
esp_rom_printf("[Panel] Abbruch: Panel wurde nicht angelegt. Haeufigste Ursache ist zu "
"wenig PSRAM - PSRAM in den Board-Einstellungen aktivieren oder in "
"pins_config.h weniger Framebuffer waehlen.\n");
return false;
}
ws7_panel_wake(io, "vor dem Start der Videoausgabe");
BSP_STEP(esp_lcd_panel_init(disp_panel), "DPI-Videoausgabe starten");
// Zweiter Anlauf, jetzt bei laufender Videoausgabe: faengt den Fall ab, dass das
// Panel beim ersten Mal noch nicht aufnahmebereit war.
vTaskDelay(pdMS_TO_TICKS(WS7_PANEL_SETTLE_MS));
ws7_bridge_core_init("nach dem Start der Videoausgabe");
ws7_panel_wake(io, "nach dem Start der Videoausgabe");
*out_bus = mipi_dsi_bus;
*out_io = io;
*out_panel = disp_panel;
*out_dpi_config = dpi_config;
return true;
}
#endif
// Bringt Panel + Touch + LVGL-Port hoch (LVGL laeuft danach in eigenem Task).
// Rueckgabe false: Panel kam nicht hoch - der Aufrufer darf dann KEINE LVGL-Funktion
// benutzen, sonst folgt ein zweiter Absturz, der die eigentliche Ursache ueberdeckt.
@@ -483,9 +561,12 @@ bool jc_board_bringup(void)
};
BSP_STEP(esp_ldo_acquire_channel(&ldo_cfg, &phy_pwr_chan), "Stromversorgung MIPI-D-PHY");
esp_lcd_dsi_bus_handle_t mipi_dsi_bus;
esp_lcd_dsi_bus_handle_t mipi_dsi_bus = NULL;
esp_lcd_panel_io_handle_t io = NULL;
esp_lcd_panel_handle_t disp_panel = NULL;
#if JC_PANEL_TYPE == WS_PANEL_7H
esp_lcd_dpi_panel_config_t dpi_config;
#endif
#if JC_PANEL_TYPE == WS_PANEL_7H
// ---------------- Waveshare 7inch DSI LCD (H) (1280x720) ----------------
@@ -495,63 +576,29 @@ bool jc_board_bringup(void)
bsp_report_psram((size_t)BSP_LCD_H_RES * BSP_LCD_V_RES * BSP_LCD_FB_BYTES_PER_PX
* LVGL_PORT_LCD_BUFFER_NUMS);
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,
};
BSP_STEP(esp_lcd_new_dsi_bus(&bus_config, &mipi_dsi_bus), "MIPI-DSI-Bus");
esp_lcd_dbi_io_config_t dbi_config = {
.virtual_channel = 0,
.lcd_cmd_bits = 8,
.lcd_param_bits = 8,
};
BSP_STEP(esp_lcd_new_panel_io_dbi(mipi_dsi_bus, &dbi_config, &io), "DBI-Kommandokanal");
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,
#if WS7_COLOR_BITS == 24
.pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB888,
#else
.pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565,
#endif
.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,
},
};
BSP_STEP(esp_lcd_new_panel_dpi(mipi_dsi_bus, &dpi_config, &disp_panel),
"DPI-Panel (Framebuffer im PSRAM)");
if (disp_panel == NULL) {
esp_rom_printf("[Panel] Abbruch: Panel wurde nicht angelegt. Haeufigste Ursache ist zu "
"wenig PSRAM - PSRAM in den Board-Einstellungen aktivieren oder in "
"pins_config.h weniger Framebuffer waehlen.\n");
if (!ws7_dsi_bringup(&mipi_dsi_bus, &io, &disp_panel, &dpi_config)) {
return false;
}
ws7_panel_wake(io, "vor dem Start der Videoausgabe");
#if WS7_DSI_RESTART
// Die Strecke einmal komplett ab- und wieder aufbauen.
//
// Beim ersten Einschalten kam trotz fehlerfreiem Hochlauf kein Bild; erst ein Reset
// half, und zwar zuverlaessig. Ein Reset unterscheidet sich an dieser Stelle nur in
// einem Punkt von unserem Ablauf: Die DSI-Verbindung geht einmal weg und neu auf,
// waehrend Bridge und Panel bereits versorgt und eingestellt sind. Weder die
// wiederholte Grundeinstellung der Bridge noch die wiederholten Weckbefehle ersetzen
// das. Genau dieser Ab- und Wiederaufbau wird hier nachgeholt - ohne Reset.
esp_rom_printf("[Panel] DSI-Strecke wird neu aufgebaut\n");
esp_lcd_panel_del(disp_panel);
esp_lcd_panel_io_del(io);
esp_lcd_del_dsi_bus(mipi_dsi_bus);
vTaskDelay(pdMS_TO_TICKS(WS7_DSI_RESTART_MS));
BSP_STEP(esp_lcd_panel_init(disp_panel), "DPI-Videoausgabe starten");
// Zweiter Anlauf, jetzt bei laufender Videoausgabe: faengt den Fall ab, dass das
// Panel beim ersten Mal noch nicht aufnahmebereit war.
vTaskDelay(pdMS_TO_TICKS(WS7_PANEL_SETTLE_MS));
ws7_bridge_core_init("nach dem Start der Videoausgabe");
ws7_panel_wake(io, "nach dem Start der Videoausgabe");
if (!ws7_dsi_bringup(&mipi_dsi_bus, &io, &disp_panel, &dpi_config)) {
return false;
}
#endif
#if WS7_TEST_PATTERN
// Prueffarbbalken: Sie entstehen im DSI-Baustein selbst und benutzen weder den
// Bildspeicher noch LVGL. Erscheinen sie, arbeitet die Anzeigekette bis zum Panel und