BERGSONNE

System

The services every Core gives you for free — blocking delays and a millisecond clock, the independent watchdog for recovering from hangs, and fault handlers that turn a crash into a readable register dump. None of them need a pad or any configuration. Use the Core / HAL / LL toggle at the top of the sidebar to see each at the layer you work in.

Overview

System features handle timing and fault recovery. They’re available on every Core tile and require no pad assignments or peripheral configuration — they’re part of the Core itself, not something you wire up.

Delays, timekeeping, and the fault handlers come in automatically through core.h — no extra includes. The watchdog is opt-in: include core_watchdog.h when you want it. Most calls are Tier 2 — you call them directly, no handle. A few watchdog helpers are Tier 1, meant for a one-time check at boot.

Delays & timing

Blocking delays and a free-running millisecond counter come from core.h. The counter is handy for timeouts and general timekeeping without tying up a hardware timer.

core_delay_ms(500);          // block for 500 ms
core_delay_us(100);          // block for 100 us

uint32_t start = core_millis();
// ... your application code ...
if (core_timeout(start, 1000)) {
    // 1 second has elapsed since 'start'
}
  • core_delay_us is for short waits — for anything over a millisecond prefer core_delay_ms, which won’t starve the rest of the system as long.
  • core_millis() counts up from boot and wraps after ~49 days. Compare with core_timeout() rather than subtracting raw values, so a wrap doesn’t bite you.

Watchdog

The independent watchdog (IWDG) runs on its own 32 kHz LSI clock, completely separate from the system clock. Once started, it cannot be stopped — only a full MCU reset disables it. If your code doesn’t refresh it before the timeout, the MCU resets itself. That’s exactly what you want in a deployed system: a hang, an infinite loop, or a deadlock all recover automatically.

#include "core.h"
#include "core_watchdog.h"

int main(void)
{
    core_init();

    if (core_watchdog_caused_reset()) {
        // We rebooted from a watchdog reset — handle recovery
        core_watchdog_clear_flags();
    }

    core_watchdog_start(2000);   // 2-second timeout

    while (1) {
        // ... your application code ...
        core_watchdog_feed();    // must call within 2 seconds
    }
}

Pass the timeout in milliseconds; the prescaler and reload are chosen for you. The usable range is roughly 100 ms to 28 s. start and feed are the everyday Tier 2 calls; core_watchdog_caused_reset() and core_watchdog_clear_flags() are Tier 1 helpers you typically call once, at boot, to detect and acknowledge a watchdog-induced reset.

Once started, it stays started
There is no stop. Start the watchdog only after init is complete and your loop is actually feeding it, or the first slow path will reset you mid-bring-up.

Fault handlers

The SDK installs handlers for the four CPU faults — HardFault, MemManage, BusFault, and UsageFault. When one fires, the handler captures the stacked register frame (PC, LR, R0–R3, R12, PSR) and the Configurable Fault Status Register (CFSR), dumps them over USB CDC, then blinks SOS on the onboard LED.

No setup required. The handlers are compiled into every project automatically and override the default infinite-loop handlers from the startup code. The USB dump uses polled transmit that works with interrupts disabled, so it runs even from fault context; if USB CDC was never initialized, the dump is silently skipped and you still get the LED SOS.

Example output

*** HardFault ***
  PC  = 0xDEADDEAC
  LR  = 0x08002345
  R0  = 0x00000000
  R1  = 0x20001234
  R2  = 0x00000000
  R3  = 0x00000001
  R12 = 0x00000000
  PSR = 0x61000000
  CFSR = 0x00000001

SOS...

The PC value is the instruction that faulted — look it up in your .map file or a disassembly to find the source line.

Optional callback

Register a callback to run just before the dump and SOS — e.g. to log the fault to flash or set a flag for the next boot. It runs in fault context, so keep it minimal: no heap, no interrupts.

#include "core_fault.h"

void my_fault_handler(hal_fault_type_t type, const hal_fault_frame_t *frame)
{
    // Log fault PC to NVM, set a flag, etc. Keep it tiny.
    (void)type;
    (void)frame;
}

// In main, before your loop:
core_fault_set_callback(my_fault_handler);

API reference

Delays & timing

Default-instance · Tier 2
void core_delay_ms(uint32_t ms);
Blocking delay in milliseconds.
void core_delay_us(uint32_t us);
Blocking delay in microseconds. For delays > 1 ms prefer `delay_ms` — it won't starve the rest of the system as long.
uint32_t core_millis(void);
Milliseconds since boot (wraps at ~49 days).
int core_timeout(uint32_t start, uint32_t ms);
Check if a timeout has elapsed. start: value returned by core_millis() at the beginning ms: timeout duration in milliseconds Returns 1 if expired, 0 otherwise.
Lower-level · Tier 1
void core_cycle_init(void);
Enable the DWT cycle counter. Idempotent; call once at startup.
void core_delay_cycles(uint32_t cycles);
Busy-wait `cycles` CPU cycles (≈ ±a few cycles of loop overhead).
void core_delay_ns(uint32_t ns);
Busy-wait `ns` nanoseconds (rounds to whole CPU cycles).

Generated from core_timing.htiles@777be99.

Watchdog

Default-instance · Tier 2
void core_watchdog_start(uint32_t timeout_ms);
Start the independent watchdog with a timeout in milliseconds. Selects the best prescaler/reload combination automatically. Common values: 1000, 2000, 5000, 10000 (max ~28000). WARNING: Once started, the IWDG cannot be stopped.
void core_watchdog_feed(void);
Feed the watchdog. Must be called before the timeout expires.
Lower-level · Tier 1
int core_watchdog_caused_reset(void);
Check if the last reset was caused by the watchdog. On ROM_DFU builds, core_init() reads and clears the hardware flag early (for the strike counter), stashing the cause in reserved SRAM — so prefer that when it's valid; otherwise fall back to the raw RCC_CSR flag.
void core_watchdog_clear_flags(void);
Clear all reset flags (call after checking cause).
void core_watchdog_debug_freeze(void);
Freeze the IWDG while the core is halted under a debugger, so a breakpoint doesn't let the watchdog reset the chip out from under an SWD session. Firmware-side so it holds for any probe/toolchain (rev b exposes SWD on L4).

Generated from core_watchdog.htiles@0ea79c0.

Fault handlers

Fault handling has a single hook (the rest is automatic — see above). No generated manifest yet, so this one is listed by hand:

void core_fault_set_callback(hal_fault_callback_t cb);
Register a callback invoked before the register dump and SOS blink. Runs in fault context — keep it minimal.