しまねソフト研究開発センター(略称 ITOC)にいます、東です。
これは Ruby Advent Calendar 2023 の記事です。
Abstract
- mruby, mruby/c 共通のマイクロコントローラペリフェラルインターフェースガイドというものがある。
- 実体は、I2C, UART 等のインターフェースの利用 API を定義したもの。
- mrubyだけじゃなくて、やっぱり CRuby でも使いたいよね。
結論
作りました。
- GPIO https://rubygems.org/gems/mruby-sysfs-gpio
- I2C https://rubygems.org/gems/mruby-linux-i2c
- SPI https://rubygems.org/gems/mruby-linux-spi
- UART https://rubygems.org/gems/mruby-serialport-uart
うれしいこと
- CRuby でも、IoT ができる。Raspberry Pi をはじめとして、組込 Linux ボードで CRuby使って IoT とか、よさそうじゃない?
- もっと「小さく」「低コストに」「省電力に」したくなったら、マイコンボードに mruby か mruby/c を載せて、同じ Ruby プログラムをうごかすんだ。
そんなわけで、ガイドラインのうち、Linux のデバイスドライバレベルでサポートされている4種類、"GPIO", "I2C", "SPI", "UART" の rubygem ライブラリを作りました。
ラズベリーパイ4 と、アットマークテクノの Armadillo-IoT G3 で動作確認をしています。
GPIO クラスについて
GPIOは、General-purpose input/output の略で、汎用の入出力です。1ビット単位の入力または出力ができます。
入力の代表的な例はプッシュスイッチのON/OFF 状態など、出力の代表的な例は、LEDの点灯などです。
ガイドライン
実装
Linux の sysfs を使っています。GPIO の sysfs は既に使用が非推奨になっていますが、新しい仕組みが使いたいボード類で十分出そろったら、そのときに考えます。
ElChika(えるちか)サンプル
require "mruby/gpio" # or "mruby/gpio/sysfs"
led = GPIO.new(26, GPIO::OUT) # GPIO26番ピンを出力に設定し、そのインスタンスを得る
while true
led.write( 1 ) # 出力1 -> LED点灯
sleep 1
led.write( 0 ) # 出力0 -> LED消灯
sleep 1
end
プッシュスイッチとLED(入出力)のデモ
ソースコード
https://github.com/HirohitoHigashi/mruby-mio/blob/main/mruby-sysfs-gpio/test/led5sw1_polling.rb
未実装
プルアップ、プルダウンの機能などについては、sysfs にその機能が無いのでサポートできていません。
I2Cクラス, SPI クラス
I2C, SPI は、両方ともシリアル入出力バスの規格で、主にセンサーや小型ディスプレイの接続などに使用されます。
ガイドライン
実装
いずれも、Linux device driver の ioctl だけを使って PureRubyで書いています。perl ゆずり(と思われる)pack / unpack を駆使しますが、もう少しマシな方法が欲しいと思いますよね。
気圧センサ LPS25H 読み取りサンプル
require "mruby/i2c"
# create instance
i2c = I2C.new("/dev/i2c-1")
# Write to device at address 0x5c, data 0x20, 0x90.
i2c.write( 0x5c, 0x20, 0x90 )
# Read 5 bytes from the device at address 0x5c.
# Outputs 0xa8 before reading.
s = i2c.read( 0x5c, 5, 0xa8 )
加速度センサで重力方向を検出するデモ
ソースコード
https://github.com/HirohitoHigashi/mruby-mio/blob/main/mruby-linux-spi/test/ADXL345_Accelerometer.rb
未実装
I2Cの 低レベルメソッドは、実装していません。
UART クラス
UART クラスは、通常1対1のシリアル通信をサポートする規格で、RF通信モジュールをはじめとし、様々なデバイスが接続できます。
ガイドライン
実装
このクラスだけは、下層に serialport gem を使用します。汎用的に作ろうとすると、どうしてもC拡張が必要になりそうだったので、よくできている gem に頼りました。
サンプル Echo server
require "mruby/uart" # or "mruby/uart/serialport"
uart = UART.new("/dev/serial0")
while true
s = uart.read(1)
uart.write s
print s
end
おわりに
ADC と PWM については、マイコンボードの種類ごとにハードウェアを直接たたくコードを書くしかなさそうです。また、現在は LinuxOS のサポートだけですが、FreeBSD も I2C等のデバイスドライバが用意されているので、そちらへの対応もしたいと考えています。
それでは、Happy Holidays!