STM32 Rust Page: Difference between revisions

From bibbleWiki
Jump to navigation Jump to search
 
(One intermediate revision by the same user not shown)
Line 129: Line 129:
</syntaxhighlight>
</syntaxhighlight>
=Debbugging in Rust=
=Debbugging in Rust=
==General==
==VS Code Launch Settings==
This is the current setup as of April 2024. The SVD enables to XPERIPHERALS under breakpoints.
This is the current setup as of April 2024. The SVD enables to XPERIPHERALS under breakpoints.
<syntaxhighlight lang="json">
<syntaxhighlight lang="json">
Line 166: Line 166:
}
}
</syntaxhighlight>
</syntaxhighlight>
==SWO==
 
You can output text using the SWO console which is like semi-hosting.  
==Serial Wire Out SWO Debugging==
You can output text using the SWO console which is like semi-hosting. Not the settings in the VSCode Launch
<syntaxhighlight lang="rs">
<syntaxhighlight lang="rs">
#[entry]
#[entry]

Latest revision as of 22:36, 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();
    })
}

Debbugging in Rust

VS Code Launch Settings

This is the current setup as of April 2024. The SVD enables to XPERIPHERALS under breakpoints.

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "cortex-debug",
            "request": "launch",
            "servertype": "openocd",
            "cwd": "${workspaceRoot}",
            "executable": "./target/thumbv7em-none-eabihf/debug/blink",
            "name": "Debug (OpenOCD)",
            "device": "STM32F302RETx",

            "showDevDebugOutput": "parsed",
            "preLaunchTask": "cargo build",
            "runToEntryPoint": "true",

            "configFiles": [
                "interface/stlink-v2-1.cfg",
                "target/stm32f3x.cfg"
            ],
            "svdFile": "${workspaceRoot}/STM32F302.svd",
            "swoConfig": {
                "enabled": true,
                "cpuFrequency": 8000000,
                "swoFrequency": 2000000,
                "source": "probe",
                "decoders": [
                    { "type": "console", "label": "ITM", "port": 0 }
                ]
            }
        }
    ]
}

Serial Wire Out SWO Debugging

You can output text using the SWO console which is like semi-hosting. Not the settings in the VSCode Launch

#[entry]
fn main() -> ! {
    if
        let (Some(dp), Some(cp)) = (
            pac::Peripherals::take(),
            cortex_m::peripheral::Peripherals::take(),
        )
    {
...
        let mut itm = cp.ITM;
        iprintln!(&mut itm.stim[0], "Hello World for the time");
...