USBSerialを使ったCH32V203用のmrubyc_arduino
single wire debugを標準入出力としたCH32V203用のmruby/c環境は、2026/5/3や5/17のブログで紹介した。 CH32V203のUSB機能を活用して、USB serialを標準入出力にしたmruby/c環境を作りたいと考えていたが、いくつもの問題があって、なかなか実現出来無かったが、なんとかそれなりのものが出来たので、その方法について説明したい。
mrubyc_arduinoのライブラリやCH32用のpackageのインストールは2026/5/3のブログと同じである。 USB serialは21km43さんのライブラリを使うことにしたので、2026/5/16のブロクを参考にしてインストールする。 通常のflashに配置するデータを減らすために、2026/5/17のブログに書いたように、Link.ldを変更する。 USB CDCを使うためには、最適化でLTOが指定できないので、サイズが大きすぎるので、さらに工夫をする必要がある。 Floatを消すために、vm_config.hのMRBC_USE_FLOATを0にして、2026/4/15のブログに書いたようにいくつかのファイルを修正し、Taskも消すために、2026/4/20のブログに書いたようにrrt0.hとrrt0.cを修正して、_autogen_class_rrt0.hを削除する。 そして、以下のスケッチをsmallestでコンパイルすると、ぎりぎり64kに入った。
#include <usb_serial.h>
#include <mrubyc.h>
#define MEMORY_SIZE (1024*10)
#define FLASH_CODE 0x8020000 //ch32v203
static uint8_t memory_pool[MEMORY_SIZE];
int hal_write(int fd, const void *buf, int nbytes) {
Serial.write((uint8_t*)buf,(size_t)nbytes);
return (nbytes);
}
int hal_flush(int fd) { return 0; }
unsigned char hal_read(int fd) {
while (Serial.available() == 0);
return Serial.read();
}
void setup() {
Serial.begin(115200);
mrbc_init(memory_pool, MEMORY_SIZE);
mrbc_init_class_digital();
mrbc_init_class_adc();
mrbc_init_class_pwm();
mrbc_init_class_i2c();
mrbc_init_class_spi();
mrbc_init_class_get();
mrbc_run_mrblib( FLASH_CODE );
}
void loop() {}
実はここでも少し工夫をしていて、Serial.printでなくSerial.writeを使うことによって、サイズを減らしている。
書き込みも少し面倒である。 まず、2026/5/17のブログに書いたようにして、elfからバイナリを取り出す。 そして、rubyスクリプトからmrbcを使ってtemp.mrbというファイルを作って、次のrubyスクリプトを使って、バイナリと結合したall.binを作る。
bsz=1024*64
d1=File.binread("temp1.bin").bytes
d1+=[0xff]*(bsz-d1.size)
d2=File.binread("temp2.bin").bytes
d2+=[0xff]*(bsz-d2.size)
d3=File.binread("test.mrb").bytes
File.write("all.bin",(d1+d2+d3).pack("C*"))
ボタンを押しながらUSBに挿してbootloaderを立ち上げ、all.binをwchispで書き込む。
./wchisp flash all.bin
書き込みについては、本当はmrbのみを書き込むようにしたいのだが、USBのbootloaderからはflashの消去はその先頭からしか出来無い仕様らしく、flashの途中を消してからデータを書き込むということが出来無いようなのだ。 それで仕方無く、バイナリと結合してから書き込むという手法を取っている。 しかし、USBは転送が速いので、書き込みにはほとんど時間はかからない。 WCH-LinkEからの書き込みのときには、flashの途中だけを書き換えるということが出来て、USBからの書き込みではそれが出来無いのがもどかしいが、マイコン単体だけで書き込みができるという利点があるので、多少の不便には目をつぶらないといけないだろう。
USB CDCのためにLTOを有効に出来無いのでflashに余裕が無く、Taskを無効にしないといけないのが残念だが、CH32V203でUSBSerialを使ったmruby/c環境が完成した。 メモリは10k割り当てているが、これでどの程度のことが出来るのだろう。 もう少し割り振ることもできそうだが、あまり多くしすぎると、変数用のメモリ不足になるかも。 改良点としては、Serialという名称がUARTと干渉する可能性があるので、それらを区別するようにした方が良いだろう。 また、temp1.binとtemp2.binとtemp.mrbをrubyスクリプトで結合するのも複雑なので、0バイトのtemp.mrbを作って、temp1.binとtemp2.bin結合したファイルを作っておけば、それをmrbをcatで繋げて書き込めるようになるだろう。 でも、そっちの方が面倒かも。
ちなみに、今回CH32V203をUSBから使うにあたって、自作のボードを用いた。 安いCH32V203のマイコンボードが手軽に手に入るなら、それを使ったところなのだが、あまり良いのが無いんだよな。 それなりに安価なBull Pill+は少し大きいのが欠点なんだよな。 自分でマイコンボードの設計でもしようかな。