This library provides high-level access to STM32 peripherals. It's based on the STM32 Peripheral Access Crates generated by svd2rust. It provides a consistent API across multiple STM32 families, with minimal code repetition. This makes it easy to switch MCUs within, or across families, for a given project.
Family support: F3, F4, L4, L5, G0, G4, and H7. U5 is planned once its SVD files and PAC become available.
Motivation: Use STM32s in real-world hardware projects. Be able to switch MCUs with minimal code change.
Design priority: Get hardware working with a robust feature set, aimed at practical uses. The freedom to choose the right MCU for each project, without changing code bases.
Review the syntax overview example
for example uses of many of this library's features. Copy and paste its whole folder (It's set up
using Knurling's app template), or copy parts of Cargo.toml
and main.rs
as required.
```rust use cortexm; use cortexmrt::entry; use stm32hal2::{ clocks::Clocks, gpio::{GpioB, PinNum, PinMode, OutputType, AltFn}, i2c::{I2c, I2cDevice}, low_power, pac, timer::{Event::TimeOut, Timer}, };
fn main() -> ! { let mut cp = cortex_m::Peripherals::take().unwrap(); let mut dp = pac::Peripherals::take().unwrap();
let clock_cfg = Clocks::default();
clock_cfg.setup(&mut dp.RCC, &mut dp.FLASH).unwrap();
let mut gpiob = GpioB::new(dp.GPIOB, &mut dp.RCC);
let mut pb15 = gpiob.new_pin(PinNum::P15, PinMode::Output);
pb15.set_high();
let mut timer = Timer::new_tim3(dp.TIM3, 0.2, &clock_cfg, &mut dp.RCC);
timer.listen(TimeOut);
let mut scl = gpiob.new_pin(PinNum::P6, PinMode::Alt(AltFn::Af4));
scl.output_type(OutputType::OpenDrain, &mut gpiob.regs);
let mut sda = gpiob.new_pin(PinNum::P7, PinMode::Alt(AltFn::AF4));
sda.output_type(OutputType::OpenDrain, &mut gpiob.regs);
let i2c = I2c::new(dp.I2C1, I2cDevice::One, 100_000, &clock_cfg, &mut dp.RCC);
loop {
low_power::sleep_now(&mut cp.SCB);
}
} ```
The library is influenced by the stm32fyxx
HALs, and a number of the modules here are modified
versions of those. There are some areas where design philosophy is different. For example: GPIO
type-checking, level-of-abstraction from registers/PAC, role of EH traits in the API,
feature parity among STM32 families, and clock config.
Most peripheral modules are independent: The only dependency they have within this library
is the ClockCfg
trait, which we may move to a standalone crate later. This makes
it easy to interchange them with other projects.
The Rust docs page is built for STM32L4x3, and some aspects are not accurate for other variants. We currently don't have a good solution to this problem, and may self-host docs in the future.
PRs are encouraged. Documenting each step using reference manuals is encouraged, but not required.
Most peripheral modules use the following format:
#[repr(u8)]
for their associated register valuesregs
field that is the appropriate reg block. Where possible, this is defined generically
in the implementation, eg:
U: Deref<Target = pac::usart1::RegisterBlock>,
. Reference the stm32-rs-nightlies Github
to identify when we can take advantage of this.PeriphConfig
struct owned by the peripheral struct.
This struct impls Default
.new
that performs setup code, including RCC peripheral enable and resetenable_interrupt
and clear_interrupt
functions, which accept an enum of interrupt typeembedded-hal
implementations as required, that call native methods. Note that
we design APIs based on STM32 capabilities, and apply EH traits as applicable.