ESP8266のArduinoでmruby/cのPWM
USBSerialを使ったCH32V203用のmrubyc_arduino
拡張flashを活用するCH32V203用のmrubyc_arduino
CH32V203でArduinoからUSBSerial
Arduino上で、CH32V203のUSBSerialを使おうとしたが、思ったよりも苦労した。 このマイコンのUSBは以前にArduinoから使ったことがあったので、その時と同じようにすれば良いと予想していたが、使い方が変わったりしていて、素直には動かなかったが、動かし方が分かったので、そのコツを書いておく。
CH32V203でArduinoからUSBSerialを使う場合、いくつかの方法がある。その中で最も一般的なのがTinyUSBを使う方法である。 TinyUSBのライブラリは、「ライブラリを管理」から「Adafruit TinyUSB Library」を選ぶことでインストールできる。 最新versionは3.7.7で、それなりに頻繁に更新されているようだ。 すぐに動くと思ったのに、なかなかうまく動かなくて苦労したが、最終的には次のようにすると動くことが分かった。 スケッチ例のCDCのserial_echoを見ると参考になるが、ライブラリのヘッダを取り込んで、TinyUSBDevice.begin(0);を実行してから、SerialTinyUSBをSerialと同様に使えばよい。 以前使ったときには,Adafruit_USBD_CDCオブジェクトをUSBSerialなどの名前で作って使っていたが、使い方が変わったようだ。 私が試したところ、最適化でSmallest with LTOでは、USBがうまく認識せず、Smallestだとうまく動いた。 しかし、その場合には、簡単なプログラムでもコンパイルサイズが24k程と、かなり大きくなった。 また、 Suzuduinoや jobitjosephさんのものなどの、 WCH公式以外のarduino coreで、USB supportを選択できる場合でも、「なし」としないとエラーが出てしまった。 これはおそらくversionの相性の問題だろうと考えている。
サイズがもう少し小さいものとしては、 21km43さんのライブラリを使う方法がある。 これを使うには少しだけ準備が必要である。 ファイルをdownload zipとして取って来て、解凍してからsrcフォルダをCH32V203_USBCDCなどと名前を変えてから、Arduinoのlibrariesフォルダに入れるのである。 使い方は単純で、以下のようにヘッダを取り込んだら、Serialという名前で使える。
#include <usb_serial.h>
こちらも、Smallest with LTOだと駄目で、Newlib Nano + USBDにしても、LTOだと動かない。 やはりSmallestにする必要があり、このときのサイズは15kとなった。 TinyUSBよりは小さいが、それでもまだ大きいと感じる。 また、個人的にはUARTと混同しないように、Serialとは別の名前で動いてくれた方が良いので、usb_serial.hとusb_serial.cppを変更しようかと考えている。
LTOを指定した場合には、割り込みに必要な関数などが使われていないと判断されて、消去されてしまってUSBが動かないのだろう。 これらの関数に、敵切に__attribute__((used))などの指定をつければ、LTOも使えるのでは無いかと思うが、それがどこに定義されているのかを調べるのが大変だろう。 一方、LTOを指定しない時には、使われていない多くの関数が残って、コンパイルサイズが大きくなっていると思われる。 もう少しサイズが小さく出来無いものかな。
CH32X035用のmrubyc_arduino
mrubyc_arduinoのbuiltin symbolを削減
ArduinoでCH32X035のUSBSerial
CH32X035をArduinoから使うときには、通常はWCHサポートを使うが、それだけではCH32X035のUSBSerialは使えない。 WCH社が公開している CH32X035EVT には、 MounRiver Studio用のプログラムの例がある。 これをArduinoで活用することも可能だろうが、どのようにして組み込むかを検証するのはそれなりに面倒であろう。
いろいろと探していたら、CH32X035_USBSerialというライブラリを発見した。 これは、Arduinoでスケッチ-ライブラリをインクルード-ライブラリを管理…-CH32X035_USBSerialを選択してインストールできる。 Arduinoのスケッチは、こんな感じである。
#include <CH32X035_USBSerial.h>
using namespace wch::usbcdc;
void setup() {
USBSerial.begin();
USBSerial.waitForPC(); // Wait for host connection
USBSerial.println("USB CDC ready!");
}
void loop {
if(USBSerial.available()){ USBSerial.read(); }
}
しかし、このライブラリはWCHサポートでは動かず、そのフォークを使う必要がある。 環境設定で以下のURLを加えて、それをインストールする。
https://raw.githubusercontent.com/jobitjoseph/CH32_Arduino_Core/main/board_manager/package_ch32_index.json
ボードはCH32 EVT boards supportからCH32X035を選ぶ。 オリジナルのWCHサポートではCH32V EVT boards supportとなっているので、“V"の有無で区別ができる。 少し調べたところでは、WCHのgithubのファイルと比較して、 system/CH32X035/SRC/Peripheral/src/ch32x035_misc.cと system/CH32X035/SRC/Startup/startup_ch32x035.S などを更新しているようである。 コンパイルして、バイナリを出力して、wchispで書き込むと、USBSerialが使えるようになる。
USBSerialを組み込んだときと組み込まないときで、コンパイルしたときのサイズを比較すると、3k弱の違いである。 以前、CH32V203でTinyUSBを組み込んでみたときには、10kぐらい増加したので、条件の違いはあるが、このライブラリはUSBSerialにしては、それなりにコンパクトだと言えるだろう。 以後、CH32X035でUSBSerialが必要な時には、このライブラリを使ってみようと思う。 このライブラリはCDCしか対応していないので、USBの他のデバイスを作ることは出来無いが、参考にはなるかも知れない。
mruby/cでメソッドの制限
mrubyc_arduinoで、使用するflashを節約するためには、floatを無効にするとか、マルチタスク機能を削除するなど、いくつかの方法がある。 もう一つの方法は、使えるメソッドを減らすことである。
mruby/cではrubyのクラスやメソッドは、主にc言語で実装されているが、その一部はrubyで書かれたコードをmrbcでバイナリにして組み込むことによって実現している。 これがmrblibであり、そのバイナリのサイズは約4.5kである。 ch32v203でmrubyc_arduinoを使ったときには、mrblibを拡張flashに移動することによって、メインのflashを節約したが、これを組み込まないこともできる。 mrblibを組み込まなければ、必要なflashは約4.5kぐらい減る上に、mruby/cに必要なメモリの量も少なくなる。 以前、ESP8266で実験したときには、mrblibを組み込む場合にはmruby/c用に5kほどのメモリを確保しないといけなかったが、mrblibを組み込まない場合には2kでも動かすことができた。
しかし、mrblibを組み込まない場合には、そこで定義されていたメソッドが使えない。 mruby/cで使うことのできる クラス・ライブラリ の中で、下の表がmrblibで定義されているメソッドである。
| Enumerable | collect, map, each_with_index |
| Array | all?, any?, collect!, map!, delete_if, each, each_index, index, find_index, none?, reject!, reject, reverse_each, select, filter, select!, filter!, sort!, sort |
| Hash | each |
| Numeric | times, upto, downto |
| Object | loop |
| Range | each |
| String | each_byte, each_char, ljust, rjust, each_line |
一方、c言語で実装されているmethodを使わないようにするには、 _autogen_class_*.hのmethod_symbols_とmethod_functionsにある要素をコメントアウトすれば良い。 すると、コンパイル時の最適化でこれらは除かれるのである。 取り除いてはいけないメソッドもあるかも知れないが、ほとんど使わないけどコードが長くなりそうなメソッドを消せば、flashの節約になるだろう。
問題なのは、あまりメソッドを減らしすぎると、rubyっぽく無くなってしまうことである。 機能の限られたマイコンで動かすrubyとして、最低限必要なメソッドはどれかというのは、人によって意見が別れるだろう。
さらにflashの使用量を減らすためには、 マイコンには必要ないと思われるクラスを消すということも考えられる。 そのままではうまく働かないものの、 FloatやStringを無効にする指定はvm_config.hで定義されている。 Floatについては、2026/4/15のブログに書いてあるように修正すれば、無効にできるが、Stringは他のコードでも使われていることが多く、無効にするのは諦めている。 それと同様に、マイコンで使う必要性が低いクラスを無効にしてしまうことも出来るだろう。 例えば、Hashをマイコンから使う機会は少ないように思うが、SrtingやHashはmrblibにも定義が書かれているので、これらを無効にするのは単純には出来無いだろう。
2026/5/12追記 Hashはキーワード引数の処理に使われているので、消すことは出来無さそうだ。
ArduinoでCH32X035のi2c
CH32X035はWCH社の比較的新しいマイコンで、安いのにflashやメモリもそれなりにあり、USBも使える。 このマイコン用にArduinoからI2Cを使おうとしたら、少し苦労したので、その解決法について書きたい。
ArduinoでCH32マイコンを使うには、WCHサポートをインストールする必要がある。 それを使うと、CH32X035も使えるようになるのだが、I2Cなどはまだ対応できていないようで、そのままではエラーが出て使うことが出来無かった。
WCHサポートの最新のリリースは2023年12月に出たもので、それ以降はリリースされていないものの、それ以降にも若干の更新が行われている。 いくつかのファイルを最新版に入れ替えると、CH32X035でもWireを使ったプログラムのコンパイルができることが分かった。 入れ替える必要のあるファイルは、 arduino_core_ch32/variants/CH32X035/CH32X035G8U/ のvariant_CH32X035G8U.hとPeripheralPins.c、 arduino_core_ch32/cores/arduino/ch32/ のPinNamesTypes.hとanalog.cppとanalog.hとtimer.cとtimer.h である。 これらで ~/.arduino15/packages/WCH/hardware/ch32v/1.0.4の 対応するファイルを上書きするのである。 動作は確認していないが、きっと動くと信じることにする。
Toneなども最新のリリースには無いので、同じところから最新版を取って来る必要があった。 もしかすると、すべてのファイルをgithub上の最新版に入れ替えた方が良いのかも知れない。 ch32x035については、まだusbをArduinoから使えていないので、その方法を探そうと思う。