15 KiB
| tags | project | author | date | status | reviews | against | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
Project Drogheda | Helgen CTO | 2026-06-22 | Review — read before populating the protoboard or releasing Gerbers | watchdog-connections.xlsx (128-row from→to list) | blackpillrtkcode_v2.ino v2.2 · watchdog-pcb-v3-design.md |
Watchdog Connection List — Justification & Firmware Cross‑Check
Every connection in [[03-Architecture-Hardware/watchdog-connections|
watchdog-connections.xlsx]] justified — where it goes, how it's wired, why — and checked against the actual firmware (blackpillrtkcode_v2.inov2.2). This pass found 3 issues to fix before fab (one is a part‑rating error) and confirms the rest match the code. Read §5 first if you're short on time.
1. Method
Three sources had to agree: the connection list (the wires), the firmware (what each pin actually does), and the design doc (the intent + values). I walked every Blackpill pin in the firmware, found its net in the connection list, and confirmed the sub‑circuit on the other end does what the code assumes. Discrepancies are called out as findings (§5).
Legend: ✅ wired and used by firmware today · 🟡 wired, firmware pending (v3 thermal, spec'd in design §7 but not yet coded) · ⚪ system/spare · 🔴 issue to fix.
2. Firmware ↔ connection cross‑check (the core table)
| Blackpill pin | Firmware v2.2 (#define / use) |
Connects to (list) | Status | Match |
|---|---|---|---|---|
| PA0 | PIN_BAT_SENSE → analogRead×DIVIDER_RATIO 2.0 |
R5(10k)→BAT+, R6(10k)→GND, C5 | ✅ | ÷2 matches the ×2 in code |
| PA4 | PIN_5V_SENSE → analogRead×2.0; V5V_ON 4.2/OFF 3.8 |
R7(10k)→MAIN5V, R8(10k)→GND, C7 | ✅ | ÷2 correct; see Finding 3 (tap point) |
| PA5 | PIN_IGN_SENSE → digitalRead, INPUT_PULLDOWN |
R9/R10(÷2) from DFR1015, D5 clamp, C9 | ✅ | digital — see Finding 2 (level) |
| PA1 | PIN_PWR_CTRL → OUTPUT, HIGH=stack ON |
R1(1k)→Q5 base → Q1 P‑FET | ✅ | HIGH→NPN→gate low→P‑FET on ✓ |
| PA2 | GNSS TX (USART2); floated on power‑off |
P3.3 → simpleRTK2B UART1 RX | ✅ | TX→RX ✓ |
| PA3 | GNSS RX (USART2); floated on power‑off |
P3.4 ← simpleRTK2B UART1 TX | ✅ | RX←TX ✓ |
| PB0 | PIN_EXT_LED → OUTPUT (HIGH=on) |
Q4 gate; Rled(10k)→GND; D1+R3 | ✅ | active‑high via N‑MOS ✓ |
| PC13 | PIN_LED → OUTPUT, active‑LOW (!ext) |
onboard (internal) | ✅ | mirrors PB0 inverted ✓ |
| PA6 | — (not in firmware) | Rg→Q2 fan gate (PWM) | 🟡 | wired per design §7; code pending |
| PB10 | — | fan tach → EXTI | 🟡 | code pending |
| PB6 | — | I²C1 SCL → SHT40+TMP102 | 🟡 | code pending |
| PB7 | — | I²C1 SDA → SHT40+TMP102 | 🟡 | code pending |
| PA7 | — | NC (TIM3_CH2 spare) | ⚪ | reserved 2nd fan |
| PB12 | — | NC (EXTI spare) | ⚪ | reserved 2nd tach |
| PA9 | RELAY TX iff ENABLE_PHLG_RELAY (default 0) |
H3.1 (DNP) → modem DIN | ⚪ | off in v3 ✓ |
| PA10 | RELAY RX iff relay flag |
H3.2 (DNP) ← F9P UART2 TX; Rdfu 22k→3V3 | ⚪ | off in v3; 22k = DFU‑safe ✓ |
| PA13/PA14 | SWD (core) | H1.2 / H1.3 | ⚪ | debug |
| PA11/PA12 | USB CDC (Serial = STREAM log) |
micro‑USB | ✅ | log + flash |
| PC14/PC15, PB2, BOOT0, NRST | boot/clock/reset | PB2→GND, BOOT0 button→3V3 | ⚪ | Finding 2b (BOOT pins) |
No pin is double‑assigned, and no ADC/timer/UART peripheral collides: PA0/PA4 = ADC1, PA2/PA3 = USART2, PA6 = TIM3_CH1 (PB0 is TIM3_CH3 but used as plain GPIO so no PWM clash), PB6/PB7 = I²C1, PB10/PB12 = EXTI, PA9/PA10 = USART1. ✅
3. Sub‑circuit justifications (where it goes, how, why)
3.1 Power input — 24 V → rev‑pol → TVS → fan buck
- P1 (GX16‑5) brings the cabinet's clean, regulated 24 V + GND + isolated ignition. Keyed/locking because the #1 field failure was vibration on Dupont. The cabinet already has the SPD + breaker, so the board only needs reverse‑polarity + a modest TVS — not a full protection front‑end.
- Q10 sits in the 24 V high side as a reverse‑polarity gate: source to the load (24 V rail), drain to the input, gate to GND so a correctly‑polarised input turns it fully on (low drop) and a reversed input leaves it off. 🔴 This is where Finding 1 lives — the part rating is wrong for 24 V.
- D10 (TVS) clamps residual transients 24 V→GND; C10 (100 µF) is the input reservoir.
- U2 (MP1584) bucks the protected 24 V to 5V_FAN — a dedicated rail so the fan's inrush never sags the 5 V the modem bursts on (design §0a). R20/R21 set 5.0 V. JP1 can bridge 5V_FAN↔MAIN5V but stays open by default.
3.2 The 5 V rails + RTK‑stack load switch
- MAIN 5 V enters at P2 from the external Mean Well SD‑15B‑05. It powers the Blackpill's 5 V pin (→ onboard LDO → 3V3) and the load switch.
- Load switch (PA1‑driven):
setPower(true)drives PA1 HIGH → R1(1k) into the Q5 (NPN) base → Q5 conducts → pulls the Q1 (P‑MOSFET) gate toward GND → Vgs negative → Q1 on → SW_5V feeds the simpleRTK2B + 4G stack via P3. PA1 LOW → R2(10k) holds the gate at MAIN5V → Q1 off. This gives the firmware‑critical property: stack OFF at boot/reset (the gate pull‑up defines the off state before the MCU asserts) — the whole fail‑safe doctrine depends on it. F1 (PPTC) adds self‑resetting overcurrent (never black‑holes a healthy unit); C3 (47 µF) rides out LTE bursts on SW_5V. - Why PA2/PA3 float on power‑off:
setPower(false)sets them toINPUTso the MCU can't back‑power the switched rail through a GPIO while the stack is down — the connection (PA2/3 → P3 UART) is correct precisely because the firmware manages this.
3.3 Sense dividers — PA0, PA4, PA5
- PA0 battery (✅):
vBat = analogRead/4095 · 3.3 · 2.0. The 10k/10k ÷2 is exactly theDIVIDER_RATIO 2.0the code multiplies back, so 3.4–4.2 V → 1.7–2.1 V at the pin (no clipping). DrivesBAT_CRITICAL 3.40 / BAT_RECOVERY 3.70(sleep/wake). - PA4 5 V / vehicle‑present (✅, but Finding 3): same ÷2;
v5vcompared toV5V_ON 4.2 / V5V_OFF 3.8. The catch is what node it taps — it must be the vehicle‑side 5 V (the SD‑15B‑05 output, which disappears when the machine is off), not a battery‑backed rail. - PA5 ignition (✅, but Finding 2): firmware does
digitalRead(PA5)==HIGHwithINPUT_PULLDOWN. So the chain only has to land a clean logic HIGH when ignition is on — and the ÷2 may pull it too low (Finding 2). D5 clamps PA5 ≤3V3; C9 debounces with the firmware's 750 ms.
3.4 Fan driver + tach (🟡 firmware pending)
- PA6 → Rg(100R) → Q2 gate, Q2 (logic‑level N‑MOS) low‑side: drain = Fan(−) at P6.2, source = GND. Rgs(100k) gate→GND = fan OFF until the MCU drives PWM (fail‑safe, and it means an un‑programmed board can't spin the fan). D2 flyback across the fan (K→5V_FAN, A→Fan(−)) catches the inductive kick at PWM turn‑off.
- Tach: open‑collector fan tach → Rtp(10k) pull‑up to 3V3 + Rts(1k) series → PB10 (EXTI). Because PWM is on the ground leg, the tach is only valid while PWM is high — the (pending) firmware must read RPM in a brief 100 % window (design §7.4).
- Status today: the v2.2 firmware does not drive PA6 or read PB10. So a freshly‑flashed board is electrically correct but the fan won't move and tach won't read until the fan/temp code lands (design §7). That's intended sequencing, not a wiring error — see Finding 4.
3.5 Temperature / humidity (🟡 firmware pending)
- PB6/PB7 = I²C1 to U3 SHT40 (0x44) and U4 TMP102 (0x48, ADD0→GND), R30/R31 (4.7k) pull‑ups to 3V3. Two different addresses → one bus, no clash. U4 rides a P5 pigtail to the battery/modem hot spot (the actual heat casualty). Same status as §3.4: wired, code pending.
3.6 Status LED — PB0 / PC13
- Firmware drives PB0 HIGH = LED on through Q4 (N‑MOS low‑side; LED + R3 from 3V3 to
Q4 drain), with Rled(10k) holding the gate off at boot. PC13 (onboard) mirrors it
inverted (
digitalWrite(PIN_LED, !ext)) because it's active‑LOW. The proto simplification (PB0 →330Ω→ LED →GND) keeps the same HIGH=on polarity — consistent with the code.
3.7 Reserved relay + debug/boot
- PA9/PA10 (H3, DNP): only touched if
ENABLE_PHLG_RELAY=1; default 0, so the default build ignores them. Rdfu 22k on PA10→3V3 keeps DFU flashing reliable (PA10 is a bootloader‑sensitive pin) and is harmless on USART1 RX (idle‑high). H1 = SWD. BOOT0 button→3V3 = DFU; PB2 (BOOT1)→GND = boot‑from‑flash — see Finding 2b.
4. What I checked against the code, line‑for‑line
analogRead(PIN_BAT_SENSE/PIN_5V_SENSE) … · DIVIDER_RATIO 2.0⇄ both dividers are 10k/10k (÷2). Consistent.digitalRead(PIN_IGN_SENSE)+INPUT_PULLDOWN⇄ PA5 is a digital input → the divider must deliver a solid HIGH (Finding 2), and the internal ~40 k pulldown sits in parallel with R10.digitalWrite(PIN_PWR_CTRL,HIGH)=on⇄ NPN→P‑FET gate‑pull‑down topology gives HIGH=on, OFF at reset. Consistent.setPower(false)floats PA2/PA3 ⇄ UART pins go to the F9P only (no rail back‑feed). Consistent.PIN_EXT_LEDactive‑high /PIN_LEDactive‑low ⇄ Q4 low‑side + onboard inverted. Consistent.ENABLE_PHLG_RELAYdefault 0 ⇄ PA9/PA10 are DNP. Consistent.- No firmware references to PA6/PA7/PB6/PB7/PB10/PB12 (grep = 0) ⇄ those are 🟡 pending. Consistent with "design ahead of code, by intent."
5. Review findings — ✅ ALL CORRECTED 2026‑06‑22
Resolution summary (applied across the design doc, BOM, connection list, and firmware): F1 — Q10 → a −40 V/±20 V P‑FET (IRFR5305; proto IRF9540) + a 15 V gate‑source Zener (DzG) + Rrp, so Vgs stays in rating. F2 — ignition ÷2 removed; the DFR1015 logic level now reaches PA5 direct (Rig + clamp) → solid HIGH. F3 — battery resolved: dropped (vehicle‑only); PA4 senses the vehicle‑side 5 V and the list is correct as‑is (LiFePO4/supercap + moved sense‑tap documented if parked tracking is later required). F4 — the fan/temp firmware is now implemented in v2.3 (closed‑loop fan + I²C SHT40/ TMP102 + tach fault, MCU‑temp fallback). F2b — boot pins verified. Detail below is the why.
Original findings (retained for the record — now corrected)
🔴 Finding 1 — Reverse‑polarity FET (Q10) is over‑stressed on 24 V (blocking)
With source at the 24 V rail and gate at GND, Vgs ≈ −24 V. AO3401A is rated ±12 V Vgs
(and −30 V Vds) — it will be destroyed. The design's alternate SI2305 is −20 V Vds —
also unsuitable for a 24 V rail with transients.
Fix: pick a P‑FET rated Vds ≥ −40 V and Vgs ≥ ±20 V (e.g., DMP3017SFG‑class), and add
a gate→source Zener clamp (~15 V) with the existing series resistor so Vgs can never exceed
the rating. Update Q10 in the BOM + the connection list (add DzG Zener: A→Q10.G, K→Q10.S).
🔴 Finding 2 — Ignition sense (PA5) may never read HIGH (blocking if DFR1015 ≤ 3.3 V)
PA5 is a digital input. The DFR1015 conditions 24 V→logic, then the ÷2 halves it again;
the internal pulldown (~40 k ∥ R10 10 k ≈ 8 k) shifts the ratio to ≈0.44. If the DFR1015
outputs 3.3 V, PA5 sees ≈1.4 V — below VIH, and ignitionOn stays false (breaking the
1 Hz/30 s rate switch and the brownout exit).
Fix (pick one): (a) set DFR1015 to ~5 V and keep the ÷2 (PA5 ≈ 2.2 V, solid HIGH); or
(b) drop R9/R10 and feed the DFR1015 output directly to PA5 through the 100 Ω series +
D5 clamp (cleanest if DFR1015 ≤ 3.3 V). Confirm the measured DFR1015 output on the bench.
🔴 Finding 3 — 5V_SENSE (PA4) must tap the vehicle side, and depends on the battery call
"Vehicle‑power present" only works if PA4 senses a node that drops when the machine is off
— i.e. the SD‑15B‑05 output, before any battery hold‑up. The connection list assumes
the battery is dropped (MAIN5V = SD‑15B‑05 powers the MCU directly; PA4 senses MAIN5V; P4
is sense‑only). If the 18650/PowerBoost is kept, the MCU runs off the battery‑backed rail
and PA4 must instead tap the SD‑15B‑05/P2 node (not the backed rail) — otherwise v5v
reads ~5 V forever, vehiclePower never clears, and the cell drains.
Action: close the battery decision (design §6.1). Drop‑battery → list is correct as‑is.
Keep‑battery → add the PowerBoost between P2 and MAIN5V and move the PA4 tap to the vehicle side.
🟡 Finding 4 — Thermal pins are wired ahead of the firmware (expected, track it)
PA6 (fan), PB10 (tach), PB6/PB7 (I²C) are in the list per design §7 but not in v2.2. A flashed board is correct but inert on cooling until the fan‑curve + I²C‑temp code is added (after the bench bring‑up). Don't be surprised when the fan doesn't spin on first power‑up. Action: implement design §7 (I'll do it once you confirm the temp sensor you bought).
🟡 Finding 2b — Boot pins (housekeeping)
Confirm PB2 (BOOT1) → GND and BOOT0 only high via its button — a stray pull‑up on either makes flashing flaky (matches the DFU notes). The list already shows PB2→GND and the 22 k on PA10; just verify on the board.
✅ Everything else
Load switch logic, both ADC dividers, the float‑on‑power‑off, LED polarity, the relay being default‑off, and the I²C addressing all match the firmware. No pin conflicts.
6. Verdict
The connection list is sound and matches the code for the watchdog core (sensing, load switch, LED, UART, power‑off behaviour). All review findings are now corrected (§5) — the Q10 FET rating + 15 V gate Zener, the ignition direct‑feed, the battery decision (dropped / vehicle‑only with PA4 on the vehicle side), and the v2.3 fan/temp firmware. The design doc, BOM, connection list, and firmware are consistent and Gerber‑ready. For the breadboard bring‑up, none of this changes the bench steps: use a bench supply (correct polarity, so Q10/D10 are skipped anyway), confirm the ignition logic level with a meter, and the watchdog — now including the smart‑fan loop — comes up exactly as the firmware expects.
Related
- 03-Architecture-Hardware/watchdog-connections ·
03-Architecture-Hardware/watchdog-pcb-v3-design ·
03-Architecture-Hardware/watchdog-protoboard-bringup ·
04-Source-Code/firmware/blackpillrtkcode_v2/blackpillrtkcode_v2.ino(v2.2)