Arduino互換機 chipKIT Max32でmrubyを動かす

chipKIT Max32というArduinoMPUをPIC32にした基板上でmrubyが動作しました。とりあえずやり方をメモ。


chipKIT Max32 スペック

  • PIC32MX795F512L 80MHz
  • ROM:512Kb, RAM:128Kb
  • 3.3V動作
  • Arduino/Arduino Mega用のシールドが大体動く(?)
  • 大抵のArduinoスケッチが動く。Arduino標準ライブラリは全部移植されてる(が、AVR依存したスケッチは移植する必要あり)。

http://www.digilentinc.com/Products/Detail.cfm?Prod=CHIPKIT-MAX32

必要なもの

mrubyをビルドする

githubから落としてきて、makeします。後でまたMPIDE上でビルドが必要ですが、ここではmrbc(コンパイラ)やパーサのコードを出力します。

$ cd ~/work
$ git clone git://github.com/mruby/mruby.git
$ cd mruby
$ make
   ....

bin/以下にmrbc,mruby,mirbができていればOKです。

MPIDEをインストールする

chipKITの開発環境であるMPIDEをインストールします。
https://github.com/chipKIT32/chipKIT32-MAX/downloads
FTDIUSBシリアルドライバも(多分)インストールしておく必要あり。
適当なスケッチがUSB経由でchipKIT Max32にアップロードできれば良いです。

MPIDEのライブラリフォルダにmrubyのソースをコピー

ここからが色々と面倒なのですが、、、MPIDEのライブラリのパスにmrubyのソースコードを(ディレクトリ構造を変えつつ)入れます。

  1. MPIDE.appの中のContents/Resources/Java/hardware/pic32/libraries/ にmrubyというディレクトリを作成。
  2. MPIDE.app/Resources/..../libraries/mruby/に~/work/mruby/include/にあるヘッダ(mrbconf.h,mruby.h,mrubyディレクトリ)をコピー。
  3. MPIDE.app/Resources/.../libraries/mruby/にutilityというディレクトリを作成し、その中に~/work/mruby/src/*.cを全部コピー。libraries/直下と、utilityというディレクトリ以下の*.cは自動的にコンパイルされるみたい。
  4. MPIDE.app/Resources/.../libraries/mruby/utility/に~/work/mruby/mrblib/mrblib.cをコピー

mrbconf.hの編集

MPIDE.app/Resources/....libraries/mruby/mrbconf.hの以下を編集します

...
/* number of object per heap page */
//#define MRB_HEAP_PAGE_SIZE 1024
#define MRB_HEAP_PAGE_SIZE	64    //heap当たりのオブジェクト数を小さめにしておく(なんとなく)
...
#define DISABLE_REGEXP	        /* regular expression classes */
//#define DISABLE_SPRINTF	/* Kernel.sprintf method */ 
//#define DISABLE_MATH		/* Math functions */
#define DISABLE_TIME		/* Time class */ //time関係は使えないのでDisableにしておく
//#define DISABLE_STRUCT	/* Struct class */
//#define DISABLE_STDIO		/* use of stdio */

/* Now DISABLE_GEMS is added as a command line flag in Rakefile, */
/* we do not need to set it here. */

#define DISABLE_GEMS //gemをdisableに(ここでやるなと書かれてるけど,,)

スケッチ

mruby_testというスケッチを作ります。mrubyを呼び出すスケッチです。メニューのSketch->Import Library...から「mruby」を選ぶとmrbconf.hとmruby.hが勝手にインクルードされます。

//ヒープサイズ変更するためのマクロ。
//http://www.chipkit.org/forum/viewtopic.php?f=19&t=1565
#define CHANGE_HEAP_SIZE(size) __asm__ volatile ("\t.globl _min_heap_size\n\t.equ _min_heap_size, " #size "\n")

#include <mrbconf.h>
#include <mruby.h>

#include <mruby/irep.h>
#include <mruby/string.h>  
#include <mruby/value.h>

//rubyから呼び出す関数。引数に文字列をとってシリアルに出力
mrb_value myputs(mrb_state *mrb, mrb_value self){
  mrb_value val;
  mrb_get_args(mrb, "S", &val);
  Serial.println(RSTRING_PTR(val));
  return mrb_nil_value();
}  

extern const char bytecode[];//バイトコード。mrbcで出力されます

void setup(){
    CHANGE_HEAP_SIZE(102400);    //ヒープサイズを100kbに
    
    Serial.begin(9600);
    Serial.print("setup\n");

    mrb_state *mrb;
    mrb = mrb_open();
    
 //Objectクラスにmyputsをメソッドとして定義
    mrb_define_method(mrb, mrb->object_class,"myputs", myputs, ARGS_REQ(1));    
    
    //バイトコードをロード
    mrb_load_irep( mrb, bytecode);
    if (mrb->exc){
      Serial.println("exeption occured!");
    }
}

void loop(){
  Serial.print("here is a loop\n");
  delay(1000);
}

適当なrubyコードを書いて、mrbcでコンパイルします。
hoge.rb

o = Object.new
100.times do |i|
   o.myputs "index:" + i.to_s
end
$ ~/work/mruby/bin/mrbc -Bbytecode hoge.rb

これでhoge.cというファイルができます。char bytecode[]という配列が宣言されて、中身はhoge.rbのバイトコードです。このbytecode変数をメインスケッチで参照してロードするわけです。

次に、スケッチに新しいタブを作ってhoge.cppなどとして、中にhoge.cの中身を丸ごとコピーします(直接スケッチのフォルダにhoge.cをコピーしても何故かコンパイルしてくれない様子)。

hoge.cpp

const char bytecode[] = {
0x52,0x49,0x54,0x45,0x30,0x30,0x30,0x39,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x39,
0x30,0x30,0x30,0x30,0x4d,0x41,0x54,0x5a,0x20,0x20,0x20,0x20,0x30,0x30,0x30,0x39,
0x30,0x30,0x30,0x30,0x00,0x00,0x00,0xe4,0x00,0x02,0x00,0x00,0x20,0x20,0x20,0x20,
0x20,0x20,0x20,0x20,0x59,0x8e,0x00,0x00,0x00,0x4c,0x53,0x43,0x00,0x02,0x00,0x04,
0x00,0x02,0x6f,0x28,0x00,0x00,0x00,0x07,0x01,0x00,0x00,0x11,0x01,0x00,0x40,0x20,
0x00,0x80,0x80,0x01,0x01,0x40,0x31,0x83,0x01,0x80,0x03,0x40,0x01,0x00,0x80,0x21,
0x00,0x00,0x00,0x4a,0x13,0x8a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,
0x00,0x06,0x4f,0x62,0x6a,0x65,0x63,0x74,0x00,0x03,0x6e,0x65,0x77,0x00,0x05,0x74,
0x69,0x6d,0x65,0x73,0x77,0x75,0x00,0x00,0x00,0x56,0x53,0x43,0x00,0x03,0x00,0x06,
0x00,0x02,0x78,0x5a,0x00,0x00,0x00,0x08,0x02,0x00,0x00,0x26,0x01,0x80,0x40,0x15,
0x02,0x00,0x00,0x3d,0x02,0x80,0x40,0x01,0x02,0x80,0x80,0x20,0x02,0x00,0x40,0xac,
0x01,0x80,0x00,0xa0,0x01,0x80,0x00,0x29,0x49,0x75,0x00,0x00,0x00,0x01,0x11,0x00,
0x06,0x69,0x6e,0x64,0x65,0x78,0x3a,0xac,0x54,0x00,0x00,0x00,0x03,0x00,0x06,0x6d,
0x79,0x70,0x75,0x74,0x73,0x00,0x01,0x2b,0x00,0x04,0x74,0x6f,0x5f,0x73,0xd1,0xc9,
0x00,0x00,0x00,0x00,
};

ビルドしてアップロード

MPIDEのTools->BoardでchipKIT Max32が選ばれていることを確認してボードにアップロードします。コンパイルはそれほど時間かかりませんが、アップロードに5分ほどかかります・・・。

アップロードが終わった後、シリアルモニタを開けばmrubyコードからの出力が確認できます。
mrubyコードを編集した場合は、再度mrbcでコンパイルして、MPIDE上でビルド・アップロードすればOK.

雑感

  • chipKIT Max32上でmrubyの簡単なコードが動きました。LED光らせるくらいはできそうです
  • 液晶マイコンボード付きmruby学習キットと比較すると、液晶がないというのはありますが、\10,000安い、C部分も自分でいじれる、mrubyを常に最新に出来る、等の利点がありそうです。mruby学習キットの方のmrubyコード用の領域は5kbで200~300行しか書けないらしいのですが、chipKIT Max32上ではどこまでいけるのか・・。
  • MPIDE上でライブラリパスの指定などができないので、コピーが色々と面倒です。MPIDEはArduinoと同様オープンソースなので、コードを変えちゃえば良いのかもしれません。
  • アップロードに時間がかかりすぎ!気軽にコードを変えられない・・。これはmrubyの機能を外せばROMサイズが小さくなるので多少軽減されるかも・・。
  • 文字列としてコードを読み込んで実行する方法は少し試してますが、メモリ(RAM)が足りないのか、動いたり動かなかったりします。