RA4M1マイコンをRustでLチカしてみる
組込みマイコンをRustでプログラムしたい
つまりARM の「M」Cortex-MをRustでベアメタル(=OSなし)でプログラムしたいということなんだけど、STM32を使えばLチカまでキーボードポチポチで簡単にできる。
そんなのわざわざ記事にする必要もないので、「Arduino UNO R4」に搭載されたルネサス製RA4M1マイコンをRust言語を使ってLチカまでやってみる。
開発用ボード
純正の「Arduino UNO R4 Minima」は使いません。なぜかというと、水晶発振子が無いから。
水晶発振子を搭載した開発用ボードを探して Waveshare RA4M1-Zero を手に入れた。
USB-C / 水晶発振子 / WS2812 RGB LED / BOOT ボタン / RESET ボタンがあるのがお気に入りのポイント。
開発環境
- Windows 11
- Windows Terminal
- VS Code
- Renesas Flash Programmer V3.21 の Windows版
Rust言語の環境整備
Rust Web サイトから 「Rustをインストール」のページに従ってインストールする。
組込みプログラミング環境整備
The Embedded Rust Bookのツールのインストールの章を参照してインストールする。
ターゲットのRA4M1マイコンは Arm Cortex-M4 (FPU付) なのでthumbv7em-none-eabihfがインストールされていればいい。
マイコンのマニュアルを入手する
RA4M1マイコンページから「ドキュメント」->「マニュアル、ガイド」-> 「Renesas RA4M1グループ ユーザーズマニュアル ハードウェア編」をダウンロードする。
「Renesas RA4M1グループ ユーザーズマニュアル ハードウェア編」の「アドレス空間」からフラッシュとメモリアドレスを確認しておく。
本MCU は、プログラムとデータの両方を格納できる4GB のリニアアドレス空間(0000 0000h ~ FFFF
FFFFh)をサポートしています。
32ビットマイコンなのでNearポインタだのFarポインタだの気にしなくていいですね。ってこと。あとメモリマップドI/Oだから周辺I/Oレジスタがいますね。
- FLASH領域が 0000 0000h(16進数)から始まって256KB(RA4M1は256KB)
- RAM領域が 2000 0000h(16進数)から始まって32KB(RA4M1は32KB)
- 周辺I/Oレジスタが 4000 0000h(16進数)から始まる。
cortex-m-quickstart
RA4M1 は STM32 と同じ ARM Cortex-M なので、
cortex-m-quickstartを使うところなんだけど、今見たらarchiveになっていた。
STM32向けに書かれた組込みRustの情報を使えるので、細かいところはチャッピーに聞いてもらうか、検索するかでなんとかして。
memory.xファイルにはRA4M1のメモリアドレスを書いておく。
MEMORY {
FLASH : ORIGIN = 0x00000000, LENGTH = 256K
RAM : ORIGIN = 0x20000000, LENGTH = 32K
}
Waveshare RA4M1-Zeroボードにブートローダーを書き込む
ミスしてマイコンを壊したか?と焦った時のために、一度練習で Renesas Flash Programmer でブートローダーを以下の記事通りに書き込んでみる。
Waveshare RA4M1-ZeroボードはBOOTボタンとRESETボタンを同時押しすると書き込みモードになる。
変なプログラムを書き込んでおかしくなっても、ブートローダーを書き込むと、Arduino UNO R4 minimaと同じ状態に戻る。
ボードの回路図を入手する
Waveshare wikiから Schematic Diagram をダウンロードする。

水晶発振子は16MHzの物が搭載されている。

通常ArduinoのLEDピンは D13(P111)なんだけど、このボードは D6(P106)にWS2812B RGB LEDが接続されている。
ということでオンボードのRGBLEDを使ってLチカをする。
Lチカ
動作するLチカコードをGitHubにおいておきます。
- ベアメタルだからno_std環境です。
- go言語のdefer関数みたいなことをしたかったからscopeguardを使う。
- Peripheral Access Crate にra4m1_fsp_pacを使う。
ほんとうはハードウエア抽象化レイヤ(HAL)を使いたかったです。
クロック
クロックの設定にちょっと癖があって。
搭載されている水晶発振子が16MHzなのでPLLが入力規定値を超えているんですよね。
まあ動けばいいか。
参考
ビルド&実行
このように
PS C:\hello-ra4m1\pac> cargo objcopy --release -- -O ihex app.hex
Compiling hello-ra4m1 v0.1.0 (C:\hello-ra4m1\pac)
Finished `release` profile [optimized] target(s) in 1.76s
PS C:\hello-ra4m1\pac>
出来た app.hex ファイルを Renesas Flash Programmer で書き込んでリセットすることで実行する。

あとがき
最初は高速オンチップオシレータ(HOCO)を48MHz駆動するつもりだったけど、HOCOCR2レジスタがra4m1_fsp_pacにないので48MHz指定できなかった。
アドレスSYSTEM.HOCOCR2 4001 E000hとわかっているので、core::ptr::write_volatile関数に直接アドレス指定すれば出来るだろうけど、水晶発振16MHzを逓倍したPLL48MHz駆動でLチカできたのでこれでいいです。。。
何とかした
HOCOCR2 レジスタのアドレスは 4001 E000hではなかったようです。
HOCOCR2 レジスタの誤記訂正
これで48MHzで駆動の高速オンチップオシレータ(HOCO)をメインクロックに設定できた。
GPTタイマー割り込みをつかってみた
1秒delayを1秒周期GPTタイマー割り込みに変更してみた。結果は変わらない。
cortex_m::interrupt::freeは必要なのかよくわかっていない。
Arduino UNO R4 MINIMAでLチカ
BOOTとRESETを同時押ししてRenesas Flash Programmerで書き込むのが面倒になったので、
Arduino としては使わないが、DAPLINKのためにSWDコネクタが必要なので、Arduino UNO R4 Minima を買ってきた。
DAPLINK + probe-rsでプログラミング
Amazonで手に入れたDAPLINKとprobe-rsでcargo runする。

用意するもの

- DAPLINKの5Vと1ピン(VCC)
- DAPLINKのSWDと2ピン(SWDIO)
- DAPLINKのGNDと3,5,9
- DAPLINKのSCKと4ピン(CLK)
- DAPLINKのRSTと10ピン(~RESET)
を接続してArduino UNO R4 Minima のSWDコネクタにリボンケーブルを接続する。

USBケーブルをDAPLINKに接続する。
probe-rsのインストール&実行
Installationのページ通りインストール。
Arduino UNO R4 MINIMAのLEDが点滅する。
probe-rsのページに書いてある通り、cargo runする。


SWDコネクタ経由でデバッグプリントできた。
[INFO ] Hello. I'm "R7FA4M1AB3CFM " (hello_ra4m1 probe_rs/src/main.rs:109)
シリアル通信を動かしてみた
このままDAPLINKにあるシリアル通信とArduino UNO R4 MINIMAのSWDコネクタにあるSCI1_RXD, SCI1_TXDを接続して、通信してみる。
- DAPLINKのRXDと8ピン(SCI1_TXD)
- DAPLINKのTXDと7ピン(SCI1_RXD)
を接続する。
cargo runする。
hello-ra4m1\uart> cargo run
Compiling hello-ra4m1 v0.1.0 (C:\Users\aki\development\hello-ra4m1\uart)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.78s
Running `probe-rs run --chip R7FA4M1AB target\thumbv7em-none-eabihf\debug\hello-ra4m1`
Erasing ✔ 100% [####################] 86.00 KiB @ 17.72 KiB/s (took 5s)
Programming ✔ 100% [####################] 86.00 KiB @ 5.75 KiB/s (took 15s)
Finished in 19.93s
[INFO ] Hello. I'm "R7FA4M1AB3CFM " (hello_ra4m1 uart/src/main.rs:633)
[DEBUG] P110pfs is 0x40040868 (hello_ra4m1 uart/src/main.rs:278)
[DEBUG] P111pfs is 0x4004086c (hello_ra4m1 uart/src/main.rs:280)
[DEBUG] P112pfs is 0x4004086c (hello_ra4m1 uart/src/main.rs:282)
[DEBUG] P113pfs is 0x4004086c (hello_ra4m1 uart/src/main.rs:284)
[DEBUG] P114pfs is 0x4004086c (hello_ra4m1 uart/src/main.rs:286)
[DEBUG] P115pfs is 0x4004086c (hello_ra4m1 uart/src/main.rs:288)
[DEBUG] P010pfs is 0x40040828 (hello_ra4m1 uart/src/main.rs:290)
[DEBUG] P011pfs is 0x40040828 (hello_ra4m1 uart/src/main.rs:292)
[DEBUG] P012pfs is 0x40040828 (hello_ra4m1 uart/src/main.rs:294)
[DEBUG] P013pfs is 0x40040828 (hello_ra4m1 uart/src/main.rs:296)
[DEBUG] P014pfs is 0x40040828 (hello_ra4m1 uart/src/main.rs:298)
[DEBUG] P015pfs is 0x40040828 (hello_ra4m1 uart/src/main.rs:300)
[DEBUG] P500pfs is 0x40040940 (hello_ra4m1 uart/src/main.rs:302)
[DEBUG] P501pfs is 0x40040940 (hello_ra4m1 uart/src/main.rs:304)
[DEBUG] P502pfs is 0x40040940 (hello_ra4m1 uart/src/main.rs:306)
[DEBUG] P503pfs is 0x40040940 (hello_ra4m1 uart/src/main.rs:308)
[DEBUG] P504pfs is 0x40040940 (hello_ra4m1 uart/src/main.rs:310)
[DEBUG] P505pfs is 0x40040940 (hello_ra4m1 uart/src/main.rs:312)
[INFO ] RXD: aaa (hello_ra4m1 uart/src/main.rs:694)
このデバッグプリントはレジスタアドレスが変だったから。
DAPLINKのCOMポートをシリアルモニターで開くと、MCU内蔵温度センサーの値を1秒ごとに垂れ流す。
36.2432 C
36.0760 C
36.0760 C
36.4104 C
36.2432 C
36.8285 C
35.9924 C
36.5776 C
36.2432 C

Discussion