I'm trying to get started with embedded Rust on my own devboard. I've been using this for some time with C++ and I'm trying to port it to Rust.
I'm trying to get the simplest possible program running by turning on some LEDs that I have on the board but I'm getting no reaction so I'm sure there's something I'm missing.
I'm trying to just enable the HSI16 clock and set it as the system clock. Then I'm trying to enable the GPIOA and GPIOB ports and set the LEDs high. Should be simple enough I thought but I'm uploading the code and getting no reaction.
I'm running on an STM32L431RC
#![no_std]
#![no_main]
use cortex_m_rt::entry;
use panic_halt as _;
use stm32l4::stm32l4x1;
#[entry]
fn main() -> ! {
let peripherals = stm32l4x1::Peripherals::take().unwrap();
let gpioa = &peripherals.GPIOA;
let gpiob = &peripherals.GPIOB;
let rcc = &peripherals.RCC;
rcc.cr.write(|w| w.hsion().set_bit());
while !rcc.cr.read().hsirdy().bit_is_set() {}
rcc.cfgr.write(|w| unsafe{w.sw().bits(0b01)});
while rcc.cfgr.read().sws().bits() != 0b01 {}
rcc.ahb2enr.write(|w| w.gpioaen().bit(true));
rcc.ahb2enr.write(|w| w.gpioben().bit(true));
gpioa.moder.write(|w| w.moder11().bits(0b01));
gpioa.bsrr.write(|w| w.bs11().bit(true));
gpiob.moder.write(|w| w.moder10().bits(0b01));
gpiob.bsrr.write(|w| w.bs10().bit(true));
loop {}
}
I'm sure I've made some simple mistake I'm missing.
I've tried to remove the target directory with the binary and make a fresh build to make sure the correct binary is being uploaded. I seem to get a debug build, I'm guessing that's some cargo setting I have at the moment. Any other file I can share to verify I'm doing everything correct?
you are using the so-called "PAC" (peripheral access crate) directly, which is the low-level abstraction. although they are usually not marked as unsafe, because generally they would not cause UB regarding rust's definition of memory safety. however, this abstraction cannot prevent logic errors, due to the low level data types doesn't hold any higher level contracts and invariants.
the PACs are usually supposed to be used by HAL developers, and application developers should use the "HAL" crates, which build high level types on top of the PACs low level data definitions. in your case, I think you are looking for the stm32l4xx-hal crate, maintained by the stm32-rs team:
I didn't read the reference manual of the chip, so I cannot tell which part of your code might be problematic, but here's how you use the HAL crate to do similar configuration as your example. you can read the relevant code (e.g. the freeze() method) of the HAL crate if you want to dig deeper:
// this `.constraint()` method convert `PAC` type into `HAL` type
// note the linearity: the old `PAC` type is consumed -- you cannot ".constrain()` twice
let mut rcc = peripherals.RCC.constrain();
// then you can configure the RCC using the `HAL` type.
// this example enables the HSI16
// notice the linearity of the CFGR type: it consumes `self` and returns another `Self`
let cfgr = rcc.cfgr.pll_source(PllSource::HSI16);
// apply the clock configuration to hardware. `freeze()` will wait for the clock to be stable
// at the same time, configure the flash and power accordingly
// this is required by the HAL `freeze()` API
let mut flash = peripherals.FLASH.constrain();
let mut pwr = peripherals.PWR.constrain(&mut rcc.apb1r1);
let _clocks = cfgr.freeze(&mut flash.acr, &mut pwr);
// I'm assuming the LED pin is gpio a11
let mut gpioa = peripherals.GPIOA.split(&mut rcc.ahb2);
let mut led = gpioa.pa11.into_push_pull_output();
// turn the led pin voltage to high
led.set_high();
// you can do the same for other gpio pins
loop {}