This library provides high-level access to STM32 peripherals.
F3
, F4
, L4
, L5
, G
, H
, U
, and W
#[cfg]
blocks, and the cfg_if!
macro to handle differences between MCUs; use separate modules
where large differences exist [2, 3]F3, F4, L4, L5, G0, G4, H7, WB, and WL. U5 is planned once its SVD files and PAC become available.
Tested on the following devices: - STM32F303 - STM32F401, F411 - STM32L476, L433, L443, L412, L432 - STM32L552 - STM32WB5MMG - STM32G431, G491 - STM32H743(V), H745 (both cores)
rustup target add thumbv7em-none-eabihf
. You'll need to change the last part if using a Cortex-M0, Cortex-M33, (Eg Stm32G0 or L5 respectively) or if you don't want to use hardware floats.cargo install flip-link
, cargo install probe-run
.git clone https://github.com/David-OConnor/stm32-hal-quickstart
.Cargo.toml
: stm32-hal2 = { version = "^1.5.0", features = ["l4x3", "l4rt"]}
memory.x
: FLASH
and RAM
lines.cargo/config.toml
: runner
and target
lines.cargo run --release
to compile and flash.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.
The blinky example, written by toudi, provides a detailed example and instructions for how to set up a blinking light (ie hello world) using an STM32F411 "blackpill" board. Its readme provides instructions for how to get started from scratch, and its code contains detailed comments explaining each part. The blinky with timer interrupt example demonstrates how to accomplish the same in a non-blocking way, using a hardware timer. It uses RTIC.
The conductivity module example is a complete example of simple production firmware. It uses the DAC, I2C, Timer, and UART peripherals, with a simple interupt-based control flow.
The PDM mic, DAC output passthrough example demonstrates how to read audio from a digital microphone, output it to headphones or speakers using the DAC, and use DMA to do this efficiently. It conducts minimal processing, but can be modified to process using DSP between input and output. This example uses RTIC.
The SPI IMU filtered example demonstrates how to configure an external IMU (3-axis accelerometer and gyroscope) over SPI, read from multiple registers using a single SPI transfer using DMA as soon as data is ready, and apply digital filtering using the CMSIS-DSP library. This example uses RTIC.
Additional examples in the examples folder demonstrate how to use various STM32 peripherals; most of these examples focus on a single peripheral.
When specifying this crate as a dependency in Cargo.toml
, you need to specify a feature
representing your MCU. If this is for code that runs on an MCU directly (ie not a library), also
include a run-time feature, following the template l4rt
. For example:
toml
cortex-m = "0.7.3"
cortex-m-rt = "0.6.13"
stm32-hal2 = { version = "^1.4.5", features = ["l4x3", "l4rt"]}
If you need embedded-hal
traits, include the embedded_hal
feature.
You can review this section of Cargo.toml to see which MCU and runtime features are available.
```rust use cortexm; use cortexmrt::entry; use stm32hal2::{ clocks::Clocks, gpio::{Pin, Port, PinMode, OutputType}, i2c::I2c, low_power, pac, timer::{Timer, TimerInterrupt}, };
fn main() -> ! { let mut dp = pac::Peripherals::take().unwrap();
let clock_cfg = Clocks::default();
clock_cfg.setup().unwrap();
let mut pb15 = Pin::new(Port::A, 15, PinMode::Output);
pb15.set_high();
let mut timer = Timer::new_tim3(dp.TIM3, 0.2, Default::default(), &clock_cfg);
timer.enable_interrupt(TimerInterrupt::Update);
let mut scl = Pin::new(Port::B, 6, PinMode::Alt(4));
scl.output_type(OutputType::OpenDrain);
let mut sda = Pin::new(Port::B, 7, PinMode::Alt(4));
sda.output_type(OutputType::OpenDrain);
let mut dma = Dma::new(dp.DMA1);
dma::mux(DmaPeriph::Dma1, DmaChannel::C1, DmaInput::I2c1Tx);
let i2c = I2c::new(dp.I2C1, Default::default(), &clock_cfg);
loop {
i2c.write(0x50, &[1, 2, 3]);
// Or:
i2c.write_dma(0x50, &BUF, DmaChannel::C1, Default::default(), &mut dma);
low_power::sleep_now();
}
} ```
Real-Time Interrupt-driven Concurrency is
a light-weight framework that manages safely sharing state between contexts. Eg between ISRs and the main loop.
Some examples use global Mutex
es, RefCell
s, and Cell
s; others use macros to simplify syntax;
some use RTIC.
stm32yxx-hal
librariesembedded-hal
traits; treats them as an optional add-onIf you'd like to learn more about the other HALs, check them out on the stm32-rs Github. You may prefer them if you prioritize strict type checks on GPIO pins, for example.
The Rust docs page is built for STM32H735
, 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, with a separate page for each STM32 family.
PRs are encouraged. Documenting each step using reference manuals is encouraged where applicable.
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 codeenable_interrupt
and clear_interrupt
functions, which accept an enum of interrupt type.embedded-hal
implementations as required, that call native methods. Note that
we design APIs based on STM32 capabilities, and apply EH traits as applicable. We only
expose these implementations if the embedded_hal
feature is selected.en.enabled()
; use en.set_bit()
.)Mode
, prefix it with the peripheral type,
eg use RadarMode
instead. This prevents namespace conflicts when importing the enums directly.```rust
/// Select pulse repetition frequency. Sets FCRDR_CR
register, PRF
field.
enum Prf {
/// Medium PRF (less than 10Ghz)
Medium = 0,
/// High PRF (10Ghz or greater)
High = 1,
}
/// Available interrupts. Enabled in FCRDR_CR
, ...IE
fields. Cleared in FCRDR_ICR
.
enum FcRadarInterrupt {
/// Target acquired, and the system is now in tracking mode.
TgtAcq,
/// Lost the track, for any reason.
LostTrack,
}
/// Represents a Fire Control Radar (FCR) peripheral.
pub struct FcRadarregs
is public, so users can use the PAC API directly, eg for unsupported features.)
pub regs: R,
pub prf: Prf,
}
impl
regs.cr.modify(|_, w| w.prf().bit(prf as u8 != 0));
Self { regs, prf }
}
/// Track a target. See H8 RM, section 3.3.5: Tracking procedures.
pub fn track(&mut self, hit_num: u8) -> Self {
// RM: "To begin tracking a target, perform the following steps:"
// 1. Select the hit to track by setting the HIT bits in the FCRDR_TR register.
#[cfg(feature = "h8")]
self.regs.tr.modify(|_, w| unsafe { w.hit().bits(hit_num) });
#[cfg(feature = "g5")]
self.regs.tr.modify(|_, w| unsafe { w.hitn().bits(hit_num) });
// 2. Begin tracking by setting the TRKEN bit in the FCRDR_TR register.
self.regs.tr.modify(|_, w| w.trken().set_bit());
// In tracking mode, the TA flag can be monitored to make sure that the radar
// is still tracking the target.
}
/// Enable an interrupt.
pub fn enable_interrupt(&mut self, interrupt: FcRadarInterrupt) {
self.regs.cr.modify(|_, w| match interrupt {
FcRadarInterrupt::TgtAcq => w.taie().set_bit(),
FcRadarInterrupt::LostTrack => w.ltie().set_bit(),
});
}
/// Clear an interrupt flag - run this in the interrupt's handler to prevent
/// repeat firings.
pub fn clear_interrupt(&mut self, interrupt: FcRadarInterrupt) {
self.regs.icr.write(|w| match interrupt {
FcRadarInterrupt::TgtAcq => w.tacf().set_bit(),
FcRadarInterrupt::LostTrack => w.ltcf().set_bit(),
});
}
} ```
This article provides some information on using this library, as well as background information on Rust embedded in general.
This library doesn't include any radio functionality for the STM32WB. If you'd like to use it with bluetooth, use this HAL in conjuction with with @eupn's stm32wb55 bluetooth library.
STM32WL radio support is WIP, and will be provided through interaction with newAM's stm32wl-hal library.
TIMx_BDTR
register, MOE
bit.