Compare commits

..
Author SHA1 Message Date
raw-designsandClaude Opus 5 43c5d5a41a fix(P4): Hängenden I2C-Bus freitakten - Ursache des schwarzen Bildes (1.6.13)
Der Log nach einem Reset zeigte alle Panel-Schritte fehlerfrei, aber
"i2c transaction failed" beim GT911. Bridge und Touch teilen sich den Bus:
Trifft ein Reset des P4 mitten in eine Übertragung, bleibt der Baustein in
seiner Bitausgabe stehen und hält SDA dauerhaft low. Beide hängen an
Dauerstrom, der Zustand überlebt also Reset und Flashen.

- ws7_i2c_bus_recover() taktet SCL vor dem Anlegen des Busses bis zu neunmal
  von Hand, bis SDA freigegeben wird, und erzeugt dann eine Stop-Bedingung.
  Bei freiem Bus läuft die Funktion wirkungslos durch.
- ws7_bridge_write() prüft den Rückgabewert. Bisher liefen fehlgeschlagene
  Schreibzugriffe stillschweigend ins Leere - der eigentliche Grund, warum
  das schwarze Bild keinerlei Spur hinterließ.
- pins_config.h: "#elsealle" statt "#else" seit 1.6.10 korrigiert. Der
  Tippfehler traf nur den JC_PANEL_43-Zweig, der dadurch nicht mehr
  übersetzbar war. Beide Panel-Varianten wieder gegengebaut.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018QoLDQeUh1dCQz7yYZVb4Y
2026-09-01 16:16:09 +02:00
thomas dfd2aaddd1 Merge pull request 'fix(P4): Abschaltfolge zurücknehmen, Startgrund und LDO prüfen (1.6.12)' (#40) from fix/bridge-abschaltfolge-zuruecknehmen into main 2026-09-01 15:45:24 +02:00
raw-designsandClaude Opus 5 6c783c55de fix(P4): Abschaltfolge zurücknehmen, Startgrund und LDO prüfen (1.6.12)
Die Bridge-Abschaltfolge aus 1.6.11 hat den Fehler nicht behoben, sondern
verschlimmert: Nach C0/C2/AC = 0x00 kam das Panel auch direkt nach dem
Flashen nicht mehr hoch. Der Bringup entspricht wieder 1.6.10.

Stattdessen zwei Diagnosen zur Eingrenzung:
- esp_reset_reason() wird beim Hochlauf ausgegeben, um Kalt- von Warmstart
  unterscheiden zu können.
- esp_ldo_acquire_channel() läuft nicht mehr ungeprüft durch, sondern meldet
  einen Fehler über BSP_STEP. Es war der einzige Schritt ohne Prüfung.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018QoLDQeUh1dCQz7yYZVb4Y
2026-09-01 15:44:02 +02:00
raw-designs f38ea3045b Revert "Merge pull request 'fix(P4): Schwarzes Bild nach Reset am Waveshare-Panel (1.6.11)' (#39) from fix/schwarzes-bild-nach-reset into main"
This reverts commit 0a6c6ed869, reversing
changes made to edb1e333f0.
2026-09-01 15:37:29 +02:00
thomas 0a6c6ed869 Merge pull request 'fix(P4): Schwarzes Bild nach Reset am Waveshare-Panel (1.6.11)' (#39) from fix/schwarzes-bild-nach-reset into main 2026-09-01 15:23:35 +02:00
5 changed files with 111 additions and 50 deletions
+27 -12
View File
@@ -1,15 +1,30 @@
Version 1.6.11: Version 1.6.13:
- Fehlerbehebung: Nach einem Reset des P4 blieb das Bild schwarz, während die - Ursache des schwarzen Bildes gefunden: ein haengender I2C-Bus. Trifft ein Reset des P4
Hintergrundbeleuchtung brannte; erst ein erneutes Flashen half. Die Bridge des mitten in eine laufende Uebertragung, bleibt der angesprochene Baustein in seiner
Waveshare-Panels hat keine Reset-Leitung und hängt an Dauerstrom - ein Reset des P4 Bitausgabe stehen und haelt die Datenleitung dauerhaft auf Masse. Damit schlaegt jede
setzt sie also nicht zurück, ihre Register standen noch auf den Werten der vorigen weitere Uebertragung fehl. Bridge und Touch-Controller haengen an Dauerstrom, weshalb
Sitzung. Der P4 baut seine DSI-Strecke aber komplett neu auf, und ein frischer DSI-Start dieser Zustand jeden Reset und sogar das Flashen ueberlebt - nur echtes Stromabziehen
auf einer bereits laufenden Bridge liefert kein Bild. Beim Flashen wird die Versorgung loest ihn. Die Folge: Die Bridge wird nie initialisiert, das Bild bleibt schwarz, und
getrennt, deshalb war der Fehler dort nicht zu sehen. weil sie ihre Register behaelt, brennt die Hintergrundbeleuchtung weiter.
- Der Start schaltet die Bridge jetzt zuerst definiert ab (Beleuchtung, dann Ausgabe, - Vor dem Anlegen des I2C-Busses wird die Taktleitung jetzt von Hand getaktet, bis der
dann Grundregister), wartet WS7_BRIDGE_RESET_MS und fährt sie erst danach hoch. Der Baustein die Datenleitung freigibt, danach folgt eine Stopp-Bedingung. Das ist der in
Wert steht in pins_config.h (Vorgabe 120 ms) und ist die erste Stellschraube, falls der I2C-Spezifikation vorgesehene Weg und laeuft bei freiem Bus wirkungslos durch.
nach einem Reset doch einmal ein schwarzes Bild auftaucht. - Fehlerbehebung: Schreibzugriffe auf die Bridge liefen stillschweigend ins Leere. Genau
deshalb war der Fehler so schwer zu finden - das Bild blieb ohne jeden Hinweis schwarz.
Sie melden Fehler jetzt im Klartext.
- Fehlerbehebung: In pins_config.h stand seit 1.6.10 "#elsealle" statt "#else". Der
Tippfehler traf nur den Zweig des 4,3-Zoll-Panels, das damit nicht mehr uebersetzbar war.
Beide Panel-Varianten sind jetzt wieder gegengebaut.
Version 1.6.12:
- Die Abschaltfolge für die Bridge aus 1.6.11 ist zurückgenommen. Sie hat den Fehler nicht
behoben, sondern verschlimmert: Nach dem Nullsetzen von C0/C2/AC kam das Panel auch
direkt nach dem Flashen nicht mehr hoch, die normale Einschaltfolge holt es aus diesem
Zustand nicht zurück. Der Start entspricht damit wieder 1.6.10.
- Stattdessen zwei Diagnosen, um die Ursache des schwarzen Bildes nach einem Reset
einzugrenzen: Der Startgrund wird beim Hochlauf ausgegeben (1 = Kaltstart, alles andere
Warmstart), und das Anfordern der Stromversorgung für die MIPI-Strecke wird jetzt auf
Fehler geprüft - bislang lief dieser Schritt als einziger ungeprüft durch.
Version 1.6.10: Version 1.6.10:
- WS7_PARTIAL_REFRESH ist jetzt auch im Auslieferungsstand 1. Am Gerät geprüft: kein - WS7_PARTIAL_REFRESH ist jetzt auch im Auslieferungsstand 1. Am Gerät geprüft: kein
-5
View File
@@ -67,11 +67,6 @@ Das Panel hängt hinter einer Waveshare-Bridge und braucht **keinen** Hersteller
- Reihenfolge: Bridge-Grundinitialisierung (`C0`/`C2`/`AC`) → DSI → DCS `MADCTL`/`Sleep Out`/ - Reihenfolge: Bridge-Grundinitialisierung (`C0`/`C2`/`AC`) → DSI → DCS `MADCTL`/`Sleep Out`/
`Display On` → DPI-Start → **erst dann** Hintergrundbeleuchtung. Wird das Licht früher `Display On` → DPI-Start → **erst dann** Hintergrundbeleuchtung. Wird das Licht früher
eingeschaltet, blitzt beim Start Bildrauschen auf. eingeschaltet, blitzt beim Start Bildrauschen auf.
- **Nach einem Reset:** Die Bridge hat keine Reset-Leitung und hängt an Dauerstrom — ein
Reset des P4 setzt sie **nicht** zurück. Der Bringup schaltet sie deshalb zuerst
definiert ab, wartet `WS7_BRIDGE_RESET_MS` und fährt sie dann neu hoch. Ohne das trifft
ein frischer DSI-Start auf eine noch laufende Bridge: Bild schwarz, Beleuchtung an.
Nach dem Flashen fällt das nicht auf, weil dabei die Versorgung getrennt wird.
- **Einbaulage:** `WS7_ROTATE_180` in [`pins_config.h`](pins_config.h) dreht Bild **und** - **Einbaulage:** `WS7_ROTATE_180` in [`pins_config.h`](pins_config.h) dreht Bild **und**
Touch um 180°, falls das Panel auf dem Kopf montiert wird. Vorgabe ist **0** — in der 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 jetzigen Einbaulage steht das Bild richtig herum. Die Drehung macht der
+82 -25
View File
@@ -30,6 +30,7 @@
#include "esp_heap_caps.h" #include "esp_heap_caps.h"
#include "esp_rom_sys.h" #include "esp_rom_sys.h"
#include "esp_timer.h" #include "esp_timer.h"
#include "esp_system.h"
#include "esp_ldo_regulator.h" #include "esp_ldo_regulator.h"
#include "esp_lcd_panel_io.h" #include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_ops.h" #include "esp_lcd_panel_ops.h"
@@ -70,6 +71,68 @@
static i2c_master_bus_handle_t s_i2c_handle = NULL; static i2c_master_bus_handle_t s_i2c_handle = NULL;
#if JC_PANEL_TYPE == WS_PANEL_7H
// ------------------------------------------------------------------------------------
// Haengenden I2C-Bus befreien
//
// Trifft ein Reset des P4 mitten in eine laufende I2C-Uebertragung, bleibt der
// angesprochene Baustein in seiner Bitausgabe stehen und haelt die Datenleitung dauerhaft
// auf Masse. Der Bus ist damit tot: Jede weitere Uebertragung schlaegt fehl. Da Bridge und
// Touch-Controller an Dauerstrom haengen, ueberlebt dieser Zustand jeden Reset und sogar
// das Flashen - nur echtes Stromabziehen loest ihn.
//
// Folge: Die Bridge wird nie initialisiert, das Bild bleibt schwarz, und weil sie ihre
// Register behaelt, brennt die Hintergrundbeleuchtung weiter. Genau dieses Bild.
//
// Abhilfe ist der uebliche Weg aus der I2C-Spezifikation: Vor dem Anlegen des Busses die
// Taktleitung von Hand takten, bis der Baustein sein letztes Bit ausgegeben hat und die
// Datenleitung wieder loslaesst, danach eine Stopp-Bedingung erzeugen.
static void ws7_i2c_bus_recover(void)
{
gpio_config_t io = {
.pin_bit_mask = BIT64(BSP_I2C_SDA) | BIT64(BSP_I2C_SCL),
.mode = GPIO_MODE_INPUT_OUTPUT_OD, // offener Kollektor, Zustand lesbar
.pull_up_en = GPIO_PULLUP_ENABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE,
};
gpio_config(&io);
gpio_set_level(BSP_I2C_SDA, 1);
gpio_set_level(BSP_I2C_SCL, 1);
esp_rom_delay_us(10);
if (gpio_get_level(BSP_I2C_SDA) != 0) {
return; // Bus frei - nichts zu tun
}
esp_rom_printf("[Panel] I2C-Bus haengt - wird freigetaktet\n");
// Bis zu neun Takte: so viele braucht ein Baustein hoechstens, um ein angefangenes
// Byte samt Bestaetigungsbit zu Ende zu schieben.
for (int i = 0; i < 9 && gpio_get_level(BSP_I2C_SDA) == 0; i++) {
gpio_set_level(BSP_I2C_SCL, 0);
esp_rom_delay_us(5);
gpio_set_level(BSP_I2C_SCL, 1);
esp_rom_delay_us(5);
}
// Stopp-Bedingung: Datenleitung geht bei hoher Taktleitung von Masse auf High.
gpio_set_level(BSP_I2C_SDA, 0);
esp_rom_delay_us(5);
gpio_set_level(BSP_I2C_SCL, 1);
esp_rom_delay_us(5);
gpio_set_level(BSP_I2C_SDA, 1);
esp_rom_delay_us(10);
esp_rom_printf("[Panel] I2C-Bus nach Freitakten: %s\n",
gpio_get_level(BSP_I2C_SDA) ? "frei" : "weiterhin belegt");
// Pins wieder freigeben, damit der I2C-Treiber sie uebernehmen kann.
gpio_reset_pin(BSP_I2C_SDA);
gpio_reset_pin(BSP_I2C_SCL);
}
#endif // JC_PANEL_TYPE == WS_PANEL_7H
// Klartext-Meldung auf der seriellen Konsole. Bewusst esp_rom_printf: das laeuft auch bei // Klartext-Meldung auf der seriellen Konsole. Bewusst esp_rom_printf: das laeuft auch bei
// abgeschaltetem Core-Debug-Level und ohne Heap, also genau dann, wenn es darauf ankommt. // abgeschaltetem Core-Debug-Level und ohne Heap, also genau dann, wenn es darauf ankommt.
#define BSP_STEP(call, what) \ #define BSP_STEP(call, what) \
@@ -107,19 +170,17 @@ static void ws7_bridge_write(uint8_t reg, uint8_t value)
{ {
if (s_bridge_handle == NULL) return; if (s_bridge_handle == NULL) return;
uint8_t buf[2] = { reg, value }; uint8_t buf[2] = { reg, value };
i2c_master_transmit(s_bridge_handle, buf, sizeof(buf), 100); esp_err_t err = i2c_master_transmit(s_bridge_handle, buf, sizeof(buf), 100);
if (err != ESP_OK) {
// Frueher lief das stillschweigend ins Leere. Schlaegt es fehl, wird die Bridge
// nie initialisiert und das Bild bleibt schwarz - ohne jeden Hinweis darauf.
esp_rom_printf("[Panel] Bridge-Register 0x%02X liess sich nicht schreiben: %s\n",
reg, esp_err_to_name(err));
}
} }
// Bridge in einen definierten Grundzustand bringen und neu initialisieren. // Bridge am I2C-Bus anmelden und Grundinitialisierung schreiben. Muss VOR dem
// // DSI-Bringup laufen; die Hintergrundbeleuchtung bleibt dabei noch aus.
// WICHTIG - der Grund fuer das Abschalten am Anfang: Die Bridge hat keine Reset-Leitung
// und haengt an Dauerstrom. Ein Reset des P4 setzt sie also NICHT zurueck; ihre Register
// stehen noch so, wie die vorige Sitzung sie hinterlassen hat. Der P4 baut seine
// DSI-Strecke aber komplett neu auf. Trifft ein frischer DSI-Start auf eine bereits
// laufende Bridge, bleibt das Bild schwarz, waehrend die Hintergrundbeleuchtung brennt.
// Nach dem Flashen faellt das nicht auf, weil dabei die Versorgung getrennt wird.
//
// Deshalb erst ausschalten (Beleuchtung, dann Bridge), kurz warten, dann normal hochfahren.
static void ws7_bridge_pre_init(void) static void ws7_bridge_pre_init(void)
{ {
i2c_device_config_t dev_cfg = { i2c_device_config_t dev_cfg = {
@@ -131,22 +192,9 @@ static void ws7_bridge_pre_init(void)
s_bridge_handle = NULL; s_bridge_handle = NULL;
return; return;
} }
// --- definierter Aus-Zustand (umgekehrte Reihenfolge zum Einschalten) ---
ws7_bridge_write(0xAB, 0xFF); // Helligkeit 0
ws7_bridge_write(0xAA, 0x01); // uebernehmen
ws7_bridge_write(0xAD, 0x00); // Bridge-Ausgabe aus
vTaskDelay(pdMS_TO_TICKS(20));
ws7_bridge_write(0xAC, 0x00);
ws7_bridge_write(0xC2, 0x00);
ws7_bridge_write(0xC0, 0x00);
vTaskDelay(pdMS_TO_TICKS(WS7_BRIDGE_RESET_MS));
// --- Grundinitialisierung wie im Linux-Treiber ---
ws7_bridge_write(0xC0, 0x01); ws7_bridge_write(0xC0, 0x01);
ws7_bridge_write(0xC2, 0x01); ws7_bridge_write(0xC2, 0x01);
ws7_bridge_write(0xAC, 0x01); ws7_bridge_write(0xAC, 0x01);
vTaskDelay(pdMS_TO_TICKS(20));
} }
void jc_backlight_init(void) void jc_backlight_init(void)
@@ -328,6 +376,10 @@ bool jc_board_bringup(void)
{ {
jc_backlight_init(); jc_backlight_init();
#if JC_PANEL_TYPE == WS_PANEL_7H
ws7_i2c_bus_recover(); // haengenden Bus vom letzten Reset befreien
#endif
i2c_master_bus_config_t i2c_bus_conf = { i2c_master_bus_config_t i2c_bus_conf = {
.clk_source = I2C_CLK_SRC_DEFAULT, .clk_source = I2C_CLK_SRC_DEFAULT,
.sda_io_num = BSP_I2C_SDA, .sda_io_num = BSP_I2C_SDA,
@@ -341,12 +393,17 @@ bool jc_board_bringup(void)
ws7_bridge_pre_init(); ws7_bridge_pre_init();
#endif #endif
// Reset-Grund mitschreiben: 1 = Kaltstart (Strom weg), alles andere ist ein Warmstart.
// Nur beim Warmstart behalten die Bausteine ihren alten Zustand - genau dann traten
// die schwarzen Bilder auf.
esp_rom_printf("[Panel] Startgrund: %d (1 = Kaltstart)\n", (int)esp_reset_reason());
static esp_ldo_channel_handle_t phy_pwr_chan = NULL; static esp_ldo_channel_handle_t phy_pwr_chan = NULL;
esp_ldo_channel_config_t ldo_cfg = { esp_ldo_channel_config_t ldo_cfg = {
.chan_id = BSP_MIPI_DSI_PHY_PWR_LDO_CHAN, .chan_id = BSP_MIPI_DSI_PHY_PWR_LDO_CHAN,
.voltage_mv = BSP_MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV, .voltage_mv = BSP_MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV,
}; };
esp_ldo_acquire_channel(&ldo_cfg, &phy_pwr_chan); 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;
esp_lcd_panel_io_handle_t io = NULL; esp_lcd_panel_io_handle_t io = NULL;
+1 -1
View File
@@ -126,7 +126,7 @@
// ------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------
// Firmware // Firmware
// ------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------
#define DISPLAY_FW_VERSION "1.6.11" // Firmware-Stand der P4-Display-Steuerung (Info-Seite) #define DISPLAY_FW_VERSION "1.6.10" // Firmware-Stand der P4-Display-Steuerung (Info-Seite)
// ------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------
// Protokoll // Protokoll
+1 -7
View File
@@ -114,12 +114,6 @@
// nicht bekannt; die 180-Grad-Drehung macht deshalb der PPA (WS7_ROTATE_180). // nicht bekannt; die 180-Grad-Drehung macht deshalb der PPA (WS7_ROTATE_180).
#define WS7_MADCTL 0x00 #define WS7_MADCTL 0x00
// So lange bleibt die Bridge beim Start stromlos geschaltet, bevor sie neu
// initialisiert wird. Sie hat keine Reset-Leitung und ueberlebt einen Reset des P4;
// ohne diese Pause trifft ein frischer DSI-Start auf eine noch laufende Bridge und das
// Bild bleibt schwarz. Bei schwarzem Bild nach Reset zuerst diesen Wert erhoehen.
#define WS7_BRIDGE_RESET_MS 120
// Der GT9271 meldet im Hochformat: Roh-X 0..720, Roh-Y 0..1280. Fuer das Querformat // Der GT9271 meldet im Hochformat: Roh-X 0..720, Roh-Y 0..1280. Fuer das Querformat
// werden die Achsen getauscht. Die Spiegelung geschieht VOR dem Tausch, also noch auf den // werden die Achsen getauscht. Die Spiegelung geschieht VOR dem Tausch, also noch auf den
// Rohwerten: Roh-X wird zur Bildschirmhoehe, Roh-Y zur Bildschirmbreite. // Rohwerten: Roh-X wird zur Bildschirmhoehe, Roh-Y zur Bildschirmbreite.
@@ -154,7 +148,7 @@
#define LCD_RST 27 #define LCD_RST 27
#define LCD_LED 23 #define LCD_LED 23
#elsealle #else
#define LCD_H_RES 480 #define LCD_H_RES 480
#define LCD_V_RES 800 #define LCD_V_RES 800