Electrical/PCB: - LTC4040 Block B sized to the 12 Ah 1S4P pack (RPROG 825R -> 2.42 A ~ C/5, RS 8 mR -> 3.1 A input limit, PFI 4.60 V, backup 4.79 V, charge 4.00 V Li-ion via VSYS-referenced straps) + Block E cutoff (P11) + Block F PA4->VEH5V re-tap + Block H fail-safe Modo-B bypass (K1 normally-closed relay) + Block I NTC->PB1. - CARRIER-BOARD conversion: simpleRTK2B Pro on UNO-pattern female headers (MOD1; D0/D1=UART1, D2=RX2, D8=TX2, IOREF=3V3, 5V=SW_5V) + 4G NTRIP Master on on-board XBee socket (J7/J8; VCC=3V3_MODEM via new Block K MP1584 buck off SW_5V - the HP XBee socket is 3.3 V not 5 V). Board 120x100, placement + GND pour + DRC baselines. Custom symbols: LTC4040EUFD, AO4406A, SimpleRTK2B_Pro_Socket. - Fixed duplicated U2, stale no-connects, A4->A3 sheet; ERC 0 errors. Docs: - Canonical electrical-design-state + production delta (Block B values table, 5b/5c/5d/5e) + design/rationale/connections/BOM swept to the Jul-2 assumptions ledger (Conexiones-por-Bloque xlsx). - Guia de Conexion Protoboard: LaTeX source now maintained in-repo -> v2.1 PDF. - CircuiTikZ sheet + wiring Beamer: block 11 (NTC->PB1) + guinda ignition legend. - Client decks: Avance v1.1 (overclaims fixed) + RCA v1.1 (2-jul addendum). Repo hygiene: - .gitignore: live rtk-config (SIM/APN/NTRIP creds) now ignored and REMOVED from tracking (NOTE: rotate those credentials - they exist in prior commits); KiCad .bak/snapshots/.history, LaTeX intermediates, Office locks ignored+purged. - Removed rogue .history gitlinks that broke git status.
32 KiB
| tags | project | author | date | status | supersedes_section | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
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)
⚠️ Current electrical state (2026-06-24): see 03-Architecture-Hardware/watchdog-electrical-design-state (CANONICAL). Since this doc, the DFR1015 folded on-board (GX16 pin 3 = raw ignition), the battery was re-added (LTC4040 + NTC temp-qualified charging on the 1S4P pack), and reset + 4-LED gauge + power-cutoff were added. Where this doc disagrees with the canonical state, the canonical state wins. (Also: 1 fan, not "two" — see the 1-fan update.)
2026-07-02: LTC4040 sized to the 12 Ah pack — values in 03-Architecture-Hardware/watchdog-production-schematic-delta §4; capture + layout kickoff in progress.
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 fan ×1 | One extraction fan, low-side (MOSFET PWM) + tach. ⚠ Loads the same 5 V the modem bursts on — mitigated with a dedicated fan rail (§0a). Needs a passive filtered inlet to pull air through, and has no redundancy — a fan failure falls back to conduction + thermal derate (tach-fault flags it). |
| 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. |
| 5 | Live telemetry ($PHLG): bench-test first, NOT built into v3 (2026-06-22) | The 4G modem keeps its proven home on the F9P XBee socket = UART2; there is no spare UART to tap (see §2a). v3 ships health on the USB STREAM log (already works). PA9/PA10 header is reserved/DNP only. The forwarding question is settled by an isolated bench experiment (§7a), not by a board change. |
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. One 5 V fan adds ~0.15–0.25 A plus inrush. Coincident worst case ≈ 2.7 A still nears 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 fan its 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 the fan to the main 5 V — with a single ~0.2 A fan that's more defensible than with two, but the dedicated rail stays the safe default. Do not power the fan from the switched (load-switch) stack 5 V — it 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 | 1 fan driver + closed-loop control (§4, §7) |
| No SWD/header bring-out | can't debug a sealed unit | USB + reserve-USART1 headers (§6). H1 SWD DROPPED 2026-06-25 (flash/log via USB-C; optional DNP 4-pad) |
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 (fan + temperature) ────────────────────────────────────────
PA6 FAN_PWM TIM3_CH1 25 kHz PWM → fan low-side gate
PB10 FAN_TACH EXTI fan tach (open-collector, 10k pull-up to 3V3)
PA7 (spare) TIM3_CH2 reserved — 2nd fan PWM if ever needed
PB12 (spare) EXTI reserved — 2nd fan tach if ever needed
PB6 I2C1_SCL I2C1 SHT40 + TMP102 (4.7k pull-ups to 3V3)
PB7 I2C1_SDA I2C1 SHT40 + TMP102
── NEW [2026-07-02] (PROD: battery backup + Modo-B bypass + hot-spot NTC) ──
PB1 NTC_TEMP ADC1_IN9 hot-spot NTC divider (3V3–10k 1%–NTC 10k–GND + 100 nF) — block 11
PB3 CHRG_STAT GPIO in LTC4040 CHRG open-drain, 100k↑3V3 (LOW = charging)
PB4 CHRG_FAULT GPIO in LTC4040 FAULT open-drain, 100k↑3V3 (LOW = NTC/bad-battery fault)
PB5 BYP_CTRL GPIO out K1 bypass-relay driver via Q6 (HIGH = MCU in-line, §2c)
── 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 — H1 DROPPED 2026-06-25 (USB-C; opt. DNP 4-pad)
PA11 USB_DM / PA12 USB_DP Blackpill micro-USB = STREAM log capture
No conflicts: TIM3_CH1 (PA6) does fan PWM; PB0 (TIM3_CH3) stays plain-GPIO
LED. The reserved USART1 pair (H3) future-proofs the board for the
[[03-Architecture-Hardware/watchdog-health-telemetry|$PHLG health-in-server]] upgrade
without a respin — but in v3 it is left unpopulated; no relay is wired (see §2a + the
decision row above). PA10 caveat: PA10 is USART1-RX and a known Blackpill DFU-entry
pin — a load/float here can block flash mode. Keep H3 unpopulated, or fit a ~22 kΩ
pull-up on PA10 to 3V3, so this board never inherits the flaky-flashing gremlin.
2a. WeAct Black Pill header pinout — what lands on J1/J2
The module mounts on two 1×20 headers. From the WeAct MiniF4x1Cx V3.0 schematic
(MiniF4x1Cx_V30 SchDoc.pdf, headers P1/P2), the physical pin order is (pin 1 = VBAT end):
| Pin | J1 = WeAct P1 | carrier net | J2 = WeAct P2 | carrier net |
|---|---|---|---|---|
| 1 | VBAT | — | PB12 | — (spare) |
| 2 | PC13 | — (onboard LED) | PB13 | — |
| 3 | PC14 | — | PB14 | — |
| 4 | PC15 | — | PB15 | — |
| 5 | NRST | — | PA8 | — |
| 6 | PA0 | BAT_SENSE | PA9 | USART1_TX (reserve) |
| 7 | PA1 | PWR_CTRL | PA10 | USART1_RX (reserve, +Rdfu 22k) |
| 8 | PA2 | GNSS_TX | PA11 | — (USB) |
| 9 | PA3 | GNSS_RX | PA12 | — (USB) |
| 10 | PA4 | 5V_SENSE | PA15 | — |
| 11 | PA5 | IGN_SENSE | PB3 | CHRG_STAT [2026-07-02] |
| 12 | PA6 | FAN_PWM | PB4 | CHRG_FAULT [2026-07-02] |
| 13 | PA7 | — (spare) | PB5 | BYP_CTRL [2026-07-02] |
| 14 | PB0 | EXT_LED | PB6 | I2C_SCL |
| 15 | PB1 | NTC_TEMP [2026-07-02] | PB7 | I2C_SDA |
| 16 | PB2 | — (BOOT1, pulled low on-module) | PB8 | — |
| 17 | PB10 | FAN_TACH | PB9 | — |
| 18 | 3V3 | 3V3 (LDO out) | 5V | MAIN5V (in) |
| 19 | GND | GND | GND | GND |
| 20 | 5V | MAIN5V (in) | 3V3 | 3V3 (LDO out) |
Consequences (caught from the real pinout):
- SWD (PA13/PA14) is NOT on the 2×20 — it's the module's separate 4-pin SWD header. → H1 dropped; flash/debug via the Blackpill USB-C.
- 5V pin = power IN, 3V3 pin = LDO OUT.
MAIN5Vfeeds the 5V pin; the module's 3V3 LDO output is the carrier3V3rail (sensors + I²C/tach pull-ups). - BOOT1 (PB2) is pulled low on the module — no carrier action needed.
- USB (PA11/PA12) is on the header but unused (we flash via the USB-C connector).
2b. Why there is no spare UART (the telemetry reality)
The simpleRTK2B Pro breaks out both F9P UARTs, but only one is free:
| F9P port | Header pins | Used by | Free? |
|---|---|---|---|
| UART1 | TX1 / RX1 | watchdog (NMEA read + UBX rate) — PA2/PA3 | taken |
| UART2 | TX2 / RX2 and the XBee socket | 4G NTRIP Master (server uplink) | no — shared bus |
TX2 = F9P-UART2-TX = the modem's DIN (the wire the modem reads and forwards to the
server). The F9P already drives it, so the watchdog can't simply "connect a second wire" to
send $PHLG — that's two transmitters on one line. Getting health to the server therefore
needs a relay (interpose the MCU between F9P-UART2 and the modem), which is a deliberate
architecture change deferred out of v3. To learn whether it's even possible, run the
isolated bench experiment in §7a — it touches no PCB.
2c. Production additions [2026-07-02] — Block H (fail-safe uplink bypass) + Block I (NTC→PB1)
Two sub-circuits added on kicad/hbox-watchdog-v3-PROD.kicad_sch; full specs in
03-Architecture-Hardware/watchdog-production-schematic-delta §5b / §5c:
- Block H — K1 normally-closed SPDT signal-relay bypass on the Modo-B uplink. The §2b relay
is now real in Modo B: the watchdog sits in-line on the uplink (F9P TX2 → 4G DIN) to inject
$PHLG; the RTCM3 downlink stays direct. K1's NC contacts route F9P TX2 → 4G DIN with the coil de-energized — the MCU must actively energize (PB5BYP_CTRL→ Q6) to insert itself. Chosen over an analog mux because a mux dies with the 3V3 rail; relay contacts keep F9P TX2 → 4G DIN even with the Blackpill physically absent (extends invariants #2/#3 to the diagnostic path). - Block I — NTC→PB1 hot-spot temperature divider (block 11). 3V3 – 10 k 1 % – NTC 10 k – GND into PB1 (ADC1_IN9) + 100 nF; NTC placed at the battery/modem hot spot. The proto's temperature path (no SHT40 in hand); the PCB keeps U3/U4 (I²C) and this channel.
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 ───► Fan (+) ┌─── Fan tach ─10k─► PB10
Fan (−) ─ Q2 (AO3400) ◄PWM PA6 ┘ (D2 SS34 flyback ∥ fan)
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) USB/USART1 headers (H2/H3; H1 SWD DROPPED 2026-06-25)
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. ⚠ Corrected (review Finding 1): AO3401A (±12 V Vgs) and SI2305 (−20 V Vds) are NOT rated for a 24 V rail and would fail. Use Vds ≥ −40 V, Vgs ≥ ±20 V — e.g. IRFR5305 (−55 V/±20 V, DPAK; verify LCSC stock); the proto can use a TO-220 IRF9540 (−100 V/±20 V). Add a gate→source Zener clamp DzG ≈ 15 V (A→Q10.G, K→Q10.S) with Rrp 10 k gate→GND: the gate sits ~9 V, Vgs ≈ −15 V (in rating, fully on). Buck input current is ~0.2 A — the part is sized by rating, not current.
- 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 driver ×1 (low-side PWM + tach) — Q2
Single extraction fan:
5V_FAN ──► Fan(+) Fan tach ──[R_t 1k]──┬──► PB10 (EXTI)
Fan(−) ──┬──► Q2 Drain │
D2 SS34 ∥ fan │ (AO3400A, N-MOS) [R 10k pull-up → 3V3]
(cathode→5V_FAN) │ Source ── GND
PWM PAx ─[Rg 100Ω]─ Gate ──[Rgs 100k → GND]
- Q2 = 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 = SS34 Schottky flyback across the 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) | none — direct | C9 100 nF | Corrected (Finding 2): Rig 100 Ω series + D5 BAT54 clamp to 3V3, NO ÷2. PA5 is a digital input (INPUT_PULLDOWN); the DFR1015 logic level reaches PA5 undivided (a ÷2 would drop it below VIH). Internal pulldown = LOW when ignition off; clamp caps ≤3.3 V. |
| 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, Fan−(PWM), GND, Tach → fan |
| P8 | JST-XH 2-pos | 2 | EXT_LED+, EXT_LED− (panel LED) |
| H1 | 1×4 0.1″ — DROPPED 2026-06-25 | 4 | SWD: 3V3, SWDIO, SWCLK, GND — optional DNP 4-pad only (flash/debug via Blackpill USB-C) |
| 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.
- Pins: add
PIN_FAN_PWM PA6,PIN_FAN_TACH PB10(PA7/PB12 stay spare); init TIM3 CH1 PWM at 25 kHz; attach an EXTI counter on the tach pin. - I²C temps:
Wire.begin()on PB6/PB7; read SHT40 (0x44, temp+RH) and TMP102 (0x48). AddtAirC,rhPct,tBatCto telemetry. Keep MCU-internal as cross-check. - 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 75derate-to-30 s still stands as the last resort.
- Tach fault: once/30 s, command a fan to 100 % for ~300 ms, count tach edges,
compute RPM.
0 RPM while commanded > 0→ latchFAN_FAULT, logEVT, raise it in telemetry. A dead fan in a hot box must be visible, not silent. - Telemetry (on-unit only in v3): extend the v2.1
TLMrecord withtair,rh,tbat,fan_rpm,fan_pwm,fan_fault, captured to the USB STREAM log. These are the same fields a future$PHLG-to-server sentence would carry — but v3 does NOT push them live to the server (no UART relay; see §2a + decision row 5). Live telemetry is gated on the bench experiment below. - 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; implemented in v2.3 (blackpillrtkcode_v2.ino) —
closed-loop fan + I²C SHT40/TMP102 + tach fault, with MCU-temp fallback. Bench-test before
any field flash (the sandbox can't build STM32; the logic was host-verified).
7a. The one bench experiment that decides live telemetry (no PCB change)
✅ RESULT — 2026-06-22: PASS (no extra hardware needed). Enabled
$PUBX(a u-blox proprietary$P…talker — same class + checksum format as$PHLG) on the F9P UART2 and watched the serverudp/5010capture:$PUBX,00,…arrives end-to-end, intact, alongside GGA/RMC. → The 4G NTRIP Master forwards proprietary$P…sentences, so$PHLGhealth-in-server is confirmed viable. No XBee-breakout test needed. Remaining work = the UART2 relay (interpose the watchdog to inject$PHLG) + backend parser — a deliberate later board, still out of v3 scope.Incidental (flagged for GNSS follow-up): the same capture caught two live units — bench H0014 (Querétaro) at SPS (GGA quality 1), RSSI −93, and field H0017 (Veracruz/ICAVE) at DGPS (quality 2, RMC mode
D, diff base id 0133), RSSI −51. Per Leo the bench is in a basement (poor sky + weak cellular) — which alone explains the bench SPS, since RTK fix needs open sky (carrier-phase) regardless of corrections/config. But note H0017 has good sky+signal and still only reaches DGPS, not RTK (4/5) → the corrections pipeline (free rtk2go caster + RAM-only F9P config) is a separate ceiling from antenna placement. One open-sky test with a proper caster + FLASH-saved config separates the two. (Reinforces the v2.1 SPS-thrash guard: a healthy basement/field unit may legitimately sit at SPS/DGPS — do not power-cycle it.)
Settles "does the 4G NTRIP Master forward a proprietary $P… sentence?" by isolating the
modem — the F9P is not involved, so there's no bus collision:
- Remove the 4G NTRIP Master from the F9P XBee socket; mount it on a bench/XBee adapter with 3.3 V power, the SIM, and the LTE antenna.
- Wire Blackpill PA9 (USART1 TX) → modem DIN (the
TX2/F9P-UART2-TX net in the socket) and modem DOUT → Blackpill PA10 (RX) or a USB-UART so a PC can watch it. - Match the modem's UART baud (ArduSimple default 115200, 3.3 V). Let it register.
- Emit
$PHLG,2.1,RUN,LIMP,1,12,34192,4.01,5.02,63,71,2,1,420,IWDG*CS\r\nand watch the servertcpdump.- Appears → modem forwards proprietary sentences →
$PHLGis viable → then plan a relay-capable board. - Doesn't → modem whitelists talkers → fall back to a
$GPTXT,HLT,…subtype (special-cased by field 1 so it never collides with the cell-id parse).
- Appears → modem forwards proprietary sentences →
Either way, v3 ships unchanged — this experiment only informs a later decision.
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)
- Bare-board power: 24 V in, confirm 5V_FAN = 5.0 V, reverse-polarity FET blocks a flipped input, TVS not hot.
- Load switch: toggle PA1 → SW_5V on/off; confirm OFF at reset; PPTC holds the measured stack current, trips on a deliberate short.
- Fan: ramp PA6 PWM 0→100 %, scope the gate + fan node, confirm flyback,
read tach RPM vs PWM; pull the fan → confirm
FAN_FAULT. - Sensors: I²C scan finds 0x44 + 0x48; heat the TMP102 probe → fan ramps per curve.
- 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.
- Full stack: mount Blackpill + F9P + 4G, run v2.1+fan firmware, watch the STREAM log for temps/RPM, confirm RTK recovery behaviour is unchanged.
- 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 (×1): 5 V 3-wire (tach), size (40/50/60 mm), + a filtered passive inlet so the single extraction fan can pull air through. 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 — RESOLVED (Finding 3): default = dropped (vehicle-powered only) — removes the worst thermal/safety liability and makes the connection list correct as-is (MAIN5V = SD-15B-05 powers the MCU; PA4 senses the vehicle-side 5 V; P4 = sense-only, battery DNP). If ICAVE needs parked tracking, fit LiFePO4/supercap on P4 and move the PA4 sense tap to the SD-15B-05/P2 (vehicle) node, not the battery-backed rail.
Confirm the DFR1015 stays external or folds on-board→ RESOLVED 2026-06-24: folds ON-BOARD. GX16 pin 3 now carries raw machine ignition (12–24 V) into the on-board DFR1015 → Rig 100 Ω → D5 BAT54 clamp 3V3 → PA5 (digital, no divider).- Load switch: discrete (default, sourceable) vs eFuse U1 — verify AP2553 LCSC stock at order; otherwise ship discrete.
Related
- CLAUDE · 03-Architecture-Hardware/watchdog-schematic · 03-Architecture-Hardware/hardware-respec-and-pcb-brief · 03-Architecture-Hardware/watchdog-health-telemetry · 03-Architecture-Hardware/BOM-master · 03-Architecture-Hardware/watchdog-pcb-v3-bom · 03-Architecture-Hardware/watchdog-pcb-v3-kicad-guide