GR-SAKURAでmrubyを使う


ルネサステクノロジのRX63Nを積んだArduino互換ボードGR-SAKURA
(http://japan.renesas.com/products/promotion/gr/index.jsp)
でmrubyを使用することが出来たので手順をメモ
mrubyのコンパイル手順はまんま
http://d.hatena.ne.jp/kyab/20130201
の通りですkyabさんthx


ステータスとしてはとりあえず動かしてみた程度で本格的に使えるところまで試してません。なのでメモリ不足等不具合が沢山あると思います
あくまでもasisでどうぞ

GR-SAKURAの開発環境はWebコンパイラでの提供です。これではmrubyがコンパイル出来ませんのでまずは、ローカルの開発環境を構築する必要があります。
なお、当方windows環境がないので手順はLinux(Ubuntu)とMacでの手順となります。KPITよりwindows版のgcc提供されていますのでこれを利用すれば使えるとはおもいますが、確認してません。

手順は次の通り
1. ローカルビルド環境の構築
2. webコンパイラ環境からGR-SAKURA用のライブラリを取得
3. mrubyのコンパイル
* 設定の記述
* build_config.rb
* include/mrbconf.h
4. ローカルビルド環境でmrubyをコンパイル
5. 作成したlibmruby.aとヘッダファイル郡をGR-SAKURA用ローカルビルド環境へコピー
6. GR-SAKURA用ローカルビルド用makefileの修正
7. rxduino.hファイルの修正 (C99対応)


===============================================
# Build GCC Tool Chain for OS X and Ubuntu (RX版)
===============================================


___Linux環境(Ubuntu)ではKPITよりRXシリーズのGCC toolchainはrpm形式のバイナリパッケージが提供されていますのでalienでパッケージをdeb形式に変換してインストールしたほうがいいです。その場合は以下のクロスコンパイルの構築手順は飛ばして下さい___

## クロスコンパイラのコンパイル準備
=======

必要なライブラリ、プログラム

* mpfr
* gmp
* libmpc
* libelf
* texifo

が必要なのでインストールする

* Homebrewを利用する場合は

``` sh

$ brew install mpfr gmp libmpc libelf texinfo
```

でインストール

* Ubuntuの場合

クロスコンパイラをソースからコンパイルする場合依存するパッケージを

``` sh

$ sudo apt-get install curl flex bison libgmp3-dev libmpfr-dev texinfo  libelf-dev autoconf build-essential libncurses5-dev libmpc-dev 
```
でインストール



Macの場合さらにGCCが必要なのでGCCをインストールする
Homebrewの場合、標準のformulaにはgccがないのでdupsからインストールする必要がある

``` sh

$ brew install https://raw.github.com/Homebrew/homebrew-dupes/master/gcc.rb --enable-all-languages --use-llvm
```

これでgccがgcc-{Version}で利用できる

コンパイル例: 

``` sh 
$ gcc-4.7 hoge.c
```

___以降でコンパイルはgcc-4.7使用環境での手順を記述します。
実際には使用する最新のGCCのバージョンで読み替えてください。
例えばコンパイルオプションのCC=gcc-4.7はCC=gcc-{実際のバージョン}のように___



## renesas RX用ツールチェインのダウンロード
===============================

renesasのRXシリーズのコンパイラの構築なので、
御本尊のGCCでなく開発元のKPITからソースコードをダウンロードします。(要開
発者登録)
(2012.10時点だと)

* GNU v12.02
* GDB v12.02

が最新なようです。

* GDBRX v12.02 Source Code of GDB
* GNURX v12.02 Source Code of GCC
* GNURX v12.02 Source Code of Binutils
* GNURX v12.02 Source Code of Newlib

をそれぞれダウンロードしますファイル名は各々

* gdb-7.4.1_rx_v850_sh_h8_v12.02.tar.bz2
* gcc-4.7.0_rx_v850_sh_h8_v12.02.tar.bz2
* binutils-2.22_rx_v850_sh_h8_v12.02.tar.bz2
* newlib-1.20.0_rx_v850_sh_h8_v12.02.tar.bz2

となります。


## 構築
=======

後は展開してコンパイルすればよいのですが...
はまりどころがあります

まず、gccのソースディレクトリでコンパイルを実行するとエラーがでます。

### 注意:___コンパイルディレクトリとソースディレクトリが同一だとエラーになります___

ソースディレクトリとは別ディレクトリでコンパイルする必要がありますので展開後コンパイル用のディレクトリを作成します。
またgccと一緒にnewlibをコンパイルするためnewlibのシンボリックリンクをgccに張ります。

ダウンロードしたディレクトリで

``` bash
$ mkdir kpit
$ cp gdb-7.4.1_rx_v850_sh_h8_v12.02.tar.bz2 kpit
$ cp gcc-4.7.0_rx_v850_sh_h8_v12.02.tar.bz2
$ cp binutils-2.22_rx_v850_sh_h8_v12.02.tar.bz2 kpit
$ cp newlib-1.20.0_rx_v850_sh_h8_v12.02.tar.bz2 kpit

$ cd kpit
$ tar -jxvf gdb-7.4.1_rx_v850_sh_h8_v12.02.tar.bz2
$ tar -jxvf gcc-4.7.0_rx_v850_sh_h8_v12.02.tar.bz2
$ tar -jxvf binutils-2.22_rx_v850_sh_h8_v12.02.tar.bz2
$ tar -jxvf newlib-1.20.0_rx_v850_sh_h8_v12.02.tar.bz2
```

としてソースを展開します

私は複数のGNUツールチェインをインストールしておりMCUのアーキテクチャ毎にインストール先を変えています。今回はRXシリーズ用のディレクトリとして~/rx-toolsにインストールする様にします。

configureのオプション -prefix={インストールディレクトリ}でインストール先を指定します


### binutils
--------

まずはbinutils

``` sh

$ cd binutils-2.22
$ ./configure -target=rx-elf -prefix=~/rx-tools -disable-werror CC=gcc-4.7
$ make
$ make install
```

コンパイル前にパスを通す

``` sh
$ export PATH=$PATH:~/rx-tools/bin/
```

### GCC
---

``` sh

$ cd ..
$ cd gcc-4.7.0
```

ビルド用のディレクトリとシンボリックリンクの作成

``` sh

$ mkdir build
$ ln -s ../newlib-1.20.0/newlib .
$ ln -s ../newlib-1.20.0/libgloss .
$ cd build

$ ../configure --prefix=~/rx-tools --target=rx-elf --enable-lnguages=c,c++ --disable-libstdcxx-pch --disable-multilib --with-newlib --disable-nls --disable-libgfortran CC=gcc-4.7

$ make
$ make install
```

### newlib
------

``` sh

$ cd ../../newlib-1.20.0
$ ./configure --enable-newlib-hw-fp --target=rx-elf --prefix=~/rx-tools

$ make
$ make install

$ cd ../gdb-7.4.1 
$ ./configure --prefix=~/rx-tools --target=rx-elf --disable-werror

$ make
$ make install
```

.bashrcなどにパスを通しておく

``` sh

 $ export PATH=$PATH:~/rx-tools/bin/

```



参照元情報:
-----

chibiegg日誌: http://blog.chibiegg.net/2009/04/09_12_288.htm

codingcipher: http://codingcipher.wordpress.com/category/compilers/


==============================================
# webコンパイラ環境からGR-SAKURA用のライブラリを取得
==============================================

まずはローカル環境にWebコンパイラのProject_Rootと同じディレクトリツリーを構成し対応したファイルを非常に面倒くさいですが１つづつダウンロードしてローカル環境にディレクトリツリー再構成します。

再構成例: ~/src/sakuraディレクトリを作成して再構成した

``` 
src/sakura
 |
 +--gr_build
 +--gr_common
	+--include
		+--rxduino
			analogio.h
			binary.h
			delay.h
			digitalio.h
			interrupt.h
			progmem.h
			random.h
			rtc.h
			rxduino.h
			serial.h
			shiftout.h
			tone.h
			wiring.h
		+--tkdnhal
			boarddef.h
			tkdn_dflash.h
			tkdn_servo.h
			brd_grsakura.h
			tkdn_ether.h
			tkdn_spi.h
			brd_grume.h
			tkdn_gpio.h
			tkdn_timer.h
			hwsetup.h
			tkdn_hal.h
			tkdn_tone.h
			iodefine_gcc62n.h
			tkdn_i2c.h
			tkdn_usb.h
			iodefine_gcc63n.h
			tkdn_interrupt.h
			tkdn_version.h
			misc.h
			tkdn_pwm.h
			tkdnip.h
			tkdn_adc.h
			tkdn_rtc.h
			tkusbhost.h
			tkdn_dac.h
			tkdn_sci.h
 +--lib
			libc.a
			libgcc.a
			librxduino.a
			libstdc++.a
			libtkdnhal.a
			libg.a
			libm.a
			libsim.a
			libsupc++.a
			libtkdnip.a
	r_sakura.gsi	
	intvect.h
	intvect63n.h
	lowlevel.c
	gstart.o
	intvect.c
	intvect.o
	lowlevel.o
 makefile
 gr_sketch.cpp

```

===================== 
# mrubyのコンパイル
=====================

mrubyをgithubより取得

``` git
$ git clone https://github.com/mruby/mruby.git
```

## build_config.rbを編集
build_config.rbに次のコードを追加
以下例はmrubyは ~/work/mrubyに置き~/rx-toolsへクロスコンパイラをインストールしたとして記述
違う場合はTOOL_PATHを書き換えて下さい。


``` ruby 
MRuby::CrossBuild.new('gr-sakura') do |conf|
  toolchain :gcc

  TOOL_PATH = "~/rx-tools/bin"

  conf.cc do |cc|
    cc.command="#{TOOL_PATH}/rx-elf-gcc"
    cc.flags << "-Wall -g -O2"
    cc.compile_options = "%{flags} -o %{outfile} -c %{infile}"

    conf.linker do |linker|
      linker.command="#{TOOL_PATH}/rx-elf-ld"
    end
    conf.archiver do |archiver|
      archiver.command = "#{TOOL_PATH}/rx-elf-ar"
      archiver.archive_options = 'rcs %{outfile} %{objs}'
    end
  end

  conf.bins = []
end

```

include/mrbconf.hは特に書き換えなくてもコンパイルできますがメモリ使用量に影響しますので必要に応じて書き換えて下さい。
今回はそのままでいきます


## コンパイル
``` sh
$ cd ~/work/mruby
$ make clean
$ make
```

~/work/mruby/build/gr-sakura以下にGR-SAKURA用のmrubyライブラリがコンパイルされます。これらをgr-sakuraのローカル環境からリンクすることでmrubyが実行できます。

===================
# 作成したlibmruby.aとヘッダファイル郡をGR-SAKURA用ローカルビルド環境へコピー
===================

webコンパイラ環境からGR-SAKURA用のライブラリを取得で作成した
プロジェクトディレクトリへmrubyのライブラリ、ヘッダファイルをコピーします。

以下プロジェクトのディレクトリを~/src/sakuraとして説明します
プロジェクトディレクトリにmrubyディレクトリを作成し必要なファイルを~/work/mruby/build/gr-sakuraからコピーします

``` sh
$ cd ~/src/sakura
$ mkdir mruby
$ cd mruby
$ cp ~/work/mruby/build/gr-sakura/lib/libmruby.a .
$ cp -r ~/work/mruby/include .
```

========
# GR-SAKURA用ローカルビルド用makefileの修正
========
~/src/sakura/makefileを編集します
CCPATHにクロスコンパイラの実行パス~/rx-tools/bin/
LIBFILESに./mruby/libmruby.a
CCINCとCPPINCに-I./mruby/includeを追加します。

変更後のmakefile

``` makefile
CCPATH = ~/rx-tools/bin/
OBJFILES = ./gr_sketch.o  ./gr_common/intvect.o ./gr_common/lowlevel.o 
LIBFILES = ./gr_common/lib/libc.a ./gr_common/lib/libg.a ./gr_common/lib/libgcc.a ./gr_common/lib/libm.a ./gr_common/lib/librxduino.a ./gr_common/lib/libsim.a ./gr_common/lib/libstdc++.a ./gr_common/lib/libsupc++.a ./gr_common/lib/libtkdnhal.a ./gr_common/lib/libtkdnip.a ./mruby/libmruby.a
CCINC = -I./gr_build -I./gr_common -I./gr_common/include -I./gr_common/include/rxduino -I./gr_common/include/tkdnhal -I./gr_common/lib -I./mruby/include
CPPINC = -I./gr_build -I./gr_common -I./gr_common/include -I./gr_common/include/rxduino -I./gr_common/include/tkdnhal -I./gr_common/lib -I./mruby/include
TARGET = sketch
CC  = $(CCPATH)rx-elf-gcc -Wall -g -O2 $(CCINC)
CPP = $(CCPATH)rx-elf-gcc -Wall -g -O2 $(CPPINC)
AS  = $(CCPATH)rx-elf-as 
LNK = $(CCPATH)rx-elf-ld
#CNV = $(CCPATH)rx-elf-objcopy --srec-forceS3 --srec-len 32 -O srec
CNV = $(CCPATH)rx-elf-objcopy -O binary
DMP = $(CCPATH)rx-elf-objdump
OBJS = ./gr_common/gstart.o $(OBJFILES) $(LIBFILES) 
LFLAGS = -L./gr_common/lib/ -lrxduino -lstdc++ -lsupc++ -lc -lsim -lgcc -lm -ltkdnhal -nostartfiles
MAKEFILE = makefile
ROMSCRIPT=./gr_common/gr_sakura.gsi

make = make --no-print-directory 

all:	rom

rom:	$(OBJS) $(MAKEFILE) $(ROMSCRIPT)
	$(LNK) -Map ./gr_build/$(TARGET).map $(OBJS) -T $(ROMSCRIPT) $(LFLAGS) -o $(TARGET).elf
	$(CNV) $(TARGET).elf  $(TARGET).bin
	rm -f *.o
	rm -f $(TARGET).elf

#gstart.o:	gstart.s
#	$(AS) -o gstart.o gstart.s

.c.o:
	$(CC) $(CFLAGS) -c $< -o $@

.cpp.o:
	$(CPP) $(CFLAGS) -c $< -o $@
```
==============
# rxduino.hファイルの修正 (C99対応)
==============


rxduino.hで定義されている型はc99ではstdint.h
とかで定義済み、mrubyはc99のヘッダファイルを使用しているので
型が二重定義となりそのままではコンパイル出来ない
~/src/sakura/gr_common/include/rxduino/rxduino.h
の型定義をコメントアウトする

rxduino.hの
//型の定義
のコメント行から
int64_tの定義行までコメントアウトする

===
# Lチカでテスト
===
お決まりのLEDの点滅プログラムでテストする

下記のmrubyテストコードをled.rbという名前で保存する。
led.rb

``` ruby
HIGH = 1
LOW = 0


loop do
    cdigitalWrite(100, HIGH);
    cdelay(200);
    cdigitalWrite(100, LOW);
    cdelay(100);
    cdigitalWrite(101, HIGH);
    cdelay(200);
    cdigitalWrite(101, LOW);
    cdelay(100);
    cdigitalWrite(102, HIGH);
    cdelay(200);
    cdigitalWrite(102, LOW);
    cdelay(100);
    cdigitalWrite(103, HIGH);
    cdelay(200);
    cdigitalWrite(103, LOW);
    cdelay(100);
end
```
これをmrbcでC言語の配列としてバイトコンパイルする

```sh
~/work/mruby/bin/mrbc -Bcode led.rb
```
led.cが作成されるのでテスト用のスケッチにインクルードする

コンパイルするLチカスケッチは
gr_sketch.cpp

``` cpp
/*GR-SAKURA Sketch Template Version: V1.02*/
#include <rxduino.h>


#define CHANGE_HEAP_SIZE(size) __asm__ volatile ("\t.globl _min_heap_size\n\t.equ _min_heap_size, " #size "\n")


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

#include "led.c"

CHANGE_HEAP_SIZE(100*1024);  //ヒープサイズを100kbにする。

extern const char code[];



//digitalWrite function
mrb_value cdigitalWrite(mrb_state *mrb, mrb_value self){
  mrb_int pin;
  mrb_int val;

  mrb_get_args(mrb, "ii", &pin, &val);
  digitalWrite(pin, val);
  return mrb_nil_value();
}

//delay function
mrb_value cdelay(mrb_state *mrb, mrb_value self){
  mrb_int val;
  mrb_get_args(mrb,"i", &val);
  delay(val);
  return mrb_nil_value();
}



void setup(){


  pinMode(PIN_LED0,OUTPUT);
  pinMode(PIN_LED1,OUTPUT);
  pinMode(PIN_LED2,OUTPUT);
  pinMode(PIN_LED3,OUTPUT);

  mrb_state *mrb = mrb_open();

  mrb_define_method(mrb, mrb->object_class, "cdigitalWrite", cdigitalWrite, ARGS_REQ(2));
  mrb_define_method(mrb, mrb->object_class, "cdelay", cdelay, ARGS_REQ(1));


  mrb_load_irep( mrb, code);

 
 }

void loop(){


}
```
makeして出来たsketch.binをGR-SAKURAへ書き込んでボード上の4つのLEDが順番に点灯すればOKです。

##最後に
実際mrubyが動くまでかなりの手間がかかります。しかもメモリもGR-SAKURA、RAM128Kでかなり厳しいですとてもインタラクティブに使うのは無理だと思います。事前にバイトコンパイルすることで何とか使うという感じです。でもCで一から書くことを考えればライブラリを揃えることでお手軽になるかなとういう期待で動かしてみました。
ここまで書いたところで
mrubyのボードが発売になるようです
http://enzi.cc/
これならRAMも１Mあるのでいいのではないでしょうか。実際に使うにはこれくらいのリソースとC言語でのライブラリが必要だと思います