LoginSignup
21

More than 5 years have passed since last update.

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

Last updated at Posted at 2015-12-06

先日ソースコードを入手したので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
でいけるはず!

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21