tl;dr
- WCH 社の安価な RISC-V MCU CH32V203 を手に入れたよ
- RISC-V の firmware は rust で実装できるよ
- ch32-rs というライブラリを使えば firmware も実装しやすいよ
経緯
最近、 RISC-V か ARM に様々なエコシステムが集まっているように感じています。 そして、rust では RISC-V と ARM については、少しrust の追加セットアップは必要になりますが、rustだけでビルドができるようになっているます。 rust だけで完結するというのがとても開発環境構築にも楽でよさそうです。
最近 RISC-V である ESP32-C3 のFirmwareを rust で実装を試みていて、その他にも Rust で遊べる MCU をためそうと思い、そんな中同人誌『PICやAVRの代わりにCH55xはどうでしょう』で扱われていたWCH社の、STM32的な立ち位置のRISC-VのMCU CH32Vを見つけました。
本当は CH32V203 ではなく 50セントマイコンである CH32V003 を目当てに購入したのですが、USB 付属の CH32V203 も付いた開発ボードとMCU単体のセットが送料込みで2,500円であったので購入しました。
CH32V003F4P6 QingKe RISC-V2A 1-wire SDI System Main Frequency 48MHz,1Pcs/Kit
embedded-hal
Rust には、Arduino的な位置づけの embedded-hal という crate があります。
embedded-hal
これは、GPIOにアクセスするレジスタの操作を抽象化し、様々なMCUに対して統一した抽象レイヤを提供してくれます。 ESP32-C3 で使える esp-idf-hal も embedded-hal 経由で提供されています。
esp-idf-hal
ラズピコにもあります。
rp2040-hal
Rust では、このようなエコシステムができつつあるのはすごく魅力的です。 特に他のマイコン用のサブセットを移植した言語とは異なり、標準ライブラリは使えない成約があるにしても、言語ランタイムそのものが動くことも非常に筋が良く感じます。
CH32V での Rust 開発
先の WCH 社の RISC-V MCU の CH32V 用の crate はすでに作られていました。
ch32v2
これは STM32 で使われるレジスタの情報ファイル svd から(2023/2/20修正) embedded-hal を出力する レジスタにアクセスするラッパーを出力する svd2rust を使って作成されています。
このcrateでは以下のように、riscv32imac-unknown-none-elf をターゲットにビルドするように指定されています。
[package.metadata.docs.rs] default-target = "riscv32imac-unknown-none-elf"
依存にこのcrateを追加するだけで、cargo build
すると riscv32imac-unknown-none-elf でビルドされます。
これを使うことで Rust で開発できそうです。
サンプルリポジトリのビルドで環境構築をする
CH32V203 を使ったサンプルリポジトリが公開されています。
これをビルドするには、リポジトリをチェックアウトします。 このリポジトリでは、ローカルにch32v2 の crate リポジトリがあることが前提になっているので、Cargo.toml のその部分を書き換えます。
# Cargo.toml [dependencies] ch32v2 = { version = "0.1.5", features = [ "ch32v20x", "critical-section" ] }
Rust 側の準備は1コマンドだけ、以下のコマンドで riscv32imac-unknown-none-elf を入れておきます。
rustup target add riscv32imac-unknown-none-elf
そして rust の一般的なビルド方法をするだけです。
cargo build --release
ただし、これではファイルサイズが大きくなるため、最適化するために以下を Cargo.toml に追加しました。 このオプションはラズピコのビルド手順を紹介しているところから拝借しました。
# Cargo.toml [profile.release] codegen-units = 1 debug = false debug-assertions = false overflow-checks = false panic = 'abort' lto = true opt-level = "z" incremental = false strip = true
すると約9KBになります。
$ls -alh target/riscv32imac-unknown-none-elf/release/ -rwxrwxr-x 2 nnyn nnyn 9.0K Dec 21 07:22 ch32v203-demo
最初私はここで作成される target/riscv32imac-unknown-none-elf/release/ch32v203-demo
が ELF ファイルであるため、そのままFirmware として使えるバイナリかと思いこんでいました。
しかし、ビルドが動作できずに困っていて、ch32v203-demo のリポジトリで質問させてもらい、教えていただきました。
これを使うのではなく、以下のコマンドでバイナリファイルにする必要があります。
riscv64-unknown-elf-objcopy -O binary target/riscv32imac-unknown-none-elf/release/ch32v203-demo firmware.bin
riscv64-unknown-elf-objcopy は Ubuntu であれば以下のコマンドでインストールできます。
sudo apt install binutils-riscv64-unknown-elf
MacOS であれば以下の記事が参考になりそうです。
これでできた firmware.bin のサイズは 632 B でした。
$ls -alh firmware.bin -rwxrwxr-x 1 nnyn nnyn 632 Dec 22 20:31 firmware.bin
CH32V203開発ボードに焼く
CH32V203 には、WCH-LINKを使って焼く方法と、CH32V203 の USB を使って焼く方法があります。
CH32V203 のUSBを使う
CH32V203 は USB Device 機能があり、CH552 と同様に USB 経由で書き換えることができます。
この USB で書き込める状態にするには、CH32V203 の各ピンを以下のように接続して、リセットします。
- BOOT0: 3V3
- BOOT1: GND
開発ボード CH32V203C8T6-EVT-R0 には最初からBOOT0とBOOT1 をGND に接続するジャンパが付いており、このジャンパを外すことでプルアップされるものだと思っていましたが、そうではないようです。 BOOT0 と 3V3 とつないでリセットすることでこのモードに入ることができました。 このモードに入った後はBOOT0と3V3 は外します。
また、このボードには USB が3口付いていますが、このモードに入ることができる USB は MCU の USB1 に接続されている以下の方になります。
下のUSB-AとUSB-Cはどちらも USB2 に接続されています。
USB1 が write できる状態になると、以下のように認識します。
$lsusb Bus 003 Device 028: ID 4348:55e0 WinChipHead
これを使って焼くには wchisp を使うと楽です。wchisp は Rust 製のプログラマです。 これをインストールするには以下のように実行します。
cargo install wchisp
先程作った firmware.bin を焼くには以下のように実行します。
wchisp flash firmware.bin
WCH-LINK を使う
以下のように接続します。
WCH-LINK | CH32V203 |
---|---|
3V3 | 3V3 |
GND | GND |
WSDIO | PA13 |
WSCLK | PA14 |
開発ボード CH32V203C8T6-EVT-R0 ではこの4ポートが並んで配置されているので簡単に接続できます。
CH32V に対応した OpenOCD が、MountRiver Studio という IDE で提供されているツールの中に含まれています。 それは以下からダウンロードできます。MacOS、Linuxでもあるので助かります。
この OpenOCDを使って焼くには以下のように実行します。
sudo ./openocd -f wch-riscv.cfg -c init -c halt -c "program firmware.bin" -c exit
ch32v203-demo の動作
この firmware では PB8 をLチカします。
この開発ボードにはLED1、LED2 のポートがありますが、これはどこにも繋がっておらず、自分で接続することで動作します。なお、LOWになると光る仕様です。
以上
なにか作ったわけではないですが、Rustで RISC-V MCU CH32V を扱う一歩を踏み出すことができました!
CH32V203 は(2023/2/20修正) ATTiny のように MCU だけでは動作せず、クリスタルも2個必要で、扱いやすいとは言えませんが、クリスタルなしでも動作し、とても安価に手に入るので、これから Rust で触ってみようと思います。
2023/02/20追記
CH32V203 開発ボードを作りました!
参照
- CH32V203 Reference Manual http://www.wch-ic.com/downloads/CH32FV2x_V3xRM_PDF.html
- 開発ボードの回路図 https://www.wch.cn/downloads/CH32V20xEVT_ZIP.html