Framework: RTIC 2.1
The firmware uses RTIC 2.1 (Real-Time Interrupt-driven Concurrency) with the thumbv7-backend. RTIC provides:
- Static task dispatch with compile-time priority analysis
- Zero-cost shared resource access via priority-based ceiling protocol
asynctasks backed by a software task executor
The monotonic timer is TIM3 at 1 MHz, provided by rtic-monotonics. It is clocked
at 1 MHz (not the full 16 MHz system clock) to ensure the 65 ms overflow period safely
spans the STM32G4 flash page-erase time (~25 ms), preventing a missed-interrupt panic.
Task Overview
| Task | Rate | Function |
|---|---|---|
adc_task | 40 Hz (25ms) | Read ADC, update LATEST_ADC, feed stability monitor at 1 Hz |
comms_task | Event-driven | UART JSON command handler |
bias_task | 100 ms | Apply TARGET_DAC ChA/ChB targets to the AD5545 |
sht45_task | 1 Hz | Read temperature and humidity via I2C |
blinky | 2 Hz (500ms) | Toggle PA8 LED and feed the IWDG (4 s timeout) |
Shared State
All cross-task communication uses embassy_sync::Mutex<CriticalSectionRawMutex, T>:
static CALIBRATION: Mutex<_, CalibrationState> // Calibration state machine
static LATEST_ADC: Mutex<_, u16> // Latest raw ADC code
static LATEST_TEMP: Mutex<_, f32> // SHT45 temperature (°C)
static LATEST_HUMIDITY: Mutex<_, f32> // SHT45 humidity (%RH)
static ADC_STABILITY: Mutex<_, StabilityMonitor> // 30-sample mV circular buffer
static TARGET_DAC: Mutex<_, (f32, f32)> // (ChA%, ChB%) — written atomically
Crate Structure
bsp/ Board Support Package
src/
board.rs Clock init, GPIO, UART, SPI, ADC, I2C
flash.rs Flash storage (page 63, 0x0801_F800)
hardware/
adc.rs SensorAdc — VREFINT-calibrated ADC with oversampling
ad5545.rs Ad5545 — 16-bit dual DAC over SPI
sht45.rs SHT45 — I2C temperature/humidity sensor
protocol/ Wire protocol
src/lib.rs JSON message encode/decode (serde_json)
main-app/ RTIC application binary
src/
main.rs App definition, init, static resources
tasks/
adc.rs ADC sampling loop (40 Hz raw, 1 Hz stability)
comms.rs UART JSON command handler
logic/
calibration.rs CalibrationState enum + PPM conversion
stability.rs StabilityMonitor 30-sample circular buffer
Memory Layout
| Region | Used | Limit | % |
|---|---|---|---|
| Flash | ~96 KB | 128 KB | ~75% |
| RAM | ~7 KB | 32 KB | ~22% |
A 4 KB heap (embedded-alloc) supports serde_json deserialisation. All other
allocations use heapless fixed-size collections or static storage.
Embassy HAL
All Embassy crates are pinned to git revision 659496087748c86cad8732f4f95dbb3a123d941c.
Key API differences from older Embassy versions used in this project:
Peripheral<P=T>→Peri<'d, T>Output<'d, Pin>→Output<'d>Spi<'d, M>→Spi<'d, M, spi::mode::Master>Adc::new(periph)→Adc::new(periph, AdcConfig { .. })adc.blocking_read(ch)→adc.blocking_read(ch, SampleTime::CYCLES6_5)