Repository navigation
feat(firmware): PDU monitoring node and TELEM_n telemetry frame (#216) - #343
Conversation
New PowerMonitor library and PDU_Left/Right/Center sketches (NODE_IDs 3/4/5): samples the 12 V / 5 V rails (voltage + current) and the board NTC at 1 kHz, converts with per-board calibration stored in the last flash page, raises UV / OV / over-current / fuse-open / temperature / sensor flags with persistence and hysteresis, and feeds faults into HEALTH_n via FaultSource. New paged frame TELEM_n = 0x180 + n (TelemPayload, byte 0 = TelemPage): one frame per second rotating PDU_RAIL_12V / PDU_RAIL_5V / PDU_STATUS, plus rate-limited edge sends on any flag change; SYNC_REQ sends all three. PanelBridge forwards every TELEM_n frame to the host unread as _NODE_TELEM. DiagSerial calibration: CAL SHOW / CAL VDDA <mV> / CAL ZERO / CAL CLEAR / RAW. Tests/PowerMonitor (5 envs) passes on hardware; real-bus smoke of the PDU firmware with a CANable2. Spec and docs synced (D18).
📝 Docs site may need an updateThis PR touches files the docs site is built from. Before merging,
Backstop: the weekly docs-drift review. Ignore |
…nd the PDU sketches (#216)
| if (!strcmp(line, "CAL SHOW")) printCal(); | ||
| else if (!strncmp(line, "CAL VDDA ", 9)) cmdCalVdda(line + 9); | ||
| else if (!strcmp(line, "CAL ZERO")) cmdCalZero(); | ||
| else if (!strcmp(line, "CAL CLEAR")) { gStore.erase(); loadCal(); out().print(F("[PDU] cleared. ")); printCal(); } |
There was a problem hiding this comment.
[P2] Handle a failed calibration-page erase before reporting success
CalStore::erase() returns false when the HAL flash erase fails, but this command ignores that result, reloads whatever record remains, and still prints [PDU] cleared.. That can tell an operator calibration was removed when the old calibration is still active. Please check the return value, emit an error on failure, and only reload/report cleared after a successful erase.
There was a problem hiding this comment.
Fixed in bcd8b23. CAL CLEAR now checks CalStore::erase(): on failure it prints [PDU] ERROR: flash erase failed — calibration unchanged and leaves the loaded calibration as it is; only a successful erase reloads and reports cleared. Verified the success path on hardware (CAL VDDA → 1 slot → CAL CLEAR → cleared, 0 slots, confirmed by CAL SHOW); the failure branch is review-only, since a HAL erase failure can't be forced on the bench without a fault-injection hook.
…s, power-in pinout, bring-up and calibration (#216)
| !!! note "Status LED" | ||
| The red/green status LED works exactly as on every other board — CAN link and bus health (see | ||
| [Debugging](../firmware/debugging.md)). Rail faults are reported to the host app and shown on | ||
| the rail LEDs, not on the status LED. |
There was a problem hiding this comment.
[P2] Do not describe the passive rail-presence LEDs as fault indicators
D3/D4 are wired directly from the delivered +12 V/+5 V rails through resistors, so they only indicate that a rail is present. Firmware does not drive them: an over-voltage, over-current, or temperature fault can leave both LEDs lit normally. This wording can mislead bring-up/debugging. Please say that faults are reported to the host, while D3/D4 independently show rail presence (a blown/dead rail may extinguish its LED). The same inaccurate wording should also be corrected in Firmware/ScratchPad/FirmwarePlan/08-hardware-firmware-contracts.md and PduNode.h.
There was a problem hiding this comment.
Fixed in db26ab0, in all three places (docs/hardware/pdu.md, 08-hardware-firmware-contracts.md, PduNode.h). Checked against the 0.2.0 netlist: D3 (+12 V), D4 (+5 V) and D5 (+3V3) are passive, resistor-fed power LEDs; D6/D7 are the MCU status pair on PB14/PB15. The text now says rail faults are reported to the host only, the status LEDs behave as on every node and don't change for rail faults, and the power LEDs show rail presence only — dark on a dead rail or blown fuse, lit through OV / OC / overheat. The page's feature bullet also now lists all three power LEDs (it had omitted the 3.3 V one).
…try, only CTRL_BCAST coalesces (#216)
Closes #216.
What
Firmware for the PDU monitoring node (#202 hardware) and the new
TELEM_ntelemetry frame, as designed in #216 (design signed off 2026-10-15; builds on #340'sserviceNodeStatus()).TELEM_n = canIdTelem(n) = 0x180 + n, 8-byteTelemPayload(byte 0 = page)CANProtocol.h_NODE_TELEMhost contract (NODE_TELEM_PROTO_VERSION 1),TelemPage,PduRailFlag,PduStatusFlag,NodeFaultCodeFUSE_OPEN/OVER_TEMPERATURE/SENSOR_FAULTNodeStatus.hTELEM_nframe to the host unread as_NODE_TELEM <nodeId><8 bytes>(page 0 / short dropped, never liveness)PanelBridge.cppCALcommandsFirmware/Libraries/PowerMonitor/Pages —
0x01 PDU_RAIL_12V/0x02 PDU_RAIL_5V: flags · vAvgMv · vMinMv · iAvgMa (int16);0x03 PDU_STATUS: flags · NTC 0.1 °C · peak 12 V / 5 V mA. One frame per second rotating the three pages (each page every 3 s), plus an immediate frame when a page's flags change (≤ 1 / 100 ms / page);SYNC_REQsends all three. Rail / thermal faults also reachHEALTH_n.faultIdthrough the FaultSource registry. Full layouts in FirmwarePlan 02; decision D18.Calibration — per board in the last 1 KB flash page (
0x0800FC00), append-only 32-byte CRC records;board_upload.maximum_size = 64512keeps code out of it. DiagSerial:CAL SHOW,CAL VDDA <mV>(DMM on 3V3 — VDDA is assumed 3300 mV until anchored),CAL ZERO(no load; 75 / 120 mA guards — the 5 V zero subtracts the PDU's own draw),CAL CLEAR,RAW.Design decisions carried from #216: status LED unchanged (CAN/link + master-loss only); 500 ms fault blanking at power-up; no
PanelGroupdependency (the analog pins are read directly —PinReflives in PanelGroup); all thresholds arePDU_*build flags.One small change from the #216 text: on
SYNC_REQthe node sends all three pages (not just the next one), so a reconnecting host gets the full picture at once.Tests — 2026-10-15, PanelGroup Rev 0.1.0 board + CANable2 (not a PDU, so analog readings are meaningless)
Tests/PowerMonitor, on hardware, 106 checks, 0 failures:pdu_math26 ·rail_monitor27 ·board_thermal16 ·telem_schedule12 ·cal_store25 (real flash page: save / load, newest wins, corrupt record skipped, full-page wrap, left erased).PDU_Left, CANable2 ACKing + logging):READY_3at boot;HB_3every 500 ms (first 500 ms after boot);HEALTH_3every 1000 ms;TELEM_3once per second rotating 01 → 02 → 03; boot edge frame (UNCAL flags) and per-page edges when the 500 ms blanking ended;SYNC_REQ→ pages 01, 02, 03 within 300 ms; 1000 rail scans/s;CAL VDDA/CAL ZERO/CAL CLEAR/ bad-command all behave; board left uncalibrated.startup_sequence/output_submissionre-run on this branch:HB_0500 ms,HEALTH_01000 ms, exports →CTRL_BCAST, no errors.Tests/CANProtocolprotocol_layout:canIdTelemrange +TelemPayloadsize asserts.check_doc_refs.py·check_node_ids.py(4 production sketches) · MkDocs build clean.CAL VDDA+CAL ZEROstored, re-uploaded withpio … -t upload(OpenOCD),CAL SHOWunchanged.Tests/PanelBridgetest_node_telem(_NODE_TELEMforwarding) — compiles; running it needs the USB-UART adapter on PA2/PA3 (250 kbaud) → moved to feat(pcb): per-console power distribution + monitoring CAN node (PDU) — INA180 telemetry #202's bench list.CAL VDDA/CAL ZERO, threshold tuning, fault checks) → moved to feat(pcb): per-console power distribution + monitoring CAN node (PDU) — INA180 telemetry #202's bring-up checklist.Spec / docs (same PR)
02,00,10, TechSpec CANProtocol — onlyCTRL_BCASTcoalesces);00-decisions(D18; D13's stale INA226 wording),02-can-protocol(ID fn, frame table, Node Telemetry Payload, bus load, bridge accept ranges — the list also gains the REL / DIR / ACTION ranges it had drifted from),04-dcs-bios-integration(_NODE_TELEM),06-panelbridge-api,08-hardware-firmware-contracts(PDU analog front end + calibration page),10-implementation-plan(Phase 5b)CANProtocol,NodeStatus,PanelBridge(RX table gains HEALTH + TELEM), newPowerMonitor.md,READMEdependency treehardware/pdu.md(Power Distribution Unit — what it measures, fuses, power-in pinout checked against the 0.2.0 netlist, bring-up + calibration; in the Hardware nav after Base Boards, linked from Base Boards and Power),architecture/can-bus.md,architecture/power.md(PDU monitoring + wiring assumptions),firmware/index.md,firmware/build-flags.md(PDU_*),firmware/node-id.mdFirmware/NODE_IDS.md(3 / 4 / 5, next = 6),docs/_source/base-boards.md(INA226 → INA180A2, no eFuse), PDUDESIGN-NOTES.md§B1b (VDDA correction), firmware skill TechSpec listDocs-drift reminder — checked: no new hardware (firmware for the existing PDU, #202; this PR adds its published page
hardware/pdu.md); the TELEM_n decision is reflected onarchitecture/can-bus.md+architecture/power.md(design-decisions.mdkeeps its own D1–D10 architecture list, not the FirmwarePlan series); no published page still says INA226 / TMP117 / eFuse for the PDU (_source/base-boards.mdand the PDU DESIGN-NOTES corrected here); NODE_IDs stay transcluded fromFirmware/NODE_IDS.md.