CH32V003J4M6マイコンでRustでLチカをしてみた
最近マイコンで遊んでいたら、会社の同僚が、CH32V003 っていう32ビットRISC-Vマイコンが小さくて楽しそうだよ、とオススメしてきたので Rust で Lチカをしてみました。
(LED自体に抵抗が入っています。あと、変換基板に差してあるマイコンの上下が逆ですいません)
秋月で買ったもの
CH32V003 対応の Rust のコンパイル
Rust が CH32V003 自体に(まだ)対応していないため、2023年3月ころに書かれた、Rust on the CH32V003 という記事を参考に、頑張る必要があります。
というわけで、CH32 シリーズ向けの Rust 対応を進めているグループが提供している CH3200V3 向けの Rust をコンパイルします。
具体的な手順は、前述の Rust on the CH32V003 の Part 1: Custom Rust toolchain を参考にしました。
$ git clone https://github.com/ch32-rs/rust.git
$ cd rust
$ git submodule update --init --recursive
$ vi config.toml
# copied from config.example.toml
change-id = 118703
# Use defaults for codegen affecting custom builds
profile = "codegen"
[llvm]
# Use our own LLVM build instead of downloading from CI
download-ci-llvm = false
[rust]
# Enable building LLD for our target as well
lld = true
$ python x.py build
...
Build completed successfully in 0:07:57
$ rustup toolchain link custom-rv32ec $PWD/build/host/stage1
Rust のプロジェクトを作成して、CH32V003 向けにコンパイルしてみる
プロジェクトの作成と設定
$ cargo new
ch32v003j4m6-led
$ cd ch32v003j4m6-led
最低限のコードを書きます。
#![no_std]
#![no_main]
use riscv_rt::entry;
use panic_halt as _;
#[entry]
fn main() -> ! {
loop {}
}
Part 2: Boot and blink を参考に、ビルドが通るようにします。
[package]
name = "ch32v003j4m6-led"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[patch.crates-io]
riscv-rt = { git = "https://github.com/9names/riscv-rt", branch = "rv32e" }
[dependencies]
panic-halt = "0.2.0"
riscv-rt = "0.11.0"
[profile.dev]
opt-level = "s"
[build]
target = "riscv32ec-unknown-none-elf"
[unstable]
build-std = ["core", "compiler_builtins"]
PROVIDE(_hart_stack_size = 1K);
MEMORY
{
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 16K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 2K
}
REGION_ALIAS("REGION_TEXT", FLASH);
REGION_ALIAS("REGION_RODATA", FLASH);
REGION_ALIAS("REGION_DATA", RAM);
REGION_ALIAS("REGION_BSS", RAM);
REGION_ALIAS("REGION_HEAP", RAM);
REGION_ALIAS("REGION_STACK", RAM);
fn main() {
// Tell rustc to pass linker scripts to LLD
println!("cargo:rustc-link-arg=-Tmemory.x");
println!("cargo:rustc-link-arg=-Tlink.x");
// Rerun this script only when necesary
println!("cargo:rerun-if-changed=memory.x");
println!("cargo:rerun-if-changed=build.rs");
}
ビルド
$ cargo +custom-rv32ec build
実機にコピーするバイナリを作成します。
$ llvm-objcopy -O binary target/riscv32ec-unknown-none-elf/debug/ch32v003j4m6-led out.bin
実機に書き込む
WCH-LinkE の準備
WCH LinkE と CH32V002 を接続します。
- 3V3 -> マイコンの4番ピン(左下)
- GND -> マイコンの2番ピン(左上から2番目)
- SWDIO -> マイコンの8番ピン(右上)
書き込みのソフトウェアの準備
ch32v003fun が提供している minichlink を使いました。
$ git clone https://github.com/cnlohr/ch32v003fun.git
$ cd minichlink
$ make
$ ./minichlink
Warning: found at least one WCH-LinkE in ARM programming mode. To use it with minichlink, you need to change it to RISC-V mode as per https://github.com/cnlohr/ch32v003fun/issues/227
Error: Could not initialize any supported programmers
Error: Could not initialize any supported programmers
WCH-LinkE のモードの変更
PC に WCH-LinkE を差すと、青い LED が光っていたので、ドリルで横穴を開けて、ModeS
とかかれているボタンを押しながら USB を差す作業をしました。
ケースを開けてやるべきっぽいのですが、開けられませんでした。
CH32V003 に、プログラムを書き込む
$ ./minichlink -w ...../out.bin flash -b
Found WCH Link
WCH Programmer is LinkE version 2.9
Chip Type: 003
Setup success
Flash Storage: 16 kB
Part UUID : bb-71-ab-cd-23-99-bc-5b
PFlags : ff-ff-ff-ff
Part Type (B): 07-13-bb-91
Read protection: disabled
Interface Setup
Image written.
Lチカをする
Part 2: Boot and blink を参考に、Lチカのプログラミングをします。
#![no_std]
#![no_main]
use riscv_rt::entry;
use panic_halt as _;
#[entry]
fn main() -> ! {
let RCC_APB2PCENR: *mut u32 = 0x4002_1018 as _;
let GPIOC_CFGLR: *mut u32 = 0x4001_1000 as _;
let GPIOC_OUTDR: *mut u32 = 0x4001_100C as _;
unsafe {
// Enable clocks to the GPIOC bank
RCC_APB2PCENR.write_volatile(0b1_0000);
// Set pin 1 to output
GPIOC_CFGLR.write_volatile(0b0001_0000);
loop {
// Set pin 1 to high
GPIOC_OUTDR.write_volatile(0b1_0);
for _ in 0..1_000_000 {
core::hint::black_box(()); // Do nothing, but keep the loop
}
// Set pin 1 to low
GPIOC_OUTDR.write_volatile(0b0_0);
for _ in 0..1_000_000 {
core::hint::black_box(()); // Do nothing, but keep the loop
}
}
}
}
配線して電源ON
LED を マイコンPC1(右下)から GND に向けてつなぎます。
ボタン電池をマイコンの VDD から GND に向けてつなぎます。
おわり
CH32V003 というとても小さな RISC-V マイコンで、Rust で Lチカをしてみました。
かなり試行錯誤をして苦労しましたが、正解手順だけにまとめるととてもすっきりしましたね。
ソースコードは以下に置いてあります。
なにか楽しいものが作れるといいなー。
続きを書きました。
Discussion