ch32funのmruby/cでTaskの削除


最近、安価なCH32X035をmruby/cから使うための環境の開発を行っているが、 このマイコンにはflashが62kしか無いので、ある程度機能を制限する必要がある。 まず、Floatの削除は必須である。 mrbとして組み込んでいたmrblibも、組み込まないようにすることで、使えるmethodが減ってしまうが、容量を減らすことができる。 この状態で、flashは1k程余るのだが、ユーザーのプログラムが少し長くなると、足り無くなるだろう。

このような単純なマイコンでマルチタスクをすることは無いので、Taskも削ることができる。 mrubyc_arduinoについて2026/4/20に書いたようにして、 さらにTaskを削除すると、約3k小さくなり、合計で約4kのflashがあれば、通常の使用には十分であろう。 以前のTaskの削除の仕方は、rrt0.hやrrt0.cの中身を書き換えないといけなかったが、もう少し単純な方法を発見したので、それを紹介しよう。

まず、rrt0.hとrrt0.cと_autogen_class_rrt0.hは、完全に消してしまってよい。 ただし、mrubyc.hでrrt0.hをincludeしているので、その行をコメントアウトする。 そして、メインのコードで、rrt0.cの中でされていたメモリ確保やsleepなどの定義をすれば、Taskを削除できる。 メインのコードが少し長くなるが、この方が単純だろう。 その際のmain.cは、以下のようになる。

#include "ch32fun.h"
#include <stdio.h>
#include "fsusb.h"
#include "mrubyc.h"
#include "mrbc_gpio.h"
#include "mrbc_adc.h"
#include "mrbc_pwm.h"
#include "mrbc_i2c.h"
#include "mrbc_spi.h"
#include "mrbc_uart.h"
#include "mrbc_get.h"

#define MEMORY_SIZE (1024*10)
static uint8_t memory_pool[MEMORY_SIZE];
#define FLASH_CODE (0x8000000+59152)

#define RX_BUFFER_SIZE 64
volatile uint8_t rx_buffer[RX_BUFFER_SIZE];
volatile uint8_t rx_head = 0;
volatile uint8_t rx_tail = 0;
void rx_buffer_push(uint8_t c) {
  uint8_t next = (rx_head + 1) & (RX_BUFFER_SIZE - 1);
  if (next != rx_tail) {
    rx_buffer[rx_head] = c;
    rx_head = next;
  }
}
bool rx_buffer_available(void) {
    return rx_head != rx_tail;
}
uint8_t rx_buffer_pop(void) {
  if (rx_head == rx_tail) return 0;
  uint8_t c = rx_buffer[rx_tail];
  rx_tail = (rx_tail + 1) & (RX_BUFFER_SIZE - 1);
  return c;
}
void handle_usbfs_input(int numbytes, uint8_t *data) {
  for( int i = 0; i < numbytes; i++ ) rx_buffer_push(data[i]);
}

unsigned char hal_read(int fd) {
  while(!rx_buffer_available());
  return rx_buffer_pop();
}

long atol(const char *str) {
  return (long) mrbc_atoi( str,10 );
}

static void c_sleep(mrbc_vm *vm, mrbc_value v[], int argc){
  if(argc>0){
    mrbc_int_t sec = mrbc_integer(v[1]);
    SET_INT_RETURN(sec);
    Delay_Ms(sec * 1000);
  }
}
static void c_sleep_ms(mrbc_vm *vm, mrbc_value v[], int argc){
  if(argc>0){
    mrbc_int_t sec = mrbc_integer(v[1]);
    SET_INT_RETURN(sec);
    Delay_Ms( sec );
  }
}

int main()
{
  SystemInit();
  funGpioInitAll();
  funAnalogInit();
  hal_init();
  mrbc_init_alloc(memory_pool, MEMORY_SIZE);
  mrbc_init_global();
  mrbc_init_class();
  mrbc_define_method(0, 0, "sleep", c_sleep);
  mrbc_define_method(0, 0, "sleep_ms", c_sleep_ms);
  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();
  USBFSSetup();
  mrbc_run_mrblib( (uint8_t *) FLASH_CODE );
  while(1){}
}

atolとほとんど同じことをする関数をmruby/cのコードの中に発見したので、それを使うことによって、さらに少しだけコンパクトになっている。 コンパイルした時のサイズがFLASH_CODEの所の値と異なっている場合には、それを変更して、コンパイルし直す。 私の環境では、58k程度となって、flashに約4.2kの余裕があることが確かめられる。

mrubyc_arduinoで環境の構築を行っていたときには、それでも容量オーバーになるので、C言語で書かれているmethodの数を減らしたりと、さらなる機能の制限が必要であった。 しかし、ch32funを使ったことによって、かなり容量が減ったので、上記の三つの工夫で余裕を持ってflashに収まるようになった。