先日ソースコードを入手したのでArduino MicroでLチカしてみました。
mruby/cとは
えむるびーすらっしゅしーと読むようです。
mrubyをさらに小型・軽量化したもので16bitマイコンで動くとのことで
例としてPIC24などが挙がっていました。
ちなみにGCなど削除されているので動的なメモリ確保はできません。
今後ソースコードは開示される予定とのことですが、
まだ公開されていないので、今のところe-mailで問い合わせてソースコードを送ってもらう必要があります。
ここが公式かな?
mruby/cの取り組み|しまねソフト研究開発センター
環境
- OS
- Windows8.1
- mruby
- mruby/cはVMのみ提供しているのでrubyコードのコンパイルなどに別途mrubyを使用します。
- 今回はmruby1.2.0を使用しました。
- PlatformIO
- Atmel AVRマイコンの開発環境を作るのも楽なのでPlatformIOを使います。
- インストールについてはこちらが詳しいです → コマンドラインでArduino開発 : vim + platformio
上記に加えてmrubyのビルドのために
- Ruby
- MinGW
- 今回はTDM GCC 5.1.0を使用
を使いました。mrubyはrubyコードのコンパイルが目的なので、ホストOS用のビルドだけでOKです。
プロジェクトだけ作っておく
適当にディレクトリを切って
platformio init -b micro
とコマンドを打てばプロジェクトが初期化されます。
mruby/cをビルドする
コンパイラにはPlatformIOが入れてくれるAVRマイコン用のGCCを使います。
%USERPROFILE%/.platformio/packages/toolchain-atmelavr/bin
以下にあると思うのでPATHを通しておきます。
mruby/cソースコードの修正
まだソースコードが開示されていないので具体的には書けませんが、いくつか修正すべき個所があります。
VMの設定
vm_config.h
にVMに関するコンパイル設定が書かれています。
とりあえず、全部デフォルトの1/5にします(そのままでは動きませんでした)
#define MAX_VM_COUNT 2
#define MAX_IREP_SIZE 100
#define MAX_IREP_COUNT 10
#define MAX_REGS_SIZE 20
#define MAX_CALLINFO_SIZE 20
#define MAX_OBJECT_COUNT 80
#define MAX_CLASS_COUNT 4
#define MAX_PROC_COUNT 10
#define MAX_SYMBOLS_SIZE 40
ヘッダファイル
ArduinoのスケッチはC++としてコンパイルされるので
ヘッダファイルのプロトタイプ宣言部をextern "C" { ... }
で囲む必要があります。
vm.h
だけはextern "C"
が付いてたので、今後修正されて全部のヘッダファイルに付くかもしれませんが、
今のところマニュアルでextern "C"
を付けてく必要があります。
load.c
load.c
というファイルがあり、この中にload_mrb_file
という
File IOの関数を使っている関数があるのですが、ArduinoではFile IOはないので
このload_mrb_file
ごとコメントアウトします。
Makefile
arコマンド
だけ変数にされていないので
avr-ar
に修正します。
ビルド・インストール
make CC=avr-gcc CFLAGS="-Wall -O -Wall -ffunction-sections -fdata-sections -MMD -mmcu=atmega32u4"
で同じディレクトリにlibmrubyc.a
ができるはずですので、これを使います。
先ほど作っておいたArduinoプロジェクトディレクトリにファイルを移動します。
プロジェクトディレクトリにscripts
というディレクトリを、
その下にmrubyc/include
とmrubyc/lib
を作り、ビルドしたlibmrubyc.a
とヘッダファイルを以下のように設置します。
│ platformio.ini
│
├─lib
│ readme.txt
│
├─scripts
│ └─mrubyc
│ ├─include
│ │ class.h
~~~~~~~~~~~~ (省略) ~~~~~~~~~~~~
│ │ vm_config.h
│ │
│ └─lib
│ libmrubyc.a
│
└─src
blinkled.c
sketch.ino
Arduino Microプロジェクトの準備
platformio.iniの修正
mruby/cをリンクするよう修正します
[env:micro]
platform = atmelavr
framework = arduino
board = micro
build_flags = -Imrubyc/include -Lmrubyc/lib -lmrubyc
targets = upload
Arduinoスケッチ
Arduinoとインターフェイスとなるメソッドを追加して、事前にコンパイルしたmrubyのバイトコードを実行します。
mrubyのコンパイルはこの後に説明します。
#include <avr/sleep.h>
#include <static.h>
#include <class.h>
#include <load.h>
#include <errorcode.h>
extern const uint8_t bytecode[];
int LED_PIN = 13;
void mrbc_set_led(mrb_vm *vm, mrb_value *v) {
// Serial.println(GET_INT_ARG(0));
digitalWrite(LED_PIN, GET_INT_ARG(0) ? HIGH : LOW);
}
void mrbc_sleep(mrb_vm *vm, mrb_value *v) {
// Serial.println(GET_INT_ARG(0));
delay(GET_INT_ARG(0));
}
mrb_class *static_class_arduino;
void setup() {
Serial.begin(9600);
pinMode(LED_PIN, OUTPUT);
init_static();
mrb_define_method(static_class_object, "set_led", mrbc_set_led);
mrb_define_method(static_class_object, "sleep", mrbc_sleep);
struct VM * vm = vm_open();
delay(5000);
if (vm == 0) {
Serial.print("VM open Error.\n");
}
else {
Serial.print("VM open Success.\n");
int ret = loca_mrb_array(vm, (char*)bytecode);
if (ret != NO_ERROR) {
Serial.print("MRB Load Error.\n");
}
else {
vm_boot( vm );
Serial.print("VM start.\n");
while (0 <= vm_run_step(vm)) {
Serial.print("PC : ");
Serial.print(vm->pc);
Serial.print("\n");
}
Serial.print("VM end.\n");
vm_close( vm );
}
}
}
void loop() {
}
mrubyバイトコード
まず、元のrubyコードを用意します
while true
set_led 1
sleep 10
set_led 0
sleep 1000
end
次にで扱えるByte配列のバイトコードにコンパイルします。
mrbc -E -Bbytecode blinkled.rb
Arduino Microはリトルエンディアンだと思うので-E
オプションは不要だと思うのですが
ビッグエンディアンでないと読み込みに失敗しました(現在調査中)
エンディアンはVMの問題なので関係ないですね(たぶん...)
出力されるblinkled.c
をsketch.ino
と同じsrc
ディレクトリに置きます。
プロジェクトのビルド、書き込み
platoformio run
でいけるはず!