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
This commit is contained in:
co-authored by
Claude Opus 5
parent
dfd2aaddd1
commit
43c5d5a41a
@@ -71,6 +71,68 @@
|
||||
|
||||
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
|
||||
// abgeschaltetem Core-Debug-Level und ohne Heap, also genau dann, wenn es darauf ankommt.
|
||||
#define BSP_STEP(call, what) \
|
||||
@@ -108,7 +170,13 @@ 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 am I2C-Bus anmelden und Grundinitialisierung schreiben. Muss VOR dem
|
||||
@@ -308,6 +376,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,
|
||||
|
||||
Reference in New Issue
Block a user