Compare commits

..
Author SHA1 Message Date
raw-designsandClaude Opus 5 e32c654b8d perf(P4): Nur bei echter Änderung neu zeichnen (1.9.2)
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>
2026-09-03 02:17:03 +02:00
thomas 484812cb4c Merge pull request 'diag(P4): Gezeichnete Fläche messen, direktes Zeichnen zurücknehmen (1.9.1)' (#70) from diag/gezeichnete-flaeche-messen into main 2026-09-03 01:42:21 +02:00
raw-designsandClaude Opus 5 ff23e0e614 diag(P4): Gezeichnete Fläche messen, direktes Zeichnen zurücknehmen (1.9.1)
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>
2026-09-03 01:42:05 +02:00
thomas 09b5231357 Merge pull request 'perf(P4): LVGL zeichnet direkt in den Bildspeicher (1.9.0)' (#69) from perf/direkt-in-bildspeicher-zeichnen into main 2026-09-03 01:27:32 +02:00
raw-designsandClaude Opus 5 16d8465b0c perf(P4): LVGL zeichnet direkt in den Bildspeicher (1.9.0)
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>
2026-09-03 01:27:14 +02:00
thomas 407d938031 Merge pull request 'diag(P4): Bildaufbau messen, Dialogknöpfe skalieren (1.8.8)' (#68) from diag/bildaufbau-messen into main 2026-09-03 01:01:36 +02:00
raw-designsandClaude Opus 5 33ce2b3ab9 diag(P4): Bildaufbau messen, Dialogknöpfe skalieren (1.8.8)
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
2026-09-03 01:01:19 +02:00
thomas d4d4f2b9d2 Merge pull request 'fix(P4): Aufweckdialog sofort statt nach fünf Sekunden (1.8.7)' (#67) from fix/vorhaenge-deckend-und-dialogbreite into main 2026-09-03 00:47:35 +02:00
raw-designsandClaude Opus 5 9fef4f8a6e fix(P4): Aufweckdialog sofort statt nach fünf Sekunden (1.8.7)
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
2026-09-03 00:47:16 +02:00
thomas 0f5b681421 Merge pull request 'feat(P4): Uhr läuft lokal weiter, wenn die S3 keine Zeit liefert (1.8.6)' (#66) from feat/uhr-laeuft-lokal-weiter into main 2026-09-03 00:34:07 +02:00
raw-designsandClaude Opus 5 01d960258a feat(P4): Uhr läuft lokal weiter, wenn die S3 keine Zeit liefert (1.8.6)
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
2026-09-03 00:33:50 +02:00
thomas 3c333f0280 Merge pull request 'fix(P4): Standby-Verzögerung, Dialog-Timeout, Kurvenhintergrund, Bindestrich (1.8.5)' (#65) from fix/standby-verzoegerung-und-feinschliff into main 2026-09-03 00:26:30 +02:00
raw-designsandClaude Opus 5 b6c6214b41 fix(P4): Standby-Verzögerung, Dialog-Timeout, Kurvenhintergrund, Bindestrich (1.8.5)
- 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
2026-09-03 00:26:12 +02:00
thomas 63290afa07 Merge pull request 'fix(P4): Übergänge ohne Animation, kein blaues Aufblitzen, Temperaturfarbe wählbar (1.8.4)' (#64) from fix/uebergaenge-und-temperaturfarbe into main 2026-09-03 00:04:43 +02:00
raw-designsandClaude Opus 5 cf57e11ccb fix(P4): Übergänge ohne Animation, kein blaues Aufblitzen, Temperaturfarbe wählbar (1.8.4)
- 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
2026-09-03 00:03:58 +02:00
thomas 6d345d2145 Merge pull request 'fix(P4): Fehlendes °C, unsichtbarer Verlauf, fette Zahlen (1.8.3)' (#63) from fix/dashboard-schrift-und-verlauf into main 2026-09-02 20:12:52 +02:00
raw-designsandClaude Opus 5 a410da6e72 fix(P4): Fehlendes °C, unsichtbarer Verlauf, fette Zahlen (1.8.3)
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>
2026-09-02 20:12:32 +02:00
thomas f0a214d712 Merge pull request 'feat(P4): Letzte Bezüge als Tabelle statt Textblock (1.8.2)' (#62) from feat/statistik-tabelle into main 2026-09-02 19:52:14 +02:00
raw-designsandClaude Opus 5 21f273aae4 feat(P4): Letzte Bezüge als Tabelle statt Textblock (1.8.2)
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>
2026-09-02 19:51:57 +02:00
thomas e42d2b3de2 Merge pull request 'feat(P4): Bezugsanzeige für alle vier Darstellungen (1.8.1)' (#61) from feat/bezugsanzeige into main 2026-09-02 19:41:07 +02:00
raw-designsandClaude Opus 5 785f64331d feat(P4): Bezugsanzeige für alle vier Darstellungen (1.8.1)
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>
2026-09-02 19:40:51 +02:00
thomas 40aabe48bc Merge pull request 'feat(P4): Vier neue Dashboard-Darstellungen (1.8.0)' (#60) from feat/dashboard-vier-darstellungen into main 2026-09-02 19:30:11 +02:00
raw-designsandClaude Opus 5 ca3a9c1264 feat(P4): Vier neue Dashboard-Darstellungen (1.8.0)
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>
2026-09-02 19:29:54 +02:00
thomas bcd9ecf0c8 Merge pull request 'refactor(P4): Schriftgröße auf die Info-Seite verschieben (1.7.3)' (#59) from refactor/schriftgroesse-auf-info-seite into main 2026-09-02 18:09:36 +02:00
raw-designsandClaude Opus 5 e5c61d42d4 refactor(P4): Schriftgröße auf die Info-Seite verschieben (1.7.3)
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
2026-09-02 18:09:21 +02:00
thomas d77b0795ea Merge pull request 'feat(P4): Schriftgröße einstellbar (1.7.2)' (#58) from feat/schriftgroesse-einstellbar into main 2026-09-02 18:02:40 +02:00
raw-designsandClaude Opus 5 7ebffdab8f feat(P4): Schriftgröße einstellbar (1.7.2)
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>
2026-09-02 18:02:23 +02:00
thomas b73fc798c3 Merge pull request 'feat(P4): Cold Extraction und Wartung mehrspaltig (1.7.1)' (#57) from feat/coldex-und-wartung-mehrspaltig into main 2026-09-02 17:52:32 +02:00
raw-designsandClaude Opus 5 5defbe362c feat(P4): Cold Extraction und Wartung mehrspaltig (1.7.1)
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>
2026-09-02 17:52:15 +02:00
thomas 749f50097f Merge pull request 'feat(P4): Brew-Control zweispaltig auf dem 7-Zoll-Panel (1.7.0)' (#56) from feat/brew-control-zweispaltig into main 2026-09-02 17:26:06 +02:00
raw-designsandClaude Opus 5 95373dc619 feat(P4): Brew-Control zweispaltig auf dem 7-Zoll-Panel (1.7.0)
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>
2026-09-02 17:24:42 +02:00
thomas a1c047e1ef Merge pull request 'perf(P4): Scrollen ohne Nachlauf am Waveshare-Panel (1.6.27)' (#55) from perf/scrollen-ohne-nachlauf into main 2026-09-02 17:03:04 +02:00
raw-designsandClaude Opus 5 52391c46c9 perf(P4): Scrollen ohne Nachlauf am Waveshare-Panel (1.6.27)
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>
2026-09-02 17:01:40 +02:00
thomas 5d47228eed Merge pull request 'fix(P4): Blaue Zwischenbilder beim Bildlauf beseitigt (1.6.26)' (#54) from fix/blaue-zwischenbilder into main 2026-09-02 03:49:23 +02:00
raw-designsandClaude Opus 5 a3461fe960 fix(P4): Blaue Zwischenbilder beim Bildlauf beseitigt (1.6.26)
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>
2026-09-02 03:47:59 +02:00
thomas 1a05f8e1b3 Merge pull request 'perf(P4): Zeichenpuffer für flüssigen Bildlauf (1.6.25)' (#53) from perf/zeichenpuffer-bildlauf into main 2026-09-02 03:38:44 +02:00
raw-designsandClaude Opus 5 dd8e641aa7 perf(P4): Zeichenpuffer für flüssigen Bildlauf (1.6.25)
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>
2026-09-02 03:37:19 +02:00
thomas 6201c1bc36 Merge pull request 'fix(P4): Nur ein Bildspeicher - Ursache des Startfehlers behoben (1.6.24)' (#52) from fix/ein-bildspeicher into main 2026-09-02 03:20:25 +02:00
raw-designsandClaude Opus 5 6d710f0129 fix(P4): Nur ein Bildspeicher - Ursache des Startfehlers behoben (1.6.24)
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
2026-09-02 03:19:00 +02:00
thomas 5cc71ffa92 Merge pull request 'diag(P4): Prüfbild mit genau einem Bildspeicher, wie im Testsketch (1.6.23)' (#51) from diag/pruefbild-ein-bildspeicher into main 2026-09-02 03:04:57 +02:00
raw-designsandClaude Opus 5 6bef94b8e1 diag(P4): Prüfbild mit genau einem Bildspeicher, wie im Testsketch (1.6.23)
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
2026-09-02 03:03:33 +02:00
thomas 95e97e5937 Merge pull request 'fix(P4): Nach Kaltstart einmal selbst neu starten (1.6.22)' (#50) from fix/kaltstart-neustart into main 2026-09-02 02:45:31 +02:00
raw-designsandClaude Opus 5 8db8e166a2 fix(P4): Nach Kaltstart einmal selbst neu starten (1.6.22)
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
2026-09-02 02:44:06 +02:00
thomas 1def9e45dc Merge pull request 'fix(P4): DSI-Strecke beim Hochlauf einmal neu aufbauen (1.6.21)' (#49) from fix/dsi-strecke-neu-aufbauen into main 2026-09-02 02:27:49 +02:00
raw-designsandClaude Opus 5 c2a8b21917 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
2026-09-02 02:26:24 +02:00
thomas 6d7d544ac7 Merge pull request 'fix(P4): Bridge-Grundeinstellung nach dem DSI-Start wiederholen (1.6.20)' (#48) from fix/bridge-grundeinstellung-wiederholen into main 2026-09-02 02:12:53 +02:00
raw-designsandClaude Opus 5 992796345c fix(P4): Bridge-Grundeinstellung nach dem DSI-Start wiederholen (1.6.20)
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
2026-09-02 02:11:29 +02:00
thomas 5e2d0f7af8 Merge pull request 'fix(P4): Panel-Weckbefehle nach dem Start der Videoausgabe wiederholen (1.6.19)' (#47) from fix/panel-weckbefehle-wiederholen into main 2026-09-02 01:41:26 +02:00
raw-designsandClaude Opus 5 b6fdaa9ad7 fix(P4): Panel-Weckbefehle nach dem Start der Videoausgabe wiederholen (1.6.19)
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
2026-09-02 01:40:01 +02:00
thomas 08d07bd1a0 Merge pull request 'fix(P4): Anlaufzeit des Displaymoduls abwarten (1.6.18)' (#46) from fix/panel-anlaufzeit into main 2026-09-02 01:27:04 +02:00
raw-designsandClaude Opus 5 ee74c700bf fix(P4): Anlaufzeit des Displaymoduls abwarten (1.6.18)
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
2026-09-02 01:25:40 +02:00
thomas 750a6fb78c Merge pull request 'diag(P4): Prüfbild hält an, statt von LVGL überschrieben zu werden (1.6.17)' (#45) from diag/pruefbild-vor-lvgl into main 2026-09-01 17:25:48 +02:00
raw-designsandClaude Opus 5 80b6eb810f diag(P4): Prüfbild hält an, statt von LVGL überschrieben zu werden (1.6.17)
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
2026-09-01 17:24:25 +02:00
thomas 6a9048411e Merge pull request 'fix(P4): I2C-Störimpulsfilter - Ursache des schwarzen Bildes (1.6.16)' (#44) from fix/i2c-stoerimpulsfilter into main 2026-09-01 17:06:15 +02:00
raw-designsandClaude Opus 5 ecb9836510 fix(P4): I2C-Störimpulsfilter - Ursache des schwarzen Bildes (1.6.16)
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
2026-09-01 17:04:51 +02:00
thomas c4cb6eb90a Merge pull request 'diag(P4): Schwarzes Bild eingrenzen - Prüfbild und lückenlose Meldungen (1.6.15)' (#43) from diag/schwarzes-bild-eingrenzen into main 2026-09-01 16:52:28 +02:00
raw-designsandClaude Opus 5 c58b901f26 diag(P4): Schwarzes Bild eingrenzen - Prüfbild und lückenlose Meldungen (1.6.15)
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
2026-09-01 16:51:04 +02:00
thomas d83619904f Merge pull request 'fix(P4): Touch erst nach Panel-Freigabe initialisieren (1.6.14)' (#42) from fix/touch-nach-panelfreigabe into main 2026-09-01 16:31:55 +02:00
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
raw-designsandClaude Opus 5 e8308a9182 fix(P4): Schwarzes Bild nach Reset am Waveshare-Panel (1.6.11)
Nach einem Reset des P4 blieb das Bild schwarz, die Hintergrundbeleuchtung
brannte; nur direkt nach dem Flashen lief es.

Die Bridge des Panels hat keine Reset-Leitung und hängt an Dauerstrom. Ein
Reset des P4 setzt sie nicht zurück - ihre Register standen noch auf den
Werten der vorigen Sitzung, während der P4 seine DSI-Strecke komplett neu
aufbaut. Beim Flashen wird die Versorgung getrennt, deshalb trat der Fehler
dort nicht auf.

ws7_bridge_pre_init() schaltet die Bridge jetzt zuerst definiert ab
(AB/AA, AD, dann AC/C2/C0), wartet WS7_BRIDGE_RESET_MS und schreibt erst
danach die Grundinitialisierung.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018QoLDQeUh1dCQz7yYZVb4Y
2026-09-01 15:22:11 +02:00
thomas edb1e333f0 Merge pull request 'perf(P4): Teil-Neuzeichnen als Vorgabe, Messeinblendung, deckende Seiten (1.6.10)' (#38) from perf/scrollen-messen-und-vorgaben into main 2026-09-01 14:46:56 +02:00
raw-designsandClaude Opus 5 528c8d5500 perf(P4): Teil-Neuzeichnen als Vorgabe, Messeinblendung, deckende Seiten (1.6.10)
- WS7_PARTIAL_REFRESH = 1 auch im Auslieferungsstand. Am Gerät geprüft: kein
  Flackern; von den drei Tempo-Maßnahmen aus 1.6.4 ist es der größte Gewinn.
- make_page() setzt einen deckenden Hintergrund in COL_BG statt LV_OPA_TRANSP.
  Optisch identisch, spart LVGL beim Scrollen aber das Zeichnen und Mischen
  der darunterliegenden Ebenen.
- Neuer Schalter WS7_PERF_MONITOR schaltet LV_USE_SYSMON/LV_USE_PERF_MONITOR
  ein und blendet Bilder je Sekunde und Prozessorlast ein. Vorgabe 0, mit 1
  gegengebaut.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018QoLDQeUh1dCQz7yYZVb4Y
2026-09-01 14:45:33 +02:00
thomas 117715dc3b Merge pull request 'fix(P4): Tipp auf einen Knopf löst nicht mehr mehrfach aus (1.6.9)' (#37) from fix/touch-mehrfachausloesung into main 2026-09-01 14:19:51 +02:00
raw-designsandClaude Opus 5 328dc06983 fix(P4): Tipp auf einen Knopf löst nicht mehr mehrfach aus (1.6.9)
Der GT9271 lässt gelegentlich einen Messzyklus aus oder liefert ein
unplausibles Paket. Der Hersteller-Treiber kann "gerade nichts Neues" nicht
von "Finger weg" unterscheiden und meldet beides als losgelassen. Seit die
Abtastrate mit 1.6.8 von 33 auf 16 ms gestiegen ist, wurde daraus sichtbar
Drücken-Loslassen-Drücken-Loslassen.

Vor den Treiber ist jetzt ein eigener get_xy-Aufsatz gesetzt: Er verwirft
unplausible Rohwerte und hält den letzten gültigen Punkt noch
WS7_TOUCH_HOLD_MS lang (Vorgabe 40 ms). Der Aufsatz wird zur Laufzeit in das
Touch-Handle eingehängt, die Herstellerdateien bleiben unverändert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018QoLDQeUh1dCQz7yYZVb4Y
2026-09-01 14:18:28 +02:00
thomas 480708c992 Merge pull request 'perf(P4): Scrollen am Waveshare-Panel flüssiger (1.6.8)' (#36) from perf/scrollen-taktrate into main 2026-09-01 14:02:46 +02:00
raw-designsandClaude Opus 5 9a0761f6da perf(P4): Scrollen am Waveshare-Panel flüssiger (1.6.8)
LV_DEF_REFR_PERIOD steuert nicht nur die Bildrate, sondern auch die
Abtastrate des Touch und die Schrittweite von Animationen. Mit 33 ms waren
das 30 Schritte je Sekunde - beim Ziehen mit dem Finger sichtbar ruckelig.

Für das Waveshare-Panel jetzt 16 ms, passend zu dessen 60 Hz. Kommt das
Zeichnen nicht hinterher, wird ein Bild später fertig; kaputt geht nichts.
Die JC-Panels bleiben unverändert bei 33 ms.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018QoLDQeUh1dCQz7yYZVb4Y
2026-09-01 14:01:23 +02:00
thomas e6c09b7a9a Merge pull request 'fix(P4): Menü-Knopf fängt Tipps auch knapp daneben ab (1.6.7)' (#35) from fix/menue-knopf-trefferflaeche into main 2026-09-01 13:49:17 +02:00
raw-designsandClaude Opus 5 4fa0c81087 fix(P4): Menü-Knopf fängt Tipps auch knapp daneben ab (1.6.7)
Eine Messung mit WS7_TOUCH_DEBUG hat gezeigt, dass die Touch-Zuordnung stimmt:
Der Tipp auf den Menü-Knopf landete bei X=66/Y=27, der Knopf liegt aber bei
X 8..56. Mit 48x36 Pixeln ist er auf dem 7-Zoll-Panel ein sehr kleines Ziel.

lv_obj_set_ext_click_area vergrößert die Trefferfläche um 20 Pixel, ohne den
Knopf optisch zu ändern. Die Vergrößerung wirkt nur innerhalb der Kopfleiste,
weil diese ihre Kinder beschneidet - dem Seiteninhalt darunter wird nichts
weggenommen, und bei offenem Menü liegt ohnehin der Vorhang darüber.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018QoLDQeUh1dCQz7yYZVb4Y
2026-09-01 13:47:54 +02:00
thomas 04eb77fb2d Merge pull request 'feat(P4): Touch-Messausgabe zum Einmessen (1.6.6)' (#34) from diag/touch-einmessen into main 2026-09-01 13:25:39 +02:00
raw-designsandClaude Opus 5 7878f1bafd feat(P4): Touch-Messausgabe zum Einmessen (1.6.6)
Der Menü-Knopf oben links reagiert am Waveshare-Panel nicht. Ob der Touch die
48x36 Pixel grosse Flaeche in der 44 Pixel hohen Kopfleiste ueberhaupt trifft,
liess sich bisher nicht nachsehen.

WS7_TOUCH_DEBUG in pins_config.h gibt jeden Berührpunkt roh und umgerechnet
über esp_rom_printf aus, also auch bei Core-Debug-Level "none". Vorgabe 0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018QoLDQeUh1dCQz7yYZVb4Y
2026-09-01 13:24:18 +02:00
thomas 60bb859fc9 Merge pull request 'fix(P4): Menü-Vorhang wieder öffenbar, RGB888 bleibt Vorgabe (1.6.5)' (#33) from fix/waveshare-vollbild-neuzeichnen into main 2026-09-01 13:14:52 +02:00
13 changed files with 19669 additions and 464 deletions
+490
View File
@@ -1,3 +1,493 @@
Version 1.9.2:
- Ursache der Trägheit endlich gefunden. Die erweiterte Messung zeigte: „1 Bereich, 100 %
der Fläche" - LVGL zeichnete bei jeder Zustandsmeldung den kompletten Bildschirm neu, also
einmal pro Sekunde 240 bis 300 Millisekunden lang. Es war also kein Tempoproblem beim
Zeichnen, sondern es wurde viel zu viel als „muss neu gezeichnet werden" gemeldet.
- Grund: LVGL macht den Bereich einer Beschriftung ungültig, sobald ihr Text gesetzt wird -
auch dann, wenn er sich gar nicht geändert hat. Dasselbe gilt für Farbwechsel. Auf dem
Dashboard wurden im Sekundentakt Werte quer über den ganzen Bildschirm gesetzt: Uhrzeit
oben, Temperaturen in der Mitte, Bezugswerte unten. LVGL fasst benachbarte ungültige
Bereiche zu einem zusammen - und der umfasste dann die gesamte Fläche.
- Alle regelmäßig gesetzten Werte werden jetzt vorher verglichen und nur bei echter Änderung
neu geschrieben; für Farben gilt dasselbe. Da sich Temperaturen selten um ein Zehntelgrad
ändern und der Sollwert praktisch nie, entfallen die meisten dieser Neuzeichnungen.
- Das betrifft alle Bildschirmgrößen; auf den JC-Panels war es nur nie störend, weil dort ein
Bildaufbau ein Bruchteil davon kostet.
Version 1.9.1:
- Das direkte Zeichnen in den Bildspeicher aus 1.9.0 ist zurückgenommen: Es hat die
Bildaufbauzeit nicht verkürzt (weiterhin 240 bis 300 ms) und stattdessen Bildfehler
erzeugt, weil in denselben Speicher gezeichnet wird, aus dem gerade angezeigt wird.
Damit ist auch klar, dass der Flaschenhals nicht im Kopieren liegt, sondern im Zeichnen
selbst. Der Schalter WS7_DIRECT_FB bleibt samt Begründung erhalten.
- Die Messung sagt jetzt zusätzlich, WIE VIEL neu gezeichnet wurde: Anzahl der Bereiche und
ihr Anteil an der Gesamtfläche. Erst damit lässt sich unterscheiden, ob LVGL nur kleine
Bereiche anfasst - dann ist das Zeichnen an sich zu langsam - oder ob jedes Mal der ganze
Bildschirm neu entsteht, weil ihn etwas unnötig ungültig macht. Das sind zwei völlig
verschiedene Ursachen mit verschiedenen Gegenmitteln.
Version 1.9.0:
- Die Messung aus 1.8.8 hat die Ursache der Trägheit gefunden: Jeder Bildaufbau kostete
240 bis 300 Millisekunden - dauerhaft, auch im Leerlauf. Fünf Sekunden für den
Aufweckdialog waren also rund zwanzig solcher Durchgänge.
- Grund war, dass zweimal durch den Bildspeicher gearbeitet wurde: LVGL zeichnete in einen
eigenen Puffer, und dessen Inhalt wurde anschließend vollständig in den Bildspeicher
kopiert. Bei 1280x720 in 24 Bit sind das zwei Durchgänge durch je 2,7 MB.
- LVGL zeichnet jetzt direkt in den Bildspeicher. Der Treiber lässt das Kopieren dann weg,
und LVGL zeichnet nur noch die geänderten Bereiche statt jedes Mal die ganze Fläche.
Schalter WS7_DIRECT_FB in pins_config.h.
- Die Anzeigen von Shot-Timer und Waage bleiben während eines Bezugs in der normalen
Schrift; der fette Wechsel ist entfernt. Der Bereich bekommt weiterhin mehr Platz.
- Neu: Die Größe der Standby-Uhr lässt sich einstellen (Klein, Mittel, Groß - 120, 180 oder
240 Pixel), zu finden auf der Info-Seite unter Darstellung. Anders als die allgemeine
Schriftgröße wirkt sie sofort, weil sie an einem einzigen Textfeld hängt.
- Die Knöpfe des Aufweckdialogs berücksichtigen jetzt ebenfalls die eingestellte
Schriftgröße und wachsen mit.
Version 1.8.8:
- Der Aufweckdialog berücksichtigt jetzt die eingestellte Schriftgröße vollständig: Die
Knöpfe bekommen dieselbe Schrift wie der Text und wachsen mit (150 / 210 / 280 Pixel).
Bisher erbten sie die kleine Grundschrift und behielten eine feste Breite - neben dem
größeren Text wirkten sie dadurch verloren.
- Die große Standby-Uhr bleibt bewusst bei ihrer festen Größe: Sie ist bereits auf die
Bildschirmhöhe abgestimmt, eine Umschaltung würde sie nur schlechter passend machen.
- Neu: eine Zeitmessung für langsame Bildaufbauten. Überschreitet ein Zeichenzyklus
200 Millisekunden, meldet die serielle Konsole seine Dauer. Damit lässt sich feststellen,
welcher Vorgang tatsächlich Zeit kostet - die bisherigen Erklärungen für die Verzögerung
beim Aufweckdialog haben sich als falsch erwiesen, und weiteres Raten hilft nicht.
Im Normalbetrieb bleibt die Ausgabe still.
Version 1.8.7:
- Vom Fingertipp auf die Standby-Uhr bis zum Aufweckdialog vergingen rund fünf Sekunden mit
schwarzem Bildschirm. Ursache war der halbdurchsichtige Vorhang, den der Dialog über den
ganzen Bildschirm legt: Dafür muss LVGL einen Vollbild-Zwischenpuffer anlegen und die
gesamte Fläche mischen - bei 1280x720 in 24 Bit die teuerste Operation überhaupt.
- Der Vorhang ist auf dem Waveshare-Panel jetzt deckend. Verloren geht dabei nichts: Im
Standby liegt dahinter ohnehin nur Schwarz.
- Aus demselben Grund ist auch der Vorhang des Menüs deckend, in einem dunklen Ton. Auf
dunklem Grund sieht das praktisch genauso aus wie halbdurchsichtig, spart aber dieselbe
Mischarbeit. Die JC-Panels behalten in beiden Fällen die Transparenz.
- Der Aufweckdialog wird mit größerer Schrift auch breiter (420 / 640 / 900 Pixel), damit
der Text nicht an unglücklichen Stellen umbricht.
Version 1.8.6:
- Die Uhrzeit verschwindet nicht mehr, wenn die Hauptplatine ihre Zeit gerade neu abgleicht.
Der P4 merkt sich die zuletzt empfangene Uhrzeit und zählt zwischen den Meldungen selbst
weiter; sobald die Hauptplatine wieder eine Zeit schickt, gilt deren Wert.
- Der P4 stellt dabei nichts richtig und ersetzt keine Zeitquelle - er überbrückt nur die
Lücke. Hat er noch nie eine Uhrzeit bekommen, bleibt die Anzeige wie bisher leer.
- Gilt für die Uhr in der Kopfleiste und für die große Standby-Uhr.
Version 1.8.5:
- Die Verzögerung von rund zwei Sekunden rund um den Standby ist behoben. Sie lag nicht an
der Helligkeitsumschaltung, sondern daran, dass die Standby-Uhr bei JEDER Zustandsmeldung
der Hauptplatine nach vorn geholt wurde. Das ordnet die Ebenen neu und lässt LVGL den
gesamten Bildschirm neu zeichnen - einmal pro Sekunde, jedes Mal 1280x720 in 24 Bit.
Dadurch hing die Oberfläche dauerhaft ein bis zwei Sekunden hinterher. Nach vorn geholt
wird die Uhr jetzt beim Einblenden, danach bleibt sie dort.
- Der Aufweckdialog schließt sich nach 30 Sekunden ohne Auswahl von selbst und wird wie
„Abbrechen" gewertet. Vorher blieb das Display hell stehen - der Dialog schaltet auf
normale Helligkeit, und ein versehentlicher Tipp auf die Uhr hätte die Maschine die ganze
Nacht leuchten lassen.
- Die Verlaufskurve hat keinen eigenen Hintergrund mehr; sie liegt jetzt direkt auf der
Karte. Die abgesetzte Fläche war nur nötig, solange die Kurve vor dem ersten Messwert
leer blieb - seit sie beim aktuellen Wert startet, ist immer eine Linie da.
- Auf der Statistikseite erschien ein leeres Rechteck, wenn ohne Waage bezogen wurde. Dort
stand ein typografischer Gedankenstrich, den der Zeichensatz der Schrift nicht enthält.
Jetzt ein einfacher Bindestrich.
Version 1.8.4:
- Standby-Uhr und Aufweckdialog erscheinen jetzt sofort statt mit spürbarer Verzögerung.
Ursache waren die weichen Ein- und Ausblendungen: Eine Deckkraft-Animation ist bei einem
Bildspeicher in RGB888 das Teuerste, was die Oberfläche tun kann, weil für jedes Einzelbild
die gesamte Fläche unter der Ebene neu gezeichnet und mit ihr gemischt werden muss. Auf
1280x720 dauerte eine solche Blende deutlich länger als die 450 ms, die vorgesehen waren.
Auf dem Waveshare-Panel laufen die Übergänge deshalb ohne Animation; die JC-Panels
behalten sie.
- Beim Wechsel der Schriftgröße blitzte kurz ein blaues Bild auf. Das kommt nicht von der
Firmware: Das Panel zeigt von sich aus Blau, sobald kein Videosignal anliegt - und beim
nötigen Neustart reißt das Signal kurz ab. Die Beleuchtung wird jetzt vorher abgeschaltet;
dunkel ist unauffälliger als blau.
- Neue Einstellung unter Darstellung: „Temperaturzahl in der Zustandsfarbe". Aus bleibt die
Zahl weiß, die Zustandsfarbe steckt dann allein im Balken darunter - ruhiger, und die Zahl
bleibt eine Zahl. Ein bedeutet, sie färbt sich mit, wie bisher. Vorgabe ist aus.
Warnungen bleiben in jedem Fall rot; das ist keine Gestaltung, sondern eine Meldung.
Version 1.8.3:
- Fehlerbehebung: Bei allen Darstellungen stand hinter der Temperatur ein leeres Rechteck
statt des C. Die beiden großen Schriften waren auf Ziffern, Komma, Punkt, Minus und
Gradzeichen beschränkt - das C fehlte darin schlicht. Es ist jetzt enthalten, ebenso g
und s für die Gewichts- und Zeitanzeige während eines Bezugs.
- Fehlerbehebung: Bei der Darstellung „Verlauf" war keine Kurve zu sehen. Ein frisch
angelegtes Diagramm enthält lauter „kein Wert"-Punkte und zeichnet deshalb nichts; ohne
Hintergrund war der Bereich vollständig unsichtbar, bis nach einer Minute genug Messwerte
zusammengekommen wären. Die Kurve startet jetzt beim aktuellen Messwert, und ihre Fläche
ist leicht abgesetzt.
- Die großen Zahlen des Dashboards stehen jetzt im fetten Schnitt und etwas enger, wie im
Entwurf. Erzeugt aus der variablen Maven-Pro-Datei mit Gewicht 700 - dieselbe Schriftart
wie bisher, nur kräftiger. Die übrige Oberfläche bleibt unverändert.
Version 1.8.2:
- Die Liste der letzten Bezüge auf der Statistikseite ist jetzt eine Tabelle mit festen
Spalten: Zeitpunkt, Dauer, Gewicht und gegebenenfalls die Kennzeichnung „kalt".
- Vorher war es ein einziges mehrzeiliges Textfeld, in dem die Werte durch Leerzeichen
getrennt aneinandergereiht standen. Weil Zahlen unterschiedlich breit sind, stand nichts
untereinander - zwei Bezüge ließen sich nicht vergleichen, ohne jede Zeile einzeln zu
lesen. Genau das sah unruhig aus.
- Ziffern haben jetzt gleiche Breite, jede zweite Zeile ist leicht abgesetzt, und eine
Kopfzeile benennt die Spalten. Wurde ohne Waage bezogen, bleibt die Gewichtsspalte leer,
statt eine Null vorzutäuschen.
- Die Zeilen werden einmal angelegt und danach nur gefüllt oder ausgeblendet, statt bei
jeder Aktualisierung neu zu entstehen.
Version 1.8.1:
- Die Bezugsanzeige ist da, und zwar für alle vier Darstellungen gemeinsam: Sobald ein
Bezug oder Dampfbezug läuft, schrumpft der Temperaturbereich und die untere Zeile wächst.
Shot-Timer und Gewicht werden dabei auf 96 Pixel vergrößert - während eines Bezugs zählen
Zeit und Gewicht, die Kesseltemperaturen sind dann Nebensache.
- Es gibt keine zweite Ansicht: Die Seite verschiebt nur das Gewicht zwischen ihren beiden
Bereichen. Damit bleibt alles an seinem Platz, und es gibt nichts doppelt zu pflegen.
- 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 - das wäre unruhiger als gar
kein Wechsel.
Version 1.8.0:
- Das Dashboard hat vier neue Darstellungen, die die bisherigen fünf ersetzen. Sie sind
keine Varianten desselben Bildes, sondern vier Antworten auf die Frage, was die große
Fläche des 7-Zöllers leisten soll:
* Gewichtet - Wasser bekommt zwei Drittel der Fläche, Dampf ein Drittel. Beim Espresso
zählt die Wassertemperatur; die Asymmetrie ist die Aussage.
* Verlauf - unter jeder Temperatur eine flache Kurve der letzten Minute. Die eigentliche
Frage an eine PID-Regelung ist nicht „wie warm", sondern „hält sie" - und das kann eine
Zahl grundsätzlich nicht zeigen. Der Ausschnitt hängt am Sollwert, damit die Abweichung
sichtbar wird statt in der Skala unterzugehen.
* Flächen - keine Kartenkanten, zwei Felder mit einem Hauch Helligkeitsunterschied.
* Band - ein farbiges Band über die volle Breite sagt den Zustand, bevor eine Zahl
gelesen wird: bereit, heizt, Bezug, Cold Extraction oder Standby. Neue Vorgabe.
- Dafür gibt es zwei neue Schriftgrade (96 und 140 Pixel). Sie enthalten nur Ziffern,
Komma, Punkt, Minus und Gradzeichen - mit vollem Zeichensatz wären sie um ein Vielfaches
größer, ohne etwas beizutragen. Die größte Textschrift hatte bisher 48 Pixel, was für die
großen Zahlen nicht reichte.
- Ältere Stände haben in den Einstellungen noch die Nummer einer der früheren Darstellungen
gespeichert; liegt sie außerhalb, fällt sie auf die Vorgabe zurück.
- Der Aufbau der Bezugsanzeige - untere Zeile wechselt während eines Bezugs auf große
Timer- und Gewichtsanzeige - folgt als nächster Schritt.
Version 1.7.3:
- Die Schriftgröße steht jetzt auf der Info-Seite im Abschnitt „Darstellung", zusammen mit
der Wahl der Temperaturanzeige und dem Live-Bezugsschirm. Dort gehört sie hin: Es ist
eine Einstellung dieses Displays, keine Wartungsaufgabe.
- Die Seite Reinigung & Wartung hat damit wieder vier Karten in zwei Spalten.
- Die Auswahl selbst ist unverändert: drei Stufen, Neustart nach der Auswahl.
- Sie steht auf allen Panels zur Verfügung, nicht nur auf dem 7-Zöller.
Version 1.7.2:
- Die Schriftgröße lässt sich jetzt einstellen: Klein, Mittel oder Groß, zu finden auf der
Seite Reinigung & Wartung in der neuen Karte „Darstellung".
- LVGL-Schriften sind fest einkompilierte Bilddaten; es gibt sie nur in den Größen, die im
Projekt liegen (14, 18, 28, 40 und 48 Pixel). Stufenlos skalieren lässt sich also nichts.
Stattdessen gibt es drei Rollen - klein, normal, hervorgehoben -, die je nach Einstellung
eine Stufe höher greifen.
- Die großen Anzeigen für Temperatur und Uhrzeit bleiben unverändert: Sie sind bereits auf
die Bildschirmgröße abgestimmt und sollen nicht mitwachsen.
- Die Einstellung liegt lokal im Display, nicht auf der Hauptplatine - sie betrifft nur
dieses Gerät. Nach der Auswahl startet der P4 neu, weil die Schriften in bereits
angelegten Bedienelementen stecken und sich nicht nachträglich umhängen lassen.
- Zu erwarten: 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.
Version 1.7.1:
- Cold Extraction ist auf dem 7-Zoll-Panel dreispaltig: oben die drei Karten mit
Erklaerungstext (Modus, Vorbenetzung, Bezugsende), darunter die knappen (Grundeinstellung,
Hauptbezug, Pumpenschutz), der Speichern-Knopf frei unter allen sechs. Drei statt zwei
Spalten, weil die Erklaerungstexte keine volle Zeilenbreite brauchen und so am Ende keine
halbleere Reihe stehen bleibt.
- Der Warnhinweis stand bisher als eigene Zeile am Seitenende, weit entfernt von dem
Schalter, auf den er sich bezieht. Er sitzt jetzt in der Modus-Karte.
- Reinigung & Wartung ist zweispaltig und besteht aus vier Karten: Wartungszaehler,
Flush-Zeiten, Display-Helligkeit sowie Reinigung & Entkalkung. Bisher standen dort lose
Zeilen unter blossen Zwischenueberschriften, dazwischen freistehende Knoepfe.
- Anders als bei Bruehen und Cold Extraction sitzt der Speichern-Knopf hier IN der Karte:
Jede Karte speichert etwas anderes, deshalb gehoert der Knopf zur Karte statt unter die
Seite.
- Alle drei umgestellten Seiten passen jetzt vollstaendig auf den Bildschirm. Die JC-Panels
behalten ihr einspaltiges Layout.
Version 1.7.0:
- Brew-Control ist auf dem 7-Zoll-Panel zweispaltig: Pre-Infusion und Brew-by-Weight oben,
Brew-by-Time und Dampf-Timer darunter, der Speichern-Knopf frei unter allen Karten.
Damit passt die Seite vollstaendig auf den Bildschirm und muss nicht mehr gescrollt
werden - der teuerste Vorgang der Oberflaeche entfaellt dort ersatzlos.
- Die Anordnung folgt der Bedeutung: links steht, was den Bezug startet, rechts, was ihn
beendet.
- Der Speichern-Knopf sitzt bewusst nicht in einer der Karten. Er speichert die ganze Seite
und wuerde in einer einzelnen Karte so wirken, als gaelte er nur fuer diese.
- Die JC-Panels bleiben einspaltig - dort ist der Platz knapp, nicht ueppig.
- Cold Extraction und Reinigung/Wartung folgen als naechstes.
Version 1.6.27:
- Beim Waveshare-Panel rollen scrollbare Listen nach dem Loslassen nicht mehr aus, sondern
folgen nur dem Finger. Ohne Doppelpufferung entsteht beim Scrollen jedes Bild komplett
neu; am staerksten faellt das beim Ausrollen auf, wo sich das Bild ohne fuehrenden Finger
weiterbewegt und jedes Stocken unmittelbar sichtbar ist.
- Die JC-Panels sind ausgenommen, ihr Bediengefuehl bleibt unveraendert.
Version 1.6.26:
- Fehlerbehebung: Beim Bildlauf blitzten blaue Zwischenbilder auf. Ursache war der zweite
Zeichenpuffer aus 1.6.25. Der Panel-Treiber lehnt eine Uebertragung ab, solange die
vorige noch laeuft; mit zwei Puffern schickt LVGL die naechste aber sofort los. Die
abgelehnte Uebertragung faellt ersatzlos aus, und der betroffene Bildbereich behaelt
seinen alten Inhalt.
- Der zweite Zeichenpuffer ist deshalb wieder entfernt, die Herstellerdatei lvgl_port_v9.c
damit wieder unveraendert. Der eigentliche Gewinn beim Bildlauf bleibt erhalten: Der
Zwischenpuffer hat weiterhin volle Bildhoehe, ein Bildlauf braucht also einen Durchgang
statt sechs.
Version 1.6.25:
- Der Bildlauf war nach der Umstellung auf einen Bildspeicher sehr zaeh. Grund war der
Zwischenpuffer, in den LVGL zeichnet: Mit 120 Zeilen brauchte ein Bildlauf ueber die
ganze Seite sechs Durchgaenge, jeder mit eigener Uebertragung in den Bildspeicher.
- Der Zwischenpuffer hat jetzt volle Bildhoehe - ein Durchgang statt sechs. Dazu kommt ein
zweiter Puffer, damit LVGL bereits den naechsten Bereich zeichnen kann, waehrend der
vorige noch uebertragen wird.
- Kosten: 2 x 2,8 MB PSRAM zusaetzlich, bei 32 MB unkritisch. Am Startverhalten aendert
sich nichts: Diese Puffer sind Zeichenpuffer, keine Bildspeicher der Anzeige - es bleibt
bei EINEM Bildspeicher, und nur der war fuer den Startfehler verantwortlich.
Version 1.6.24:
- Ursache des unzuverlaessigen Starts gefunden und behoben: die Anzahl der Bildspeicher.
Mit zwei Bildspeichern kam nach dem Einschalten kein Bild - der Hochlauf meldete
durchgehend Erfolg, das Panel blieb dunkel, und erst ein Reset half. Mit genau einem
startet es zuverlaessig. Belegt wurde das mit den Prueffarbbalken: Sie erscheinen mit
einem Speicher sofort, mit zweien nicht. Der Werks-Testsketch benutzt ebenfalls einen -
das war der letzte verbliebene Unterschied zu ihm.
- Die Oberflaeche laeuft deshalb ohne Doppelpufferung: LVGL zeichnet in einen
Zwischenpuffer von 120 Zeilen im PSRAM, der dann in den einen Bildspeicher uebertragen
wird. Bei schnellen Bildwechseln kann kurz eine Kante sichtbar werden; ein zuverlaessig
startendes Display wiegt das auf.
- Schalter WS7_SINGLE_FB in pins_config.h. WS7_PARTIAL_REFRESH ist damit wirkungslos, weil
es ohne Doppelpufferung nichts umzuschalten gibt.
- Der PSRAM-Bedarf sinkt von 5,4 MB auf 2,8 MB.
- Die Umgehungen aus den Vorversionen bleiben erhalten: Anlaufzeit, wiederholte
Bridge-Grundeinstellung, wiederholte Weckbefehle und der Neustart nach Kaltstart. Ob
jede davon noch noetig ist, laesst sich jetzt einzeln pruefen - der Startfehler selbst
ist behoben.
Version 1.6.23:
- Der Selbst-Neustart aus 1.6.22 reicht nicht: Ein Software-Neustart setzt offenbar nicht
dasselbe zurueck wie die Reset-Taste. Der Schalter bleibt eingeschaltet, er schadet nicht,
loest das Problem aber nicht allein.
- Zurueck zu dem einen Unterschied zum funktionierenden Werks-Testsketch, der bisher nie
ueberprueft wurde: Dieser legt EINEN Bildspeicher an, die Firmware zwei. Der Pruefbild-Test
lief bislang ebenfalls mit zwei und war damit nie ein echter Nachbau des Testsketches - er
wich an genau der Stelle ab, die noch offen ist.
- Mit WS7_TEST_PATTERN = 1 wird jetzt genau ein Bildspeicher angelegt, wie im Testsketch.
Erscheinen die Farbbalken damit zuverlaessig, liegt es an der Anzahl der Bildspeicher, und
die Oberflaeche laesst sich darauf umstellen.
Version 1.6.22:
- Der Ab- und Wiederaufbau der DSI-Strecke aus 1.6.21 hat nicht geholfen, sondern das Bild
um einen Schritt verschlechtert: Nach dem Einschalten kam gar nichts mehr, nach dem
ersten Reset nur die Beleuchtung, erst nach dem zweiten das Bild. Ein Ab- und Wiederaufbau
im laufenden Betrieb ist einem echten Chip-Reset also nicht gleichwertig. WS7_DSI_RESTART
steht deshalb wieder auf 0; der Schalter bleibt samt Begruendung erhalten.
- Stattdessen der Weg, den die Messungen eindeutig stuetzen: Nach einem Kaltstart startet
der P4 sich genau einmal selbst neu, sobald der erste Hochlauf durch ist. Damit passiert
genau das, was bei jedem Versuch zuverlaessig geholfen hat - ohne dass jemand die
Reset-Taste druecken muss.
- Eine Schleife ist ausgeschlossen: Beim zweiten Durchlauf ist der Startgrund kein Kaltstart
mehr, die Bedingung greift nicht erneut. Der Fruehstart-Zaehler der Absturzsicherung wird
vor dem gewollten Neustart zurueckgesetzt, damit dieser nicht als Absturz zaehlt.
- Kostet rund drei Sekunden, und nur beim Einschalten. Schalter WS7_COLD_BOOT_RESTART in
pins_config.h.
- Das ist eine Umgehung, keine Erklaerung: Warum das Panel den ersten Anlauf nach dem
Einschalten nicht annimmt, ist weiterhin offen. Der Hochlauf meldet durchgehend Erfolg.
Version 1.6.21:
- Der Hochlauf lief zuletzt vollstaendig 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 zuverlaessig. Es fehlte also kein
Befehl mehr; es fehlte der Vorgang selbst.
- Ein Reset unterscheidet sich an dieser Stelle in genau einem Punkt: Die DSI-Verbindung
geht einmal weg und neu auf, waehrend Bridge und Panel bereits versorgt und eingestellt
sind. Weder die wiederholte Grundeinstellung noch die wiederholten Weckbefehle ersetzen
das - beide laufen ueber eine Verbindung, die durchgehend bestand.
- Der Hochlauf baut die DSI-Strecke jetzt einmal komplett ab und wieder auf: Bildausgabe,
Kommandokanal und Bus werden freigegeben und neu angelegt. Damit passiert ohne Reset,
was vorher erst der zweite Start brachte. Schalter WS7_DSI_RESTART in pins_config.h,
Pause dazwischen WS7_DSI_RESTART_MS (Vorgabe 200 ms).
- Der DSI-Aufbau steckt dafuer in einer eigenen Funktion, damit der Vorgang wiederholbar
ist statt zweimal im Quelltext zu stehen.
Version 1.6.20:
- Nach 1.6.19 lief es reproduzierbar so ab: Beim Einschalten ging nach zwei bis drei
Sekunden die Hintergrundbeleuchtung an, dann kam nichts mehr; nach einem Reset ging die
Beleuchtung kurz aus und danach erschien Beleuchtung samt Bild. Daraus folgt der letzte
fehlende Schritt: Auch die Grundeinstellung der Bridge lief bisher nur einmal, und zwar
bevor die DSI-Strecke ueberhaupt existierte. Beim Reset half es nur deshalb, weil die
Bridge ihre Einstellung aus dem vorigen Durchlauf noch hatte und diesmal ein DSI-Signal
vorfand.
- Die Grundeinstellung der Bridge wird jetzt ein zweites Mal geschrieben, sobald die
Videoausgabe laeuft - dasselbe Vorgehen wie bei den Weckbefehlen des Panels in 1.6.19.
Damit wird ohne Reset erreicht, was vorher erst der zweite Durchlauf brachte.
- Im Start-Log sind beide Durchgaenge benannt ("Bridge-Grundeinstellung vor dem DSI-Start"
und "... nach dem Start der Videoausgabe").
Version 1.6.19:
- Die Wartezeit aus 1.6.18 hat den Start deutlich verbessert, aber noch nicht zuverlässig
gemacht. Aus dem verbliebenen Fehlerbild folgt der nächste Schritt: Die Beleuchtung ging
an, das Bild fehlte. Die Beleuchtung hängt an der Bridge und wird über I2C geschaltet -
sie funktioniert also. Verloren gehen die Weckbefehle an das Panel selbst.
- Diese Befehle wurden bisher genau einmal geschickt, bevor die Videoausgabe lief. War der
Panel-Controller in dem Moment noch nicht aufnahmebereit, waren sie weg, und danach hat
nie wieder jemand nachgefragt. Sie werden jetzt ein zweites Mal gesendet, sobald die
Videoausgabe steht. Die Befehle sind wiederholbar, der zweite Anlauf kostet nichts.
- Die Pause dazwischen steht als WS7_PANEL_SETTLE_MS in pins_config.h (Vorgabe 200 ms).
- Im Start-Log ist jeder Anlauf einzeln zu sehen ("Weckbefehle vor/nach dem Start der
Videoausgabe").
Version 1.6.18:
- Ursache des unzuverlässigen Starts gefunden: Der P4 sprach Bridge und Panel sofort nach
dem Einschalten an. Das Displaymodul braucht danach aber einen Moment, bis es bereit ist.
Kam der Hochlauf zu früh, nahm die Bridge ihre Register nicht an oder das Panel zeigte
trotz korrekt gesendeter DSI-Daten nichts - beides ohne Fehlermeldung, weil aus Sicht des
P4 jeder Schritt geklappt hatte. Das Ergebnis war ein Display, das mal ansprang und mal
nicht, und beim ersten Anstecken meist gar nicht.
- Der Hochlauf wartet jetzt WS7_PANEL_WARMUP_MS (Vorgabe 2000 ms), bevor er beginnt. Der
Werks-Testsketch wartet aus demselben Grund 2 Sekunden am Anfang.
- Damit erklärt sich auch, warum es mit geöffnetem seriellen Monitor fast immer klappte:
Dessen USB-Anmeldung verzögert den Start und ersetzte damit unbeabsichtigt die Wartezeit.
- Der Wert steht in pins_config.h. Läuft der Start zuverlässig, lässt er sich vorsichtig
senken; springt die Anzeige nicht an, ist er der erste Wert zum Erhöhen.
Version 1.6.17:
- Der I2C-Stoerimpulsfilter aus 1.6.16 wirkt: Nach dem Panel-Start melden sich wieder alle
drei Bausteine, Bridge und Touch bleiben ansprechbar.
- Das Pruefbild aus 1.6.15 war allerdings wirkungslos und damit als Test untauglich: Es
wurde zwar gesetzt, doch unmittelbar danach startete LVGL und schrieb in den Bildspeicher,
womit das Pruefbild wieder verschwand. Der Test sah deshalb genauso aus wie der Fehler,
den er finden sollte.
- Mit WS7_TEST_PATTERN = 1 endet der Hochlauf jetzt direkt nach dem Pruefbild: Beleuchtung
an, Farbbalken stehen, kein LVGL. Damit ist die Frage eindeutig zu beantworten, ob die
Anzeigekette bis zum Panel arbeitet.
Version 1.6.16:
- Ursache des schwarzen Bildes gefunden. Der Start-Log zeigte es eindeutig: Vor dem
Panel-Start meldeten sich alle drei I2C-Bausteine (Touch 0x14, Audio 0x18, Bridge 0x45),
danach nur noch der Audio-Baustein. Es fielen also genau die beiden weg, die am
Displaykabel haengen - der Bus selbst arbeitete weiter. Sobald die DSI-Ausgabe laeuft,
stoeren deren schnelle Signale auf das lange Flachbandkabel ein, und ohne Filterung
bringen diese Stoerspitzen die I2C-Uebertragung aus dem Tritt. Die Bridge liess sich
daraufhin nicht mehr ansprechen, das Panel blieb dunkel.
- Der I2C-Bus laeuft fuer das Waveshare-Panel jetzt mit Stoerimpulsfilter und internen
Abschlusswiderstaenden, so wie es auch das Waveshare-Beispiel tut. Beides fehlte, weil
die Bus-Einrichtung urspruenglich von den JC-Panels uebernommen wurde, die kein
Flachbandkabel dieser Laenge haben.
- Das erklaert rueckwirkend auch, warum sich der Fehler so sprunghaft verhielt: Ob eine
Uebertragung durchkam, hing von der Stoerlage ab.
Version 1.6.15:
- Diagnose fuer das schwarze Bild, das der Log bisher nicht erklaeren konnte: Alle Schritte
liefen fehlerfrei durch, trotzdem blieb die Anzeige leer.
- Die drei Weckbefehle an das Panel (MADCTL, Sleep Out, Display On) liefen bislang
ungeprueft durch und sind jetzt in die Fehlerausgabe einbezogen.
- Neuer Schalter WS7_TEST_PATTERN in pins_config.h: zeigt statt der Oberflaeche
Prueffarbbalken an. Sie entstehen im DSI-Baustein selbst und benutzen weder Bildspeicher
noch LVGL. Damit laesst sich in einem Durchgang trennen, ob die Anzeigekette bis zum
Panel arbeitet oder ob der Fehler weiter oben liegt.
- Das Ende des Hochlaufs wird gemeldet ("Bringup fertig" / "LVGL laeuft"). Bisher endete
die Ausgabe nach dem Panel-Start, und ein Haengenbleiben in LVGL war von einem
fehlenden Bild nicht zu unterscheiden.
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
Flackern, und der Gewinn ist der größte der drei Tempo-Maßnahmen - vor allem während
eines Bezugs, wo die Zeitanzeige zehnmal je Sekunde weiterläuft.
- Der Hintergrund der Seiten ist deckend statt durchsichtig. Sichtbar ändert sich nichts,
die Ebenen darunter haben dieselbe Farbe; LVGL muss sie beim Scrollen aber nicht mehr
mitzeichnen und durchmischen.
- Neuer Schalter WS7_PERF_MONITOR in pins_config.h: blendet unten rechts Bilder je Sekunde
und Prozessorlast ein. Damit lässt sich beantworten, ob weitere Mühe beim Zeichnen
überhaupt noch etwas bringt, statt ins Blaue zu optimieren.
Version 1.6.9:
- Fehlerbehebung: Ein Tipp auf einen Knopf löste oft mehrfach aus. Der GT9271 lässt
gelegentlich einen Messzyklus aus oder liefert ein unplausibles Paket; der
Hersteller-Treiber kann "gerade nichts Neues" nicht von "Finger weg" unterscheiden und
meldet beides als losgelassen. Seit die Oberfläche mit 1.6.8 doppelt so oft abtastet,
wurde daraus sichtbar Drücken-Loslassen-Drücken-Loslassen.
- Vor den Treiber ist deshalb ein Filter gesetzt: Er verwirft unplausible Rohwerte und hält
den letzten gültigen Berührpunkt noch WS7_TOUCH_HOLD_MS lang (Vorgabe 40 ms). Losgelassen
wird erst gemeldet, wenn wirklich nichts mehr kommt. Der Wert steht in pins_config.h;
0 schaltet die Überbrückung ab. Zu groß gewählt verzögert er das Loslassen und dämpft
den Schwung beim Wischen.
- Der Filter hängt sich zur Laufzeit in den Treiber ein, die Herstellerdateien bleiben
unverändert.
Version 1.6.8:
- Scrollen und Wischen laufen am Waveshare-Panel flüssiger: LVGL rechnet dort jetzt im
16-Millisekunden-Takt statt alle 33 ms. Dieser Wert steuert nicht nur die Bildrate,
sondern auch, wie oft der Touch abgetastet und wie fein eine Animation gerechnet wird -
mit 30 Schritten je Sekunde war vor allem das Ziehen mit dem Finger sichtbar ruckelig.
Das Panel läuft mit 60 Hz, mehr als 16 ms bringt also nichts.
- Kommt das Zeichnen einmal nicht hinterher, wird ein Bild später fertig; kaputt geht
dabei nichts. Die JC-Panels bleiben bei 33 ms.
Version 1.6.7:
- Der Menue-Knopf oben links fängt Tipps jetzt auch knapp daneben ab. Mit 48x36 Pixeln war
er auf dem 7-Zoll-Panel ein sehr kleines Ziel; gemessen wurde ein Fehlgriff von rund
10 Pixeln neben der Fläche, weshalb sich das Menü scheinbar nicht öffnen ließ. Optisch
bleibt der Knopf unverändert, die Trefferfläche wächst um 20 Pixel nach allen Seiten.
Sie wirkt nur innerhalb der Kopfleiste - dem Seiteninhalt darunter wird nichts genommen.
- Die Touch-Zuordnung selbst war korrekt: Eine Messung mit WS7_TOUCH_DEBUG hat gezeigt,
dass Achsen und Spiegelung stimmen.
Version 1.6.6:
- Neuer Schalter WS7_TOUCH_DEBUG in pins_config.h: Auf 1 gesetzt, gibt jeder Berührpunkt
seine Rohwerte und die daraus errechnete Bildposition auf der seriellen Konsole aus.
Gedacht zum Einmessen des Touch, wenn Bedienelemente nicht reagieren - insbesondere am
oberen Bildrand, wo die 44 Pixel hohe Kopfleiste sitzt.
Version 1.6.5:
- Zwei der drei Tempo-Maßnahmen aus 1.6.4 haben sich am Gerät als untauglich erwiesen und
stehen wieder auf ihrem alten Wert. Sie bleiben als Schalter erhalten, mit Notiz, woran
@@ -24,6 +24,7 @@
#include "protocol_client.h"
#include "ui.h"
#include "display_hal.h"
#include "pins_config.h"
#include <ArduinoJson.h>
#include <Update.h>
#include <Preferences.h>
@@ -296,6 +297,31 @@ void setup() {
g_client.onOta(onOta);
hal_init(&g_client); // LVGL + Panel/Touch + Dashboard (ruft ui_init intern auf)
// --- Waveshare-Panel: einmaliger Neustart nach dem Einschalten ---
//
// Das Panel kommt nach dem Anlegen der Versorgung im ersten Anlauf nicht zuverlaessig
// hoch: Die Beleuchtung geht an, ein Bild bleibt aus - obwohl jeder Schritt des
// Hochlaufs Erfolg meldet. Ein Reset behebt es zuverlaessig, und zwar nur ein echter
// Chip-Reset; die DSI-Strecke im laufenden Betrieb ab- und wieder aufzubauen genuegt
// nicht (siehe WS7_DSI_RESTART).
//
// Deshalb startet der P4 sich nach einem Kaltstart genau einmal selbst neu, nachdem
// der erste Hochlauf durch ist. Beim zweiten Durchlauf ist der Startgrund kein
// Kaltstart mehr, die Bedingung greift also nicht erneut - eine Schleife ist
// ausgeschlossen. Kostet rund drei Sekunden, aber nur beim Einschalten.
#if (JC_PANEL_TYPE == WS_PANEL_7H) && WS7_COLD_BOOT_RESTART
if (esp_reset_reason() == ESP_RST_POWERON) {
// Der Fruehstart-Zaehler wurde oben bereits erhoeht. Diesen gewollten Neustart
// darf er nicht mitzaehlen, sonst laeuft die Absturzsicherung nach ein paar
// Einschaltvorgaengen in den Update-Modus.
{ Preferences p; p.begin("bootguard", false); p.putUShort("early", 0); p.end(); }
DBG_SERIAL.println(F("[Panel] Kaltstart - einmaliger Neustart fuer das Displaypanel"));
DBG_SERIAL.flush();
delay(50);
esp_restart();
}
#endif
g_client.begin(); // UART starten, hello folgt automatisch in loop()
DBG_SERIAL.println(F("Bereit. Warte auf Verbindung zur Hauptplatine..."));
+1 -1
View File
@@ -50,7 +50,7 @@ Vendor-Pakete: 4,3" im Ordner `JC4880P443C_I_W/`, 7,0" im Repo-Ordner
| Touch-Rohkoordinaten | 480×800 (= Panelraster) | **800×480** → wird auf 1024×600 skaliert | **720×1280** (Hochformat) → X/Y werden getauscht |
| LCD-Reset | GPIO5 | **GPIO27** | kein Reset-Pin (macht die Bridge) |
| Backlight | GPIO23 (LEDC-PWM) | GPIO23 (LEDC-PWM) | **Bridge-Register** auf I²C **0x45** (`AD`/`AB`/`AA`) |
| Framebuffer | 3 × 750 KB ≈ 2,3 MB PSRAM | 3 × 1,2 MB ≈ 3,6 MB PSRAM | 3 × 2,8 MB ≈ 8,3 MB PSRAM |
| Framebuffer | 3 × 750 KB ≈ 2,3 MB PSRAM | 3 × 1,2 MB ≈ 3,6 MB PSRAM | **1 × 2,8 MB** — mehr verträgt das Panel beim Start nicht |
| Freie Expansion-IO | Stiftleiste **JP1**: GPIO 52/51/50/49/35/34/33/32/31/30/29/28 | FPC 1,0 mm 16-pol. **FPC4**: GPIO 34/33/32/31/30/29/28 · **FPC3**: 48/47/46/45/5/4/3/2 | 40-poliger Header im Raspberry-Pi-Pico-Format; belegt sind I²C (7/8), TF-Karte (9/10/11/12/13/53) und Debug-UART0 (37/38) |
| UART zur Hauptplatine | TX GPIO33 / RX GPIO31 | TX GPIO33 / RX GPIO31 | **TX GPIO20 / RX GPIO21** |
+351 -51
View File
@@ -29,6 +29,8 @@
#include "esp_cache.h"
#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"
@@ -69,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) \
@@ -106,11 +184,33 @@ 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
// DSI-Bringup laufen; die Hintergrundbeleuchtung bleibt dabei noch aus.
// Grundeinstellung der Bridge. Bewusst mehrfach aufrufbar, siehe unten.
//
// Warum zweimal: Beim ersten Aufruf existiert die DSI-Strecke noch gar nicht - die Bridge
// bekommt ihre Einstellung also, bevor ein Signal anliegt. Beim ersten Einschalten reichte
// das nicht: Die Beleuchtung ging an (die haengt an der Bridge), ein Bild kam aber nicht.
// Erst ein Reset half - und dann nur deshalb, weil die Bridge ihre Einstellung aus dem
// vorigen Durchlauf noch hatte und diesmal ein DSI-Signal vorfand. Genau das holt der
// zweite Aufruf nach, ohne dass ein Reset noetig ist. Die Register sind wiederholbar.
static void ws7_bridge_core_init(const char *wann)
{
esp_rom_printf("[Panel] Bridge-Grundeinstellung %s\n", wann);
ws7_bridge_write(0xC0, 0x01);
ws7_bridge_write(0xC2, 0x01);
ws7_bridge_write(0xAC, 0x01);
}
// Bridge am I2C-Bus anmelden und erstmalig einstellen. Laeuft VOR dem DSI-Bringup;
// die Hintergrundbeleuchtung bleibt dabei noch aus.
static void ws7_bridge_pre_init(void)
{
i2c_device_config_t dev_cfg = {
@@ -122,9 +222,7 @@ static void ws7_bridge_pre_init(void)
s_bridge_handle = NULL;
return;
}
ws7_bridge_write(0xC0, 0x01);
ws7_bridge_write(0xC2, 0x01);
ws7_bridge_write(0xAC, 0x01);
ws7_bridge_core_init("vor dem DSI-Start");
}
void jc_backlight_init(void)
@@ -184,6 +282,63 @@ IRAM_ATTR static bool on_vsync(esp_lcd_panel_handle_t panel,
}
#if JC_PANEL_TYPE == WS_PANEL_7H
// ------------------------------------------------------------------------------------
// Aussetzer des GT9271 ueberbruecken
//
// Der Controller laesst gelegentlich einen Messzyklus aus und liefert ab und zu ein
// unplausibles Paket - die Werks-Testskizze hat solche Pakete ebenfalls verworfen. Der
// Hersteller-Treiber kann "gerade nichts Neues" nicht von "Finger weg" unterscheiden und
// meldet beides als losgelassen. Seit die Oberflaeche doppelt so oft abtastet, faellt das
// auf: Aus einem Tipp wird Druecken-Loslassen-Druecken-Loslassen, der Knopf loest also
// mehrfach aus.
//
// Deshalb liegt hier ein eigener get_xy-Aufsatz vor dem Treiber: Er verwirft unplausible
// Rohwerte und haelt den letzten gueltigen Punkt kurz fest. Losgelassen wird erst
// gemeldet, wenn WS7_TOUCH_HOLD_MS lang wirklich nichts mehr kam.
// ------------------------------------------------------------------------------------
static bool (*s_touch_get_xy_orig)(esp_lcd_touch_handle_t, uint16_t *, uint16_t *,
uint16_t *, uint8_t *, uint8_t) = NULL;
static uint16_t s_touch_last_x = 0;
static uint16_t s_touch_last_y = 0;
static int64_t s_touch_last_us = 0;
static bool s_touch_down = false;
static bool ws7_touch_get_xy(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y,
uint16_t *strength, uint8_t *point_num, uint8_t max_point_num)
{
bool got = s_touch_get_xy_orig(tp, x, y, strength, point_num, max_point_num);
int64_t now = esp_timer_get_time();
// Unplausible Rohwerte gelten als Aussetzer, nicht als Beruehrung.
if (got && *point_num > 0 &&
(x[0] > WS7_TOUCH_RAW_X_MAX || y[0] > WS7_TOUCH_RAW_Y_MAX)) {
got = false;
*point_num = 0;
}
if (got && *point_num > 0) {
s_touch_last_x = x[0];
s_touch_last_y = y[0];
s_touch_last_us = now;
s_touch_down = true;
return true;
}
#if WS7_TOUCH_HOLD_MS > 0
if (s_touch_down && (now - s_touch_last_us) < ((int64_t)WS7_TOUCH_HOLD_MS * 1000)) {
x[0] = s_touch_last_x;
y[0] = s_touch_last_y;
if (strength) strength[0] = 0;
*point_num = 1;
return true;
}
#endif
s_touch_down = false;
return false;
}
// Der GT9271 des Waveshare-Panels meldet im Hochformat (Roh-X 0..720, Roh-Y 0..1280),
// das Bild laeuft aber im Querformat 1280x720. Achsentausch (und bei Bedarf Spiegelung)
// deshalb ueber den process_coordinates-Hook, der VOR den swap/mirror-Flags von
@@ -211,6 +366,10 @@ static void ws7_touch_map(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y,
// Bild wird um 180 Grad gedreht ausgegeben -> Touch muss mitdrehen.
px = (uint16_t)(LCD_H_RES - 1 - px);
py = (uint16_t)(LCD_V_RES - 1 - py);
#endif
#if WS7_TOUCH_DEBUG
esp_rom_printf("[Touch] roh X=%u Y=%u -> Bild X=%u Y=%u\n",
(unsigned)x[i], (unsigned)y[i], (unsigned)px, (unsigned)py);
#endif
x[i] = px;
y[i] = py;
@@ -238,45 +397,43 @@ static void jc_touch_scale(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y,
}
#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.
bool jc_board_bringup(void)
{
jc_backlight_init();
i2c_master_bus_config_t i2c_bus_conf = {
.clk_source = I2C_CLK_SRC_DEFAULT,
.sda_io_num = BSP_I2C_SDA,
.scl_io_num = BSP_I2C_SCL,
.i2c_port = BSP_I2C_NUM,
};
i2c_new_master_bus(&i2c_bus_conf, &s_i2c_handle);
#if JC_PANEL_TYPE == WS_PANEL_7H
// Bridge des Waveshare-Panels vorbereiten (noch ohne Hintergrundbeleuchtung).
ws7_bridge_pre_init();
// Panel wecken. Bewusst mehrfach, siehe unten.
//
// Ein reines DPI-Panel kennt keine reset-Funktion, esp_lcd_panel_reset() wuerde ins Leere
// greifen - deshalb nur die DCS-Befehle.
//
// Warum mehrfach: Verpasst der Panel-Controller diese Befehle, weil er nach dem
// Einschalten noch nicht bereit war, bleibt der Bildschirm dunkel, obwohl der P4 alles
// korrekt gesendet hat und jeder Schritt Erfolg meldet. Die Hintergrundbeleuchtung geht
// trotzdem an, weil sie an der Bridge haengt und nicht am Panel - genau dieses Bild.
// Die Befehle sind wiederholbar, ein zweiter Anlauf nach dem Start der Videoausgabe
// kostet nichts und faengt den Fall ab.
static void ws7_panel_wake(esp_lcd_panel_io_handle_t io, const char *wann)
{
uint8_t zero = 0x00;
uint8_t madctl = WS7_MADCTL;
esp_rom_printf("[Panel] Weckbefehle %s\n", wann);
BSP_STEP(esp_lcd_panel_io_tx_param(io, 0x36, &madctl, 1), "Panel-Befehl MADCTL");
BSP_STEP(esp_lcd_panel_io_tx_param(io, 0x11, &zero, 1), "Panel-Befehl Sleep Out");
vTaskDelay(pdMS_TO_TICKS(120));
BSP_STEP(esp_lcd_panel_io_tx_param(io, 0x29, &zero, 1), "Panel-Befehl Display On");
vTaskDelay(pdMS_TO_TICKS(20));
}
#endif
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);
esp_lcd_dsi_bus_handle_t mipi_dsi_bus;
#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;
#if JC_PANEL_TYPE == WS_PANEL_7H
// ---------------- Waveshare 7inch DSI LCD (H) (1280x720) ----------------
// Kein Hersteller-Panel-Treiber: DSI-Bus, DBI-Kommandokanal und DPI-Panel werden
// direkt angelegt. Entscheidend ist die Referenztaktquelle PLL_F20M - mit der
// Standardquelle bleibt das Bild auf ESP32-P4 Rev. 1.3 / ECO2 schwarz.
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,
@@ -301,6 +458,8 @@ bool jc_board_bringup(void)
#else
.pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565,
#endif
// Anzahl der Bildspeicher. Beim Waveshare-Panel genau einer: mit zweien kam nach
// dem Einschalten kein Bild (siehe WS7_SINGLE_FB in pins_config.h).
.num_fbs = LVGL_PORT_LCD_BUFFER_NUMS,
.video_timing = {
.h_size = BSP_LCD_H_RES,
@@ -325,19 +484,142 @@ bool jc_board_bringup(void)
return false;
}
// Panel wecken (MADCTL / Sleep Out / Display On). Ein Reset gibt es hier nicht:
// ein reines DPI-Panel kennt keine reset-Funktion, esp_lcd_panel_reset() wuerde
// ins Leere greifen.
{
uint8_t zero = 0x00;
uint8_t madctl = WS7_MADCTL;
esp_lcd_panel_io_tx_param(io, 0x36, &madctl, 1); // MADCTL
esp_lcd_panel_io_tx_param(io, 0x11, &zero, 1); // Sleep Out
vTaskDelay(pdMS_TO_TICKS(120));
esp_lcd_panel_io_tx_param(io, 0x29, &zero, 1); // Display On
vTaskDelay(pdMS_TO_TICKS(20));
}
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.
bool jc_board_bringup(void)
{
#if JC_PANEL_TYPE == WS_PANEL_7H
// Anlaufzeit abwarten, BEVOR Bridge und Panel angesprochen werden.
//
// Das Displaymodul braucht nach dem Anlegen der Versorgung einen Moment, bis Bridge
// und Panel bereit sind. Faengt der P4 sofort an, laeuft der Hochlauf ins Leere: 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 alles geklappt
// hat. Das Ergebnis war ein Display, das mal ansprang und mal nicht.
//
// Der Werks-Testsketch wartet aus demselben Grund 2 Sekunden am Anfang von setup().
// Dass es mit geoeffnetem seriellen Monitor fast immer klappte, hatte dieselbe
// Ursache: Dessen USB-Anmeldung verzoegert den Start und ersetzte damit die Wartezeit.
vTaskDelay(pdMS_TO_TICKS(WS7_PANEL_WARMUP_MS));
#endif
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,
.scl_io_num = BSP_I2C_SCL,
.i2c_port = BSP_I2C_NUM,
#if JC_PANEL_TYPE == WS_PANEL_7H
// Stoerimpulsfilter und interne Abschlusswiderstaende - beides setzt auch das
// Waveshare-Beispiel. Ohne den Filter brechen Bridge und Touch weg, sobald die
// DSI-Ausgabe laeuft: Deren schnelle Signale stoeren auf das lange Flachbandkabel
// ein, und ungefilterte Stoerspitzen bringen die I2C-Uebertragung aus dem Tritt.
// Der Audio-Baustein auf der Platine bleibt dabei erreichbar, weil er nicht am
// Displaykabel haengt - genau dieses Muster war im Start-Log zu sehen.
.glitch_ignore_cnt = 7,
.flags.enable_internal_pullup = true,
#endif
};
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,
};
BSP_STEP(esp_ldo_acquire_channel(&ldo_cfg, &phy_pwr_chan), "Stromversorgung MIPI-D-PHY");
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) ----------------
// Kein Hersteller-Panel-Treiber: DSI-Bus, DBI-Kommandokanal und DPI-Panel werden
// direkt angelegt. Entscheidend ist die Referenztaktquelle PLL_F20M - mit der
// Standardquelle bleibt das Bild auf ESP32-P4 Rev. 1.3 / ECO2 schwarz.
bsp_report_psram((size_t)BSP_LCD_H_RES * BSP_LCD_V_RES * BSP_LCD_FB_BYTES_PER_PX
* LVGL_PORT_LCD_BUFFER_NUMS);
if (!ws7_dsi_bringup(&mipi_dsi_bus, &io, &disp_panel, &dpi_config)) {
return false;
}
#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));
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
// der Fehler liegt weiter oben. Bleibt es schwarz, liegt es an DSI, Zeitbasis oder
// Panel.
//
// Der Hochlauf endet hier bewusst: Wuerde LVGL danach starten, schriebe es sofort in
// den Bildspeicher und das Pruefbild waere wieder weg - der Test saehe dann genauso
// aus wie der Fehler, den er finden soll.
jc_backlight_set(100); // Beleuchtung an, sonst ist nichts zu sehen
BSP_STEP(esp_lcd_dpi_panel_set_pattern(disp_panel, MIPI_DSI_PATTERN_BAR_VERTICAL),
"Prueffarbbalken");
esp_rom_printf("[Panel] Pruefbild steht - erwartet werden senkrechte Farbbalken.\n");
esp_rom_printf("[Panel] Hochlauf endet hier (WS7_TEST_PATTERN = 1, keine Oberflaeche).\n");
return false; // ohne LVGL: Anzeige bleibt beim Pruefbild
#endif
#elif JC_PANEL_TYPE == JC_PANEL_70
// ---------------- 7,0" JD9165 (1024x600) ----------------
esp_lcd_dsi_bus_config_t bus_config = JD9165_PANEL_BUS_DSI_2CH_CONFIG();
@@ -427,6 +709,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.
@@ -463,11 +755,19 @@ bool jc_board_bringup(void)
esp_rom_printf("[Panel] Touch-Controller nicht gefunden - Anzeige laeuft ohne Bedienung.\n");
tp_handle = NULL;
}
#if JC_PANEL_TYPE == WS_PANEL_7H
if (tp_handle) { // Aussetzer-Filter vor den Treiber haengen
s_touch_get_xy_orig = tp_handle->get_xy;
tp_handle->get_xy = ws7_touch_get_xy;
}
#endif
lvgl_port_interface_t interface =
(dpi_config.flags.use_dma2d) ? LVGL_PORT_INTERFACE_MIPI_DSI_DMA
: LVGL_PORT_INTERFACE_MIPI_DSI_NO_DMA;
esp_rom_printf("[Panel] Bringup fertig - LVGL wird gestartet\n");
lvgl_port_init(disp_panel, tp_handle, interface);
esp_rom_printf("[Panel] LVGL laeuft\n");
return true;
}
+1 -1
View File
@@ -126,7 +126,7 @@
// -------------------------------------------------------------------------------------
// Firmware
// -------------------------------------------------------------------------------------
#define DISPLAY_FW_VERSION "1.6.5" // Firmware-Stand der P4-Display-Steuerung (Info-Seite)
#define DISPLAY_FW_VERSION "1.6.10" // Firmware-Stand der P4-Display-Steuerung (Info-Seite)
// -------------------------------------------------------------------------------------
// Protokoll
+20 -1
View File
@@ -91,7 +91,17 @@
*====================*/
/*Default display refresh, input device read and animation step period.*/
/* Der Wert bestimmt nicht nur die Bildrate, sondern auch, wie oft der Touch abgetastet
* und wie fein eine Animation gerechnet wird. 33 ms sind 30 Schritte je Sekunde - beim
* Ziehen mit dem Finger deutlich als Stocken zu sehen. Das Waveshare-Panel laeuft mit
* 60 Hz, deshalb dort 16 ms; mehr als das Panel zeigen kann, bringt nichts. Kommt das
* Zeichnen nicht hinterher, wird es einfach seltener fertig - kaputt geht dabei nichts.
* Die JC-Panels bleiben bei 33 ms, damit sich ihr Verhalten nicht aendert. */
#if JC_PANEL_TYPE == WS_PANEL_7H
#define LV_DEF_REFR_PERIOD 16 /*[ms]*/
#else
#define LV_DEF_REFR_PERIOD 33 /*[ms]*/
#endif
/*Default Dot Per Inch. Used to initialize default sizes such as widgets sized, style paddings.
*(Not so important, you can adjust it to modify default sizes and spaces)*/
@@ -557,6 +567,10 @@
LV_FONT_DECLARE(lv_font_maven_pro_28) \
LV_FONT_DECLARE(lv_font_maven_pro_40) \
LV_FONT_DECLARE(lv_font_maven_pro_48) \
LV_FONT_DECLARE(lv_font_maven_pro_bold_96) \
LV_FONT_DECLARE(lv_font_maven_pro_bold_140) \
LV_FONT_DECLARE(lv_font_clock_120) \
LV_FONT_DECLARE(lv_font_clock_180) \
LV_FONT_DECLARE(lv_font_clock_240)
/*Always set a default font*/
@@ -905,14 +919,19 @@
#define LV_USE_SNAPSHOT 0
/*1: Enable system monitor component*/
/* Nur fuer die Messeinblendung des Waveshare-Panels, siehe WS7_PERF_MONITOR. */
#if (JC_PANEL_TYPE == WS_PANEL_7H) && WS7_PERF_MONITOR
#define LV_USE_SYSMON 1
#else
#define LV_USE_SYSMON 0
#endif
#if LV_USE_SYSMON
/*Get the idle percentage. E.g. uint32_t my_get_idle(void);*/
#define LV_SYSMON_GET_IDLE lv_timer_get_idle
/*1: Show CPU usage and FPS count
* Requires `LV_USE_SYSMON = 1`*/
#define LV_USE_PERF_MONITOR 0
#define LV_USE_PERF_MONITOR 1
#if LV_USE_PERF_MONITOR
#define LV_USE_PERF_MONITOR_POS LV_ALIGN_BOTTOM_RIGHT
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+27 -1
View File
@@ -496,6 +496,32 @@ static lv_display_t *display_init(esp_lcd_panel_handle_t panel_handle)
// buf1 = heap_caps_malloc(buffer_size * sizeof(lv_color_t), MALLOC_CAP_DMA);
assert(buf1);
ESP_LOGI(TAG, "LVGL buffer size: %dKB", buffer_size * sizeof(lv_color_t) / 1024);
#if WS7_DIRECT_FB
// PROJEKTAENDERUNG: LVGL zeichnet direkt in den Bildspeicher.
//
// Der Hersteller-Port legt einen eigenen Zeichenpuffer an; der fertige Inhalt wird
// danach in den Bildspeicher kopiert. Bei 1280x720 in 24 Bit sind das zwei Durchgaenge
// durch je 2,7 MB PSRAM - gemessen rund 250 bis 300 ms pro Bild, und das dauerhaft.
// Genau deshalb hing die Oberflaeche eine gute Viertelsekunde hinterher, und Vorgaenge
// mit mehreren Bildern brauchten Sekunden.
//
// Ist der Zeichenpuffer derselbe Speicher wie der Bildspeicher, laesst der
// esp_lcd-Treiber das Kopieren weg und schreibt nur den Prozessor-Cache zurueck. Dazu
// kommt LV_DISPLAY_RENDER_MODE_DIRECT: LVGL zeichnet dann nur die geaenderten Bereiche
// neu, statt jedes Mal die ganze Flaeche.
//
// Preis: Gezeichnet wird in den Speicher, der gerade angezeigt wird - bei schnellen
// Wechseln kann kurz eine Kante durchs Bild laufen. Mit nur einem Bildspeicher (den das
// Panel verlangt, siehe WS7_SINGLE_FB) ist das ohnehin nicht zu vermeiden.
void* fb0 = NULL;
if (esp_lcd_dpi_panel_get_frame_buffer(panel_handle, 1, &fb0) == ESP_OK && fb0) {
buf1 = fb0;
buffer_size = LVGL_PORT_H_RES * LVGL_PORT_V_RES;
ESP_LOGI(TAG, "LVGL zeichnet direkt in den Bildspeicher (%dKB)",
(int)(buffer_size * sizeof(lv_color_t) / 1024));
}
#endif
#endif /* LVGL_PORT_AVOID_TEAR_ENABLE */
ESP_LOGD(TAG, "Register display driver to LVGL");
@@ -511,7 +537,7 @@ static lv_display_t *display_init(esp_lcd_panel_handle_t panel_handle)
display, buf1, buf2, buffer_size * sizeof(lv_color_t),
#if LVGL_PORT_FULL_REFRESH
LV_DISPLAY_RENDER_MODE_FULL
#elif LVGL_PORT_DIRECT_MODE
#elif LVGL_PORT_DIRECT_MODE || WS7_DIRECT_FB
LV_DISPLAY_RENDER_MODE_DIRECT
#else
LV_DISPLAY_RENDER_MODE_PARTIAL
+96 -9
View File
@@ -20,20 +20,31 @@
// an - mit 16 kommt kein brauchbares Bild. Einstellbar bleibt es
// nur, weil andere Waveshare-Panels an derselben Firmware
// haengen koennten.
// WS7_PARTIAL_REFRESH 0 = Vollbild neu zeichnen. GEPRUEFT: Mit 1 (nur geaenderte
// Bereiche, zwei wechselnde Bildpuffer) laesst sich der
// Menue-Vorhang nicht mehr oeffnen. Er ist halbtransparent und
// wird in den gerade aktiven Puffer eingemischt; die naechste
// Zustandsmeldung der S3 zeichnet in den anderen, der ihn nie
// bekommen hat. Am 4,3-Zoll-Panel hatte derselbe Modus
// geflackert. Nutzbar erst, wenn der LVGL-Port die geaenderten
// Bereiche zwischen beiden Puffern abgleicht.
// WS7_PARTIAL_REFRESH 1 = nur geaenderte Bildbereiche neu zeichnen statt jedes Mal des
// gesamten Bildes (LVGL-Direct-Mode, zwei wechselnde Puffer).
// Groesster Tempogewinn, besonders waehrend eines Bezugs: Die
// Zeitanzeige laeuft zehnmal je Sekunde weiter, und mit 0 wuerde
// dafuer jedes Mal das ganze Bild neu gezeichnet. Am Geraet
// geprueft, kein Flackern - am 4,3-Zoll-Panel hatte derselbe
// Modus dagegen geflackert.
// WS7_PARALLEL_RENDER 1 = LVGL zeichnet mit zwei Threads auf beiden Prozessorkernen.
// Kostet zwei zusaetzliche Task-Stacks im knappen internen RAM;
// startet der P4 nicht mehr, hier zuerst auf 0 stellen.
// -------------------------------------------------------------------------------------
#define WS7_COLOR_BITS 24
#define WS7_PARTIAL_REFRESH 0
// Ohne Wirkung, solange WS7_SINGLE_FB = 1 ist: Mit nur einem Bildspeicher gibt es keine
// Doppelpufferung, zwischen deren Betriebsarten man waehlen koennte.
#define WS7_PARTIAL_REFRESH 1
// Nur EIN Bildspeicher. Zwei vertraegt die DSI-Ausgabe dieses Panels beim Einschalten
// nicht - siehe die ausfuehrliche Begruendung weiter unten beim Avoid-Tear-Schalter.
// Auf 0 nur, wenn das Startverhalten erneut untersucht wird.
#define WS7_SINGLE_FB 1
// LVGL zeichnet direkt in den Bildspeicher statt in einen eigenen Puffer, dessen Inhalt
// danach kopiert wird. GEPRUEFT: bringt an diesem Panel nichts (die Bildaufbauzeit blieb bei
// 240-300 ms) und erzeugt Bildfehler, weil in denselben Speicher gezeichnet wird, aus dem
// gerade angezeigt wird. Der Flaschenhals liegt also nicht im Kopieren, sondern im Zeichnen
// selbst. Bleibt als Schalter erhalten, damit der Versuch nicht erneut gemacht wird.
#define WS7_DIRECT_FB 0
#define WS7_PARALLEL_RENDER 1
#define EXAMPLE_LVGL_PORT_TASK_MAX_DELAY_MS 500 //range 2 to 2000
@@ -43,7 +54,32 @@
#define EXAMPLE_LVGL_PORT_TASK_CORE -1 //range -1 to 1
#define EXAMPLE_LVGL_PORT_TICK 2 //ragne 1 to 100
// Ruckelfreie Ausgabe braucht mindestens zwei Bildspeicher, aus denen abwechselnd
// angezeigt und in die gezeichnet wird.
//
// Das Waveshare-Panel vertraegt das nicht: Mit zwei Bildspeichern kam nach dem Einschalten
// kein Bild - der Hochlauf meldete durchgehend Erfolg, das Panel blieb dunkel, und erst ein
// Reset half. Mit genau einem Bildspeicher startet es zuverlaessig; belegt wurde das mit den
// Prueffarbbalken, die der Werks-Testsketch ebenfalls mit einem Speicher anzeigt.
// Deshalb hier ohne Doppelpufferung: LVGL zeichnet in einen kleinen Zwischenpuffer, der
// dann in den einen Bildspeicher uebertragen wird. Bei schnellen Bildwechseln kann dabei
// kurz eine Kante sichtbar werden - ein zuverlaessig startendes Display wiegt das auf.
#if (JC_PANEL_TYPE == WS_PANEL_7H) && WS7_SINGLE_FB
#define EXAMPLE_LVGL_PORT_AVOID_TEAR_ENABLE 0
// Zwischenpuffer fuer das Zeichnen. Volle Bildhoehe, damit ein Bildlauf in EINEM Durchgang
// gezeichnet und uebertragen wird. Mit 120 Zeilen waren es sechs Durchgaenge samt sechs
// Uebertragungen - das war der Grund fuer den zaehen Bildlauf. Kostet 2,8 MB PSRAM.
//
// Bewusst nur EIN Zeichenpuffer: Ein zweiter wuerde LVGL erlauben, schon den naechsten
// Bereich zu zeichnen, waehrend der vorige uebertragen wird. Der Panel-Treiber lehnt eine
// Uebertragung aber ab, solange die vorige laeuft (ESP_ERR_INVALID_STATE) - der betroffene
// Bildbereich wird dann gar nicht geschrieben und behaelt seinen alten Inhalt. Sichtbar
// war das als blaue Zwischenbilder beim Bildlauf.
#define CONFIG_EXAMPLE_LVGL_PORT_BUF_PSRAM 1
#define CONFIG_EXAMPLE_LVGL_PORT_BUF_HEIGHT LCD_V_RES
#else
#define EXAMPLE_LVGL_PORT_AVOID_TEAR_ENABLE 1
#endif
#ifdef EXAMPLE_LVGL_PORT_AVOID_TEAR_ENABLE
// 2 = Triple-Buffer + LVGL Full-Refresh: zeichnet bei jeder Aenderung das komplette
@@ -127,6 +163,57 @@
#define WS7_TOUCH_MIRROR_RAW_X 1
#define WS7_TOUCH_MIRROR_RAW_Y 0
// Zeigt unten rechts Bilder je Sekunde und Prozessorlast ein. Nur zum Messen gedacht:
// Der Wert sagt, ob sich weitere Muehe beim Zeichnen ueberhaupt lohnt.
#define WS7_PERF_MONITOR 0
// Zum Einmessen des Touch: 1 gibt jeden Beruehrpunkt roh und umgerechnet auf der
// seriellen Konsole aus. Danach wieder auf 0, sonst laeuft das Log dauernd mit.
#define WS7_TOUCH_DEBUG 0
// So lange gilt eine Beruehrung nach dem letzten gueltigen Messwert noch als anliegend.
// Ueberbrueckt Aussetzer des GT9271, die sonst als Loslassen durchgehen und einen Tipp in
// mehrere Klicks zerlegen. 0 schaltet die Ueberbrueckung ab. Nicht zu gross waehlen: Der
// 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
// Prueffarbbalken statt Oberflaeche anzeigen. Sie entstehen im DSI-Baustein selbst und
// benutzen weder Bildspeicher noch LVGL. Damit laesst sich trennen, ob die Anzeigekette
// bis zum Panel arbeitet (Balken sichtbar) oder nicht (schwarz). Nur zur Fehlersuche.
// Anlaufzeit des Displaymoduls, bevor Bridge und Panel angesprochen werden. Ohne diese
// Pause startet die Anzeige nur zufaellig - der Werks-Testsketch wartet aus demselben
// Grund 2 Sekunden. Springt das Display beim Einschalten nicht zuverlaessig an, ist das
// der erste Wert zum Erhoehen; laeuft es sicher, kann er vorsichtig gesenkt werden.
#define WS7_PANEL_WARMUP_MS 2000
// Pause zwischen dem Start der Videoausgabe und dem zweiten Anlauf der Weckbefehle.
// Verpasst das Panel den ersten Anlauf, bleibt der Bildschirm dunkel, waehrend die
// Beleuchtung brennt - sie haengt an der Bridge, nicht am Panel.
#define WS7_PANEL_SETTLE_MS 200
// Die DSI-Strecke beim Hochlauf einmal ab- und wieder aufbauen. Beim ersten Einschalten
// kam sonst trotz fehlerfreiem Ablauf kein Bild; erst ein Reset half. Der einzige
// Unterschied dabei: Die DSI-Verbindung geht einmal weg und neu auf, waehrend Bridge und
// Panel schon versorgt und eingestellt sind. Genau das holt der zweite Aufbau nach.
// Kostet WS7_DSI_RESTART_MS zusaetzliche Startzeit.
#define WS7_DSI_RESTART 0
#define WS7_DSI_RESTART_MS 200
// Nach einem Kaltstart einmal selbst neu starten, sobald der erste Hochlauf durch ist.
// Das Panel kommt beim ersten Anlauf nach dem Einschalten nicht zuverlaessig hoch;
// ein echter Chip-Reset behebt es zuverlaessig, der Ab- und Wiederaufbau der
// DSI-Strecke im Betrieb dagegen nicht. Kostet rund drei Sekunden beim Einschalten.
// Eine Schleife ist ausgeschlossen: Beim zweiten Durchlauf ist der Startgrund kein
// Kaltstart mehr.
#define WS7_COLD_BOOT_RESTART 1
#define WS7_TEST_PATTERN 0
#elif JC_PANEL_TYPE == JC_PANEL_70
#define LCD_H_RES 1024
+944 -400
View File
File diff suppressed because it is too large Load Diff