mruby/c 環境利用の基礎知識

はじめに

本演習では, 高級言語 (mrubyc) による開発の基礎において 「方法 2: マイコンの C 言語開発環境を使う」と書かれた方式でプログラミングを行う. メーカが用意した C 言語開発環境と VM のソースコードを使って, 既存の C 言語のプログラムに mruby バイトコードを結合する.

この方法 2 を簡単に実現するための環境を 羽角均氏(株式会社モンスター・ラボ 島根開発拠点)が公開している <URL:https://github.com/hasumikin/mrubyc-template-esp32>. この環境の詳細を知るには ITOC (しまねソフト研究開発センター) で公開されている 羽角均氏による ESP32 × mruby/c の ハンズオン資料 を参照すると良いが, このソースをそのまま使う場合には Ruby のコードと, Ruby から ESP-IDF 環境 (C 言語) を呼ぶためのラッパーの 2 つを書かねばならない.

初心者がラッパーをいちいち自分で書くのは困難であるため, ラッパーを含めた環境を <URL:https://github.com/gfd-dennou-club/iotex-esp32-mrubyc> に公開した. 本演習ではこのリポジトリを利用する. git clone したソースコードをみると, 基本的に ESP-IDF と同じディレクトリ構造であり, componets/mrubyc, mrblib といった mruby/c 用のディレクトリが追加されていることがわかる. component/mrubyc 以下には mrubyc の VM を make するためのソースコードが存在している. ユーザは mrlib 以下に自分のプログラムを置くことになる. mrblib/loops 以下にメインプログラムを, mrblib/models 以下に新たに定義したクラスを置く. なお, プログラムのコンパイルおよび実行方法は ESP-IDF 環境 と全く同じである.

$ tree -L 4 iotex-mrubyc-esp32/

  mrubyc-template-esp32/
  ├── Makefile
  ├── components
  │   └── mrubyc              mruby/c の VM のソースなど
  │       ├── component.mk
  │       ├── mrubyc_mrblib
  │       │   ├── Makefile
  │       │   ├── array.rb
  │       │   ├── numeric.rb
  │       │   ├── object.rb
  │       │   ├── range.rb
  │       │   └── string.rb
  │       └── mrubyc_src
  │           ├── Doxyfile
  │           ├── Makefile
  │           ├── alloc.c
  │           ├── alloc.h
  │           ├── c_array.c
  │           ├── c_array.h
..........(中略)...............
  │           ├── symbol.c
  │           ├── symbol.h
  │           ├── value.c
  │           ├── value.h
  │           ├── vm.c
  │           ├── vm.h
  │           └── vm_config.h
  ├── main
  │   ├── component.mk
  │   └ mrbc_esp32_gpio.c     ラッパー
  │   └ mrbc_esp32_gpih
..........(中略)...............
  │   └── main.c
  └── mrblib
      ├── loops        メインプログラム
      └── models             クラス

初めの一歩: Hello World

プロジェクトの作成

基本的に ESP-IDF 環境と同じなので, ESP-IDF 環境がインストールされているディレクトリ (ここでは $HOME/esp) 以下にプロジェクト用のディレクトリを作る. GitHub から j5_es_2020 ブランチを git clone する.

$ cd ~/esp

$ git clone https://github.com/gfd-dennou-club/iotex-esp32-mrubyc.git mrubyc-00-hello-world

$ cd mrubyc-00-hello-world

make menuconfig で “IoTeX ESP32 mrubyc Configuration” の全ての項目のチェックを外す.

$ make menuconfig

プログラムの作成

mruby/c のコードはプロジェクトディレクトリ内の mrblib/loops 以下に置く. mrblib/loops/master.rb というファイルを作成し, 以下のようなプログラムを書き込む. このプログラムは 5 秒毎に "Hello World!" を延々と表示するものである.

1 while true
2   puts "Hello World!"
3   sleep 5
4 end

ビルドする前に

ビルドする前に, ESP32 のデバイス名の確認を行う.

ESP32 は /dev/tty* というデバイス名で認識されていることが普通である. /dev/tty* を調べ, "USB" と付くもの or tty.<USB-Serial の型番> を探す. Linux の場合は /dev/ttyUSB0 となるのが普通である.

$ ls /dev/tty*

  ...(略)...

ビルド

make コマンドもしくは idf.py コマンドでビルドする. ESP-IDF の公式ドキュメントでは idf.py を使うことになっているが, make コマンドで全く問題ない.

ESP32 のデバイス名を確認した後に, make コマンドを実行する. プロジェクトのディレクトリで最初に make コマンドを実行した時には 以下の例のように config menu が表示される. TOP から Serial flasher config を選択し, "Default serial port" を先に調べたデバイス名 (以下の例では /dev/ttyUSB0) にする.

$ make

一番最初に make するときは 必要となるライブラリを全てコンパイルしているので時間がかかる. プロジェクトのディレクトリをみると, build という新たなディレクトリが 作成され, その下にオブジェクトファイルが置かれているのがわかる.

$ tree -L 3
  .
  ├── CMakeLists.txt
  ├── Makefile
  ├── README.md
  ├── build
  │   ├── app_trace
  │   │   ├── app_trace.d
  │   │   ├── app_trace.o
  │   │   ├── app_trace_util.d
  │   │   ├── app_trace_util.o
  │   │   ├── component_project_vars.mk
  │   │   ├── gcov
  │   │   ├── heap_trace_tohost.d
  │   │   ├── heap_trace_tohost.o
  │   │   ├── host_file_io.d
  │   │   ├── host_file_io.o
  │   │   └── libapp_trace.a
  │   ├── app_update
  │   │   ├── component_project_vars.mk
  │   │   ├── esp_app_desc.d
  │   │   ├── esp_app_desc.o
  │   │   ├── esp_ota_ops.d
  │   │   ├── esp_ota_ops.o
  │   │   ├── libapp_update.a
  │   │   └── tmp_cppflags.txt
  │   ├── asio
  │   │   ├── asio
  │   │   ├── component_project_vars.mk
  │   │   └── libasio.a

  ...(以下, 略)...

設定した内容はプロジェクトディレクトリ直下に置かれている sdkconfig ファイルに含まれている. デバイス名は CONFIG_ESPTOOLPY_PORT に値が設定されている. sdkconfig はテキストファイルであるため, 簡単に中身を確認することができる. CONFIG_ESPTOOLPY_PORT に設定されている値を確認したければ grep すれば良い.

$ grep CONFIG_ESPTOOLPY_PORT sdkconfig 

  sdkconfig:CONFIG_ESPTOOLPY_PORT="/dev/ttyUSB0"
補足: 最初の make の時には自動的に config menu が表示される. 2 回目以降で config menu を表示させたい場合は陽に make menuconfig コマンドを実行する必要がある.

マイコンへの書き込みと標準出力の表示

マイコンに書き込むのは make flash コマンド, 標準出力を表示するのは make monitor コマンドである. まとめて make flash monitor としても良い. なお, puts や print で何らかの情報を書き出すようにしている場合は make monitor する必要がある.

プログラムのマイコンへの書き込みが終了すれば, "Leaving...." "Hard resetting via RTS pin..." といった表示がなされる.

$ make flash

  ...(中略)...

  App "hello-world" version: 1
  Flashing binaries to serial port /dev/ttyUSB0 (app at offset 0x10000)...
  esptool.py v2.9-dev
  Serial port /dev/ttyUSB0
  Connecting.......
  Chip is ESP32D0WDQ6 (revision 0)
  Features: WiFi, BT, Dual Core, Coding Scheme None
  Crystal is 40MHz
  MAC: 30:ae:a4:02:26:34
  Uploading stub...
  Running stub...
  Stub running...
  Configuring flash size...
  Auto-detected Flash size: 4MB
  Flash params set to 0x0220

  ...(中略)...

  Leaving...
  Hard resetting via RTS pin...

プログラム中で "printf("Hello world!\n");" と書いたのを表示させたければ, make monitor する必要がある. monitor を終了するのは Ctrl-] である.

$ make  monitor

  ...(中略)...

  Hello World!
  Hello World!
  Hello World!

  ...(以下略)...
monitor を終了するのは Ctrl-] である.