Arduionoで電子工作を始めた人がGR-CITRUSに戸惑ったこと


この記事は Shinosaka.rb Advent Calendar 2016 の 14日目の記事です。

はじめに

GR-CITRUSは、Ruby(正確にはmruby)でプログラムが書けるマイコンボードです。

私の場合は、先にArduinoを使ったことがあったので、理解が早い部分が多かった反面、GR-CITRUSとArduinoの違いで戸惑った部分もありました。
今年の10月に発売されたばかりでまだ情報量が少ないので、同じように戸惑っている人の参考になれば幸いです。

開発環境

Arduinoと違って、ガッツリしたIDEが用意されている訳ではありませんが、公式サイトで解説されているRubicなど、簡単に開発が始められるソフトがいくつか存在しています。

  • Rubic Chromeアプリ
  • Crione Electron製のGUIクライアント
  • setgem CLIクライアント

私の場合はsetgemを使うのに慣れてしまったので、主にターミナルから操作しています。

プログラムの自動実行

Arduinoは電源を入れるとスケッチが自動実行されます。
対して、GR-CITRUSの場合は、標準では自動実行されずに簡易なOSが立ち上がります。

自動実行させるには、特定のファイルを設置した上でボードに少し細工が必要です。
詳しくはファームウェアのドキュメントを参照。
Ruby Firmware on GR-CITRUS.pdf

1. 自動実行させるプログラムを指定

どちらかの方法で指定できます。

  • wrbb.xmlファイルに自動実行させたいファイルを記載する
  • main.mrbという名前で保存する
    • 正確には、wrbb.xmlが存在しない場合のデフォルトがmain.mrbになる

2. 自動実行モードに切り替える

これも、以下のどちらかの方法で切り替えます。

  • ボード上のJ10にハンダを盛ってショートさせる
  • ボード上のJP2にジャンパを挿してショートさせる

私の場合は、抵抗の足を切った余りの線をU字に曲げてJP2に差し込みました。

プルアップ

普段から電子回路を扱い慣れている人にとっては、当たり前のことかも知れません。

Arduinoの場合は内部的にプルアップしてくれるモードがあるのであまり意識しなくても問題ないのですが、GR-CITRUSでは物理的に何とかしてあげる必要があります。

プルアップ抵抗とは

その目的は主として、「そのラインに何も接続されていない状態になった時」に、そのラインの電位を「Hレベル」に固定することにある。

CPU等が、回路からの入力を判断する基準は電圧である。しかしもし、回路がどこにも接続されない状態の場合、その回路のレベルはHかLかはっきりしない、宙に浮いた状態となる。これでは、CPU等は入力がONなのかOFFなのか判断できない。

プルアップは、入力レベルがVCCレベル(Hレベル)であることを明確にするために行なわれ、この目的のためにプルアップ抵抗が取り付けられる。
プルアップ - 通信用語の基礎知識

C言語とかで、宣言した直後の変数に入っている値が不定なのと似てますね。

プルアップしていないとき

折角なので、プルアップしていないときに入力値がどう変化しているのかを調べてみました。

analog_test.rb
@usb = Serial.new(0, 115200)

100.times do
  @usb.print(micros().to_s)
  @usb.print(", ")
  @usb.println(analogRead(16).to_s)
  delay(100)
end

上記のコードを実行した結果をグラフにするとこんな感じ。

analogRead()の出力は0から1023の範囲ですので、微妙な範囲を上下しているのが分かります。

接続例

I2C接続のセンサーを繋ぐときはこんな具合です。

データ(DI)とクロック(CK)の信号線と並列に、5V電源のラインに繋がれている抵抗(1kΩ)がプルアップ抵抗です。

I2Cのreadとwrite

GR-CITRUSのI2cクラスは、ArduinoであればWireクラスに相当するのですが、readwriteメソッドの意味が違うので注意が必要です。

Arduinoとの違い

GR-CITRUS Arduino 意味
read - 指定したアドレスからデータを読み込み
write - 指定したアドレスにデータを書き込む
lread read リクエストして返ってきたデータを受け取る
lwrite write 送信バッファに数値を追加する

通常、I2Cデバイスとの送受信には、若干煩雑な手続きが必要です。
GR-CITRUSのreadwriteメソッドは、その手続きをカプセル化して、直感的に扱えるようにしたものです。

Arduinoと同等のメソッドとしては、lreadlwriteメソッドが用意されています。(頭の「l」は、「ローレベル」のことだと思います。)
この2つは単独では使えず、beginendと組み合わせて使う必要があります。

気を付けないといけない点

上記のように便利にまとめてくれていることから、Arduinoのスケッチを移植するときは、基本的にGR-CITRUSの方がコードの量は減るはずです。
ただ、readwriteはとてもシンプルな実装なので、そのまま使えないこともあり得ます。

例えば、adafruit/Adafruit_LED_BackpackAdafruit_LEDBackpack.cppにこんな感じの関数があります。

Adafruit_LEDBackpack.cpp
void Adafruit_LEDBackpack::writeDisplay(void) {
  Wire.beginTransmission(i2c_addr);
  Wire.write((uint8_t)0x00); // start at address $00

  for (uint8_t i=0; i<8; i++) {
    Wire.write(displaybuffer[i] & 0xFF);    
    Wire.write(displaybuffer[i] >> 8);    
  }
  Wire.endTransmission();  
}

こういうのをGR-CITRUSに移植するときは、lwriteを使って低レベルな実装をする方が分かりやすいかもしれません。

まとめ

こんな具合に戸惑いポイントは色々ありましたが、何とか自分で解決できそうな範囲で楽しくやれています。

まだまだ書籍なんかは無い状況ですが、コードはともかく電子回路の作例はArduinoやIchigoJam向けのものがほぼそのまま使えますので、意外に困らなかったりします。
微妙な修正のために回路を頑張って理解したりするので、そういう意味で勉強になったかも。

何と言っても、Rubyで書けるのが快適で素晴らしい!

おまけ: I2Cスキャナ

I2Cデバイスの配線をしたあと、いきなりコードを書き始めるよりは、とりあえず配線がうまくいっているか確認したいものです。
こういった用途向けに、とりあえずデバイスとお話ができているかを確認するコードを書いてみました。(eachが使えるって素敵。)

コードと使い方

I2Cバスの全アドレスに読み込みを試してみて、成功したものだけ表示します。
I2CデバイスをGR-CITRUSと繋いでみたときに、とりあえずの動作確認で使えるかと思います。

honeniq/i2c_scanner.rb

i2c_scanner.rb
#!mruby
@Usb = Serial.new(0, 115200)
@Dev = I2c.new(1) # SDA=>pin0, SCL=>pin1
@Address = 0x00   # Register address to read.

@Usb.println("I2C Scanner")

(1..127).each do |i|
  r = @Dev.read(i, @Address)
  @Usb.println(i.to_s(16) + ' ' + r.to_s(16)) if r != 255
end

この例だと、各I2Cデバイスのレジスタ0x00を読み込んでデータが取得できれば表示する、というのをI2Cアドレス0x01から0xEFまで繰り返します。

加速度センサーのKP-ADXL343を、プルアップ抵抗の解説のように繋いで実行するとこんな感じ。

WAKAYAMA.RB Board Ver.CITRUS-2.19(2016/11/19)f3(256KB), mruby 1.2.0 (H [ENTER])
>R i2c
I2C Scanner
53 e5

出力があっさりすぎてアレですが、I2Cアドレス0x53のデバイスが0xe5を返しています。