CH32V203をPlatformIOで開発するときにやっていることをまとめたものです。
tl;dr
- WCHのRISC-VマイコンCH32Vシリーズは、STM32のペリフェラルをRISC-Vに移植したようなマイコンで、割と安価に購入できるよ。秋月でも取り扱いがあるよ。
- 組み込みファームウェアの開発プラットフォームである PlatformIO で、CH32Vを開発できるよ。
- PlatformIOの公式のモジュールと違ってとっかかりのサポートが薄いけど、それがわかっていれば十分使えるよ。
WCHのRISC-VマイコンCH32Vシリーズとは
WCHから出ているRISC-Vマイコンであり、ペリフェラルの機能はSTM32シリーズにとても似せてあるものです。安価に購入でき、USB機能も持っていることから、私としては積極的に使ってきています。
その中でもCH32V203C8T6は、LCSCで USD 0.62-(約90円) で購入できます。
CH32V203C8T6 WCH(Jiangsu Qin Heng) | C3001172 - LCSC Electronics
Aliexpressの公式ショップでも、USD 16.15/20pcsで扱っています。
20Pcs/Lot CH32V203 RISC-V MCU 144MHz 2*USB touchkey CAN - AliExpress
これの更に良いところが、USB経由で書き込める機能を持っています。BOOT1をLowにし、BOOT0をHighにして電源を投入することで、USBで書き込める状態になります。
USBでの書き込みには、公式ツールWCHISPToolを使うか、wchispを使います。私は、CLIでLinux、MacOSでも利用できるwchispを使っています。
このシリーズの中でも、USB機能はなくても安価なCH32V003については、開発の仕方を記事にしたりしました。
CH32V203と、CH32V003を、ProMicro型にしたマイコン開発ボードを、Boothで販売しています。
最近は、CH32X035という安価なマイコンが、CH32V203相当の機能がありながら、USB PD Sink機能もついていてかなり挑戦的なマイコンになっていて、気になっています。
ということで、安価にUSBを使ったマイコンが欲しいならば、良さそうな選択肢といえます。
CH32Vシリーズの公式開発環境
CH32Vシリーズの公式の開発環境は、MounRiverStudioというEclipseをベースにした開発環境です。ここにgcc、OpenOCD、公式SDKが含まれています。
公式SDK自体は、GitHub上で公開されています。openwchというGitHubユーザで、各MCUのリポジトリが作られており、その中のC++というディレクトリに、MounRiverStudioのプロジェクトファイルという形で提供されています。なお、ライセンスはApache 2.0です。
Eclipseに抵抗がなければ、こちらの環境を使うのも良いでしょう。
VS Code上で開発できるPlatformIO
VS Codeをベースとした拡張機能として、マイコンの開発環境を整備したPlatformIOというプロダクトがあります。
Your Gateway to Embedded Software Development Excellence · PlatformIO
Arduinoと同様に、そのマイコンをビルドするためのgccや、OpenOCD等のツールを自動でダウンロードして利用できる環境を一括して用意してくれます。
PlatformIOについては、以前VS Code Conference Japan 2021で『PlatformIO で シュッと Arduino開発を高速化しよう Speed up your Arduino development with PlatformIO!』というタイトルで発表しました。
PlatformIOをCH32Vシリーズで使う
このPlatformIOを使ってCH32Vシリーズを開発できるようにする環境(Platform)が、コミュニティでメンテナンスされています。
このインストール方法についても公式ドキュメントが用意されています。これをみながらインストールを進めることができます。若干公式ドキュメントは、Installだけで力尽きている感じがあります。
ただし、現状x86_64のWindows、MacOS、Linuxで利用できますが、ラズパイのようなarm64では利用できません。MacOSではM1 Macでも特に問題なく利用できます(OpenOCDは動かない問題はありますが)。これは、RISC-Vにカスタム拡張が入っていて(RV32IMACXW)、カスタムのgccが必要であり、x86_64のビルドしか提供されていないのがあります。(いや、gccがGNUなのにコード公開していないという話もあるのですが、OpenOCDのように請求したらいただけるのでしょうけれど、なんだかなと)
実際にどう使っているか
PlatformIOでは、Platformをインストールすると、プロジェクト作成ウィザードから、目的のボードやマイコンを選べるようになります。generic CH32V203C8T6を選ぶことができます。
さらに、フレームワークを選択します。私の場合は、noneos-sdk、リアルタイムOSなしのSDKを選びます。
プロジェクトを作成するとVS Codeで、プロジェクトが開かれます。
platformio.ini に、選択した設定が記述されています。
; platfromio.ini [env:genericCH32V203C8T6] platform = ch32v board = genericCH32V203C8T6 framework = noneos-sdk
公式のPlatformIOが整備しているPlatformであれば、この時点でビルド可能な状態になりますが、現状そうはなっていません。src、includeディレクトリが空になっています。
ここには、MounRiverStudioののSDKにあるUserディレクトリのコードをsrcに入れる想定になっています。 ただし、システムクロックの初期設定ファイルである system_ch32v20x.c、system_ch32v20x.h は除いて、ch32v20x_conf.h、ch32v20x_it.c、ch32v20x_it.h、main.cpp のみを入れるようにしてください。
すると、ビルドが通るようになります。
書き込みをする
PlatformIOではUploadボタン、もしくはコマンド「PlatformIO: Upload」を実行するとWCH-LinkE経由で書き込みができます。
このPlatformIOのCH32Vパッケージでは、複数のアップロードツール(OpenOCD、wchisp、minichlink)に対応しています。標準では、OpenOCDになっていますが、CH32V203が持つUSB経由で書き込む機能を利用する場合は、以下のようにupload_protocol=isp
を指定します。
; platformio.ini [env:genericCH32V203C8T6] platform = ch32v board = genericCH32V203C8T6 framework = noneos-sdk upload_protocol = isp
公式デバッガWCH-Linkを使う場合に、MacOSだとOpenOCDが上手く動かない問題への対応として、私の場合はminichlinkを以下のように指定しています。
; platformio.ini [env:genericCH32V203C8T6] platform = ch32v board = genericCH32V203C8T6 framework = noneos-sdk upload_protocol = minichlink
STM32の開発時との違って面倒なところ
STM32では、STM32CubeMXを使うことで、クロックの設定、ペリフェラルの初期設定は、GUIでポチポチすると行うことができます。
しかし、CH32Vシリーズにはそのような機能はないため、構造体に設定を定義して公式SDKを呼び出して初期化する必要があります。
クロックの設定だけは、system_ch32v20x.c に定義されており、ビルドフラグで設定可能です。
/* Clock Definitions */#ifdef SYSCLK_FREQ_HSEuint32_t SystemCoreClock = SYSCLK_FREQ_HSE; /* System Clock Frequency (Core Clock) */#elif defined SYSCLK_FREQ_48MHz_HSEuint32_t SystemCoreClock = SYSCLK_FREQ_48MHz_HSE; /* System Clock Frequency (Core Clock) */#elif defined SYSCLK_FREQ_56MHz_HSEuint32_t SystemCoreClock = SYSCLK_FREQ_56MHz_HSE; /* System Clock Frequency (Core Clock) */#elif defined SYSCLK_FREQ_72MHz_HSEuint32_t SystemCoreClock = SYSCLK_FREQ_72MHz_HSE; /* System Clock Frequency (Core Clock) */#elif defined SYSCLK_FREQ_96MHz_HSEuint32_t SystemCoreClock = SYSCLK_FREQ_96MHz_HSE; /* System Clock Frequency (Core Clock) */#elif defined SYSCLK_FREQ_120MHz_HSEuint32_t SystemCoreClock = SYSCLK_FREQ_120MHz_HSE; /* System Clock Frequency (Core Clock) */#elif defined SYSCLK_FREQ_144MHz_HSEuint32_t SystemCoreClock = SYSCLK_FREQ_144MHz_HSE; /* System Clock Frequency (Core Clock) */#elif defined SYSCLK_FREQ_48MHz_HSIuint32_t SystemCoreClock = SYSCLK_FREQ_48MHz_HSI; /* System Clock Frequency (Core Clock) */#elif defined SYSCLK_FREQ_56MHz_HSIuint32_t SystemCoreClock = SYSCLK_FREQ_56MHz_HSI; /* System Clock Frequency (Core Clock) */#elif defined SYSCLK_FREQ_72MHz_HSIuint32_t SystemCoreClock = SYSCLK_FREQ_72MHz_HSI; /* System Clock Frequency (Core Clock) */#elif defined SYSCLK_FREQ_96MHz_HSIuint32_t SystemCoreClock = SYSCLK_FREQ_96MHz_HSI; /* System Clock Frequency (Core Clock) */#elif defined SYSCLK_FREQ_120MHz_HSIuint32_t SystemCoreClock = SYSCLK_FREQ_120MHz_HSI; /* System Clock Frequency (Core Clock) */#elif defined SYSCLK_FREQ_144MHz_HSIuint32_t SystemCoreClock = SYSCLK_FREQ_144MHz_HSI; /* System Clock Frequency (Core Clock) */#elseuint32_t SystemCoreClock = HSI_VALUE; /* System Clock Frequency (Core Clock) */#endif
これを設定するには、platformio.iniを書き換えます。HSE=High Speed External、HSI=High Speed Internalで、内蔵のクロックを使う場合にはHSIを指定します。指定が無いと外部クロックを検出しようとして、検出できないと遅いHSIに自動で切り替わる機能があるため、適切に設定が必要です。
; platformio.ini build_flags = -D SYSCLK_FREQ_96MHz_HSI=96000000
公式SDKの使い方を学ぶ
公式SDKには、ドキュメントは存在しません。しかし、元がSTM32の古いライブラリにちなんでいることもあり、下記の本が参考になります。というか、私は各ペリフェラルを使うために必要な作法を、この書籍を読んで理解するようにしています。
10年以上前の古い本ですが、CH32Vを使うには非常に参考になります。
例えば、UART TXを標準のピン以外でも使えるようにする、Alternate Functionsという機能があります。これを利用するためにレジスタを設定していましたが、動作しませんでした。この本を読んで、Alternate Functionsを使うためにはAlternate Functionsにクロックを設定する必要があることを知りました。STM32CubeMXだったらGUIでやって、生成してくれる範囲ですね。
また、WCHのGitHubリポジトリには、公式SDKを使ったサンプルコードも、EVT/EXAMというディレクトリにコミットされています。MounRiverStudioで読み込めるようになっています。多種多様に用意されているように見えますが、意外と簡単な内容になっています。
サンプルコードをPlatformIOで使う
PlatformIOでの開発においても、サンプルコードのUserディレクトリをsrcにコピーしてこればだいたい動作すると思います(system_ch32v20x.c、system_ch32v20x.hは除いてください)。ですが、中には簡単には動作しないものもあります。
例えば、CH32V203のUSBキーボードのサンプルが用意されていますが、User内に複数のディレクトリを持って構築されています。
その場合、なんとかlibに分離したりして動くように持っていきます。PlatformIOはlibにディレクトリを作ると、一つのライブラリとして認識します。各include文から各ライブラリの依存関係をツリーにして、その順にビルドしてくれます。そのため、User/USBLIBの中にあるCONFIG、USB-Driverを、lib/USBLIB-CONFIG、lib/USBLIB-Driverというライブラリとして切り出し、src、includeから参照するようにします。慣れが必要で、わかってくるとできる感じがします。
実際にこのサンプルコードを動作するようにしたのを以下にコミットしています。
また、一部、PlatformIOのCH32Vパッケージが利便性のため改変していることもあって、それが原因で動かないことがあります。その場合には、PlatformIOのパッケージのコードを見て、原因を探っていたりします。
PlatformIOのCH32Vパッケージの他の機能
system_ch32v20x.c、system_ch32v20x.hは、パッケージで提供されますが、書き換えたかったりすることもあると思います。
この辺りを設定で有効無効を設定できるようにはなっています。
たとえば、system_ch32v20x.c、system_ch32v20x.hを含めなくするには以下のように追記します。
; platformio.ini board_build.use_builtin_system_code=false
終わりに、公式SDKを使ってみよう
使うのにIDEの制約から抵抗があった公式SDKも、PlatformIOで使えることを解説しました。
ちょっとした単機能キーキーボードのようなものであれば、安価なCH32V203をつかっても良いのではと思っています。
是非使ってみてください。その際には、ぜひ私の作成したCH32V203のProMicro開発ボードも使ってみていただけると嬉しいです。Boothでもキットを販売していますが、KiCadファイル自体はGitHubで公開しているので、自分で発注可能です。