Short project summary
Manual-control Zephyr RTOS console for STM32U585 (BlackPill), featuring Zbus message bus, supervisor FSM, SSD1306 OLED display thread, and diagnostic sensor monitoring. See docs/DESIGN_DES.md for full architecture and task roadmap.
Phase 1: Manual button/shell control (OFF ↔ ACTIVE ↔ SLEEP)
- Zbus message bus for thread coordination
- Supervisor FSM for state transitions
- SSD1306 OLED display thread: updates automatically in ACTIVE, manual override via shell
- Internal/external sensor reads (BME280, MPU6050, ADC)
- All state transitions are user-initiated (button/shell)
See docs/DESIGN_DES.md for details.
This project is a Zephyr RTOS application for STM32U585 that provides:
- USB CDC ACM shell console
- Interrupt-driven button handling with software debounce
- LED auto-blink timer that runs independently of shell activity
- Internal sensor reads via Zephyr sensor API (temperature, VREF, VBAT)
- External I2C sensor reads (BME280, MPU6050)
- Periodic sensor sampling via a dedicated work queue
Code organization (key directories):
src/app: application state + pure app logicsrc/sensors: internal/external sensor modulessrc/shell: shell commands + shell parsing logicsrc/hal: Zephyr HAL wrappers used for host-side unit testing
- STM32U585 board (BlackPill STM32U585CI or compatible)
- Zephyr SDK/toolchain for firmware build + flash
- Python virtual environment at
../.venv - Ruby + Ceedling for host-side unit tests
gcovr(Python package) for coverage reports
Firmware build / flash (example):
source ../.venv/bin/activate
# Build
west build -p always -b blackpill_u585ci -d build/console
# Flash (after successful build)
west flash -d build/consoleShell connection (example):
minicom -D /dev/ttyACM0 -b 115200VS Code tasks are available for common workflows (build/flash/monitor/test).
display on— turn the SSD1306 OLED on (ACTIVE only)display off— turn the display offdisplay write "text"— write a single line to the displaydisplay status— show display state
led onled offled toggle
button info— show button statsbutton reset— reset button counters
sensor temp— read internal temperaturesensor vref— read internal VREFsensor vbat— read VBATsensor all— show latest environmental datasensor bme280— read external BME280sensor mpu6050— read external MPU6050
- The display thread subscribes to sensor data and
displaycommands. - In
ACTIVEmode the display updates automatically on new sensor data (data-driven). - In
OFFandSLEEPthe display remains off;display oncan force it on for diagnostics. - Manual display commands override rendering but do not change the system FSM state.
Development follows Red → Green → Refactor with Ceedling + Unity + CMock:
- Add failing unit test(s)
- Implement smallest production change
- Refactor while tests remain green
- Run
ceedling test:all - Run Zephyr firmware build to prevent regressions
Run unit tests (host-side Ceedling):
source ../.venv/bin/activate
export PATH="$HOME/.local/share/gem/ruby/3.2.0/bin:$PATH"
ceedling test:allGenerate coverage (clean run recommended):
source ../.venv/bin/activate
export PATH="$HOME/.local/share/gem/ruby/3.2.0/bin:$PATH"
ceedling clobber
ceedling gcov:allOptional: produce full HTML/XML report:
ceedling gcov:all report:gcovNote: coverage generation can take several minutes; results are printed to the runner console.
GitHub Actions workflow: .github/workflows/ceedling-ci.yml
- Runs
ceedling test:all - Runs
ceedling gcov:all - Coverage is emitted to runner logs (no CI artifact upload)
Phase 1 is focused on manual control (OFF ↔ ACTIVE ↔ SLEEP). Current highlights:
- Zbus and message definitions: ✅
- Central sensor thread (BME280 + MPU6050) and I2C mutex: ✅
- Supervisor FSM (button-driven): ✅
- Display thread (SSD1306): ✅ (data-driven updates in ACTIVE; manual override via shell)
- Internal ADC sensors (temp, VREF, VBAT): partial — next task (TG 4.4)
See docs/DESIGN_DES.md for full task order and future Phase 2/3 work (IMU interrupts, GPS).
- Internal sensor readings are intended for diagnostics, not precision calibration.
- LED auto-blink starts at boot (500 ms period).
- Button debounce window is 50 ms.
- Periodic sampling runs through Zephyr work queue infrastructure.