229 lines
15 KiB
Markdown
229 lines
15 KiB
Markdown
---
|
||
tags: [project-drogheda, hardware, watchdog, connections, review, firmware, verification]
|
||
project: Project Drogheda
|
||
author: Helgen CTO
|
||
date: 2026-06-22
|
||
status: Review — read before populating the protoboard or releasing Gerbers
|
||
reviews: watchdog-connections.xlsx (128-row from→to list)
|
||
against: 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.ino` v2.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 to `INPUT` so 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 the
|
||
`DIVIDER_RATIO 2.0` the code multiplies back, so 3.4–4.2 V → 1.7–2.1 V at the pin (no
|
||
clipping). Drives `BAT_CRITICAL 3.40 / BAT_RECOVERY 3.70` (sleep/wake).
|
||
- **PA4 5 V / vehicle‑present (✅, but Finding 3):** same ÷2; `v5v` compared to `V5V_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)==HIGH` with
|
||
`INPUT_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_LED` active‑high / `PIN_LED` active‑low ⇄ Q4 low‑side + onboard inverted.
|
||
**Consistent.**
|
||
- `ENABLE_PHLG_RELAY` default 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|connection list (xlsx)]] ·
|
||
[[03-Architecture-Hardware/watchdog-pcb-v3-design|v3 design (sub‑circuits)]] ·
|
||
[[03-Architecture-Hardware/watchdog-protoboard-bringup|protoboard bring‑up]] ·
|
||
`04-Source-Code/firmware/blackpillrtkcode_v2/blackpillrtkcode_v2.ino` (v2.2)
|