拡張flashを活用するCH32V203用のmrubyc_arduino


CH32V203でmrubyc_arduinoを使うために、2026/5/3のブログでは、FloatとTaskを無効にしたり、mrblibを拡張flashに移動させたりする方法を紹介した。 拡張flashをさらに有効に活用することによって、Floatを無効にするだけで、mruby/cを動かすことに成功したので、その手法を紹介する。

環境の構築は、先のブログの通りである。 Arduinoのスケッチは非常に単純で、以下の通りである。

#include <mrubyc.h>
#include "swd.h"

#define MEMORY_SIZE (1024*10)
#define FLASH_CODE 0x8020000 //ch32v203

static uint8_t memory_pool[MEMORY_SIZE];
static volatile char inbytes=0;
static volatile uint8_t last=' ';

extern "C" {
void handle_debug_input( int numbytes, uint8_t * data ) {
  inbytes+=numbytes;
  last = data[0];
}
}
int hal_write(int fd, const void *buf, int nbytes) {
  _write(0, (char*)buf, nbytes);
  return (nbytes);
}
int hal_flush(int fd) { return 0; }
unsigned char hal_read(int fd) {
  while(inbytes==0) _write(0, "", 1);
  inbytes=0;
  return last;
}

void setup() {
  SetupDebugPrintf();
  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_uart();
  mrbc_init_class_get();
  mrbc_create_task( FLASH_CODE, 0 );
  mrbc_run();
}
void loop() {}

これをそのままsmallest with LTOでコンパイルすると、flashの容量オーバーとなる。 そこで、constの配列などのデータを拡張flashに配置させるように指定する。 そのために、 ~/.arduino15/packages/WCH/hardware/ch32v/1.0.4/system/CH32V20x/SRC/Ld/Link.ldの容量の指定に拡張flashに対応するFLASH2を追加する。

FLASH (rx) :  ORIGIN = 0x00000000, LENGTH = 64K
FLASH2 (rx) : ORIGIN = 0x08010000, LENGTH = 160K
RAM (xrw) :   ORIGIN = 0x20000000, LENGTH = 20K

そして、同じファイルに.data2を作って、.textからrodataを含む二行を移動して、これがFLASH2に入るように指定する。

.data2 :
{
. = ALIGN(8);
*(.rodata)
*(.rodata*)
. = ALIGN(8);
} >FLASH2 AT>FLASH2

これで、constなどが通常のflash上の.textから、拡張flash上の.data2に移動する。 当然、mrblibも移動することになる。 この状態でsmallest with LTOでコンパイルすると、flashの九割ほどになる。 難しいのはここから、binaryを取り出す作業である。 そのままバイナリを出力すると、130Mほどになるので、無駄が多い。 Linuxでは、コンパイルを実行すると、/tmp/arduino_build_*にelfファイルが出来ているので、これをtemp.elfとして、~/.arduino15/packages/WCH/tools/riscv-none-embed-gcc/8.2.0/binにコピーする。 そして、以下のコマンドを実行すると、通常のflashと拡張flashに書き込む二つのファイルができる。

./riscv-none-embed-objcopy -O binary -R .data2 temp.elf temp1.bin
./riscv-none-embed-objcopy -O binary -j .data2 temp.elf temp2.bin

これらを以下のコマンドで書き込めば終了である。

./minichlink -w temp1.bin flash -b
./minichlink -w temp2.bin 0x8010000 -b

ユーザー用のmrbは0x8020000に書き込む。 platform.txtのcompiler.elf2bin.extra_flagsに-R .data2と指定して、通常のflashの内容だけがバイナリに出力されるようにして、拡張flashの内容は別途取り出すようにした方が良いかも知れない。

Floatを無効にした以外は、mruby/cの機能をほぼ使えるようなCH32V203用の環境が構築できた。 Taskが使える以外は以前とあまり変わらないが、mruby/cのコードをほとんど加工すること無く組み込めたという意味で、こちらの方が良い気がする。 しかし、拡張flashにはmrblib以外にも定数などが載ったので、実行速度は少し遅くなっているかも知れない。 また、すべての機能が動くことを確認したわけでは無いので、何か不都合がある可能性もあり、今後に検証する必要があるだろう。