Um den Beschnitt an der rechten Kante zu vermeiden, war der Punkt um eine
halbe Punktbreite nach innen gerueckt - die Linie schaute dadurch rechts
unter ihm hervor.
Statt den Punkt zu verschieben, laesst die Kurvenflaeche jetzt rechts
einen schmalen Rand frei. Der Platz gehoert noch zum Diagramm, wird aber
nicht mehr bezeichnet: Die Linie endet frueher, der Punkt sitzt genau auf
ihrem letzten Wert und wird nicht abgeschnitten.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wx7wu7uXXgRzp1zHUhtUa6
Der Punkt sass mittig auf dem letzten Messwert und damit auf der rechten
Kante der Kurvenflaeche - seine rechte Haelfte lag ausserhalb und wurde
abgeschnitten. Er sitzt jetzt vollstaendig innerhalb; der Schein darf
weiterhin darueber hinausreichen.
Der Punkt ist auf etwa zwei Drittel verkleinert. Das Pulsieren ist neu
choreografiert: Der Punkt selbst atmet leicht, der Schein macht das
Gegenteil - zieht der Punkt sich zusammen, geht der Schein auf.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wx7wu7uXXgRzp1zHUhtUa6
Das Diagramm beschnitt seine Kinder an der eigenen Kante: Der Punkt am
rechten Ende war angeschnitten, und vom Schein war nichts zu sehen -
damit blieb auch das Pulsieren unsichtbar. Punkt und Schein duerfen jetzt
darueber hinausreichen; der Schein ist kraeftiger, der Punkt etwas
groesser.
Die Kurven verlaufen jetzt weich statt kantig. Gemessen wird weiterhin
einmal je Sekunde, gezeichnet viermal so fein: Zwischen zwei Messwerten
liegen vier Stuetzpunkte auf einem Kosinusbogen, der an den Messpunkten
waagerecht beginnt und endet. Linienenden und -ecken sind abgerundet.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wx7wu7uXXgRzp1zHUhtUa6
Der aelteste Wert einer Kurve liegt jetzt links genau auf halber Hoehe,
die Kurve waechst von dort nach oben oder unten. Der Verlauf sieht damit
bei jeder Kesseltemperatur gleich aus.
Beide Kurven behalten denselben Massstab. Die absolute Hoehe laesst sich
dadurch nicht mehr zwischen Wasser und Dampf vergleichen, der Ausschlag
aber schon.
Am juengsten Messwert sitzt ein kleiner weisser Punkt mit weichem Schein,
der langsam pulsiert. Beide Linien sind weiss.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wx7wu7uXXgRzp1zHUhtUa6
Die Massnahme aus 1.10.3 verlaengerte die Delle, statt sie zu entfernen.
Sie hielt beim Umschalten des Standby-Merkers den zuletzt gemeldeten Wert
fest - zu diesem Zeitpunkt lag die gestoerte Probe aber bereits an.
Festgehalten wurde also ausgerechnet die Delle, und das sekundenlang.
Die Verlaufskurven tragen jetzt den mittleren Wert der letzten fuenf
Proben ein (Median). Ein bis zwei verirrte Proben verschwinden damit
vollstaendig, unabhaengig vom Zeitpunkt. Echte Aenderungen kommen
unverfaelscht durch, nur zwei Sekunden spaeter.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011gwqJf2DcqHFQpoY3XkDHX
Direkt nach dem Aufwachen aus dem Standby zog die Wasserkurve eine kurze
Delle nach unten. Ursache ist die Messung, nicht der Kessel: In genau
diesem Moment schalten die Heizungen, und der Wassersensor haengt als NTC
am ADC. Ein Kessel kann binnen einer Sekunde nicht um Grade einbrechen.
Die Verlaufskurven halten deshalb rund um jeden Standby-Wechsel sechs
Sekunden lang ihren letzten Wert, statt die gestoerte Probe einzutragen.
Das gilt fuer die kleinen Kurven im Dashboard und fuer die grosse
Verlaufsseite. Die angezeigten Temperaturzahlen bleiben unveraendert.
Ausserdem: DISPLAY_FW_VERSION stand seit dem Ruecknehmen von 1.6.11 auf
1.6.10 fest und wurde bei keinem der folgenden Staende mitgezogen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fe8KxS47iPmuByJPs5RvEw
Die Linien blieben identisch und unbewegt - kein Skalierungsproblem, wie
1.10.0 und 1.10.1 angenommen hatten.
lv_chart_set_next_value() für g_sparkW/g_sparkD stand am Ende von
chart_duty_btn_cb(), dem Callback des Heizleistungs-Umschalters auf der
Verlauf-SEITE. Die Sparklines wuchsen also nur, wenn jemand genau diesen
Knopf drückte. Ansonsten zeigten sie unverändert, was lv_chart_set_all_value()
beim Aufbau der Darstellung eingetragen hatte.
Der Block sitzt jetzt in chart_sample_cb() (1-s-Timer), und zwar vor dessen
"if (!g_chart || !g_hist) return" - die Dashboard-Kurven sollen nicht davon
abhängen, ob die Verlauf-Seite samt großem Diagramm aufgebaut ist.
Die gemeinsame Skala aus 1.10.1 bleibt richtig, konnte bisher aber nichts
ausrichten, weil nie neue Werte ankamen.
Beide Panel-Varianten mit arduino-cli gegengebaut.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012gBXGt5M22ns5YfNJRaiMu
Nachbesserung zu 1.10.0. Dort bekam jede Kurve ihren eigenen Ausschnitt aus
ihren eigenen min/max. Bei zwei flachen Kurven (Wasser 70 °C, Dampf 0 °C)
greift beidesmal die Mindestspanne, jede Linie sitzt mittig in ihrem Fenster -
und beide liegen auf identischer Höhe. Die Skalierung war zu clever: Bewegung
wurde sichtbar, aber die Höhe verlor jede Bedeutung.
- spark_range_fit(ch, ser) ersetzt durch spark_ranges_fit(): scannt beide
Serien, bildet einen gemeinsamen Bereich und setzt ihn auf beide Charts.
- Der gemerkte Bereich liegt jetzt in zwei Datei-Statics statt in user_data
der Charts; das nimmt auch das nicht freigegebene lv_malloc bei jedem
Neuaufbau der Temperaturzeile weg.
- build_temp_row_content() setzt den Merker beim Aufbau zurück und ruft
spark_ranges_fit() erst, wenn beide Kurven stehen.
Beide Panel-Varianten mit arduino-cli gegengebaut.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018ZJ2iUTbm7Zz5DTPkwgJyC
Die Sparklines im Dashboard lagen flach auf gleicher Höhe und bewegten sich
nicht, obwohl ein Kessel bei 80 °C stand und der andere bei 0.
Ursache: lv_chart_set_range() war an den Sollwert gebunden (soll-60 bis
soll+30 in Zehntelgrad). Liegt die Temperatur unter diesem Fenster - beim
Aufheizen oder bei abgeschaltetem Kessel -, klemmt LVGL jeden Punkt auf den
unteren Rand. Beide Kurven landeten dadurch auf derselben Linie.
- Neues spark_range_fit(): Ausschnitt aus min/max der vorhandenen Punkte
(lv_chart_get_y_array), Mindestspanne DASH_SPARK_MIN_SPAN (40 = 4,0 °C),
sonst ein Achtel Luft nach oben und unten.
- Der zuletzt gesetzte Bereich wird in user_data gemerkt, weil LVGL keinen
Getter dafür hat; ohne den Vergleich würde set_range das Diagramm bei jeder
Zustandsmeldung invalidieren.
- Die Charts füllen jetzt den Platz unterhalb der Zahlen (flex_grow 1,
min_height 90) statt als 64-px-Streifen mittig zu hängen.
Aufräumen nach der abgeschlossenen Fehlersuche:
- Herzschlag, [Zustand]- und [Touch]-Messzeilen entfernt.
- refr_monitor_install() hinter WS7_PERF_MONITOR (aus).
- scroll_ohne_nachlauf() gibt LV_OBJ_FLAG_SCROLL_MOMENTUM wieder frei.
Beide Panel-Varianten mit arduino-cli gegengebaut.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019G95njDFkedFqXiz5sEaJ2
Der Nutzer hat es im Gegenlicht gesehen: Das Bild steht nach 446 ms fertig
da, nur die Beleuchtung kommt Sekunden später. Die gesamte Suche im
Zeichenablauf lief damit am falschen Ort - die Messungen dort waren alle
unauffällig, weil dort auch nichts war.
Der Referenz-Sketch (dsi-test.ino, enableBacklight) setzt 0xAB/0xAA zweimal
mit delay(100) dazwischen, ausdrücklich "sicherheitshalber Helligkeit noch
einmal übernehmen". jc_backlight_set() schrieb die Sequenz nur einmal.
- 0xAB/0xAA werden jetzt wiederholt, Pause über WS7_BACKLIGHT_LATCH_MS (20).
- 0xAD (Freigabe) nur noch beim ersten Aufruf statt bei jeder Änderung; der
Referenzcode setzt sie ebenfalls nur einmal, und sie erneut zu schreiben
stößt die Helligkeitsstufe der Bridge neu an.
- jc_backlight_set() meldet seine Dauer selbst; die doppelte Messung im .ino
entfällt.
Beide Panel-Varianten mit arduino-cli gegengebaut.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Log zeigt zweimal hintereinander "rst:0x1 (POWERON)" und
"[Panel] Startgrund: 1", danach nichts mehr - Beleuchtung an, kein Bild.
Ursache: Der gewollte einmalige Neustart nach Kaltstart (WS7_COLD_BOOT_RESTART)
prüfte nur esp_reset_reason() == ESP_RST_POWERON. Der Kommentar nahm an, der
zweite Durchlauf melde einen Software-Reset. Tatsächlich meldet der Chip auch
nach esp_restart() wieder POWERON, die Bedingung greift erneut - Endlosschleife.
Der bootguard konnte nicht eingreifen, weil derselbe Zweig "early" jedes Mal
auf 0 zurücksetzt.
- Zusätzliches NVS-Flag "kaltneu" in bootguard: wird vor esp_restart() gesetzt
und beim zweiten Durchlauf erkannt und gelöscht. Unabhängig vom gemeldeten
Startgrund, damit die Schleife strukturell ausgeschlossen ist.
- Die Meldung lief über DBG_SERIAL (USB-CDC) und war im Monitor an der UART
nicht zu sehen - jetzt esp_rom_printf wie die übrigen Panel-Meldungen.
Beide Panel-Varianten mit arduino-cli gegengebaut.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NeFMr439WcLMdebE3kU7fS
Auswertung des letzten Logs (lv_tick lief 2728 ms hinter millis):
Tipp erkannt 49428, Rückfrage aufgebaut 49430, Bildaufbau fertig 49746.
Also 318 ms vom erkannten Tipp bis zum fertigen Bild - die gemessene Kette
ist schnell. Der Knopfdruck im Dialog liegt bei 55638 (Bereich 645..856,
374..426), die Antwort des S3 bei 59303, also 937 ms Rundlauf.
Die Verzögerung liegt damit VOR der Erkennung. Deshalb:
- ws7_touch_get_xy() meldet den ersten verworfenen Rohwert nach Ruhe mit
Koordinaten und zählt, wie viele bis zur akzeptierten Berührung anfallen.
- Alle Messzeilen auf millis() statt lv_tick_get(); die beiden Uhren
auseinanderzurechnen hat das Lesen unnötig erschwert.
Beide Panel-Varianten mit arduino-cli gegengebaut.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NeFMr439WcLMdebE3kU7fS
- dash_brew_mode() verteilt die flex_grow-Werte nicht mehr um. Die untere
Zeile bekam während des Bezugs 3 statt 2 und die Temperaturzeile 1 statt 3;
die kleinen Kacheln wurden dadurch enorm hoch und das Layout sprang.
- Die Messzeilen aus dem .ino liefen über Serial und damit über USB-CDC,
während der Monitor an der UART hängt - sie waren nie zu sehen. Jetzt
durchgängig esp_rom_printf wie die Panel-Meldungen.
- Alle Messzeilen tragen eine Zeitmarke in ms; ohne die sind die Lücken
nicht zu erkennen.
- onState() misst Ankunft der Zustandsmeldung, Wartezeit auf hal_lock() und
Dauer von ui_update(). standby_screen_cb() klammert wake_confirm_show()
ein. Das deckt beide Richtungen der gemeldeten Fünf-Sekunden-Verzögerung ab.
Das Einblenden der Standby-Uhr scheidet als Ursache aus: laut Messung 2 ms.
Beide Panel-Varianten mit arduino-cli gegengebaut.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NeFMr439WcLMdebE3kU7fS
Ursache gefunden. lv_draw_label.c legt pro Glyphe einen A8-Draw-Buf an:
box_w * LV_ROUND_UP(box_h, 32) Byte. Größte Ziffer des 360er-Fonts ist
190x247 -> 190*256 = 48 KB. Mit LV_DRAW_SW_DRAW_UNIT_CNT 2 sind zwei davon
gleichzeitig offen, also ~97 KB. Der LVGL-Pool (LV_MEM_SIZE 256 KB) hatte
laut Herzschlag nur 98068 Byte am Stück frei - es reichte knapp nicht.
LV_USE_ASSERT_MALLOC ist 1 und LV_ASSERT_HANDLER war "while(1);". Bei
fehlgeschlagener Allokation hält der LVGL-Task also stumm an: kein Panic,
kein Backtrace, Log bricht einfach ab. Genau das beobachtete Bild.
- font_buf_malloc/-free über lv_draw_buf_get_font_handlers(): Puffer ab
16 KB kommen per heap_caps_malloc aus dem PSRAM, kleinere weiter aus dem
LVGL-Pool (schneller; sonst würde jeder Text langsamer). Freigabe
unterscheidet über esp_ptr_external_ram().
- LV_ASSERT_HANDLER gibt jetzt eine Meldung aus, bevor er anhält.
Der interne RAM bleibt unangetastet - LV_MEM_SIZE zu erhöhen war keine
Option, der statische Speicher liegt bereits bei ~98 %.
Beide Panel-Varianten mit arduino-cli gegengebaut.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NeFMr439WcLMdebE3kU7fS
Beim Wechsel in den Standby bleibt das Display stehen: Bild bleibt auf der
alten Seite, keine Bedienung, auch der S3 weckt nicht mehr auf. Der Log
bricht nach dem letzten Bildaufbau ab, ohne Panic.
Statt zu raten, Messpunkte:
- Herzschlag alle 2 s aus dem Arduino-loop (freier Heap) und aus einem
lv_timer im LVGL-Task (lv_mem_monitor). Bleibt nur einer aus, ist klar,
welcher Task steht.
- ui_fade_in() der Standby-Uhr wird eingeklammert: "wird eingeblendet" /
"eingeblendet, N ms".
- hal_backlight() wird gemessen; über 50 ms wird die Dauer gemeldet.
Der Bridge-Schreibzugriff läuft über denselben I2C-Bus wie der Touch.
Außerdem entfernt: die LV_EVENT_INVALIDATE_AREA-Callbacks aus 1.9.5. Das
Event geht per lv_display_send_event an das Display, nicht an Objekte - die
Callbacks konnten nie feuern, ihr Ausbleiben war kein Beweis.
Beide Panel-Varianten mit arduino-cli gegengebaut.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NeFMr439WcLMdebE3kU7fS
- Der Darstellungsblock wandert aus build_info() in ein eigenes build_display()
mit neuer Seite PG_DISPLAY. Die Info-Seite zeigt nur noch Firmware-Stände und
Verbindungsdaten.
- clock_font() liefert für WS_PANEL_7H jetzt 180/270/360 statt 120/180/240. Für
JC_PANEL_43 bleiben die alten Stufen - 360 px passen nicht auf 480x480.
- Neue Fonts lv_font_clock_270/_360 (Maven Pro Regular, bpp 4, Range
32,45,0x30-0x3A). bpp 3 scheidet aus: lv_font_conv erlaubt das nur mit
Kompression, und die kostet beim Zeichnen genau das, was gerade eingespart wird.
- Alle fünf Uhr-Fonts sind deklariert; der Linker verwirft die je nach Panel
ungenutzten. Netto wächst die WS-Firmware um 196 KB.
Beide Panel-Varianten mit arduino-cli gegengebaut (PartitionScheme=custom,
passend zur partitions.csv mit zwei 6,5-MB-Slots).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NeFMr439WcLMdebE3kU7fS
Die festen Breiten aus 1.9.4 haben nicht gereicht. lv_label_set_text ruft
lv_obj_refresh_self_size(); ist eines der beiden Maße LV_SIZE_CONTENT, gilt
das Parent-Layout als dirty und der Container wird komplett invalidiert.
- tempField(): big und setp bekommen zusätzlich eine feste Höhe aus
lv_font_get_line_height().
- infoCell(): val ebenso, mit Platz für zwei Zeilen.
- g_clock: feste Breite/Höhe, rechtsbündig. Erklärt den Bereich
"x 6..57, y 2..41" (Menü-Knopf), der bei jedem Minutenwechsel durch das
Header-Relayout mit invalidiert wurde.
Zusätzlich eine gezielte Diagnose: LV_EVENT_INVALIDATE_AREA auf g_content
und der Dashboard-Seite meldet, wenn ein ganzer Container invalidiert wird -
damit ist "einzelnes Label" von "kompletter Bereich" zu unterscheiden.
Beide Panel-Varianten mit arduino-cli gegengebaut.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Koordinaten haben den Verursacher benannt: Der invalidierte Bereich war
"x 0..1279, y 44..719" - der komplette Content-Container, bei jeder
Zustandsmeldung.
Grund: Die Wert-Labels hatten LV_SIZE_CONTENT. Ändert sich ihre Breite mit
dem Inhalt (92,4 °C -> 100,1 °C), löst LVGL ein Flex-Relayout der ganzen
Seite aus und invalidiert sie komplett. Change-checked Text allein reicht
also nicht - der Text darf beim Ändern auch die Breite nicht ändern.
tempField() und infoCell() setzen die Wert-Labels jetzt auf LV_PCT(100) mit
zentriertem Text. Optisch identisch, da die Werte ohnehin mittig standen.
Beide Panel-Varianten mit arduino-cli gegengebaut.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- Regression aus 1.8.7: Der deckende Drawer-Scrim verdeckte den
Seiteninhalt, der dahinter sichtbar bleiben soll. Zurück auf LV_OPA_50.
- ready_band_update() setzte Text, Textfarbe und Hintergrundfarbe des
Zustandsbands bei jeder Zustandsmeldung neu. Das Band spannt sich über die
volle Breite - allein dadurch wurde ein Streifen über den ganzen Bildschirm
ungültig. Jetzt über die change-checked Helfer.
- temp_progress_set() setzte Balkenwert und -farbe unbedingt; jetzt nur bei
echter Änderung.
- Das WLAN-Symbol ebenso.
- Die Messung gibt zusätzlich die Koordinaten der invalidierten Bereiche aus.
Die Fläche allein sagt nicht, welcher Teil der UI den Redraw auslöst.
Beide Panel-Varianten mit arduino-cli gegengebaut.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die erweiterte Messung war eindeutig: "1 Bereich, 100 % der Fläche" - LVGL
zeichnete bei jeder Zustandsmeldung den kompletten Bildschirm neu, also
einmal pro Sekunde 240-300 ms lang. Kein Rendering-Tempoproblem, sondern
massiv zu viel Invalidierung.
lv_label_set_text invalidiert den Label-Bereich unbedingt, auch bei
identischem Text; lv_obj_set_style_text_color ebenso. Auf dem Dashboard
wurden pro Sekunde Werte quer über den Bildschirm gesetzt (Uhr oben,
Temperaturen Mitte, Bezugswerte unten) - LVGL joint die Bereiche, und die
Bounding-Box ist die ganze Fläche.
- Neue Helfer label_fmt_if_changed() und label_color_if_changed() neben dem
vorhandenen label_set_if_changed().
- Alle 13 zyklischen Textzuweisungen und alle 10 Farbzuweisungen in
ui_update darauf umgestellt.
Da sich Temperaturen selten um ein Zehntelgrad ändern und Sollwerte
praktisch nie, entfallen die meisten Neuzeichnungen ganz.
Beide Panel-Varianten mit arduino-cli gegengebaut.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
WS7_DIRECT_FB hat die Bildaufbauzeit nicht verkürzt (weiterhin 240-300 ms)
und Bildfehler erzeugt - in denselben Speicher zu zeichnen, aus dem gerade
angezeigt wird, geht ohne zweiten Framebuffer nicht sauber. Zurück auf 0,
Schalter mit Begründung erhalten.
Damit ist belegt: Der Flaschenhals liegt nicht im Kopieren, sondern im
Rendern selbst. Offen ist, ob LVGL kleine Bereiche langsam zeichnet oder
jedes Mal die volle Fläche - zwei verschiedene Ursachen.
refr_start_cb summiert deshalb jetzt die nicht zusammengefassten
inv_areas und meldet Anzahl und Flächenanteil zusammen mit der Dauer.
Beide Panel-Varianten mit arduino-cli gegengebaut.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Messung aus 1.8.8 hat es gezeigt: Jeder Bildaufbau kostete 240-300 ms,
dauerhaft, auch im Leerlauf. Die fünf Sekunden für den Aufweckdialog waren
rund zwanzig solcher Durchgänge - meine bisherigen Erklärungen (Fades,
Scrims) waren Symptome, nicht die Ursache.
Grund: zwei Durchgänge durch je 2,7 MB PSRAM pro Bild. LVGL rendert in einen
eigenen Draw-Buffer, esp_lcd_panel_draw_bitmap kopiert ihn danach komplett
in den Framebuffer.
WS7_DIRECT_FB holt den Framebuffer über esp_lcd_dpi_panel_get_frame_buffer
und übergibt ihn als LVGL-Draw-Buffer. Der IDF-Treiber erkennt das
(draw_buffer im Framebuffer-Bereich) und macht nur noch Cache-Writeback statt
Kopie; dazu LV_DISPLAY_RENDER_MODE_DIRECT, sodass nur geänderte Bereiche neu
gezeichnet werden.
Außerdem:
- Shot-Timer und Waage behalten während eines Bezugs die normale Schrift;
der Wechsel auf den fetten 96er ist entfernt.
- Größe der Standby-Uhr einstellbar (120/180/240 px, Info-Seite,
NVS ui/uhrgr). Wirkt sofort - sie hängt an einem einzigen Label.
- Die Knöpfe des Aufweckdialogs skalieren mit der Schriftgröße.
Beide Panel-Varianten mit arduino-cli gegengebaut.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der Aufweckdialog braucht weiterhin ~5 s. Zwei Erklärungsversuche lagen
daneben (Fade-Animationen, transparenter Scrim), also wird ab jetzt
gemessen statt geraten.
- refr_monitor_install() hängt sich über LV_EVENT_REFR_START/READY an die
Anzeige und meldet jeden Zeichenzyklus, der 200 ms überschreitet. Im
Normalbetrieb bleibt die Konsole still.
- Der Aufweckdialog berücksichtigt die Schriftgröße jetzt vollständig:
Knöpfe mit font_text() statt geerbter Grundschrift, Breite 150/210/280 je
Stufe. Bisher wirkten sie neben dem größeren Text verloren.
- Die große Standby-Uhr bleibt bewusst fest: Sie ist auf die Bildschirmhöhe
abgestimmt.
Beide Panel-Varianten mit arduino-cli gegengebaut.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01STPpZoK3ToDhrcniVqE6MJ
Vom Fingertipp auf die Standby-Uhr bis zum Dialog vergingen ~5 s mit
schwarzem Bildschirm. Ursache war der Scrim mit LV_OPA_70 über den ganzen
Bildschirm: Ein durchscheinender Vollbild-Layer zwingt LVGL zu einem
Zwischenpuffer und zum Mischen der gesamten Fläche - bei 1280x720 in 24 Bit
die teuerste Operation überhaupt.
- Wake-Scrim auf WS_PANEL_7H jetzt LV_OPA_COVER. Verloren geht nichts: Im
Standby liegt dahinter ohnehin nur Schwarz.
- Der Drawer-Scrim (LV_OPA_50) hat dasselbe Problem und ist ebenfalls
deckend, in 0x0d0d0d - auf dunklem Grund optisch praktisch identisch.
- Die JC-Panels behalten in beiden Fällen die Transparenz.
- Die Dialogkarte wächst mit der Schriftgröße (420 / 640 / 900 px), damit
der Text nicht an unglücklichen Stellen umbricht.
Beide Panel-Varianten mit arduino-cli gegengebaut.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01STPpZoK3ToDhrcniVqE6MJ
Die Uhrzeit kommt von der Hauptplatine und ist leer, solange dort keine
Zeitquelle synchronisiert ist. Bei einem erneuten Abgleich ist sie kurz weg,
und die Uhr verschwand für ein paar Sekunden - im Standby unruhig.
Der P4 merkt sich jetzt die zuletzt empfangene Zeit (Minuten seit
Mitternacht plus lv_tick zum Empfangszeitpunkt) und rechnet zwischen den
Meldungen selbst weiter. Sobald die S3 wieder eine Zeit schickt, gilt deren
Wert - der P4 stellt nichts richtig und ersetzt keine Zeitquelle, er
überbrückt nur die Lücke. Ohne je empfangene Zeit bleibt die Anzeige leer
wie bisher.
Gilt für die Kopfleisten-Uhr und die große Standby-Uhr; beide setzen den
Text jetzt über label_set_if_changed, sparen also unnötige Neuzeichnungen.
Beide Panel-Varianten mit arduino-cli gegengebaut.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01STPpZoK3ToDhrcniVqE6MJ
- Die ~2 s Verzögerung rund um den Standby lag nicht an der Helligkeit:
lv_obj_move_foreground(g_standbyScreen) lief bei JEDER Zustandsmeldung.
Das ordnet die Ebenen neu und lässt LVGL den ganzen Bildschirm neu
zeichnen - einmal pro Sekunde, 1280x720 in 24 Bit. Nach vorn geholt wird
die Uhr jetzt nur beim Einblenden.
- Der Aufweckdialog schließt sich nach 30 s ohne Auswahl selbst und wird wie
Abbrechen gewertet (lv_timer, repeat_count 1). Sonst bliebe das Display
hell stehen, weil der Dialog auf normale Helligkeit schaltet.
- Die Verlaufskurve hat keinen eigenen Hintergrund mehr. Die abgesetzte
Fläche war nur nötig, solange die Kurve vor dem ersten Messwert leer war -
seit sie beim aktuellen Wert startet, ist immer eine Linie da.
- Statistik: Bei fehlendem Gewicht stand ein En-Dash, den der Zeichensatz
nicht enthält - erschien als leeres Rechteck. Jetzt ASCII-Bindestrich.
Beide Panel-Varianten mit arduino-cli gegengebaut.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01STPpZoK3ToDhrcniVqE6MJ
- Standby-Uhr und Aufweckdialog kamen spürbar verzögert. Ursache waren die
Fade-Animationen: Eine Deckkraft-Animation ist bei einem Bildspeicher in
RGB888 das Teuerste überhaupt, weil pro Einzelbild die ganze Fläche unter
der Ebene neu gezeichnet und gemischt werden muss. UI_FADE_MS ist für
WS_PANEL_7H auf 0; ui_fade_in/ui_fade_out_hide zeigen bzw. verstecken dann
direkt. Die JC-Panels behalten die Animation.
- Beim Wechsel der Schriftgröße blitzte Blau auf. Das ist das Panel selbst -
ohne Videosignal zeigt es Blau, und der nötige Neustart reißt das Signal
ab. hal_backlight(0) vor esp_restart().
- Neue Einstellung "Temperaturzahl in der Zustandsfarbe" (Info-Seite,
Abschnitt Darstellung, NVS ui/tempcol, Vorgabe aus). Aus bleibt die Zahl
weiß; die Zustandsfarbe steckt dann allein im Balken. Warnungen bleiben
immer rot.
Beide Panel-Varianten mit arduino-cli gegengebaut.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01STPpZoK3ToDhrcniVqE6MJ
Drei Punkte am neuen Dashboard:
- Hinter der Temperatur stand ein leeres Rechteck statt des C. Die großen
Schriften waren auf Ziffern, Komma, Punkt, Minus und Gradzeichen
beschränkt; C fehlte. Jetzt enthalten, ebenso g und s für die Anzeige
während eines Bezugs.
- Bei "Verlauf" war keine Kurve zu sehen: Ein frisches lv_chart hat lauter
LV_CHART_POINT_NONE und zeichnet nichts, und ohne Hintergrund war der
Bereich unsichtbar, bis nach einer Minute Messwerte zusammenkamen. Die
Kurve startet jetzt beim aktuellen Wert (lv_chart_set_all_value), Bereich
und Fläche sind sofort gesetzt.
- Die großen Zahlen stehen im fetten Schnitt und mit engerem Zeichenabstand,
wie im Entwurf. Erzeugt aus MavenPro-VariableFont bei wght=700 via
fontTools varLib.instancer; dieselbe Schriftart, nur kräftiger. Die
Dateien heißen entsprechend lv_font_maven_pro_bold_96/_140.
Beide Panel-Varianten mit arduino-cli gegengebaut.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Liste war ein einziges mehrzeiliges Label: Zeitpunkt, Dauer und Gewicht
durch Leerzeichen getrennt aneinandergereiht. Weil Zahlen unterschiedlich
breit sind, stand nichts untereinander - zwei Bezüge ließen sich nicht
vergleichen, ohne jede Zeile einzeln zu lesen.
Jetzt eine Tabelle mit festen Spalten (Zeitpunkt / Dauer / Gewicht / kalt),
Ziffern gleicher Breite, Kopfzeile und leicht abgesetzten wechselnden
Zeilen statt Trennlinien. Ohne Waage bezogen bleibt die Gewichtsspalte leer
statt eine Null vorzutäuschen.
Die Zeilen werden einmal angelegt und danach nur gefüllt oder ausgeblendet -
kein Neuanlegen bei jeder Aktualisierung.
Beide Panel-Varianten mit arduino-cli gegengebaut.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sobald ein Bezug oder Dampfbezug läuft, schrumpft der Temperaturbereich
(flex-grow 3 -> 1) und die untere Zeile wächst (2 -> 3); Shot-Timer und
Gewicht wechseln auf 96 px. Während eines Bezugs zählen Zeit und Gewicht,
die Kesseltemperaturen sind dann Nebensache.
Keine zweite Ansicht: Die Seite verschiebt nur das Gewicht zwischen ihren
beiden Bereichen. Nichts doppelt zu pflegen, nichts springt an eine andere
Stelle.
Der Wechsel hält nach dem Bezug noch vier Sekunden an - ohne dieses
Nachhalten würde die Seite bei jeder kurzen Unterbrechung hin- und
herspringen.
Beide Panel-Varianten mit arduino-cli gegengebaut.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ersetzt die bisherigen fünf (Klassisch, Instrumente, Minimal, Soft-3D,
Thermometer) durch vier, die nicht nur den Temperaturbereich anders zeichnen,
sondern die Fläche unterschiedlich nutzen:
- Gewichtet: Wasser mit flex-grow 2, Dampf mit 1.
- Verlauf: lv_chart-Sparkline je Kessel, gespeist aus der bestehenden
Sekundenabtastung; Ausschnitt am Sollwert ausgerichtet.
- Flächen: ohne Kartenkanten, zwei Felder mit leicht verschiedenem Grund.
- Band: Zustandsband über volle Breite (bereit / heizt / Bezug / Cold
Extraction / Standby). Neue Vorgabe.
Zwei neue Schriftgrade (96 und 140 px), erzeugt mit lv_font_conv aus
MavenPro-Regular.ttf, beschränkt auf Ziffern, Komma, Punkt, Minus und
Gradzeichen - die größte Textschrift hatte 48 px und reichte für die großen
Zahlen nicht.
Ein gespeicherter Wert außerhalb des neuen Bereichs fällt auf die Vorgabe
zurück. Die fünf alten Builder sind entfernt.
Beide Panel-Varianten mit arduino-cli gegengebaut.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Info-Seite hat bereits einen Abschnitt "Darstellung" mit der Wahl der
Temperaturanzeige und dem Live-Bezugsschirm. Die Schriftgröße gehört dort
hinein - sie ist eine Einstellung dieses Displays, keine Wartungsaufgabe.
- Die eigene Karte auf der Wartungsseite entfällt; diese hat damit wieder
vier Karten in zwei Spalten.
- Die Auswahl selbst ist unverändert: drei Stufen, Neustart danach.
- Sie gilt für alle Panels, nicht nur den 7-Zöller.
Beide Panel-Varianten mit arduino-cli gegengebaut.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFRMCnijNEA7obGAq5Jz9v
Klein, Mittel oder Groß - Karte "Darstellung" auf der Seite Reinigung &
Wartung.
LVGL-Schriften sind fest einkompilierte Bilddaten und existieren nur in den
Größen, die im Projekt liegen (14/18/28/40/48). Stufenloses Skalieren gibt
es also nicht. Stattdessen drei Rollen - font_small(), font_text(),
font_title() -, die je nach Einstellung eine Stufe höher greifen; die 45
festen Schriftverweise in ui.cpp sind darauf umgestellt.
- Die großen Anzeigen (Temperatur 40/48, Uhr) bleiben fest: Sie sind auf die
Bildschirmgröße abgestimmt.
- Die Grundschrift wird am Bildschirmobjekt gesetzt, damit alles ohne eigene
Schrift sie erbt.
- Die Einstellung liegt lokal im P4 (NVS "anzeige"), nicht auf der S3.
- Nach der Auswahl folgt ein Neustart; der Frühstart-Zähler der
Absturzsicherung wird vorher zurückgesetzt.
Offen: In der Stufe Groß brauchen die Karten mehr Platz - ob alle Seiten
dann noch vollständig auf den Bildschirm passen, zeigt erst das Gerät.
Beide Panel-Varianten mit arduino-cli gegengebaut.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Zweiter Teil der Layoutumstellung für das 7-Zoll-Panel.
Cold Extraction, drei Spalten:
- Oben die Karten mit Erklärungstext (Modus, Vorbenetzung, Bezugsende),
darunter die knappen (Grundeinstellung, Hauptbezug, Pumpenschutz).
- Drei statt zwei Spalten, weil die Erklärungstexte keine volle
Zeilenbreite brauchen und so keine halbleere Reihe stehen bleibt.
- Der Warnhinweis stand als eigene Zeile am Seitenende, weit entfernt vom
zugehörigen Schalter - er sitzt jetzt in der Modus-Karte.
- Speichern frei unter allen Karten.
Reinigung & Wartung, zwei Spalten, vier Karten:
- Wartungszähler, Flush-Zeiten, Display-Helligkeit, Reinigung & Entkalkung.
- Bisher lose Zeilen unter bloßen Zwischenüberschriften mit freistehenden
Knöpfen dazwischen.
- Hier sitzt Speichern IN der Karte: Jede Karte speichert etwas anderes.
Die JC-Panels behalten ihr einspaltiges Layout; beide Varianten mit
arduino-cli gegengebaut.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Seiten sind als einspaltige Stapel für 800x480 entstanden. Auf 1280x720
bleibt daneben rund 40 % der Fläche leer, während unten Karten aus dem Bild
fallen - und Scrollen ist auf diesem Panel teuer, weil ohne Doppelpufferung
jedes Bild komplett neu entsteht.
- Neue Helfer page_grid() und grid_at() legen eine Seite als LVGL-Raster an.
- build_brew() ordnet die vier Karten in zwei Spalten: links was den Bezug
startet (Pre-Infusion, Brew-by-Time), rechts was ihn beendet
(Brew-by-Weight, Dampf-Timer).
- Der Speichern-Knopf steht frei unter allen Karten statt in einer davon -
er speichert die ganze Seite.
- Nur für WS_PANEL_7H; die JC-Panels bleiben einspaltig.
Beide Panel-Varianten mit arduino-cli gegengebaut.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ohne Doppelpufferung entsteht beim Scrollen jedes Bild komplett neu
(1280x676 in 24 Bit, per Software). Am stärksten fällt das beim Ausrollen
nach dem Loslassen auf: Dort bewegt sich das Bild weiter, ohne dass ein
Finger es führt, und jedes Stocken ist unmittelbar zu sehen.
LV_OBJ_FLAG_SCROLL_MOMENTUM ist für die scrollbaren Container deshalb
abgeschaltet - die Liste folgt nur noch dem Finger. Nur für WS_PANEL_7H;
die JC-Panels haben das Tempoproblem nicht und bleiben unverändert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ursache war der zweite Zeichenpuffer aus 1.6.25. esp_lcd_dpi_panel_draw_bitmap
lehnt eine Übertragung ab, solange die vorige noch läuft:
ESP_RETURN_ON_FALSE(xSemaphoreTake(dpi_panel->draw_sem, 0) == pdTRUE,
ESP_ERR_INVALID_STATE, ...)
Mit zwei Puffern schickt LVGL die nächste Übertragung sofort los, statt auf
lv_disp_flush_ready zu warten. Die abgelehnte Übertragung fällt ersatzlos
aus, und der betroffene Bildbereich behält seinen alten oder noch nicht
geschriebenen Inhalt - sichtbar als blaue Zwischenbilder.
Der zweite Zeichenpuffer ist entfernt, lvgl_port_v9.c ist damit wieder
unverändert gegenüber der Hersteller-Portierung. Der eigentliche Gewinn
bleibt: Der Zwischenpuffer hat weiterhin volle Bildhöhe, ein Bildlauf
braucht einen Durchgang statt sechs.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Nach der Umstellung auf einen Bildspeicher war der Bildlauf sehr zäh. Grund
war der Zwischenpuffer: Mit 120 Zeilen brauchte ein Bildlauf über die ganze
Seite sechs Durchgänge, jeder mit eigener Übertragung in den Bildspeicher.
- CONFIG_EXAMPLE_LVGL_PORT_BUF_HEIGHT auf LCD_V_RES: ein Durchgang statt
sechs.
- Zweiter Zeichenpuffer (LVGL_PORT_SECOND_DRAW_BUFFER), damit LVGL den
nächsten Bereich zeichnen kann, während der vorige übertragen wird. Dafür
eine kleine, markierte Änderung in lvgl_port_v9.c - der Hersteller-Port
legt dort nur einen Puffer an.
Kosten 2 x 2,8 MB PSRAM. Das Startverhalten bleibt unberührt: Es handelt
sich um Zeichenpuffer, nicht um Bildspeicher der Anzeige - es bleibt bei
einem Bildspeicher.
Beide Panel-Varianten mit arduino-cli gegengebaut.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Mit dem Prüfbild bei num_fbs = 1 startet das Panel zuverlässig, mit zwei
Bildspeichern nicht. Das war der letzte verbliebene Unterschied zum
funktionierenden Werks-Testsketch - und die Ursache des ganzen
Startproblems: Der Hochlauf meldete durchgehend Erfolg, das Panel blieb
dunkel, erst ein Reset half.
- WS7_SINGLE_FB schaltet die Doppelpufferung für das Waveshare-Panel ab
(EXAMPLE_LVGL_PORT_AVOID_TEAR_ENABLE = 0). LVGL zeichnet dann in einen
Zwischenpuffer von 120 Zeilen im PSRAM, der per DMA in den einen
Bildspeicher übertragen wird.
- num_fbs folgt wieder LVGL_PORT_LCD_BUFFER_NUMS, das in diesem Modus 1
ist - die Sonderbehandlung im Prüfbild-Modus entfällt.
- WS7_PARTIAL_REFRESH ist damit wirkungslos und als solches vermerkt.
- PSRAM-Bedarf sinkt von 5,4 MB auf 2,8 MB.
Preis ist mögliches Tearing bei schnellen Bildwechseln.
Beide Panel-Varianten mit arduino-cli gegengebaut.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P7JsiDJ1QbNFLDz5chf8Jt
Der Selbst-Neustart aus 1.6.22 reicht nicht - ein Software-Neustart setzt
offenbar nicht dasselbe zurück wie die Reset-Taste.
Damit zurück zu dem einen Unterschied zum funktionierenden Werks-Testsketch,
der bisher nie überprüft wurde: dsi-test.ino setzt num_fbs = 1, die Firmware
nutzt LVGL_PORT_LCD_BUFFER_NUMS = 2. Der Prüfbild-Test lief bislang ebenfalls
mit zwei Speichern und war damit nie ein echter Nachbau - er wich an genau
der offenen Stelle ab.
Mit WS7_TEST_PATTERN = 1 wird num_fbs jetzt fest auf 1 gesetzt. Erscheinen
die Farbbalken damit zuverlässig, liegt es an der Anzahl der Bildspeicher.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P7JsiDJ1QbNFLDz5chf8Jt
Der DSI-Ab- und Wiederaufbau aus 1.6.21 hat nicht geholfen, sondern das
Bild um einen Schritt verschlechtert: Einschalten - gar nichts, erster
Reset - nur Beleuchtung, zweiter Reset - Bild. Ein Neuaufbau im laufenden
Betrieb ist einem echten Chip-Reset also nicht gleichwertig.
WS7_DSI_RESTART steht wieder auf 0, der Schalter bleibt dokumentiert.
Stattdessen der Weg, den die Messungen stützen: Nach einem Kaltstart
startet der P4 sich genau einmal selbst neu, sobald der erste Hochlauf
durch ist. Ein Reset hat in jedem Versuch zuverlässig geholfen.
- Bedingung ist esp_reset_reason() == ESP_RST_POWERON, beim zweiten
Durchlauf greift sie nicht mehr - keine Schleife möglich.
- Der Frühstart-Zähler der Absturzsicherung wird vorher zurückgesetzt,
damit der gewollte Neustart nicht in den Update-Modus führt.
- Schalter WS7_COLD_BOOT_RESTART, kostet ~3 s beim Einschalten.
Das ist eine Umgehung, keine Erklärung: Warum das Panel den ersten Anlauf
nicht annimmt, bleibt offen - der Hochlauf meldet durchgehend Erfolg.
Beide Panel-Varianten mit arduino-cli gegengebaut.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P7JsiDJ1QbNFLDz5chf8Jt
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
Beobachtung am Gerät: Beim Einschalten geht nach 2-3 s die Beleuchtung an,
dann kommt nichts. Nach einem Reset geht die Beleuchtung kurz aus, danach
erscheint Beleuchtung samt Bild - reproduzierbar in zwei von zwei Fällen.
Dass die Beleuchtung ausgeht, zeigt: Die Bridge folgt dem DSI-Signal. Und
dass der zweite Durchlauf klappt, zeigt warum - die Bridge hatte ihre
Grundeinstellung aus dem ersten Durchlauf noch und fand diesmal ein
DSI-Signal vor. Beim ersten Start bekommt sie ihre Einstellung dagegen,
bevor die DSI-Strecke überhaupt existiert.
ws7_bridge_core_init() ist aus ws7_bridge_pre_init() herausgelöst und wird
jetzt ein zweites Mal aufgerufen, sobald esp_lcd_panel_init() läuft -
dasselbe Vorgehen wie bei ws7_panel_wake() in 1.6.19. Die Register sind
wiederholbar.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P7JsiDJ1QbNFLDz5chf8Jt
Die Wartezeit aus 1.6.18 hat den Start deutlich verbessert, aber noch nicht
zuverlässig gemacht: beim ersten Anstecken nur Beleuchtung, nach Reset zwei
von drei Versuchen erfolgreich.
Aus dem Fehlerbild folgt, wo es hakt: Die Beleuchtung ging an. Sie hängt an
der Bridge und wird über I2C geschaltet, die Kommunikation steht also.
Verloren gehen die DCS-Weckbefehle an das Panel selbst - sie wurden genau
einmal geschickt, bevor die Videoausgabe lief. War der Panel-Controller
dann noch nicht aufnahmebereit, blieb der Bildschirm dunkel, während jeder
Schritt Erfolg meldete.
- ws7_panel_wake() gebündelt und wird jetzt zweimal aufgerufen: vor und
nach esp_lcd_panel_init(), getrennt durch WS7_PANEL_SETTLE_MS.
- Jeder Anlauf ist im Start-Log einzeln benannt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P7JsiDJ1QbNFLDz5chf8Jt
Entscheidender Hinweis vom Gerät: "Sobald der serielle Monitor läuft,
startet es fast immer einwandfrei." Dessen USB-Anmeldung verzögert den
Start - und ersetzte damit unbeabsichtigt eine Wartezeit, die der
Werks-Testsketch explizit hat: delay(2000) am Anfang von setup().
Unsere Firmware sprach Bridge und Panel sofort nach dem Einschalten an.
Das Displaymodul ist dann noch nicht bereit: Die Bridge nimmt ihre
Register nicht an oder das Panel zeigt trotz korrekt gesendeter DSI-Daten
nichts - beides ohne Fehlermeldung, weil aus Sicht des P4 jeder Schritt
geklappt hat. Daher das sprunghafte Verhalten und der Fehlstart beim
ersten Anstecken.
jc_board_bringup() wartet für WS_PANEL_7H jetzt WS7_PANEL_WARMUP_MS
(Vorgabe 2000 ms), bevor es beginnt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P7JsiDJ1QbNFLDz5chf8Jt
Der Störimpulsfilter aus 1.6.16 wirkt - nach dem Panel-Start melden sich
wieder alle drei I2C-Bausteine, keine Bridge- oder Touch-Fehler mehr.
Das Prüfbild aus 1.6.15 war als Test jedoch untauglich: gesetzt bei
esp_lcd_dpi_panel_set_pattern(), aber unmittelbar danach lief
lvgl_port_init() und schrieb in den Framebuffer, womit das Muster wieder
verschwand. Der Test sah damit genauso aus wie der Fehler, den er finden
soll.
Mit WS7_TEST_PATTERN = 1 endet jc_board_bringup() jetzt direkt nach dem
Muster: Backlight an, Rückgabe false, kein LVGL.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018QoLDQeUh1dCQz7yYZVb4Y
Der I2C-Scan vor und nach dem Panel-Start war entscheidend:
vor: 0x14 (Touch) 0x18 (Audio) 0x45 (Bridge)
nach: 0x18
Es fallen genau die beiden Bausteine weg, die am Displaykabel hängen; der
Audio-Baustein auf der Platine bleibt erreichbar, der Bus arbeitet also.
Sobald die DSI-Ausgabe läuft, stören deren Signale auf das Flachbandkabel
ein. Die Bridge liess sich danach nicht mehr ansprechen
(ESP_ERR_INVALID_STATE), das Panel blieb dunkel.
i2c_master_bus_config_t bekommt für WS_PANEL_7H jetzt glitch_ignore_cnt = 7
und enable_internal_pullup - beides setzt auch das Waveshare-Beispiel. In
unserem Bringup fehlte es, weil die Bus-Einrichtung von den JC-Panels
übernommen wurde, die kein Flachbandkabel dieser Länge haben.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018QoLDQeUh1dCQz7yYZVb4Y
Kaltstart, kein einziger Fehler im Log, alle I2C-Bausteine da - und trotzdem
keine Anzeige. Zwei Lücken in der Diagnose:
- Die DCS-Weckbefehle (MADCTL, Sleep Out, Display On) liefen ungeprüft
durch. Jetzt über BSP_STEP gemeldet.
- Nach dem Panel-Start endete die Ausgabe. "Bringup fertig" vor und
"LVGL laeuft" nach lvgl_port_init() trennen jetzt ein Hängenbleiben in
LVGL von einem fehlenden Bild.
Neuer Schalter WS7_TEST_PATTERN nutzt esp_lcd_dpi_panel_set_pattern() für
Farbbalken aus dem DSI-Baustein, ohne Framebuffer und ohne LVGL - wie im
funktionierenden Werks-Testsketch. Erscheinen sie, arbeitet die Kette bis
zum Panel und der Fehler liegt weiter oben.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018QoLDQeUh1dCQz7yYZVb4Y
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
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