First steps with Rust on the stm32

A stm32 based traffic light I built for fun (and my kids) years ago
Since the Rust programming language is all the rage, I started exploring this programming language during the summer. These are my notes on what I needed to do to set up a working development environment using the hardware I already had in my lab.
Hello World blinky
To start off simple, I followed instructions on https://github.com/stm32-rs/stm32f1xx-hal to build the blink example program.
Flashing Using Black magic probe
Connecting the device
To connect the STM32 black magic probe to the Device under test, the usual connections are required:
- B8 = SWDCLK
- B9 = SWDIO
- Vcc = Vcc
- GND = GND
Installing a working GDB
To avoid hitting this compatibility bug I hit with gdb-multiarch, I installed the first older (8.3) GDB that came to my mind:
wget -P /tmp --progress=dot:giga https://developer.arm.com/-/media/Files/downloads/gnu-rm/9-2019q4/gcc-arm-none-eabi-9-2019-q4-major-x86_64-linux.tar.bz2 sudo mkdir -p /opt/TOOL_ARMGCCEMB sudo tar -xf /tmp/gcc-arm-none-eabi-9-2019-q4-major-x86_64-linux.tar.bz2 -C /opt/TOOL_ARMGCCEMB rm /tmp/gcc-arm-none-eabi-9-2019-q4-major-x86_64-linux.tar.bz2 sudo apt install libncurses5
I could then successfully run the commands found on the black magic probe website. A quick look through the project folder revealed the .elf program file. As you can see, GDB can step through the code.
thomas@roper ~ % /opt/TOOL_ARMGCCEMB/gcc-arm-none-eabi-9-2019-q4-major/bin/arm-none-eabi-gdb GNU gdb (GNU Tools for Arm Embedded Processors 9-2019-q4-major) 8.3.0.20190709-git Copyright (C) 2019 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "--host=x86_64-linux-gnu --target=arm-none-eabi". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word". (gdb) target extended-remote /dev/ttyACM0 Remote debugging using /dev/ttyACM0 (gdb) monitor swdp_scan Target voltage: Not Detected Available Targets: No. Att Driver 1 STM32F1 medium density (gdb) att 1 Attaching to Remote target warning: No executable has been specified and target does not support determining executable automatically. Try using the "file" command. 0x08000b54 in ?? () (gdb) file /home/thomas/pets/verkeerslicht-rust/target/ .rustc_info.json CACHEDIR.TAG debug/ thumbv7m-none-eabi/ (gdb) file /home/thomas/pets/verkeerslicht-rust/target/thumbv7m-none-eabi/ CACHEDIR.TAG debug/ (gdb) file /home/thomas/pets/verkeerslicht-rust/target/thumbv7m-none-eabi/debug/ .cargo-lock .fingerprint/ build/ deps/ examples/ incremental/ verkeerslicht-rust verkeerslicht-rust.d (gdb) file /home/thomas/pets/verkeerslicht-rust/target/thumbv7m-none-eabi/debug/verkeerslicht-rust A program is being debugged already. Are you sure you want to change the file? (y or n) y Reading symbols from /home/thomas/pets/verkeerslicht-rust/target/thumbv7m-none-eabi/debug/verkeerslicht-rust... (gdb) load Loading section .vector_table, size 0x130 lma 0x8000000 Loading section .text, size 0x2d78 lma 0x8000130 Loading section .rodata, size 0x9cc lma 0x8002eb0 Start address 0x8000130, load size 14452 Transfer rate: 11 KB/sec, 903 bytes/write. (gdb) run The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /home/thomas/pets/verkeerslicht-rust/target/thumbv7m-none-eabi/debug/verkeerslicht-rust ^C Program received signal SIGINT, Interrupt. 0x08000c82 in cortex_m::peripheral::syst::<impl cortex_m::peripheral::SYST>::has_wrapped (self=0x8002a3b <stm32f1xx_hal::timer::counter::SysCounterHz::wait+22>) at /home/thomas/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-0.7.7/src/peripheral/syst.rs:136 136 } (gdb) bt #0 0x08000c82 in cortex_m::peripheral::syst::<impl cortex_m::peripheral::SYST>::has_wrapped (self=0x8002a3b <stm32f1xx_hal::timer::counter::SysCounterHz::wait+22>) at /home/thomas/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-0.7.7/src/peripheral/syst.rs:136 #1 0x08002a3a in stm32f1xx_hal::timer::counter::SysCounterHz::wait (self=0x20004f84) at /home/thomas/.cargo/registry/src/github.com-1ecc6299db9ec823/stm32f1xx-hal-0.10.0/src/timer/counter.rs:270 #2 0x08000a52 in verkeerslicht_rust::__cortex_m_rt_main () at src/main.rs:49 #3 0x080008f2 in main () at src/main.rs:19 (gdb) l 0 file: "/home/thomas/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-0.7.7/src/peripheral/syst.rs", line number: 0, symbol: "???" 1 //! SysTick: System Timer 2 3 use volatile_register::{RO, RW}; 4 5 use crate::peripheral::SYST; 6 7 /// Register block 8 #[repr(C)] 9 pub struct RegisterBlock { 10 /// Control and Status file: "/home/thomas/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-0.7.7/src/peripheral/syst.rs", line number: 0, symbol: "???" 1 //! SysTick: System Timer 2 3 use volatile_register::{RO, RW}; 4 5 use crate::peripheral::SYST; 6 7 /// Register block 8 #[repr(C)] 9 pub struct RegisterBlock { 10 /// Control and Status (gdb) n stm32f1xx_hal::timer::counter::SysCounterHz::wait (self=0x20004f84) at /home/thomas/.cargo/registry/src/github.com-1ecc6299db9ec823/stm32f1xx-hal-0.10.0/src/timer/counter.rs:273 273 Err(nb::Error::WouldBlock) (gdb) 270 if self.tim.has_wrapped() { (gdb) 275 } (gdb) verkeerslicht_rust::__cortex_m_rt_main () at src/main.rs:49 49 block!(timer.wait()).unwrap(); (gdb) Note: automatically using hardware breakpoints for read-only addresses. 49 block!(timer.wait()).unwrap(); (
Turning it into a traffic light
Armed with VIM ALE configured with rust-analyzer and the stm32 hal code, my next steps are to convert this simple program to Rust, trying to map the code using Rust concepts I knew already.
For my original traffic light gimmic, I quickly whipped up a truth table as multi dimensional C array. I'll have to see how to elegantly implement the logic to call gpio set_high and set_low() functions.
To be continued...
Liked something? Worked on something similar? Let me know what you think on Mastodon!
You can use your Mastodon account to reply to this post.