STM32 Rust Page: Difference between revisions
Line 19: | Line 19: | ||
Now we need to install the arm software. For me I went to the arm download page and took the latest version.[[https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads here]]<br> | Now we need to install the arm software. For me I went to the arm download page and took the latest version.[[https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads here]]<br> | ||
I unzipped it and put it in the /opt directory, currently arm-gnu-toolchain-14.2, and add it to my path in .bashrc | I unzipped it and put it in the /opt directory, currently arm-gnu-toolchain-14.2, and add it to my path in .bashrc | ||
=Blinky In Rust= | |||
The new classic since hello world | The new classic since hello world | ||
<syntaxhighlight lang="rs"> | <syntaxhighlight lang="rs"> | ||
Line 58: | Line 58: | ||
cortex_m::asm::nop(); | cortex_m::asm::nop(); | ||
} | } | ||
} | |||
</syntaxhighlight> | |||
=Interrupts In Rust= | |||
This involves creating Mutexes to make the shared resource available. First we create these Mutexes | |||
<syntaxhighlight lang="rs"> | |||
type LedPin = gpio::PB10<Output<PushPull>>; | |||
static LED: Mutex<RefCell<Option<LedPin>>> = Mutex::new(RefCell::new(None)); | |||
type ButtonPin = gpio::PC13<Input>; | |||
static BUTTON: Mutex<RefCell<Option<ButtonPin>>> = Mutex::new(RefCell::new(None)); | |||
</syntaxhighlight> | |||
Next we setup the interrupt | |||
<syntaxhighlight lang="rs"> | |||
#[entry] | |||
fn main() -> ! { | |||
... | |||
// Moving ownership of the led to the global LED | |||
critical_section::with(|cs| *LED.borrow(cs).borrow_mut() = Some(led)); | |||
// Configuring the user button to trigger an interrupt when the button is pressed. | |||
let mut user_button = gpioc.pc13; | |||
// Make button an interrupt source | |||
syscfg.select_exti_interrupt_source(&user_button); | |||
// Set when to trigger | |||
user_button.trigger_on_edge(&mut exti, Edge::Rising); | |||
// Enable the interrupt for button | |||
user_button.enable_interrupt(&mut exti); | |||
// Get the interrupt number | |||
let interrupt_num = user_button.interrupt(); | |||
// Moving ownership to the global BUTTON | |||
critical_section::with(|cs| *BUTTON.borrow(cs).borrow_mut() = Some(user_button)); | |||
// Enable Interrupt | |||
unsafe { NVIC::unmask(interrupt_num) }; | |||
loop { | |||
asm::wfi(); | |||
} | |||
} | |||
</syntaxhighlight> | |||
After this we need to create the interrupt. The name of the function is derived from the line to NVIC. The is PC15 so EXTI15_10 is the correct name as EXI15_10 is Pin 10-15 or the GPIOs. We need PB10 so this is the correct one. If it was PB9 then this would be EXTI9_5. | |||
<syntaxhighlight lang="rs"> | |||
// This may be called more than once per button press from the user since the button may not be debounced. | |||
#[interrupt] | |||
fn EXTI15_10() { | |||
critical_section::with(|cs| { | |||
// Toggle the LED | |||
LED.borrow(cs) | |||
.borrow_mut() | |||
.as_mut() | |||
.unwrap() | |||
.toggle() | |||
.unwrap(); | |||
// Clear the interrupt pending bit so we don't infinitely call this routine | |||
BUTTON | |||
.borrow(cs) | |||
.borrow_mut() | |||
.as_mut() | |||
.unwrap() | |||
.clear_interrupt(); | |||
}) | |||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> |
Revision as of 22:33, 5 February 2025
Introduction
This is meant to be a general page for rust when using STM32
Install Rust For Embedded
First we install rust. This adds something to ~/.bashrc so rebooting is the quickest way
sudo apt install curl
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
For stm32 we need the toolchain
rustup target add thumbv7em-none-eabihf
cargo install cargo-binutils
cargo install cargo-generate
Install the gcc tools
sudo apt install gdb-multiarch openocd qemu-system-arm
Now we need to install the arm software. For me I went to the arm download page and took the latest version.[here]
I unzipped it and put it in the /opt directory, currently arm-gnu-toolchain-14.2, and add it to my path in .bashrc
Blinky In Rust
The new classic since hello world
#[entry]
fn main() -> ! {
if let Some(dp) = pac::Peripherals::take() {
// Set up the system clock.
let mut rcc = dp.RCC.constrain();
// Get the GPIOB peripheral
let mut gpiob = dp.GPIOB.split(&mut rcc.ahb);
// (Re-)configure PE13 as output
let mut led = gpiob.pb13.into_push_pull_output(&mut gpiob.moder, &mut gpiob.otyper);
led.set_low().unwrap();
loop {
led.toggle().unwrap();
// Wait for 1_000_000 cycles
cortex_m::asm::delay(1_000_000);
if led.is_set_low().unwrap() {
led.set_high().unwrap();
} else {
led.set_low().unwrap();
}
// Wait for 1_000_000 cycles
cortex_m::asm::delay(1_000_000);
}
}
loop {
cortex_m::asm::nop();
}
}
Interrupts In Rust
This involves creating Mutexes to make the shared resource available. First we create these Mutexes
type LedPin = gpio::PB10<Output<PushPull>>;
static LED: Mutex<RefCell<Option<LedPin>>> = Mutex::new(RefCell::new(None));
type ButtonPin = gpio::PC13<Input>;
static BUTTON: Mutex<RefCell<Option<ButtonPin>>> = Mutex::new(RefCell::new(None));
Next we setup the interrupt
#[entry]
fn main() -> ! {
...
// Moving ownership of the led to the global LED
critical_section::with(|cs| *LED.borrow(cs).borrow_mut() = Some(led));
// Configuring the user button to trigger an interrupt when the button is pressed.
let mut user_button = gpioc.pc13;
// Make button an interrupt source
syscfg.select_exti_interrupt_source(&user_button);
// Set when to trigger
user_button.trigger_on_edge(&mut exti, Edge::Rising);
// Enable the interrupt for button
user_button.enable_interrupt(&mut exti);
// Get the interrupt number
let interrupt_num = user_button.interrupt();
// Moving ownership to the global BUTTON
critical_section::with(|cs| *BUTTON.borrow(cs).borrow_mut() = Some(user_button));
// Enable Interrupt
unsafe { NVIC::unmask(interrupt_num) };
loop {
asm::wfi();
}
}
After this we need to create the interrupt. The name of the function is derived from the line to NVIC. The is PC15 so EXTI15_10 is the correct name as EXI15_10 is Pin 10-15 or the GPIOs. We need PB10 so this is the correct one. If it was PB9 then this would be EXTI9_5.
// This may be called more than once per button press from the user since the button may not be debounced.
#[interrupt]
fn EXTI15_10() {
critical_section::with(|cs| {
// Toggle the LED
LED.borrow(cs)
.borrow_mut()
.as_mut()
.unwrap()
.toggle()
.unwrap();
// Clear the interrupt pending bit so we don't infinitely call this routine
BUTTON
.borrow(cs)
.borrow_mut()
.as_mut()
.unwrap()
.clear_interrupt();
})
}