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]embedded-hal
trait implementations for non-DMA interfaces; use additional
struct methods for DMA interfaces [4, 5, 7]Current family support: F3, F4, L4, L5, G0, G4, H7, and WB. U5 is planned once its SVD files and PAC become available. WL support is a WIP, with many features not implemented.
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.
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 = "^0.2.9", 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::{GpioB, PinMode, OutputType}, i2c::{I2c, I2cDevice}, low_power, pac, timer::{Timer, TimerInterrupt}, };
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);
let mut pb15 = gpiob.new_pin(15, PinMode::Output);
pb15.set_high();
let mut timer = Timer::new_tim3(dp.TIM3, 0.2, &clock_cfg);
timer.enable_interrupt(TimerInterrupt::Update);
let mut scl = gpiob.new_pin(6, PinMode::Alt(4));
scl.output_type(OutputType::OpenDrain, &mut gpiob.regs);
let mut sda = gpiob.new_pin(7, PinMode::Alt(4));
sda.output_type(OutputType::OpenDrain, &mut gpiob.regs);
let i2c = I2c::new(dp.I2C1, I2cDevice::One, 100_000, &clock_cfg);
loop {
low_power::sleep_now(&mut cp.SCB);
}
} ```
stm32yxx-hal
librariesThere are some areas where design philosophy is different. For example: GPIO
type-checking, level-of-abstraction from registers/PAC, role of DMA, role of embedded-hal
traits in the API,
feature parity among STM32 families, code documentation, and clock config.
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 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 typeembedded-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()
.)```rust
/// Select pulse repetition frequency. Modifies FCRDR_CR
register, PRF
field.
enum Prf {
Medium = 0,
High = 1,
}
/// Available interrupts. Enabled in FCRDR_CR
, ...IE
fields. Cleared in FCRDR_ICR
.
enum FcRadarInterrupt {
TgtAcq,
LostTrack,
}
/// Represents a Fire Control Radar (FCR) peripheral.
pub struct FcRadar
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.
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(),
});
}
}
/// Wrap our native methods with embedded-hal
traits.
impl
fn track(&mut self, track: u8) -> Result<(), Error> {
FcRadar::track(self, track);
Ok(())
}
} ```
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 Epun's stm32wb55 bluetooth library.
STM32WL radio support is WIP, and will be provided through interaction withnewAM's stm32wl-hal library.