Drogheda/03-Architecture-Hardware/watchdog-pcb-v3-design.md

22 KiB
Raw Blame History

tags project author date status supersedes_section
project-drogheda
hardware
watchdog
pcb
thermal
fans
schematic
v3
Project Drogheda Helgen CTO 2026-06-21 Active — design for review; bench-validate before fab hardware-respec-and-pcb-brief.md §4 (watchdog carrier detail)

HBOX Watchdog Carrier PCB — v3.0 Design (Watchdog + Smart-Fan Thermal)

The production PCB for the STM32F411 watchdog, expanded to drive two extraction fans and monitor internal temperature/humidity. This is the schematic-capture spec: every sub-circuit, every value, every part, the pin map, the firmware deltas, and the layout/fab path. Pairs with: 03-Architecture-Hardware/watchdog-pcb-v3-bom · 03-Architecture-Hardware/watchdog-pcb-v3-kicad-guide · 04-Source-Code/firmware/blackpillrtkcode_v2/blackpillrtkcode_v2 · 03-Architecture-Hardware/watchdog-schematic.

Decisions driving this revision (2026-06-21, Leo):

# Decision Consequence
1 Scope = watchdog + thermal carrier Blackpill plugs on via 2×20 headers (reuse v2.1 firmware, no MCU bring-up). Mean Well SD-15B-05 and the battery stay external modules. Lowest-risk first board.
2 5 V fans Driven low-side (MOSFET PWM) + tach. ⚠ They load the same 5 V the modem bursts on — mitigated with a dedicated fan rail (see §0a).
3 I²C temp + humidity SHT40 (board ambient + RH) + TMP102 probe (battery/modem hot spot) on one I²C bus.
4 JLCPCB with assembly Parts chosen from JLC/LCSC stock; we output Gerbers + BOM + CPL. Footprints biased to JLC-placeable + hand-reworkable.

0. Read this first — two engineering caveats

0a. 5 V fans must NOT share the RTK stack rail

The Mean Well SD-15B-05 gives 5 V @ 3 A. The RTK+4G stack already peaks ~2–2.5 A on LTE-TX bursts — the brownout the whole redesign is fixing. Two 5 V fans add ~0.3–0.5 A plus inrush. Coincident worst case ≈ 2.8–3.0 A sits right on the supply limit, and fan inrush + a modem burst at the same instant is exactly the sag that drops the link. So the board gives the fans their own 5 V from a small 24→5 V buck tapped off the cabinet 24 V (which is already inside the HBOX). A 0 Ω jumper (JP1) lets you instead bridge fans to the main 5 V if you later upsize the supply — one board, both strategies. Do not power fans from the switched (load-switch) stack 5 V — fans must run when hot even while the stack is power-cycling.

0b. Fans + IP67 is a real tradeoff — own it

Moving air in/out of the box breaks the IP67 seal. A fan only helps if it exchanges HBOX/cabinet air with outside air; that path is an opening. The honest position for the v3 mechanical:

  • Ventilation drops the rating from IP67 → ~IP54/IP55 at best, with filtered, hooded, downward-facing louvers. In a salty, humid, dusty port that is a maintenance item (filters clog/corrode).
  • Keep every electronic mitigation we already have: conformal-coat the PCB (acrylic/urethane), keep a Gore pressure-vent for condensation, and treat the fans as assist, not the whole thermal solution. Conduction to the metal plate (hardware brief §2b) still does the heavy lifting; fans buy the last few °C.
  • The firmware runs the fans only when temperature demands it (closed loop, §7), minimising the hours the vents are actively pulling dirty air.

If ICAVE can accept IP54 with filter maintenance, fans are fine. If they require IP67, the answer is conduction + sunshade, not fans. This board supports both — populate or depopulate the fan section. Confirm the rating target with ICAVE.


1. What the close look at the watchdog found

The as-built watchdog (watchdog-schematic.md) + v2.1 firmware is sound logic on fragile hardware. Keep the brains, fix the body.

Keep (proven):

  • The high-side power gate concept (PA1 → stack 5 V), fail-safe OFF at boot via the gate pull-up. This is the heart of 4G/NTRIP recovery — don't change its behaviour, only its build quality.
  • Three sense dividers (battery PA0, 5 V PA4, ignition PA5) and the v2.1 recovery state machine (backoff + LIMP + NMEA-silence + IWDG + MCU-thermal).
  • USART2 (PA2/PA3) to the F9P UART1 for NMEA read + UBX rate.

Fix (the liabilities):

Liability Root issue v3 board fix
2N3904 + IRF9540N + pull-up, hand-wired vibration intermittents; IRF9540N is not logic-level (marginal gate drive from a 5 V swing) SMD discrete high-side switch (AO3401A logic-level P-FET + MMBT3904) + PPTC overcurrent; optional eFuse upgrade
LED + dividers on Dupont mechanical all on-board, 0603, conformal-coatable
1.5 kΩ "????" mystery R undocumented resolved on this schematic (it was the LED series R; dividers are 10k/10k — see §6)
MCU temp only heat casualties are the 18650/modem, not the die external I²C sensors at the hot spot (§5)
No thermal actuation firmware can derate but can't cool 2× fan drivers + closed-loop control (§4, §7)
No SWD/header bring-out can't debug a sealed unit SWD + USB + reserve-USART1 headers (§6)

2. Expanded STM32F411 pin map (v2.1 pins kept; 6 added)

                       STM32F411 "Blackpill" (mounted on 2×20 headers)
  ── existing (firmware v2.1, unchanged) ───────────────────────────────────
  PA0  BAT_SENSE     ADC1_IN0   18650 ÷2 divider
  PA1  PWR_CTRL      GPIO out   → RTK-stack load switch enable (HIGH = ON)
  PA2  GNSS_TX       USART2_TX  → simpleRTK2B UART1 RX (UBX rate cmds)
  PA3  GNSS_RX       USART2_RX  ← simpleRTK2B UART1 TX (NMEA read)
  PA4  5V_SENSE      ADC1_IN4   stack 5 V ÷2 divider (vehicle-power present)
  PA5  IGN_SENSE     GPIO in    ignition via DFR1015 (INPUT_PULLDOWN)
  PB0  EXT_LED       GPIO out   external status LED (low-side MOSFET)
  PC13 LED           GPIO out   onboard LED (active-LOW)
  ── NEW for v3 (fans + temperature) ───────────────────────────────────────
  PA6  FAN1_PWM      TIM3_CH1   25 kHz PWM → fan-1 low-side gate
  PA7  FAN2_PWM      TIM3_CH2   25 kHz PWM → fan-2 low-side gate
  PB10 FAN1_TACH     EXTI       fan-1 tach (open-collector, 10k pull-up to 3V3)
  PB12 FAN2_TACH     EXTI       fan-2 tach (open-collector, 10k pull-up to 3V3)
  PB6  I2C1_SCL      I2C1       SHT40 + TMP102 (4.7k pull-ups to 3V3)
  PB7  I2C1_SDA      I2C1       SHT40 + TMP102
  ── reserved (do not populate now; future in-band $PHLG telemetry relay) ───
  PA9  USART1_TX     header     → future: inject $PHLG into modem uplink
  PA10 USART1_RX     header     ← future: F9P UART2 NMEA tap
  PA13 SWDIO / PA14 SWCLK       SWD debug header
  PA11 USB_DM / PA12 USB_DP     Blackpill micro-USB = STREAM log capture

No conflicts: TIM3_CH1/CH2 (PA6/PA7) do fan PWM; PB0 (TIM3_CH3) stays plain-GPIO LED. The reserved USART1 pair future-proofs the board for the [[03-Architecture-Hardware/watchdog-health-telemetry|$PHLG health-in-server]] upgrade without a respin.


3. Block diagram

 Cabinet 24 V  ──GX16-5(pin1/2)──►  P1 [24V_IN]
   │                                  ├─► reverse-pol P-FET (Q10) + TVS (D10, SMBJ33A) ─► 24V rail
   │                                  │        ├──────────────────────────────► FAN buck in
   │   (ignition 24V ─GX16 pin3─► DFR1015 ext module ─► P1[IGN] ─► PA5 divider)
   │
 Mean Well SD-15B-05  (EXTERNAL, 24→5 V 3 A)  ──►  P2 [5V_IN]  ─► MAIN 5V rail
      MAIN 5V ─► Blackpill 5V pin (onboard LDO → 3V3)
      MAIN 5V ─► high-side load switch (Q1 AO3401A / U1 eFuse opt) ─EN◄PA1─► SW_5V ─► P3 simpleRTK2B + 4G
      MAIN 5V ─► PA4 sense divider
 18650 / PowerBoost (EXTERNAL) ──► P4 [BAT+ , BAT_SENSE] ─► PA0 divider

 FAN rail:  24V ─► U2 buck (MP1584EN) ─► 5V_FAN (JP1: alt-bridge to MAIN 5V)
      5V_FAN ─┬─► Fan1 (+) ───┐                 ┌─── Fan1 tach ─10k─► PB10
              │   Fan1 (−) ─ Q2 (AO3400) ◄PWM PA6 │   (D2 SS34 flyback ∥ fan)
              └─► Fan2 (+) ───┘                 └─── Fan2 tach ─10k─► PB12
                  Fan2 (−) ─ Q3 (AO3400) ◄PWM PA7

 I²C1 (PB6/7) ─┬─ SHT40  (U3, 0x44)  board ambient temp + RH
               └─ TMP102 (U4, 0x48)  on P5 pigtail → battery/modem hot spot

 PB0 ─► Q4 (AO3400) ─► status LED (D1)        SWD/USB/USART1 headers (H1/H2/H3)

4. Sub-circuit detail (capture this exactly)

4.1 24 V input protection (light — the cabinet does the heavy lifting)

The cabinet already has the Phoenix SPD + breaker, so the board needs only:

  • Q10 reverse-polarity P-MOSFET in the 24 V high side (e.g., AO3401A if fan+buck draw <few-hundred mA; for margin use a bigger P-FET like SI2305 — buck input current at 24 V is small, ~0.2 A, so AO3401A is fine).
  • D10 TVS SMBJ33A (33 V standoff) 24 V→GND, plus C10 100 µF/50 V electrolytic + C11 100 nF bulk/decoupling.

4.2 Dedicated fan 5 V buck (U2) — see caveat §0a

  • U2 = MP1584EN (SOP-8, 4.5–28 V in, up to 3 A) set to 5.0 V out.
    • FB divider for 5 V: R20 = 100 kΩ top, R21 = 19.1 kΩ bottom (Vout = 0.8 V·(1+R20/R21) ≈ 5.0 V — verify against the MP1584 datasheet FB = 0.8 V).
    • L2 = 10 µH (≥1 A sat), C22 = 22 µF in, C23 = 22 µF out, freewheel Schottky per datasheet (SS34), EN tied to 24V-rail-derived enable.
  • JP1: 0 Ω / solder-jumper. Open = fans on U2 (recommended). Closed = fans bridged to MAIN 5 V (only if SD-15B-05 is upsized; never both).
  • Keep U2's switching node small; keep this buck away from the GNSS antenna feed (RF cleanliness — see §8).

Simpler alternative if you'd rather not lay out a buck on the first spin: drop U2, close JP1, and upsize the external 5 V supply to a 5 V/5 A unit so the rail has true headroom. The board supports it; it's a BOM/jumper choice, not a respin.

4.3 RTK-stack high-side load switch (Q1 trio — proven, SMD)

Keeps the as-built topology (so firmware PA1 logic is unchanged) but in solid, sourceable SMD, plus a resettable fuse for the missing current limit:

 MAIN 5V ──[F1 PPTC 3A]──┬───────────────[R2 10k]──┐
                          │                          │
            Q1 AO3401A  Source                      Gate ── Q5 MMBT3904 Collector
            (P-MOS)       │                          │
                        Drain ──► SW_5V ─► P3 stack   Q5 Emitter ── GND
                                                       │
                PA1 ──[R1 1k]── Q5 Base ───────────────┘
  • PA1 HIGH → MMBT3904 on → P-FET gate low → SW_5V ON. PA1 LOW → R2 holds gate high → OFF (fail-safe at boot). Identical to as-built.
  • AO3401A is logic-level and switches fully from the 5 V gate swing (the old IRF9540N was not — a real latent bug we're removing).
  • F1 PPTC (3 A hold / ~6 A trip, e.g., MF-MSMF300) gives overcurrent protection without a hard-to-source eFuse, and cannot permanently latch a healthy unit out (it self-resets) — satisfies the "never black-hole" invariant.
  • C3 = 47 µF bulk on SW_5V (modem-burst reservoir).
  • Optional upgrade footprint U1: pin-compatible-ish current-limit load switch / eFuse (e.g., AP2553W6-7 SOT-23-6, EN active-high, FLAGn). Lay the footprint and the discrete; populate one. Verify LCSC stock at order; default = discrete.

4.4 Fan drivers ×2 (low-side PWM + tach) — Q2/Q3

Per fan (identical for fan-1 and fan-2):

 5V_FAN ──► Fan(+)                         Fan tach ──[R_t 1k]──┬──► PBxx (EXTI)
            Fan(−) ──┬──► Q2/Q3 Drain                          │
   D2/D3 SS34 ∥ fan  │     (AO3400A, N-MOS)              [R 10k pull-up → 3V3]
   (cathode→5V_FAN)  │     Source ── GND
                  PWM PAx ─[Rg 100Ω]─ Gate ──[Rgs 100k → GND]
  • Q2/Q3 = AO3400A logic-level N-MOSFET (SOT-23): full-on from 3.3 V PWM, 5.7 A / 30 V — vast margin over a <0.5 A fan.
  • D2/D3 = SS34 Schottky flyback across each fan (motor is inductive — protects the FET at PWM turn-off). Cathode to 5V_FAN, anode to drain.
  • Rg 100 Ω gate series (tames edges/EMI), Rgs 100 kΩ gate→GND pull-down = fans OFF until the MCU drives PWM (fail-safe; consistent with the ethos — if the MCU is dead the stack is also unpowered, so there's nothing to cool).
  • Tach: 3-wire fan's open-collector tach → 10 kΩ pull-up to 3.3 V + 1 kΩ series into the EXTI pin. 2 pulses/rev → MCU computes RPM and flags a stalled/failed fan. Use 3-wire (or 4-wire) fans so tach exists. PWM is on the ground leg, so on a 3-wire fan the tach is valid only while PWM is high — firmware samples RPM during a brief 100 % window (§7). (4-wire fans avoid this entirely; if you can source 5 V 4-wire, drive their PWM pin from PAx via a 2N7002 open-drain and leave power always-on — cleaner tach. 5 V 4-wire fans are rarer, hence 3-wire default.)

4.5 Status LED (unchanged topology, SMD)

3V3 ─[R3 1k]─►|D1 LED|─► Q4 (AO3400) drain; source→GND; PB0 ─ gate, [10k → GND] pull-down. (Resolves the "1.5 kΩ ????" — it was this series resistor; 1 kΩ is the clean value for a 3.3 V drive.)

4.6 Sense conditioning (filtered; protect the ignition input)

Net Divider RC filter Protection
PA0 BAT (3.0–4.2 V) R5 10k / R6 10k (÷2) C5 100 nF —
PA4 5V (≈5 V) R7 10k / R8 10k (÷2) C7 100 nF —
PA5 IGN (from DFR1015) R9 10k / R10 10k (÷2) C9 100 nF D5 BAT54 clamp to 3V3 + 100 Ω series; the DFR1015 already bucks 24 V→logic, divider+clamp is belt-and-suspenders
ADC stays ≤3.3 V with margin (verified in firmware-review). Firmware
DIVIDER_RATIO = 2.0 matches the 10k/10k legs.

5. Temperature + humidity sensing (I²C1)

Ref Part Addr Where Why
U3 SHT40-AD1B-R2 (DFN-4) 0x44 on-board, near an air-path edge board-ambient temp + RH (RH flags condensation risk — IP/coastal)
U4 TMP102AIDRLR (SOT-563) 0x48 (ADD0→GND) on P5 pigtail to the 18650/modem the actual heat casualty spot — the data the thermal RCA needs
  • One bus, 4.7 kΩ pull-ups (R30/R31) on SCL/SDA to 3.3 V. Both 3.3 V parts.
  • 100 nF decoupling each. SHT40 wants a small keep-out/slot so it reads air, not board.
  • Firmware reads all three temps (SHT40, TMP102, plus the existing MCU-internal) → triangulated thermal picture and the fan-control input (§7).

6. Connectors & headers (all keyed/locking)

Ref Connector Pins Net
P1 GX16-5 (HBOX↔cabinet, keep) 5 24V_IN, GND, IGN, (spare ×2)
P2 Molex Micro-Fit 3.0, 2-pos 2 5V_IN from SD-15B-05, GND
P3 JST-XH 4-pos 4 SW_5V, GND, GNSS_TX(PA2), GNSS_RX(PA3) → simpleRTK2B
P4 JST-XH 2-pos 2 BAT+ (to PA0 divider), GND (18650/PowerBoost)
P5 JST-XH 4-pos 4 3V3, GND, SDA, SCL → TMP102 probe pigtail
P6 JST-XH 4-pos 4 5V_FAN, Fan1−(PWM), GND, Tach1 → fan 1
P7 JST-XH 4-pos 4 5V_FAN, Fan2−(PWM), GND, Tach2 → fan 2
P8 JST-XH 2-pos 2 EXT_LED+, EXT_LED− (panel LED)
H1 1×4 0.1″ 4 SWD: 3V3, SWDIO, SWCLK, GND
H2 (Blackpill micro-USB) — STREAM log capture / flashing
H3 1×3 0.1″ DNP 3 reserve USART1: PA9, PA10, GND (future $PHLG)
— 2× 2×20 female headers 40 Blackpill seats here

Pin-1 / keying: silkscreen pin-1 arrows + the GX16 keyway; JST-XH is already keyed. Label every connector net on silk (DFM/serviceability requirement).


7. Firmware deltas (spec only — bench-test before any field flash)

The v2.1 .ino changes are small and additive (the ethos: bench first; the sandbox can't build STM32). New globals + functions, no state-machine surgery.

  1. Pins: add PIN_FAN1_PWM PA6, PIN_FAN2_PWM PA7, PIN_FAN1_TACH PB10, PIN_FAN2_TACH PB12; init TIM3 CH1/CH2 PWM at 25 kHz; attach EXTI counters on the tach pins.
  2. I²C temps: Wire.begin() on PB6/PB7; read SHT40 (0x44, temp+RH) and TMP102 (0x48). Add tAirC, rhPct, tBatC to telemetry. Keep MCU-internal as cross-check.
  3. Closed-loop fan curve (input = max(tAirC, tBatC)):
    • < 45 °C → fans off (0 % — minimise vent hours / dust ingress).
    • 45–70 °C → linear 30 → 100 % PWM.
    • ≥ 70 °C → 100 %.
    • Hysteresis 3 °C on the off→on edge (no chatter). This replaces nothing — the existing THERM_WARN_C 75 derate-to-30 s still stands as the last resort.
  4. Tach fault: once/30 s, command a fan to 100 % for ~300 ms, count tach edges, compute RPM. 0 RPM while commanded > 0 → latch FAN_FAULT, log EVT, raise it in telemetry. A dead fan in a hot box must be visible, not silent.
  5. Telemetry: extend the v2.1 TLM/$PHLG record with tair,rh,tbat,fan1_rpm,fan2_rpm,fan_pwm,fan_fault. These are exactly the fields the $PHLG-to-server upgrade will carry — capture them on-unit now via the STREAM log.
  6. IWDG-safe: fan/tach/I²C work is non-blocking; keep petting the dog. I²C read uses a short timeout so a stuck sensor can't hang the loop.

Pin map and control law live here; the implementation lands in blackpillrtkcode_v2.ino after bench validation on the prototype board.


8. Layout, stackup & DFM (for a relative beginner — the rules that matter)

  • Stackup: 2-layer is acceptable for this mostly-DC/low-speed board and is cheaper; 4-layer (GND + power inner planes) is better for the GNSS RF and the buck noise — recommended if budget allows. Either way: solid ground pour on a full layer.
  • Star-ground the power: fan return currents (PWM, pulsed) and the modem-burst return must not share a thin trace with the ADC/sensor grounds. Bring power grounds to the pour at one stitching region; keep sensor/MCU ground quiet.
  • Buck (U2) discipline: tiny switch-node copper, input cap right at the IC, ground the cap to the pour with vias. Keep U2 and the fan-PWM traces away from the GNSS antenna pigtail / P3 — switcher harmonics degrade the ZED-F9P front-end (= the watchdog's own "link health" signal).
  • Trace widths (1 oz Cu): 24 V_IN and 5 V rails ≥ 0.5 mm (fan + stack current); SW_5V to P3 ≥ 0.8 mm (modem bursts); signals 0.25 mm fine.
  • Thermal: copper pour + vias under Q1/Q10/U2 tabs. Mounting holes positioned to let the board bolt to the cabinet metal plate (conduction path, hardware brief §2b).
  • Creepage: nothing >24 V here, so standard clearances are ample; still keep the 24 V input section tidy.
  • Conformal coat after assembly (mask connectors/headers/SHT40 slot) — humidity + vibration joint stability.
  • JLC specifics: 0603 passives (hand-reworkable and machine-placeable), SOT-23 actives, 1.6 mm FR-4, HASL or ENIG. Add fiducials if you want tight placement. Put the JLC order number on silk (free, helps reorders).

9. Bring-up & test plan (prototype first)

  1. Bare-board power: 24 V in, confirm 5V_FAN = 5.0 V, reverse-polarity FET blocks a flipped input, TVS not hot.
  2. Load switch: toggle PA1 → SW_5V on/off; confirm OFF at reset; PPTC holds the measured stack current, trips on a deliberate short.
  3. Fans: ramp PA6/PA7 PWM 0→100 %, scope the gate + fan node, confirm flyback, read tach RPM vs PWM; pull a fan → confirm FAN_FAULT.
  4. Sensors: I²C scan finds 0x44 + 0x48; heat the TMP102 probe → fan ramps per curve.
  5. Power budget (the §0a check): with JP1 open, scope MAIN 5 V during an LTE burst and a fan ramp simultaneously — confirm the stack rail no longer sags. Repeat with JP1 closed to demonstrate the coupling you're avoiding.
  6. Full stack: mount Blackpill + F9P + 4G, run v2.1+fan firmware, watch the STREAM log for temps/RPM, confirm RTK recovery behaviour is unchanged.
  7. Only then: pilot 2–3 boards in real cabinets before the fleet (mirrors the August-30-unit ramp).

10. Open questions / decisions

  • IP rating target with ICAVE: IP67 (no vents → conduction only) vs IP54/55 (filtered louvers + fans). Determines whether the fan section is populated.
  • Fan choice: 5 V 3-wire (tach) confirmed? Size (40/50/60 mm) + measured static-pressure need through the chosen duct/filter. Source 2–3 candidates.
  • U2 buck vs upsize supply (§4.2): lay the buck (default) or go 5 V/5 A external + JP1-closed. Recommend laying the buck for rail isolation.
  • Battery: still drop / LiFePO4 / supercap (hardware brief §6.1). Board only exposes P4 + sense; charger stays external until decided.
  • Confirm the DFR1015 stays an external module (P1 IGN) or folds on-board later.
  • Load switch: discrete (default, sourceable) vs eFuse U1 — verify AP2553 LCSC stock at order; otherwise ship discrete.