Expand description
§stm32f1-hal
stm32f1-hal is a Rust Hardware Abstraction Layer (HAL) for STM32F1 microcontrollers (All F1 series devices). It provides a clear, idiomatic interface for embedded development on STM32F1.
- It implements selected embedded-hal traits.
- It uses the os-trait crate, which makes it easy to integrate with different RTOSes.
- It works with stable Rust.
§🎯 Motivation
Existing crates didn’t fully meet my needs:
- stm32f1xx-hal’s design didn’t align with my workflow.
- stm32-hal lacks support for the STM32F1 series.
- Embassy and RTIC are async frameworks, but I need a blocking one.
To address this gap, I created stm32f1-hal. While parts of the implementation are adapted from stm32f1xx-hal, the focus here is on clarity, readability, and usability.
§📖 Design Philosophy
-
Readability is the most important. We only write code a few times, but we read it countless times. Clear understanding is essential for long-term maintenance.
-
Prefer sync-code over complex macros In complex modules, combining macros with generics and calling a lot of low level interfaces often makes the code harder to follow and maintain. Instead, I use sync-code to synchronizes code blocks across peripherals, keeping peripheral code easy to read and maintain.
-
A script is used to generate code for GPIO alternate function remapping.
-
-
Concise is not equal to simple. Fewer lines of code do not necessarily mean easier to read or understand.
- The initialization code is not hidden. This makes the
mainfunction more verbose, but everything that’s happening is clearly visible. - Static variables are kept to a minimum in the library.
- The initialization code is not hidden. This makes the
§📦 Usage
cargo add stm32f1-haluse stm32f1_hal::{self as hal, pac, cortex_m_rt::entry, prelude::*};
#[entry]
fn main() -> ! {
let dp = pac::Peripherals::take().unwrap();
let mut flash = dp.FLASH.init();
let cfg = rcc::Config::default();
let mut rcc = dp.RCC.init().freeze(cfg, &mut flash.acr);
let mut gpioa = dp.GPIOA.split(&mut rcc);
let mut led = gpioa.pa5.into_push_pull_output(&mut gpioa.crl);
loop {
led.set_high();
// delay...
led.set_low();
// delay...
}
}§Examples
For a more complete example, see example. And stm32f1-FreeRTOS-example shows how to use this crate with FreeRTOS together.
§🗺 Roadmap
This project is still in its early stages, with only a few features implemented so far. Contributions and feedback are welcome to help expand support for more peripherals and features.
- GPIO (tested)
- EXTI (tested)
- UART + poll mode (tested)
- UART + interrupt (stress tested)
- UART + DMA (stress tested)
- I2C + interrupt (tested)
- SPI + interrupt (tested)
- DMA
- PWM output
- DAC
- ADC
- More features
§🛠Contributing
- Submit PRs with documents, improvements or new peripheral support.
- Open issues for bugs or feature requests.
§🔖 Keywords
stm32 · stm32f1 · rust · embedded-hal · hal · microcontroller · embedded development
Re-exports§
pub use mcu::Mcu;pub use common::ringbuf;pub use cortex_m;pub use cortex_m_rt;pub use critical_section;pub use fugit;pub use os_trait;pub use embedded_hal;pub use embedded_io;pub use nb;
Modules§
- afio
- Alternate Function I/Os
- backup_
domain - Registers that are not reset as long as Vbat or Vdd has power.
- bb
- Bit banding
- common
- dma
- Direct Memory Access
- flash
- Flash memory
- gpio
- General Purpose I/Os
- i2c
- interrupt
- mcu
- nvic_
scb - pac
- Peripheral access API for STM32F103 microcontrollers (generated using svd2rust v0.36.1 (4052ce6 2025-04-04))
- prelude
- raw_os
- rcc
- Reset & Control Clock
- spi
- time
- Time units
- timer
- uart