mruby/cをつかってArduino MicroでLチカしてみた

More than 3 years have passed since last update.

先日ソースコードを入手したので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



上記に加えて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にします(そのままでは動きませんでした)


vm_config.h

#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/includemrubyc/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のコンパイルはこの後に説明します。


sketch.ino

#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コードを用意します


blinkled.rb

while true

set_led 1
sleep 10
set_led 0
sleep 1000
end

次にで扱えるByte配列のバイトコードにコンパイルします。

mrbc -E -Bbytecode blinkled.rb

Arduino Microはリトルエンディアンだと思うので-Eオプションは不要だと思うのですが

ビッグエンディアンでないと読み込みに失敗しました(現在調査中)


エンディアンはVMの問題なので関係ないですね(たぶん...)

出力されるblinkled.csketch.inoと同じsrcディレクトリに置きます。


プロジェクトのビルド、書き込み

platoformio run

でいけるはず!