refactor(radio): chart-first restructure on hsmc 0.3 + soak hardening
Migrate from hsmc 0.2 (local-patched) to hsmc 0.3.0 (crates.io, with embassy + trace-defmt features). Restructure radio chart and bundle several adjacent stability changes that need to land together for soak runs. Radio chart: - Booting (default, no handlers) -> Operational (default Unconfigured; super-state owning CmdPing/CmdGetInfo/Reset/WedgeDetected handlers + Recovering + CheckRecoveryBudget) -> Dead (terminal). - Cold init's during is structurally un-cancellable. - radio_task is a 30-line shim that panics if run() returns (chart is non-terminating). - Internal queue capacity bumped 8 -> 32 to cover action-emit bursts. Host chart: - Connected splits into WaitingForFirstFrame (default, no timer) + Active (chart-owned 1s inactivity timer via on(after) + self- transition on FrameReceived). Manual Timer::after + last_frame_at removed. Soak hardening: - ld/nrf52840-memory.x: app start 0x1000 -> 0x26000 to leave the factory s140 SoftDevice dormant in flash. - hal/nrf52840.rs: dump POWER.RESETREAS on boot -- WARN on DOG/LOCKUP, INFO on RESETPIN/SREQ/wake-from-OFF. - host/usb.rs: read_packet errors discriminated -- Disabled is debug (normal during USB enum), BufferOverflow stays warn. - COBS encode warns now carry type/tag/payload-length for diagnosis. - RADIO_THROTTLED static initializes to true (no proof of host drain at boot). - driver/sh1106.rs: init retries 3x with 100ms backoff (intermittent first-write race on power-up). - Cargo.toml: unexpected_cfgs allowlist for hsmc's journal/trace-* features. docs/semtech_lora_cad_lbt_guidebook.md: vendor the Semtech CAD/LBT reference for offline lookup.
This commit is contained in:
16 files changed
+2417
-262
No files matched your search
@@ -56,6 +56,76 @@ pub fn alloc_vbus_detect(
|
||||
))
|
||||
}
|
||||
|
||||
// ── Reset reason ────────────────────────────────────────────────────
|
||||
|
||||
/// Read the POWER.RESETREAS register, log a human-readable summary,
|
||||
/// then clear it so the next boot reflects only the next reset cause.
|
||||
///
|
||||
/// This is the post-mortem diagnostic for soak runs: if the firmware
|
||||
/// crashes and the chip resets, the next boot's RESETREAS tells us
|
||||
/// what happened (cortex-m lockup, watchdog, soft reset, debugger,
|
||||
/// pin reset, etc.). Without this, a self-rebooting firmware just
|
||||
/// looks like log restarts with no signal as to why.
|
||||
///
|
||||
/// nRF52840 `POWER.RESETREAS` (PS §15.4.1): bits are write-1-to-clear.
|
||||
/// The register accumulates causes across resets until cleared, so
|
||||
/// always clear after reading.
|
||||
pub fn dump_reset_reason() {
|
||||
// POWER.RESETREAS lives at 0x40000400 (POWER base 0x40000000 +
|
||||
// offset 0x400). Direct memory access avoids requiring embassy_nrf's
|
||||
// `unstable-pac` feature. Bit layout per nRF52840 PS §15.4.1:
|
||||
// 0 RESETPIN - external NRESET pin asserted
|
||||
// 1 DOG - watchdog reset
|
||||
// 2 SREQ - software-requested reset (cortex SYSRESETREQ)
|
||||
// 3 LOCKUP - cortex-m core lockup
|
||||
// 16 OFF - wake from System OFF via DETECT
|
||||
// 17 LPCOMP - wake from System OFF via ANADETECT
|
||||
// 18 DIF - wake from System OFF via debug interface
|
||||
// 24 NFC - wake from System OFF via NFC field
|
||||
const RESETREAS_ADDR: *mut u32 = 0x4000_0400 as *mut u32;
|
||||
// SAFETY: 0x40000400 is the POWER.RESETREAS register on nRF52840;
|
||||
// read/write_volatile is correct for memory-mapped hardware.
|
||||
let raw = unsafe { core::ptr::read_volatile(RESETREAS_ADDR) };
|
||||
let dog = (raw & (1 << 1)) != 0;
|
||||
let lockup = (raw & (1 << 3)) != 0;
|
||||
if raw == 0 {
|
||||
defmt::info!("boot: cold POR (RESETREAS=0)");
|
||||
} else if dog || lockup {
|
||||
// Real problems: watchdog timeout (hung task) OR CPU lockup
|
||||
// (HardFault → escalated). Worth a WARN — these are bugs.
|
||||
defmt::warn!(
|
||||
"boot: ABNORMAL reset RESETREAS=0x{=u32:08x} resetpin={=bool} dog={=bool} sreq={=bool} lockup={=bool} off={=bool} lpcomp={=bool} dif={=bool} nfc={=bool}",
|
||||
raw,
|
||||
(raw & (1 << 0)) != 0,
|
||||
dog,
|
||||
(raw & (1 << 2)) != 0,
|
||||
lockup,
|
||||
(raw & (1 << 16)) != 0,
|
||||
(raw & (1 << 17)) != 0,
|
||||
(raw & (1 << 18)) != 0,
|
||||
(raw & (1 << 24)) != 0,
|
||||
);
|
||||
} else {
|
||||
// Normal reset paths: RESETPIN (UF2 bootloader pulses NRESET on
|
||||
// app start; user reset button), SREQ (deliberate sys_reset),
|
||||
// OFF/LPCOMP/DIF/NFC (wake from System OFF). All expected
|
||||
// operational reasons; INFO not WARN.
|
||||
defmt::info!(
|
||||
"boot: RESETREAS=0x{=u32:08x} resetpin={=bool} sreq={=bool} off={=bool} lpcomp={=bool} dif={=bool} nfc={=bool}",
|
||||
raw,
|
||||
(raw & (1 << 0)) != 0,
|
||||
(raw & (1 << 2)) != 0,
|
||||
(raw & (1 << 16)) != 0,
|
||||
(raw & (1 << 17)) != 0,
|
||||
(raw & (1 << 18)) != 0,
|
||||
(raw & (1 << 24)) != 0,
|
||||
);
|
||||
}
|
||||
// Clear all bits — write-1-to-clear per nRF52840 PS §15.4.1.
|
||||
// SAFETY: same justification as the read above.
|
||||
unsafe { core::ptr::write_volatile(RESETREAS_ADDR, 0xFFFF_FFFF) };
|
||||
}
|
||||
|
||||
// ── MAC address ─────────────────────────────────────────────────────
|
||||
|
||||
/// Read the factory-programmed device address from FICR registers.
|
||||
|
||||
Reference in new issue
Block a user