From 6a3d4efa82688b44ab19ee9e1eb3af78c3ddeb1b Mon Sep 17 00:00:00 2001
From: Michak <121102425+KreutzM@users.noreply.github.com>
Date: Thu, 12 Nov 2026 12:58:25 +0100
Subject: [PATCH 1/5] feat(dot): explain OC2REF, low-polarity PE11 and
low-active DOT in expandable path (#5)
---
README.md | 12 ++
src/demos/timer-pwm/TimerPwmDemo.tsx | 11 +-
.../timer-pwm/components/DotSignalPath.tsx | 126 ++++++++++++++++++
src/styles.css | 64 +++++++++
4 files changed, 211 insertions(+), 2 deletions(-)
create mode 100644 src/demos/timer-pwm/components/DotSignalPath.tsx
diff --git a/README.md b/README.md
index 9bf9f4c..b159e2a 100644
--- a/README.md
+++ b/README.md
@@ -101,3 +101,15 @@ Der geführte Modus ist ein didaktisches Angebot, keine Speicherung oder Benotun
Im **freien Labor** erscheinen Registersteuerung, CNT-Zähler, Zeitdiagramm und Kennwerte zuerst. Danach folgen die vollständigen Vertiefungen für **RCC-Taktbaum** und **Prescaler**; ihre Rechen- und Eingabefunktionen bleiben unverändert. Die Sprungnavigation bedient die Bereiche ohne Routenwechsel (die Anwendung nutzt Hash-Routing) und bewegt den Tastaturfokus zum gewählten Abschnitt. Aus den Vertiefungen gibt es einen direkten Rückweg zu den Registern.
Register-Eingaben referenzieren ihre Erklärtexte über `aria-describedby`; mobile Layouts, Textgrößen und Tasten sind auf **320 bis 1280 px** ausgerichtet. E2E prüft die Navigation, die unabhängige ARR/CCR2-Bearbeitung und die horizontale Breite in beiden Modi. Diese Änderungen betreffen Layout/Bedienbarkeit, **nicht** die Timer-Berechnungen.
+
+## Virtuelles DOT an PE11: Signalweg (Issue #5)
+
+Der Abschnitt „Virtuelles DOT · PE11“ besitzt ein **standardmäßig geschlossenes, per Tastatur zugängliches Ausklappfeld** mit einem dynamischen **Signalweg und einer Zustandstabelle**. Er trennt das **interne OC2REF-Signal**, die Ausgangspolarität `TIM_OCPOLARITY_LOW`, den **elektrischen PE11-Pegel** und die **low-aktive DOT-Anzeige**.
+
+- PWM Mode 1: `OC2REF = 1` für `CNT < CCR2` (gemeinsamer Berechnungspfad `pwmActive`).
+- Bei `TIM1_CH2` mit `OCPolarity LOW` entspricht OC2REF=1 einem **LOW-Pegel an PE11**; eine low-aktive DOT-Leitung lässt das gewählte Segment dann leuchten.
+- Die physikalische Darstellung gilt nur bei **TIM1** und unter Annahme aktivierter Ausgangsfreigaben **CC2E/MOE**, AF1-Konfiguration sowie einer aktivierten Anzeigenstelle über **CNTL1…CNTL4**. Diese Voraussetzungen sind in der Website nicht dynamisch modelliert. **TIM2_CH2 ist nicht mit DOT/PE11 verbunden.**
+- Das Blockschaltbild ist eine **didaktische Funktionsdarstellung, kein elektrischer Stromlaufplan** und behauptet keine zusätzlichen physischen Inverter. Der tatsächliche Treiber-/Multiplex-Strompfad des 8-Segment-Adapterboards ist nicht rekonstruiert.
+- Materialgrundlage: Praktikumsanleitung, Kapitel 7.1.1 (low-aktive Segmente und CNTL-Leitungen) sowie Kapitel 7.6.3 (TIM1_CH2/PE11, AF1, DOT); das Open429Z-D-Basisschaltbild dokumentiert PE11, aber nicht die vollständige Adapterboard-Beschaltung.
+
+Das vorhandene OC2REF-Zeitdiagramm und die Simulations-Engine bleiben unverändert; die Tabelle bietet die alternative synchrone Darstellung der drei Pegel-/LED-Ebenen und reagiert auf CNT, CCR2 und Timerwechsel.
diff --git a/src/demos/timer-pwm/TimerPwmDemo.tsx b/src/demos/timer-pwm/TimerPwmDemo.tsx
index a933496..7b7f623 100644
--- a/src/demos/timer-pwm/TimerPwmDemo.tsx
+++ b/src/demos/timer-pwm/TimerPwmDemo.tsx
@@ -3,6 +3,7 @@ import Waveform from "./components/Waveform";
import ClockTree from "./components/ClockTree";
import PrescalerPipeline from "./components/PrescalerPipeline";
import GuidedTimerLesson from "./components/GuidedTimerLesson";
+import DotSignalPath from "./components/DotSignalPath";
import {
advanceTimerClocks, INITIAL_CLOCKED_COUNTER, type ClockedCounterState,
} from "./model/prescaler";
@@ -455,8 +456,9 @@ export default function TimerPwmDemo() {
-
-
05 / HARDWAREBEZUG
+
+
+
05 / HARDWAREBEZUG
Virtuelles DOT · PE11
{pe11Connected
? "TIM1_CH2 → AF1 → PE11. Die LED ist low-aktiv. Wir setzen eine aktivierte Anzeigenstelle und freigeschalteten TIM1-Ausgang voraus (CC2E/MOE)."
@@ -477,6 +479,11 @@ export default function TimerPwmDemo() {
Mittelwert
+
+
diff --git a/src/demos/timer-pwm/components/DotSignalPath.tsx b/src/demos/timer-pwm/components/DotSignalPath.tsx
new file mode 100644
index 0000000..7c914f9
--- /dev/null
+++ b/src/demos/timer-pwm/components/DotSignalPath.tsx
@@ -0,0 +1,126 @@
+import type { TimerId } from "../model/timer";
+
+interface DotSignalPathProps {
+ timer: TimerId;
+ cnt: number;
+ arr: number;
+ psc: number;
+ ccr: number;
+ /** Der Zustand stammt aus dem gemeinsamen pwmActive-Modell des Parents. */
+ oc2refActive: boolean;
+}
+
+export default function DotSignalPath({
+ timer, cnt, arr, psc, ccr, oc2refActive,
+}: DotSignalPathProps) {
+ const connected = timer === "TIM1";
+ // Die Ausgangspolarität LOW invertiert den logischen OC2REF-Zustand.
+ // PE11 und DOT werden nur bei TIM1 unter den dokumentierten Annahmen modelliert.
+ const pe11Level = !connected ? "nicht verbunden" : oc2refActive ? "LOW (0)" : "HIGH (1)";
+ const dotState = !connected ? "nicht verbunden" : oc2refActive ? "AN" : "AUS";
+
+ return (
+
+
+
+ Signalweg verstehen
+ Warum leuchtet DOT bei OC2REF = 1?
+
+ ⌄
+
+
+
+ Das Zeitdiagramm zeigt OC2REF – ein internes logisches Signal,
+ nicht den elektrischen Pegel an PE11. Im dargestellten PWM-Modus 1 gilt
+ OC2REF = 1 bei CNT < CCR2.
+
+
+
+ Timer-Taktweg
+ {timer}CLK → PSC = {psc.toLocaleString("de-DE")} (÷{(psc + 1).toLocaleString("de-DE")}) → CNT = {cnt.toLocaleString("de-DE")} (0 … {arr.toLocaleString("de-DE")})
+
+
+
+
+ 1 · PWM-Vergleich
+ OC2REF = {oc2refActive ? "1" : "0"}
+ CNT = {cnt.toLocaleString("de-DE")} · CCR2 = {ccr.toLocaleString("de-DE")}
+ {oc2refActive ? "intern aktiv" : "intern inaktiv"}
+
+
→
+
+ 2 · Ausgangsstufe
+ OCPolarity LOW
+ Invertiert den OC2REF-Pegel
+ CC2E / MOE als freigegeben angenommen
+
+
→
+
+ 3 · TIM1_CH2 / AF1
+ PE11: {pe11Level}
+ {connected ? "physikalischer Pinpegel im Modell" : "TIM2_CH2 liegt nicht auf PE11"}
+
+
→
+
+ 4 · low-aktive Last
+ DOT: {dotState}
+ {connected ? "Segment leuchtet bei PE11 = LOW" : "kein DOT-Signalpfad über PE11"}
+
+
+
+
+ {connected ? (
+ <>Aktuell: OC2REF = {oc2refActive ? "1" : "0"} →{" "}
+ PE11 = {pe11Level} → DOT {dotState}.>
+ ) : (
+ <>Aktuell: OC2REF = {oc2refActive ? "1" : "0"} für TIM2,
+ aber keine Verbindung von TIM2_CH2 zum DOT an PE11.>
+ )}
+
+
+
+
+ Signalzustände für TIM1_CH2 mit Ausgangspolarität LOW und aktivierter DOT-Anzeigenstelle
+
+
+ | OC2REF (intern) |
+ PE11 (Pin) |
+ DOT (low-aktiv) |
+ Zustand |
+
+
+
+
+ | 1 · aktiv |
+ LOW (0) |
+ AN |
+ {connected && oc2refActive ? "← aktuell" : "–"} |
+
+
+ | 0 · inaktiv |
+ HIGH (1) |
+ AUS |
+ {connected && !oc2refActive ? "← aktuell" : "–"} |
+
+
+
+
+
+
+ Warum zwei Umkehrungen? Ausgangspolarität LOW erzeugt bei
+ OC2REF = 1 einen LOW-Pegel an PE11. Die low-aktive DOT-Beschaltung
+ interpretiert gerade diesen LOW-Pegel als „Segment AN“. Das sind zwei
+ logische Zuordnungen – keine Behauptung über zwei reale Inverterbausteine.
+
+
+ Modellannahmen: TIM1_CH2 ist über AF1 auf PE11 geschaltet,
+ der Timer-Ausgang ist freigegeben (CC2E/MOE), und eine DOT-Anzeigenstelle
+ wird über CNTL1…CNTL4 aktiviert. Diese Freigaben und der reale
+ Treiber-/Multiplex-Strompfad werden hier nicht simuliert. Dies ist ein
+ didaktisches Blockschaltbild, kein verifizierter elektrischer Schaltplan.
+ Bei TIM2 bleibt die virtuelle PE11-Verbindung unterbrochen.
+
+
+
+ );
+}
diff --git a/src/styles.css b/src/styles.css
index a0cff38..ac04741 100644
--- a/src/styles.css
+++ b/src/styles.css
@@ -499,3 +499,67 @@ button:disabled { opacity:.45; cursor:not-allowed; }
background:#1a4955; border:1px solid #4c9c9b; border-radius:8px; cursor:pointer;
}
.lab-local-jumps button:hover { background:#26606b; }
+
+/* Issue #5: expandable, model-based OC2REF → polarity → PE11 → DOT explanation. */
+.physical-panel { flex-direction:column; align-items:stretch; }
+.physical-summary { display:flex; align-items:center; justify-content:space-between; gap:20px; }
+.dot-signal-path { border:1px solid #36596a; background:#0c1e2f; border-radius:12px; min-width:0; }
+.dot-signal-path summary {
+ display:flex; align-items:center; justify-content:space-between; gap:12px;
+ cursor:pointer; list-style:none; padding:15px 17px; min-height:54px;
+}
+.dot-signal-path summary::-webkit-details-marker { display:none; }
+.dot-signal-path summary:focus-visible { outline:2px solid #6de1d0; outline-offset:3px; border-radius:9px; }
+.dot-signal-path summary > span:first-child { display:flex; flex-direction:column; gap:4px; min-width:0; }
+.dot-signal-path summary strong { font-size:14px; color:#d5f5ec; }
+.dot-signal-path summary small { font-size:12px; color:#b7cdd8; }
+.dot-signal-path-toggle { color:#8ef1dc; font-weight:800; font-size:23px; transition:transform .15s; }
+.dot-signal-path[open] .dot-signal-path-toggle { transform:rotate(180deg); }
+.dot-signal-path-body { border-top:1px solid #315166; padding:17px; min-width:0; }
+.physical-panel .dot-signal-path-body p { max-width:none; font-size:13px; color:#c0d4df; line-height:1.65; margin:0 0 14px; }
+.dot-path-source {
+ display:flex; flex-wrap:wrap; gap:6px 12px; align-items:baseline;
+ padding:10px 13px; border:1px solid #345467; background:#122c3c;
+ border-radius:9px; margin:10px 0 16px; font-size:13px;
+}
+.dot-path-source strong { color:#83edda; }
+.dot-path-source span { color:#e0f4f7; overflow-wrap:anywhere; }
+.dot-path-stages { display:flex; align-items:stretch; gap:8px; min-width:0; }
+.dot-path-stage {
+ flex:1 1 0; min-width:0; display:flex; flex-direction:column; gap:8px;
+ padding:13px 10px; background:#142c3d; border:1px solid #3a5970; border-radius:10px;
+}
+.dot-path-stage-label { font-size:11px; color:#a2c9d2; font-weight:800; line-height:1.4; }
+.dot-path-stage strong { font-size:15px; color:#77e7d5; overflow-wrap:anywhere; }
+.dot-path-stage small,.dot-path-stage-description { color:#bacdd9; font-size:12px; line-height:1.5; overflow-wrap:anywhere; }
+.dot-path-arrow { align-self:center; flex:0 0 auto; color:#71cbbb; font-size:18px; font-weight:800; }
+.dot-path-disconnected { border-style:dashed; opacity:.8; }
+.dot-path-disconnected strong { color:#cfdeec; }
+.dot-path-lit { background:#214344; border-color:#68dcc0; }
+.dot-path-current {
+ background:#16353f; border-left:3px solid #64dcc9; color:#cfe8eb;
+ border-radius:5px; padding:11px 13px; margin:15px 0; font-size:13px; line-height:1.6;
+}
+.dot-path-current strong { color:#9df8e3; }
+.dot-path-table-wrap { max-width:100%; overflow-x:auto; }
+.dot-path-table { width:100%; border-collapse:collapse; text-align:left; font-size:12px; line-height:1.55; }
+.dot-path-table caption { text-align:left; color:#c5dce7; padding:0 0 8px; font-weight:700; }
+.dot-path-table th,.dot-path-table td { padding:9px 10px; border-bottom:1px solid #385264; }
+.dot-path-table thead th { background:#183344; color:#d5edf0; }
+.dot-path-table tbody th { color:#d3e9ef; font-weight:650; }
+.dot-path-row-active { background:#22504a; }
+.dot-path-row-active td:last-child { color:#96f5d6; font-weight:800; }
+.physical-panel .dot-path-assumptions { color:#adbfcd; font-size:12px; margin-top:14px; }
+@media(max-width:1000px) {
+ .dot-path-stages { flex-direction:column; }
+ .dot-path-arrow { transform:rotate(90deg); padding:0; }
+ .dot-path-stage { flex:0 0 auto; }
+}
+@media(max-width:700px) {
+ .physical-summary { flex-direction:column; align-items:stretch; }
+ .dot-signal-path-body { padding:12px; }
+ .dot-path-table th,.dot-path-table td { padding:8px 5px; }
+}
+@media(prefers-reduced-motion:reduce) {
+ .dot-signal-path-toggle { transition:none; }
+}
From face8b38d426ded71b64a34ef74fc6f7ff5cd2b9 Mon Sep 17 00:00:00 2001
From: Michak <121102425+KreutzM@users.noreply.github.com>
Date: Thu, 12 Nov 2026 12:59:17 +0100
Subject: [PATCH 2/5] test(dot): cover live polarity, compare/overflow, PWM
limits, TIM2 and mobile details (#5)
---
e2e/visual.spec.ts | 77 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 77 insertions(+)
diff --git a/e2e/visual.spec.ts b/e2e/visual.spec.ts
index 1073b63..fdb12ad 100644
--- a/e2e/visual.spec.ts
+++ b/e2e/visual.spec.ts
@@ -478,3 +478,80 @@ test("Sprungziele bleiben bei Desktop und 320 px unterhalb des Sticky Headers si
}
}
});
+
+test("DOT-Signalweg: interne Referenz, PE11-Pegel und low-aktive LED bleiben synchron", async ({ page }, info) => {
+ await page.goto("/PES-Demos/#/timer-pwm");
+ await page.getByRole("button", { name: "Freies Labor", exact: true }).click();
+ const details = page.getByTestId("dot-signal-path");
+ const summary = details.locator("summary");
+ await expect(details).not.toHaveAttribute("open", "");
+ await summary.click();
+ await expect(details).toHaveAttribute("open", "");
+ await expect(details.getByTestId("path-oc2ref")).toContainText("OC2REF = 1");
+ await expect(details.getByTestId("path-pe11")).toContainText("PE11: LOW (0)");
+ await expect(details.getByTestId("path-dot")).toContainText("DOT: AN");
+ await expect(details.locator(".dot-path-row-active")).toContainText("LOW (0)");
+ await expect(details).toContainText("CC2E / MOE");
+ await expect(details).toContainText("kein verifizierter elektrischer Schaltplan");
+ await details.scrollIntoViewIfNeeded();
+ await capture(page, info.project.name, "dot-path-tim1-on");
+
+ const counterStep = page.locator(".transport-buttons")
+ .getByRole("button", { name: "+1 CNT-Zählschritt" });
+ for (let i = 0; i < 3; i++) await counterStep.click();
+ await expect(page.locator(".counter-number")).toHaveText("3");
+ await expect(details).toHaveAttribute("open", "");
+ await expect(details.getByTestId("path-oc2ref")).toContainText("OC2REF = 0");
+ await expect(details.getByTestId("path-pe11")).toContainText("PE11: HIGH (1)");
+ await expect(details.getByTestId("path-dot")).toContainText("DOT: AUS");
+ await expect(details.locator(".dot-path-row-active")).toContainText("HIGH (1)");
+ await details.scrollIntoViewIfNeeded();
+ await capture(page, info.project.name, "dot-path-tim1-off");
+
+ await page.locator(".transport-buttons").getByRole("button", { name: /Zum Rücksprung/ }).click();
+ await expect(page.locator(".counter-number")).toHaveText("0");
+ await expect(details.getByTestId("path-dot")).toContainText("DOT: AN");
+
+ // Boundary cases: no active step at CCR2=0 and always active when CCR2>ARR.
+ await page.locator("#ccr").fill("0");
+ await expect(details.getByTestId("path-dot")).toContainText("DOT: AUS");
+ await expect(details.getByTestId("path-pe11")).toContainText("PE11: HIGH (1)");
+ await page.locator("#ccr").fill("12");
+ await expect(details.getByTestId("path-dot")).toContainText("DOT: AN");
+ await expect(details.getByTestId("path-pe11")).toContainText("PE11: LOW (0)");
+
+ await page.locator("#timer").selectOption("TIM2");
+ await expect(details.getByTestId("path-oc2ref")).toContainText("OC2REF = 1");
+ await expect(details.getByTestId("path-pe11")).toContainText("PE11: nicht verbunden");
+ await expect(details.getByTestId("path-dot")).toContainText("DOT: nicht verbunden");
+ await expect(details.getByTestId("path-current-state")).toContainText("keine Verbindung");
+ await expect(page.locator(".led-visual").first().getByRole("img")).toHaveAttribute(
+ "aria-label", "LED momentan ausgeschaltet");
+ await details.scrollIntoViewIfNeeded();
+ await capture(page, info.project.name, "dot-path-tim2-disconnected");
+
+ // A native details/summary is operable with a keyboard, no separate button needed.
+ await summary.focus();
+ await page.keyboard.press("Enter");
+ await expect(details).not.toHaveAttribute("open", "");
+});
+
+test("DOT-Signalweg ist mobil aufklappbar ohne horizontale Überbreite", async ({ page }, info) => {
+ await page.goto("/PES-Demos/#/timer-pwm");
+ await page.getByRole("button", { name: "Freies Labor", exact: true }).click();
+ const details = page.getByTestId("dot-signal-path");
+ await details.locator("summary").click();
+ for (const width of [320, 360, 393]) {
+ await page.setViewportSize({ width, height: 800 });
+ await expect(details.getByTestId("path-dot")).toBeVisible();
+ const dimensions = await page.evaluate(() => ({
+ documentOverflow: document.documentElement.scrollWidth - document.documentElement.clientWidth,
+ stageOverflow: [...document.querySelectorAll(".dot-path-stage")]
+ .map(el => el.scrollWidth - el.clientWidth),
+ }));
+ expect(dimensions.documentOverflow, "Dokument bei " + width + "px").toBeLessThanOrEqual(2);
+ expect(Math.max(...dimensions.stageOverflow), "Signalweg-Knoten bei " + width + "px").toBeLessThanOrEqual(2);
+ await details.scrollIntoViewIfNeeded();
+ await capture(page, info.project.name, "dot-path-mobile-" + width);
+ }
+});
From 5ddec879982ca999c2437e198e69c0f26d67fbb1 Mon Sep 17 00:00:00 2001
From: Michak <121102425+KreutzM@users.noreply.github.com>
Date: Thu, 12 Nov 2026 13:04:06 +0100
Subject: [PATCH 3/5] fix(dot): avoid implying TIM1 output enables apply to
unconnected TIM2 (#5)
---
src/demos/timer-pwm/components/DotSignalPath.tsx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/demos/timer-pwm/components/DotSignalPath.tsx b/src/demos/timer-pwm/components/DotSignalPath.tsx
index 7c914f9..c8aad00 100644
--- a/src/demos/timer-pwm/components/DotSignalPath.tsx
+++ b/src/demos/timer-pwm/components/DotSignalPath.tsx
@@ -52,11 +52,11 @@ export default function DotSignalPath({
2 · Ausgangsstufe
OCPolarity LOW
Invertiert den OC2REF-Pegel
- CC2E / MOE als freigegeben angenommen
+ {connected ? "CC2E und MOE für TIM1 als freigegeben angenommen" : "Interner TIM2-Kanal; kein PE11-Ausgang"}
→
- 3 · TIM1_CH2 / AF1
+ 3 · {connected ? "TIM1_CH2 / AF1" : "PE11-Anschluss"}
PE11: {pe11Level}
{connected ? "physikalischer Pinpegel im Modell" : "TIM2_CH2 liegt nicht auf PE11"}
From 21a815b6433bff2da626052fce3eb7379607ba13 Mon Sep 17 00:00:00 2001
From: Michak <121102425+KreutzM@users.noreply.github.com>
Date: Thu, 12 Nov 2026 13:06:58 +0100
Subject: [PATCH 4/5] test(dot): assert precise TIM1 output-enable explanation
(#5)
---
e2e/visual.spec.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/e2e/visual.spec.ts b/e2e/visual.spec.ts
index fdb12ad..08ba924 100644
--- a/e2e/visual.spec.ts
+++ b/e2e/visual.spec.ts
@@ -491,7 +491,7 @@ test("DOT-Signalweg: interne Referenz, PE11-Pegel und low-aktive LED bleiben syn
await expect(details.getByTestId("path-pe11")).toContainText("PE11: LOW (0)");
await expect(details.getByTestId("path-dot")).toContainText("DOT: AN");
await expect(details.locator(".dot-path-row-active")).toContainText("LOW (0)");
- await expect(details).toContainText("CC2E / MOE");
+ await expect(details).toContainText("CC2E und MOE für TIM1");
await expect(details).toContainText("kein verifizierter elektrischer Schaltplan");
await details.scrollIntoViewIfNeeded();
await capture(page, info.project.name, "dot-path-tim1-on");
From 14b3e0c2b97a4d0201f32e858c5efccc6a6211ef Mon Sep 17 00:00:00 2001
From: Michak <121102425+KreutzM@users.noreply.github.com>
Date: Thu, 12 Nov 2026 13:33:29 +0100
Subject: [PATCH 5/5] fix(dot): resolve disconnected TIM2 wording, widget state
and hardware references (#5)
---
README.md | 5 +++-
e2e/visual.spec.ts | 30 ++++++++++++++++---
src/demos/timer-pwm/TimerPwmDemo.tsx | 12 ++++----
.../timer-pwm/components/DotSignalPath.tsx | 22 ++++++++------
4 files changed, 50 insertions(+), 19 deletions(-)
diff --git a/README.md b/README.md
index b159e2a..26e4dfe 100644
--- a/README.md
+++ b/README.md
@@ -110,6 +110,9 @@ Der Abschnitt „Virtuelles DOT · PE11“ besitzt ein **standardmäßig geschlo
- Bei `TIM1_CH2` mit `OCPolarity LOW` entspricht OC2REF=1 einem **LOW-Pegel an PE11**; eine low-aktive DOT-Leitung lässt das gewählte Segment dann leuchten.
- Die physikalische Darstellung gilt nur bei **TIM1** und unter Annahme aktivierter Ausgangsfreigaben **CC2E/MOE**, AF1-Konfiguration sowie einer aktivierten Anzeigenstelle über **CNTL1…CNTL4**. Diese Voraussetzungen sind in der Website nicht dynamisch modelliert. **TIM2_CH2 ist nicht mit DOT/PE11 verbunden.**
- Das Blockschaltbild ist eine **didaktische Funktionsdarstellung, kein elektrischer Stromlaufplan** und behauptet keine zusätzlichen physischen Inverter. Der tatsächliche Treiber-/Multiplex-Strompfad des 8-Segment-Adapterboards ist nicht rekonstruiert.
-- Materialgrundlage: Praktikumsanleitung, Kapitel 7.1.1 (low-aktive Segmente und CNTL-Leitungen) sowie Kapitel 7.6.3 (TIM1_CH2/PE11, AF1, DOT); das Open429Z-D-Basisschaltbild dokumentiert PE11, aber nicht die vollständige Adapterboard-Beschaltung.
+- **Primärquelle der Praktikumshardware:** *Praktikum Eingebettete Systeme – Praktikumsanleitung*, Technische Hochschule Mittelhessen, **Version 1.6 vom 13.10.2026**, Kap. **7.1.1**, Druckseiten **28–29/79** (low-aktive Segmentleitungen, CNTL1…CNTL4, Verweis auf das 8-Segment-Board-Schematic), sowie Kap. **7.6.3**, Druckseiten **51–52/79** (TIM1_CH2 → AF1 → PE11 → DOT). Die konkrete Kurs-PDF liegt in den Praktikumsressourcen, **nicht als öffentlich verlinkte Kopie** in diesem Repository.
+- **Offizielle Hardwaredokumente:** [ST STM32F429-Datenblatt, Pin-/AF-Tabelle (PE11 / TIM1_CH2)](https://www.st.com/resource/en/datasheet/stm32f429zg.pdf), [Waveshare Open429Z-D – Ressourcen inkl. Basisschaltplan](https://www.waveshare.com/wiki/Open429Z-D) und [Waveshare 8 SEG LED Board – Ressourcen inkl. Adapterschaltplan](https://www.waveshare.com/wiki/8_SEG_LED_Board). Das vorliegende Open429Z-D-Basisschaltbild von 2014 belegt **nicht** den vollständigen Strompfad des Adapterboards; dieser wurde für die Demo nicht elektrisch rekonstruiert.
Das vorhandene OC2REF-Zeitdiagramm und die Simulations-Engine bleiben unverändert; die Tabelle bietet die alternative synchrone Darstellung der drei Pegel-/LED-Ebenen und reagiert auf CNT, CCR2 und Timerwechsel.
+
+**TIM2-Darstellung:** Das geschlossene Ausklappfeld und beide LED-Widgets weisen ausdrücklich auf die fehlende Verbindung zu DOT/PE11 hin. Die TIM1-Pegeltabelle wird bei ausgewähltem TIM2 nicht angezeigt, damit keine hypothetischen PE11-HIGH-/LOW-Werte als aktueller TIM2-Pegel missverstanden werden.
diff --git a/e2e/visual.spec.ts b/e2e/visual.spec.ts
index 08ba924..37625af 100644
--- a/e2e/visual.spec.ts
+++ b/e2e/visual.spec.ts
@@ -485,6 +485,7 @@ test("DOT-Signalweg: interne Referenz, PE11-Pegel und low-aktive LED bleiben syn
const details = page.getByTestId("dot-signal-path");
const summary = details.locator("summary");
await expect(details).not.toHaveAttribute("open", "");
+ await expect(summary).toContainText("Warum leuchtet DOT bei OC2REF = 1 (im TIM1-Modell)?");
await summary.click();
await expect(details).toHaveAttribute("open", "");
await expect(details.getByTestId("path-oc2ref")).toContainText("OC2REF = 1");
@@ -525,15 +526,36 @@ test("DOT-Signalweg: interne Referenz, PE11-Pegel und low-aktive LED bleiben syn
await expect(details.getByTestId("path-pe11")).toContainText("PE11: nicht verbunden");
await expect(details.getByTestId("path-dot")).toContainText("DOT: nicht verbunden");
await expect(details.getByTestId("path-current-state")).toContainText("keine Verbindung");
+ await expect(details.locator(".dot-path-table")).toHaveCount(0);
+ await expect(details.locator(".dot-path-row-active")).toHaveCount(0);
+ await expect(details.getByTestId("tim2-table-explanation")).toContainText("ausschließlich für das TIM1-Beispiel");
await expect(page.locator(".led-visual").first().getByRole("img")).toHaveAttribute(
- "aria-label", "LED momentan ausgeschaltet");
- await details.scrollIntoViewIfNeeded();
- await capture(page, info.project.name, "dot-path-tim2-disconnected");
+ "aria-label", "DOT nicht verbunden: TIM2_CH2 hat keinen Signalpfad über PE11");
+ await expect(page.locator(".led-visual").nth(1).getByRole("img")).toHaveAttribute(
+ "aria-label", "Kein Helligkeitsmittelwert: TIM2_CH2 ist nicht mit dem DOT an PE11 verbunden");
+ await expect(page.locator(".led-visual").first()).toContainText("Nicht verbunden");
+ await expect(page.locator(".led-visual").nth(1)).toContainText("Kein Mittelwert");
- // A native details/summary is operable with a keyboard, no separate button needed.
+ // Auch wenn das interne Referenzsignal auf 0 wechselt, bleibt der PE11-Pfad getrennt.
+ await page.locator("#ccr").fill("0");
+ await expect(details.getByTestId("path-oc2ref")).toContainText("OC2REF = 0");
+ await expect(details.getByTestId("path-pe11")).toContainText("PE11: nicht verbunden");
+ await expect(details.getByTestId("path-dot")).toContainText("DOT: nicht verbunden");
+ await expect(details.locator(".dot-path-table")).toHaveCount(0);
+ await expect(page.locator(".led-visual").first().getByRole("img")).toHaveAttribute(
+ "aria-label", "DOT nicht verbunden: TIM2_CH2 hat keinen Signalpfad über PE11");
+
+ // Zusammengeklappt ist bereits der erste Erklärungssatz timerabhängig.
await summary.focus();
await page.keyboard.press("Enter");
await expect(details).not.toHaveAttribute("open", "");
+ await expect(summary).toContainText("Warum hat TIM2_CH2 keinen DOT-Pfad über PE11?");
+ await details.scrollIntoViewIfNeeded();
+ await capture(page, info.project.name, "dot-path-tim2-disconnected");
+
+ // A native details/summary is operable with a keyboard in both directions.
+ await page.keyboard.press("Enter");
+ await expect(details).toHaveAttribute("open", "");
});
test("DOT-Signalweg ist mobil aufklappbar ohne horizontale Überbreite", async ({ page }, info) => {
diff --git a/src/demos/timer-pwm/TimerPwmDemo.tsx b/src/demos/timer-pwm/TimerPwmDemo.tsx
index 7b7f623..015b934 100644
--- a/src/demos/timer-pwm/TimerPwmDemo.tsx
+++ b/src/demos/timer-pwm/TimerPwmDemo.tsx
@@ -463,20 +463,22 @@ export default function TimerPwmDemo() {
{pe11Connected
? "TIM1_CH2 → AF1 → PE11. Die LED ist low-aktiv. Wir setzen eine aktivierte Anzeigenstelle und freigeschalteten TIM1-Ausgang voraus (CC2E/MOE)."
: "TIM2_CH2 liegt nicht auf PE11. Deshalb bleibt das virtuelle DOT-Segment unverbunden; oben wird trotzdem das interne PWM-Signal simuliert."}
- Links: momentaner LED-Zustand gemäß CNT. Rechts: gemitteltes Helligkeitsmodell, nur bei ausreichend hoher PWM-Frequenz sinnvoll.
+ {pe11Connected
+ ? "Links: momentaner LED-Zustand gemäß CNT. Rechts: gemitteltes Helligkeitsmodell, nur bei ausreichend hoher PWM-Frequenz sinnvoll."
+ : "Beide LED-Anzeigen sind für TIM2 nicht verbunden; es wird kein PE11-Pegel und kein LED-Mittelwert simuliert."}
-
+
-
Momentan
+
{pe11Connected ? "Momentan" : "Nicht verbunden"}
-
+
-
Mittelwert
+
{pe11Connected ? "Mittelwert" : "Kein Mittelwert"}
diff --git a/src/demos/timer-pwm/components/DotSignalPath.tsx b/src/demos/timer-pwm/components/DotSignalPath.tsx
index c8aad00..0b63843 100644
--- a/src/demos/timer-pwm/components/DotSignalPath.tsx
+++ b/src/demos/timer-pwm/components/DotSignalPath.tsx
@@ -24,7 +24,7 @@ export default function DotSignalPath({
Signalweg verstehen
- Warum leuchtet DOT bei OC2REF = 1?
+ {connected ? "Warum leuchtet DOT bei OC2REF = 1 (im TIM1-Modell)?" : "Warum hat TIM2_CH2 keinen DOT-Pfad über PE11?"}
⌄
@@ -49,10 +49,10 @@ export default function DotSignalPath({
→
- 2 · Ausgangsstufe
- OCPolarity LOW
- Invertiert den OC2REF-Pegel
- {connected ? "CC2E und MOE für TIM1 als freigegeben angenommen" : "Interner TIM2-Kanal; kein PE11-Ausgang"}
+ 2 · {connected ? "Ausgangsstufe" : "Keine PE11-Ausgabe"}
+ {connected ? "OCPolarity LOW" : "TIM2_CH2 intern"}
+ {connected ? "Invertiert den OC2REF-Pegel" : "Kein Pegel am PE11-DOT-Anschluss"}
+ {connected ? "CC2E und MOE für TIM1 als freigegeben angenommen" : "TIM2_CH2 ist nicht nach PE11 geroutet"}
→
@@ -78,7 +78,7 @@ export default function DotSignalPath({
)}
-
+ {connected ?
Signalzustände für TIM1_CH2 mit Ausgangspolarität LOW und aktivierter DOT-Anzeigenstelle
@@ -104,14 +104,18 @@ export default function DotSignalPath({
-
+
:
+ Die Zuordnung OC2REF → PE11 → DOT gilt ausschließlich für das TIM1-Beispiel.
+ Für TIM2 existieren hier weder ein modellierter PE11-Pegel noch eine
+ DOT-LED-Zustandstabelle.
+
}
-
+ {connected &&
Warum zwei Umkehrungen? Ausgangspolarität LOW erzeugt bei
OC2REF = 1 einen LOW-Pegel an PE11. Die low-aktive DOT-Beschaltung
interpretiert gerade diesen LOW-Pegel als „Segment AN“. Das sind zwei
logische Zuordnungen – keine Behauptung über zwei reale Inverterbausteine.
-
+
}
Modellannahmen: TIM1_CH2 ist über AF1 auf PE11 geschaltet,
der Timer-Ausgang ist freigegeben (CC2E/MOE), und eine DOT-Anzeigenstelle