mruby/cをPSoC5で動かす


この記事では，mruby/cのα版をPSoC5 Prototyping Kit（CY8CKIT-059）で動かす手順を示します．

> PSoC4 Prototyping Kit（CY8CKIT-049）も同様の手順で可能です．

mruby/cは，実行時に必要な資源が少なくなるようにした mrubyの実装です．64KB以下での動作を想定しています．現在，α版を配布しております．

mruby/c α版の入手については，[しまねソフト開発センター（ITOC）](http://www.s-itoc.jp/)の[mruby/c の取り組み](http://www.s-itoc.jp/news/10)をご覧ください．

# 必要なもの

- CY8CKIT-059
- PSoC Creator
- mruby/c α版
- mruby OSS版（[mrubyフォーラム](http://forum.mruby.org/)からダウンロードできます）

# 全体の流れ

1. 簡単なCのプログラムのプロジェクトを作成する
2. 1のプロジェクトにmruby/cを追加する
3. mrubyプログラムをコンパイルして，2に組込む

# プロジェクト作成

空のプロジェクトを作成します．

![img01.png](https://qiita-image-store.s3.amazonaws.com/0/104404/0c7904b8-1767-941b-9479-969a7c8fed0a.png)

もし「Target hardware」に「CY8CKIT-059」が出てこない場合は，「Target device」で「CY8C5888LTI-LP097」を選択します．

> PSoC4の場合は「CY8CKIT-049」または「CY8C4247AZI-M485」になります．

次の画面では「Empty Schematic」を選択します．次に，プロジェクト名などを入力します．ここではプロジェクト名を「mrubyc_sample」としています．

![img02.png](https://qiita-image-store.s3.amazonaws.com/0/104404/f91a922c-995b-4e8d-07d6-eb0f87f79c7c.png)

# LEDを点滅させる

回路図にDigital Output Pinを追加します．

![img03.png](https://qiita-image-store.s3.amazonaws.com/0/104404/037a3356-885c-041a-38d8-c1af484099aa.png)

このPinをダブルクリックして，設定します．

![img04.png](https://qiita-image-store.s3.amazonaws.com/0/104404/e8c196e8-0dc6-71db-2fc5-8511d9a956ec.png)

- 「Name」を「LED」にする
- 「HW connection」のチェックを外す

# ピンを設定する

<プロジェクト名>.cydwr ファイルを開き，LEDのポートを「P2[1]」に設定します．

![img05.png](https://qiita-image-store.s3.amazonaws.com/0/104404/58aedf53-a653-4eae-a22a-cb0442b29e39.png)

> PSoC4の場合は，LEDのポートは「P1[6]」になります．


# ビルドする

ここでプロジェクトをビルドします．

ビルドすることで，先ほど設定したLEDの出力に関するコードが自動生成されます．

# Cプログラムの作成

main.cのmain関数を次のように作成します．

```c:main関数
int main()
{
    CyGlobalIntEnable; /* Enable global interrupts. */

    /* Place your initialization/startup code here (e.g. MyInst_Start()) */

    for(;;)
    {
        /* Place your application code here. */
        LED_Write(1);
        CyDelay(200);
        LED_Write(0);
        CyDelay(200);
    }
}
```

# 実行

ビルドを行い，[Debug]-[Program]でボードに書き込まれます．ボード上のLEDが点滅すればOKです．

-----

# mruby/c のファイルをコピーする

mruby/c α版を解凍して得られる srcフォルダ内の以下のすべてのファイル（xxx.cとxxx.h）を，PSoC Creatorのプロジェクトフォルダ（main.cがあるフォルダにコピーします）．

# プロジェクトにファイルを追加する

[Project]-[Existing Item...]で，mruby/c α版のファイル（xxx.c）を追加します．複数のファイルを選択して，一度に追加できます．

# メソッドの追加

Cのプログラムで使用したLED_Write関数とCyDelay関数を，mrubyから利用できるようにします．Objectクラスにそれぞれのメソッドを追加します．

class.cファイルを開き，以下を追加，修正します．

```c:追加するヘッダファイル
#include "LED.h"
#include "CyLib.h"
```

```c:追加する関数
mrb_value c_led(struct VM *vm, mrb_value v)
{
  LED_Write( v.value.i );
  return v;
}

mrb_value c_delay(struct VM *vm, mrb_value v)
{
  CyDelay(v.value.i);
  return v;
}
```

```c:mrb_init_class_object関数を書き換える
static void mrb_init_class_object(void)
{
  // Class
  static_class_object = mrb_class_alloc("Object", -1);
  // Methods
  mrb_define_method(static_class_object, "led", c_led);
  mrb_define_method(static_class_object, "delay", c_delay);
}
```

mrb_init_class_object関数内のmrb_define_method関数により，Cの関数とmrubyのメソッドを対応付けます．

-----

# mrubyプログラムの作成

次のmrubyのプログラムを sample.rb として作成します．Cで作ったプログラムと違うタイミングでLEDが点滅します．

```ruby:sample.rb
led 1
delay 100
led 0
delay 900
```

# mrbcによるコンパイル

sample.rb を mruby（OSS版）でコンパイルして sample.c を作成します．sample.cをPSoCのプロジェクト内のmain.cと同じフォルダにコピーしておきます．

```
  mrbc -E -Bary sample.rb 
```

# main.c を書き換え，Cからmrubyプログラムを呼び出す

main.cに以下を追加します．

```c:ヘッダファイルの追加
#include "vm.h" 
#include "load.h" 
#include "errorcode.h" 
#include "static.h" 
#include "sample.c"
```

mrubyc関数を追加します．

```c:mrubyc関数
int mrubyc(void)
{
  struct VM *vm;

  init_static();

  vm = vm_open();
  if( vm == 0 ){
    printf("VM open Error\n");
    return -1;
  }

  int ret = loca_mrb_array(vm, ary);
  if( ret != NO_ERROR ){
    printf("MRB Load Error (%04x_%04x)\n", ret>>16, ret&0xffff);
    return -1;
  }

  vm_boot( vm );

  int keep_execute = 1;
  while( keep_execute ){
    if( vm_run_step(vm) < 0 ){
      keep_execute = 0;
    }
  }

  vm_close( vm );

  return 0;
}
```

```c:main関数
int main()
{
    CyGlobalIntEnable; /* Enable global interrupts. */

    /* Place your initialization/startup code here (e.g. MyInst_Start()) */

    for(;;)
    {
        /* Place your application code here. */
        mrubyc();
    }
}
```

# ビルドと実行

ビルドを行い，[Debug]-[Program]でボードに書き込まれます．ボード上のLEDが点滅すればOKです．


----

少々長い説明となりましたが，以上で mruby/c α版を PSoC5で動かすことができます．