Gas Sensor
STM32G431KB · Firmware v0.1.0
Firmware

Firmware Architecture

RTIC task model, shared state, Embassy HAL drivers, and crate structure.

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
  • async tasks 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

TaskRateFunction
adc_task40 Hz (25ms)Read ADC, update LATEST_ADC, feed stability monitor at 1 Hz
comms_taskEvent-drivenUART JSON command handler
bias_task100 msApply TARGET_DAC ChA/ChB targets to the AD5545
sht45_task1 HzRead temperature and humidity via I2C
blinky2 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

RegionUsedLimit%
Flash~96 KB128 KB~75%
RAM~7 KB32 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)

Last updated: March 2026