Introduction
ferrite-sdk is an embedded Rust firmware observability SDK designed for ARM Cortex-M microcontrollers. It provides crash capture, metrics collection, structured logging, and reboot reason tracking -- all in a no_std, zero-allocation library that uploads telemetry over any transport you choose.
What problem does it solve?
Embedded devices deployed in the field are difficult to debug. When a sensor node crashes at 2 AM, you typically have no stack trace, no logs, and no idea what happened. ferrite-sdk solves this by:
Capturing HardFaults automatically. The SDK installs a Cortex-M exception handler that saves all registers (R0-R12, SP, LR, PC, xPSR), the CFSR/HFSR/MMFAR/BFAR fault status registers, and a 64-byte stack snapshot into retained RAM before resetting.
Recording why the device rebooted. After every reset, your firmware reads the MCU's reset-cause register and stores the result. On the next upload cycle, the server receives a structured reboot event.
Collecting metrics without heap allocation. Counters, gauges, and histograms are stored in a fixed-capacity ring buffer (
MetricsBuffer<N>). When the buffer is full, the oldest metric entry is evicted. Metric keys are limited to 32 bytes to keep things compact.Buffering structured trace logs. If you use
defmt, the SDK captures formatted log output into a circularTraceBuffer<N>. Frames are framed with a level byte, a 4-byte tick count, a length-prefixed payload, and a sentinel byte.Uploading everything as binary chunks. All telemetry is encoded into a compact binary wire format (max 256 bytes per chunk) with CRC-16 integrity checks. You implement one trait --
ChunkTransportin Rust or asend_chunkcallback in C -- and the SDK handles the rest.
Who is it for?
- Embedded Rust developers shipping firmware on Cortex-M3, M4, or M4F targets (thumbv7m, thumbv7em-none-eabi, thumbv7em-none-eabihf).
- C/C++ firmware teams who want the same observability without rewriting their RTOS. The
ferrite-fficrate produces a static library (.a) and a C header that work with Zephyr, FreeRTOS, or any bare-metal C project. - Platform engineers building fleet-wide device monitoring. The companion
ferrite-serveringests chunks over HTTP, stores them in SQLite, and symbolicates fault addresses usingarm-none-eabi-addr2line.
Repository structure
| Crate | Description |
|---|---|
ferrite-sdk | Core no_std SDK -- metrics, faults, trace, chunks, transport, encryption, compression |
ferrite-embassy | Embassy async task for periodic/triggered uploads |
ferrite-rtic | RTIC resource wrapper and blocking upload helper |
ferrite-ffi | C FFI static library (libferrite_ffi.a) |
ferrite-server | Ingestion server with auth, alerting, groups, OTA, Prometheus, rate limiting |
ferrite-dashboard | Dioxus WASM dashboard -- fleet view, metrics charts, fault diagnostics, CSV/JSON export |
ferrite-gateway | Edge gateway -- BLE/USB/LoRa chunk forwarding with offline SQLite buffering |
ferrite-ble-nrf | nRF52840 BLE transport (SoftDevice, excluded from workspace) |
Design principles
- No alloc, anywhere. The SDK never calls
alloc. All buffers are fixed-size and stack- or static-allocated. - No panics in production code paths. Functions return
Result<T, SdkError>or silently drop data when buffers overflow. The only panic is callinginit()twice (which is a programming error). - Feature flags gate all hardware dependencies. The
cortex-mfeature pulls incortex-mandcortex-m-rt; thedefmtfeature pulls in the defmt logger; theembassyfeature enables async transport. With all features disabled, the SDK compiles and tests on the host. - Critical sections via
critical-sectioncrate. This lets the same code run on real hardware (usingcortex-mcritical sections) and in host tests (using astdmutex implementation). - Hand-rolled binary encoding. The chunk wire format is simple enough to implement without serde or postcard, though a
postcardfeature is available for those who prefer it.
Memory overhead
With default buffer sizes (32 metric entries, 512-byte trace buffer):
| Resource | Usage |
|---|---|
| RAM (retained) | 256 bytes (.uninit.ferrite section) |
| RAM (runtime) | ~1.4 KB (MetricsBuffer + TraceBuffer + SdkState) |
| Flash | ~6 KB (depends on enabled features) |
These numbers scale with the const-generic buffer size parameters. A MetricsBuffer<8> with a TraceBuffer<128> can bring total RAM under 600 bytes.
Platform overview
Beyond the core SDK, ferrite provides a full observability pipeline:
- Transport layer -- UART, BLE, USB CDC, HTTP, and LoRa transports with optional AES-128-CCM encryption and RLE compression
- Edge gateway -- bridges BLE/USB/LoRa devices to the server with offline buffering
- Ingestion server -- Keycloak or Basic auth, RBAC (admin/provisioner/viewer), webhook alerting, Prometheus metrics, SSE live events, data retention policies, rate limiting, database backup
- Web dashboard -- real-time fleet monitoring, SVG metric charts, fault diagnostics with symbolication, fleet view with tag grouping, device comparison, CSV/JSON export
Next steps
- Quickstart -- get a working example in 10 minutes
- Core Concepts -- understand retained RAM, chunks, and transport
- Architecture -- module-level data flow diagram
- Transport Layer -- UART, BLE, USB CDC, HTTP, LoRa
- Security -- encryption, authentication, RBAC