STM32 Rust Page: Difference between revisions

From bibbleWiki
Jump to navigation Jump to search
Line 1: Line 1:
=Introduction=
=Introduction=
This is meant to be a general page for rust when using STM32
This is meant to be a general page for rust when using STM32
==Install Rust For Embedded==
=Install Rust For Embedded=
First we install rust. This adds something to ~/.bashrc so rebooting is the quickest way
First we install rust. This adds something to ~/.bashrc so rebooting is the quickest way
<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
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=
=Blinky In Rust=
The new classic since hello world
The new classic since hello world

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();
    })
}