This project is a reference F´ deployment for embedded systems with strict
hardware and memory constraints. ReferenceDeployment contains only the basic
F´ components needed to demonstrate a bare-metal flight-software architecture:
static initialization, a cyclic executive, cooperative active components, and a
bounded communication path.
F´ (F Prime) is a component-driven framework for developing and deploying spaceflight and other embedded software applications. See the F´ website.
lib/fprime-stm32 is a chip-family-portable F´ library (STM32H7 today, other
STM32 families addable without forking it): reusable OSAL delegates, drivers,
and a bootstrap allocator that any consuming project gets "for free," while
everything CubeMX-generated or board-specific (this board's .ioc output,
clock/tick-source glue, the linker script) stays owned by this project in
FprimeStm32BaremetalReference/Hardware/. See the
lib/fprime-stm32 module README for the full
architecture and the driver-configuration pattern described below. Sensor
components (currently an MPU-6050 IMU, wired directly to Stm32I2cDriver) come
from the fprime-sensors
submodule and connect directly to the STM32 drivers' ports.
Every STM32 driver (Stm32UartDriver, Stm32I2cDriver, STM32Timer) reads
which peripheral instance it's allowed to use from
Stm32Config.hpp — a #define-per-instance file (e.g. I2C1_INSTANCE,
TIM2_INSTANCE) that keeps a driver from touching a peripheral your board's
.ioc never actually configured. The library ships a default copy at
lib/fprime-stm32/Drv/config/Stm32Config.hpp; this project overrides it with
its own copy at FprimeStm32BaremetalReference/config/fprime-stm32/Stm32Config.hpp
(via settings.ini's config_directory) to match this board's real wiring.
When starting a new project from this reference, edit the override copy, not
the library's default. Selecting a disabled instance in a driver's open()
call is treated as a build-time mistake and fails a FW_ASSERT, not a
runtime condition to recover from — see each sensor's docs/sdd.md for the
exact enable-then-select steps.
The project uses the GNU Arm Embedded toolchain and the stm32h7 F´ platform.
From the project root:
source fprime-venv/bin/activate
fprime-util generate -f
fprime-util build -j"$(nproc)"To build the deployment after generation:
ninja -C build-fprime-stm32h7 ReferenceDeploymentThe deployment runs without threads or an operating system. Its main loop:
- Initializes the hardware platform and TIM2-backed time source.
- Configures the generated topology.
- Triggers the configured rate-group schedule.
- Calls
Os::Baremetal::TaskRunner::runAll()to execute one cooperative dispatch step for every registered active component.
The cyclic executive contains no blocking waits or delays. Commands, telemetry,
events, and file services are handled by the active components and their fixed
queues. Svc::OsTime supplies the deployment time source; the topology does
not depend on a host or newlib real-time clock.
The deployment also initializes the bare-metal MicroFs service with a bounded
configuration. The current MicroFs implementation recognizes /bin<N>/file<M>
paths; persistent parameter and file support for the framework's standard paths
remains future work.
The deployment is designed to avoid dynamic allocation after initialization.
Os_Baremetal_OverrideNewDelete routes C++ allocations through a fixed
bootstrap pool during startup. The pool is locked after topology initialization,
so an allocation request during cyclic execution asserts instead of silently
growing an unbounded heap.
The deployment also wraps malloc, calloc, realloc, and free at link time.
malloc uses the same bootstrap pool to support toolchain allocations that can
occur before main(). The other C heap entry points assert when used.
The reference linker script separates CPU-only state from DMA-visible storage:
| Region | Capacity |
|---|---|
FLASH |
2 MiB |
AXI_SRAM |
512 KiB |
DTCM_RAM |
128 KiB |
The latest recorded baremetal-size stm32h7 result for the complete deployment
(re-measured September 14, 2026, after the Week 8 topology wiring and Week 9
driver-architecture split) was:
| Region | Used | Remaining |
|---|---|---|
Flash (.text+.data) |
645,708 bytes | 69.2% |
AXI SRAM .bss |
261,308 bytes | 50.1% |
DTCM .dtcm_bss |
8,584 bytes | 93.5% |
| Bootstrap pool | 112,656 of 131,072 bytes | 14.1% |
Flash and AXI SRAM .bss grew modestly (Week 8's led/gpioDriver topology
wiring plus the Week 9 driver split adding a handful of new members per
driver); DTCM .dtcm_bss is unchanged byte-for-byte. The bootstrap-pool
figure is a runtime allocation count, not a static section size, and is
carried over from the last hardware run (no board was attached in this
measurement pass) — it should still be re-verified live once convenient.
The reduced framework configuration in config/ keeps queue depths, telemetry
hash tables, command tables, and file catalog capacity proportional to this
deployment's actual component set.
ReferenceDeployment has been flashed to and run on the physical
STM32H753XI-EVAL2 board. The complete topology has reached main(), completed
setup, and run with cooperative dispatch enabled. Recorded validation includes:
- No assertion, abort, exit, HardFault, BusFault, or fatal-handler hits during the endurance runs.
- The on-board LED (PF10), driven exclusively through
Stm32::Stm32GpioDriver(no application code touchesHAL_GPIO_*directly), confirmed blinking end-to-end via a GDS-based integration test rather than manual register polling. - All registered active-component queues created and dispatched successfully.
- The USART1 DMA ground link exercised with command, telemetry, and event
traffic through
fprime-gds. Stm32::Stm32I2cDriver(I2C1, blocking/polled) driving a real MPU-6050 IMU throughfprime-sensors'MpuImu.ImuManagercomponent, wired directly to the driver'sDrv.I2cports with no adapter — accel/gyro telemetry and range/error events confirmed streaming correctly throughfprime-gds.
Detailed board pin mappings, clock initialization, DMA cache requirements,
driver behavior, hardware measurements, and the remaining STM32 soak tests are
documented in lib/fprime-stm32/README.md.
Two independent layers of automated testing back this deployment:
- Host unit tests (
fprime-util check, run from a component's own directory): every STM32 driver underlib/fprime-stm32/Drv/splits into a hardware-independent implementation and a thin HAL boundary that's swapped for a stub on the host, soStm32GpioDriver,Stm32UartDriver, andSTM32Timerall get real GTest coverage without an ARM toolchain. See "Host unit testing" inlib/fprime-stm32/README.mdfor the pattern.Stm32I2cDriverfollows the sameCommon/Real/Stubsplit but has notest/ut/files written yet —register_fprime_utis scaffolded but commented out. - Hardware-in-the-loop integration tests (
pytest+ the F´ GDS Integration Test API, against the real board):led_integration_tests.pyanduart_integration_tests.pydrive commands over the live ground link and assert on the resulting events/telemetry.
- Re-verify the bootstrap-pool usage figure live on hardware (it's a runtime
allocation count, not a static section size, so the host-only
baremetal-sizere-measurement above couldn't refresh it). - Repeat the extended ground-link and GDS soak at the corrected system clock.
- Validate TIM2 rollover, interrupt masking, and long-duration stability.
- Continue hardware-in-the-loop automation for the STM32 target.
- Add persistent file support for the MicroFs-backed services.
- Run the full I2C exit-criterion soak (1,000-iteration read at 400 kHz with explicit event evidence for every injected error path — NACK, timeout, bus error), not just confirmed-working normal operation.
Stm32I2cDriverhas no host unit tests yet, despite already following theCommon/Real/Stubsplit; write them.- When adding another
fprime-sensorsfamily (e.g.Bmp280for Week 11's SPI driver), register only itsTypes/Ports/Componentsdirectly inCMakeLists.txt— don't add the whole library vialibrary_locationsor that family's own top-levelCMakeLists.txt. Both pull in that family's bundled exampleSubtopology, which hardcodes aDrv.Linux*Drivertype that doesn't exist in the fpp model onstm32h7and breaks the build. Seelib/fprime-stm32/README.md's "Adding a sensor" section for the exact pattern already used forMpuImu.
With the board flashed and running, either ground tool talks to it over the
same live UART link — both read their flags from the fprime-gds.yml file
at the project root, so the only difference is which command you run.
fprime-gds is F´'s development/test GDS: a single-session developer
console for exercising commands, telemetry, and events while iterating on
hardware and flight software.
source fprime-venv/bin/activate
fprime-gdslib/fprime-yamcs is a submodule of YAMCS, a full
mission control system with a persistent telemetry/event archive, alarms,
and multi-user operations support — the ground system this project graduates
to once it needs operations-grade ground support rather than a developer's
test console. It's a drop-in replacement for fprime-gds on the
command/telemetry path, including automatic dictionary-to-XTCE conversion
and an F´-flavored severity-colored Events page. See
lib/fprime-yamcs/README.md for the full
option set.
source fprime-venv/bin/activate
fprime-yamcs