ESP32用のmruby/c
ESP32用のmruby/cとしては,FemtoRubyを使ったR2P2があるが,PWMを使おうとしたらエラーが出たので,自分でもESP32用にmruby/cの環境を作ってみることにした. 自分のブログを見直してみたら,私がmruby/cを最初に使ってみたのはESP32だった. そのときには,Arduinoを使ってmrbのコードをソースに埋め込んでコンパイルしていた. そのため,rubyのコードを変えると,mrbを作って,それを埋め込んでArduinoでコンパイルして,マイコンに書き込むという作業をする必要があり,時間もかかるし面倒だった.
これまで,何種類かのマイコン用にmruby/cの環境を作ってきた. それらにおいては,mrbファイルはflashに書き込んで,そのアドレスを使って直接mrbコードを読み出して使っている. しかし,同じことをESP32でやろうとしたら,そのままではうまく行かなかった. ESP32では,フラッシュに直接アドレスが割り当てられるわけでは無く,その内容が使われるときにcacheにコピーされるので,単にflashに書き込むだけでは駄目である. また,mrbコードをプログラムに埋め込んでおいて,その部分だけを書き換えようとしても,チェックデジットや誤り訂正などがあり,その内容を不用意に書き換えるとエラーが出てしまった. いろいろ試行錯誤した結果,使っていないflash領域にmrbを書き込んで,それをメモリに割り当てることで,ほぼ同じ感覚で使えるようになった.
まず,私のホームページに載っているようにArduino用のmruby/cをセットアップする. そして,Arduinoで以下のコードをコンパイルして,ESP32に書き込む.
#include "spi_flash_mmap.h"
#include <mrubyc.h>
#define MEMORY_SIZE (1024*30)
static uint8_t memory_pool[MEMORY_SIZE];
#define FLASH_CODE 0x10000 + 0x120000 //esp32
spi_flash_mmap_handle_t s_data_map_handle;
const uint8_t *flash_code = NULL;
int hal_write(int fd, const void *buf, int nbytes) {
Serial.write((char*)buf,nbytes);
return (nbytes);
}
int hal_flush(int fd) { return 0; }
void hal_abort(const char *s){}
unsigned char hal_read(int fd) {
while (Serial.available() == 0);
return Serial.read();
}
void setup() {
uint32_t data_flash_offset = FLASH_CODE; // running->address + 1114112;
uint32_t map_size = 0x10000; // 64KB
esp_err_t err = spi_flash_mmap(
data_flash_offset, map_size, SPI_FLASH_MMAP_DATA, // as rodata
(const void **)&flash_code, &s_data_map_handle);
Serial.begin(19200);
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_init_class_wifi();
mrbc_create_task( (uint8_t *) flash_code, 0 );
mrbc_run();
}
void loop() {}
rubyスクリプトはmrbcでコンパイルして,mrbファイルを作り,それをrodata用のflashの空いた領域に書き込む.
mrbc temp.rb python3 esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 921600 write-flash 0x130000 temp.mrb
この際,Arduinoのコードと重ならないような64k区切りの場所を選んで,flashのパーティションの容量に収まるようにもしなければならない. すると上のプログラムが,この内容をメモリに割り当ててくれるので,他のマイコンと同様にmrbコードを実行することができる.
まあ,ESP32では他のmruby/c環境もあるので,それらを使う方が良いかも知れない. でも,自分で組んだプログラムだと,仕組みが分かっているので,トラブルが起きたときに,その原因を究明するのが比較的に容易である. まだ、様々な機能がきちんと動くか確認していないので、追って確認しようと思う。