Compare commits

..
Author SHA1 Message Date
raw-designsandClaude Opus 5 50540179c7 fix(P4): Touch erst nach Panel-Freigabe initialisieren (1.6.14)
Der GT9271 meldete "i2c transaction failed" auch beim Kaltstart, während
alle Panel-Schritte fehlerfrei durchliefen und die Bus-Freitaktung aus 1.6.13
den Bus als frei meldete.

Ursache ist die Reihenfolge: Im funktionierenden Werks-Testsketch steht
initTouch() hinter enableBacklight(). Der GT9271 hängt an derselben
Versorgung wie das Panel und antwortet erst, wenn die Bridge über 0xAD
freigegeben ist. Beim Übertragen in die Firmware war das verloren gegangen -
jc_backlight_set() lief erst nach jc_board_bringup().

- Für WS_PANEL_7H wird die Beleuchtung jetzt innerhalb des Bringups vor der
  Touch-Initialisierung eingeschaltet, mit WS7_TOUCH_POWER_MS Pause.
- Neue Diagnose ws7_i2c_scan() listet die antwortenden I2C-Adressen vor und
  nach dem Panel-Start.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018QoLDQeUh1dCQz7yYZVb4Y
2026-09-01 16:30:31 +02:00
thomas 9bbd7d72aa Merge pull request 'fix(P4): Hängenden I2C-Bus freitakten - Ursache des schwarzen Bildes (1.6.13)' (#41) from fix/i2c-bus-freitakten into main 2026-09-01 16:17:42 +02:00
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 153 additions and 50 deletions
+39 -12
View File
@@ -1,15 +1,42 @@
Version 1.6.11:
- Fehlerbehebung: Nach einem Reset des P4 blieb das Bild schwarz, während die
Hintergrundbeleuchtung brannte; erst ein erneutes Flashen half. Die Bridge des
Waveshare-Panels hat keine Reset-Leitung und hängt an Dauerstrom - ein Reset des P4
setzt sie also nicht zurück, ihre Register standen noch auf den Werten der vorigen
Sitzung. Der P4 baut seine DSI-Strecke aber komplett neu auf, und ein frischer DSI-Start
auf einer bereits laufenden Bridge liefert kein Bild. Beim Flashen wird die Versorgung
getrennt, deshalb war der Fehler dort nicht zu sehen.
- Der Start schaltet die Bridge jetzt zuerst definiert ab (Beleuchtung, dann Ausgabe,
dann Grundregister), wartet WS7_BRIDGE_RESET_MS und fährt sie erst danach hoch. Der
Wert steht in pins_config.h (Vorgabe 120 ms) und ist die erste Stellschraube, falls
nach einem Reset doch einmal ein schwarzes Bild auftaucht.
Version 1.6.14:
- Der Touch-Controller wird jetzt erst angesprochen, nachdem die Bridge freigegeben und die
Hintergrundbeleuchtung eingeschaltet ist. Der GT9271 haengt an derselben Versorgung und
antwortet vorher nicht auf I2C - deshalb schlug seine Initialisierung bisher schon beim
Kaltstart fehl. In der Werks-Testskizze steht die Touch-Initialisierung aus demselben
Grund hinter dem Einschalten der Beleuchtung; beim Uebertragen in die Firmware war diese
Reihenfolge verloren gegangen.
- Die Wartezeit dazwischen steht als WS7_TOUCH_POWER_MS in pins_config.h (Vorgabe 120 ms).
- Neu im Start-Log: eine Liste aller Bausteine am I2C-Bus, einmal vor und einmal nach dem
Panel-Start. Erwartet werden 0x45 (Bridge) und 0x14 (Touch). Damit ist auf einen Blick zu
sehen, ob ein Baustein gar nicht antwortet, statt aus Treiberfehlern raten zu muessen.
Version 1.6.13:
- Ursache des schwarzen Bildes gefunden: ein haengender I2C-Bus. Trifft ein Reset des P4
mitten in eine laufende Uebertragung, bleibt der angesprochene Baustein in seiner
Bitausgabe stehen und haelt die Datenleitung dauerhaft auf Masse. Damit schlaegt jede
weitere Uebertragung fehl. Bridge und Touch-Controller haengen an Dauerstrom, weshalb
dieser Zustand jeden Reset und sogar das Flashen ueberlebt - nur echtes Stromabziehen
loest ihn. Die Folge: Die Bridge wird nie initialisiert, das Bild bleibt schwarz, und
weil sie ihre Register behaelt, brennt die Hintergrundbeleuchtung weiter.
- Vor dem Anlegen des I2C-Busses wird die Taktleitung jetzt von Hand getaktet, bis der
Baustein die Datenleitung freigibt, danach folgt eine Stopp-Bedingung. Das ist der in
der I2C-Spezifikation vorgesehene Weg und laeuft bei freiem Bus wirkungslos durch.
- 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:
- 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`/
`Display On` → DPI-Start → **erst dann** Hintergrundbeleuchtung. Wird das Licht früher
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**
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
+107 -25
View File
@@ -30,6 +30,7 @@
#include "esp_heap_caps.h"
#include "esp_rom_sys.h"
#include "esp_timer.h"
#include "esp_system.h"
#include "esp_ldo_regulator.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_ops.h"
@@ -70,6 +71,82 @@
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);
}
// Zeigt, welche Bausteine sich am I2C-Bus melden. Erwartet werden 0x45 (Bridge) und
// 0x14 (GT9271-Touch); 0x18 waere der Audio-Baustein. Fehlt einer, sagt das mehr aus als
// jede Fehlermeldung des Treibers.
static void ws7_i2c_scan(const char *wann)
{
esp_rom_printf("[Panel] I2C-Bausteine (%s):", wann);
for (uint8_t addr = 1; addr < 127; addr++) {
if (i2c_master_probe(s_i2c_handle, addr, 50) == ESP_OK) {
esp_rom_printf(" 0x%02X", addr);
}
}
esp_rom_printf("\n");
}
#endif // JC_PANEL_TYPE == WS_PANEL_7H
// 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.
#define BSP_STEP(call, what) \
@@ -107,19 +184,17 @@ 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);
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.
//
// 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.
// 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 = {
@@ -131,22 +206,9 @@ static void ws7_bridge_pre_init(void)
s_bridge_handle = NULL;
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(0xC2, 0x01);
ws7_bridge_write(0xAC, 0x01);
vTaskDelay(pdMS_TO_TICKS(20));
}
void jc_backlight_init(void)
@@ -328,6 +390,10 @@ bool jc_board_bringup(void)
{
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 = {
.clk_source = I2C_CLK_SRC_DEFAULT,
.sda_io_num = BSP_I2C_SDA,
@@ -337,16 +403,22 @@ bool jc_board_bringup(void)
i2c_new_master_bus(&i2c_bus_conf, &s_i2c_handle);
#if JC_PANEL_TYPE == WS_PANEL_7H
ws7_i2c_scan("vor dem Panel-Start");
// Bridge des Waveshare-Panels vorbereiten (noch ohne Hintergrundbeleuchtung).
ws7_bridge_pre_init();
#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;
esp_ldo_channel_config_t ldo_cfg = {
.chan_id = BSP_MIPI_DSI_PHY_PWR_LDO_CHAN,
.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_panel_io_handle_t io = NULL;
@@ -510,6 +582,16 @@ bool jc_board_bringup(void)
};
esp_lcd_dpi_panel_register_event_callbacks(disp_panel, &cbs, NULL);
#if JC_PANEL_TYPE == WS_PANEL_7H
// Bridge freigeben und Beleuchtung einschalten, BEVOR der Touch angesprochen wird.
// Der GT9271 antwortet erst danach: Die Freigabe der Bridge (Register 0xAD) versorgt
// offenbar auch ihn. In der Werks-Testskizze steht die Touch-Initialisierung aus
// demselben Grund hinter dem Einschalten der Beleuchtung.
jc_backlight_set(100);
vTaskDelay(pdMS_TO_TICKS(WS7_TOUCH_POWER_MS));
ws7_i2c_scan("nach dem Panel-Start");
#endif
esp_lcd_panel_io_handle_t tp_io_handle = NULL;
// MUSS vorbelegt sein: schlaegt die Touch-Initialisierung fehl, gibt der Treiber einen
// unbrauchbaren Zeiger zurueck. Ohne Vorbelegung landet Muell im LVGL-Port.
+1 -1
View File
@@ -126,7 +126,7 @@
// -------------------------------------------------------------------------------------
// 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
+6 -7
View File
@@ -114,12 +114,6 @@
// nicht bekannt; die 180-Grad-Drehung macht deshalb der PPA (WS7_ROTATE_180).
#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
// werden die Achsen getauscht. Die Spiegelung geschieht VOR dem Tausch, also noch auf den
// Rohwerten: Roh-X wird zur Bildschirmhoehe, Roh-Y zur Bildschirmbreite.
@@ -146,6 +140,11 @@
// Wert verzoegert das Loslassen und daempft dadurch den Schwung beim Wischen.
#define WS7_TOUCH_HOLD_MS 40
// Wartezeit zwischen dem Freigeben der Bridge und dem Ansprechen des Touch. Der GT9271
// haengt an derselben Versorgung und braucht nach dem Einschalten einen Moment, bis er
// auf I2C antwortet. Meldet sich 0x14 beim Start nicht, diesen Wert erhoehen.
#define WS7_TOUCH_POWER_MS 120
#elif JC_PANEL_TYPE == JC_PANEL_70
#define LCD_H_RES 1024
@@ -154,7 +153,7 @@
#define LCD_RST 27
#define LCD_LED 23
#elsealle
#else
#define LCD_H_RES 480
#define LCD_V_RES 800