Thomas shares makes

2023-08-03

First steps with Rust on the stm32

placeholder

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.

Reply to post

You can respond to this post with an account on the Fediverse or Mastodon. Since Mastodon is decentralized, you can use your existing account or create your account on a server of your choice.

Copy and paste this URL into the search field of your favourite Fediverse app or the web interface of your Mastodon server.

Learn how @carlschwan wrote the code that loads Mastodon posts into this webpage here.

Follow me on Mastodon!