Arduino互換機 chipKIT Max32でmrubyを動かす
chipKIT Max32というArduinoのMPUを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のソースコードを(ディレクトリ構造を変えつつ)入れます。
- MPIDE.appの中のContents/Resources/Java/hardware/pic32/libraries/ にmrubyというディレクトリを作成。
- MPIDE.app/Resources/..../libraries/mruby/に~/work/mruby/include/にあるヘッダ(mrbconf.h,mruby.h,mrubyディレクトリ)をコピー。
- MPIDE.app/Resources/.../libraries/mruby/にutilityというディレクトリを作成し、その中に~/work/mruby/src/*.cを全部コピー。libraries/直下と、utilityというディレクトリ以下の*.cは自動的にコンパイルされるみたい。
- 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)が足りないのか、動いたり動かなかったりします。