STM32F103 に Rust に stm32f1xx-hal を使ってビルドして書き込む

動機とやったこと

STM32 は、組み込み Rust の抽象レイヤーである embedded-hal がとても整っているようです。

docs.rs

STM32F1xx だけではなく、STM32G0xx などもあり、非常に充実しているようです。 このため、Rust で組み込みファームウェアを作りたいならば、STM32がとても良い選択肢になると思いました。

そのため、Rust で開発を初めてFirmwareを書き込むところまでをやってみました。

STM32F103 用の Rust のパッケージの準備

cargo init して、dependencies に以下を書き換えました。

# Cargo.toml

[dependencies]
panic-halt = "0.2.0"

cortex-m = "0.7.6"
cortex-m-rt = "0.7.1"
stm32f1xx-hal = { version = "0.10.0", features = ["rt", "stm32f103"]}
nb = "^1"

ビルドするtargetは .cargo/config で指定するようで、stm32f1xx-hal にある .cargo/config ものを利用します。

このビルドには memory.x というファイルで MCUFLASHとRAMのサイズを指定するため、stm32f1xx-hal にある memory.xかコピーして、目的のサイズに書き換えます。

MEMORY
{
  FLASH : ORIGIN = 0x08000000, LENGTH = 64k
  RAM : ORIGIN = 0x20000000, LENGTH = 20k
}

あと、必要なビルドに必要なターゲットをインストールする。これはstm32f1xx-halのREADMEのinstalling softwareに書かれています。

rustup target install thumbv7m-none-eabi

ライター

STM32 のライターとして、ST-Link V2がAmazon でも安価に購入できます。

ちょっと前に nanoDAP という Type-CのDAP-Link を購入して持っていたので、それを使っています。

Mini DAPLink Debug Probe TYPE C STM32 NRF51/52 ARM Cortex M MCU JTAG/SWD/CDC Serial Port/Drag and Drop Program Keil/MDK OpenOCD|Demo Board| - AliExpress

Build &Write

cargo-flash を使うと非常に便利です。BuildとWriteが同時に行われます。 これはUSB接続されているDAP Link を認識して、必要な形式に書き換え、

cargo install cargo-flash
cargo flash --chip STM32F103C8

VS Code で can't find crate for test can't find crate とでる

不必要なターゲットを見ているためらしい。設定に以下を追加して、でなくなりました。

// .vscode/settings.json
{
  "rust-analyzer.checkOnSave.allTargets": false
}

cargo-flashを使わずopenocdでbuild & write

一応、cargo-flash を使う前に試していた手順を残しておきます。

ビルドするには、cargo build するだけで良いです。

cargo build

それを、書き込むときに使うものに、書き換えます。Ubuntu 22.04 であれば binutils-arm-none-eabi をインストールすると arm-none-eabi-objcopy が使えます。

arm-none-eabi-objcopy -O binary ./target/thumbv7m-none-eabi/debug/try-rust-stm32 firmware.bin

OpenOCD に ST-Link と DAP-Link(nanoDAP) の設定があり、それを読み込むようにします。

# openocd.cfg

# DAP-Link
source [find interface/cmsis-dap.cfg]
# ST-Link
# source [find interface/stlink-v2.cfg]

source [find target/stm32f1x.cfg]

これを実行するコマンドをつくりました。いろいろ検索した結果、以下のコマンドになりました。

#!/bin/bash
set -xe

cargo build

arm-none-eabi-objcopy -O binary ./target/thumbv7m-none-eabi/debug/try-rust-stm32 firmware.bin

sudo /usr/bin/openocd -f openocd.cfg \
    -c init \
    -c "reset halt" \
    -c "flash write_image erase firmware.bin 0x08000000" \
    -c "verify_image firmware.bin" \
    -c "reset" \
    -c shutdown

STM32G030 でもできた

STM32G030J6M6 は SOP-8 パッケージで、そしてTaoBaoで150円くらいで買えます。内蔵オシレータも付いていて、MCU単体で動作する便利なやつです。 STM32F103 よりは、STM32G030 を小物に使いたく、STM32 での Rust チャレンジをしていました。 stm32g0xx-hal

一度ハンダブリッジがあって動かなかったという凡ミスをしたのですが、その後は動作するようになりました。