6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

FreeBSDAdvent Calendar 2015

Day 20

FreeBSD + RaspberryPi で I2C 通信

Last updated at Posted at 2015-12-19

#センサーさんやキャラクター液晶さんと「お話」したい
RaspberryPi で IoT 気取りで何かやりたいとなるとセンサーの値を取得して、それに合わせてプログラムが起動したり、データを集めたりとかやってみたいと思うわけですが、私のように電子工作に明るくない身としては、接続はなるべく簡単に接続できるとありがたいわけです。そういった向きにぴったりなのがI2Cです。
とりあえずセンサーやら繋ぎたいパーツと Raspberry Pi を二本の信号線(と電源線)で繋いでやると、センサーさんとお話が出来るようになります。電子工作系パーツ屋さんには I2C が喋れるセンサーやキャラクタ液晶などのパーツが結構売ってるので、そういうのを買ってきて繋げば制御できます(出来ないこともありますが…)。
しかも複数のパーツを数珠つなぎに配線することができるので(パーティーライン)Raspberry Pi の pin を消費せずにたくさんのパーツをつなぐことが出来ます。どのデバイスとお話するかは各デバイスに固定の「アドレス」があるので、それを指定してあげます。

FreeBSD にはI2C を扱うコマンド、その名もまんま "i2c(/usr/sbin/i2c)" というのがあるので、簡単なデータのやり取りならばプログラミングも不要です。

#上記には若干嘘が…
というわけなのですが、上記には嘘というか Raspberry Pi 特有の重要な補足が必要で、実は FreeBSD の標準 i2c コマンドは、Raspberry Pi では現状動きません。実行すると

Device not configured

などと怒られてしまいます。
なぜ動かないのかは Vadim Zaigrin のブログで調査しています。

ようするに Raspberry Pi の i2c ドライバでは実装されてない機能を i2c コマンドでは使用しているので、Raspberry Pi では i2c が動かないというわけです。

Vadim Zaigrin さんは原因を調べただけでなく、Raspberry Pi で動くように i2c コマンドを作り変えたバージョンを公開しています。

ブログ記事
https://vzaigrin.wordpress.com/2014/05/18/changing-i2c8-utility-in-freebsd-to-work-on-raspberry-pi/

ソースの github
https://github.com/vzaigrin/newi2c

パッチを投げたら FreeBSD 本流チームからダメ出し食らってしまったそうなので At your own risk で
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=189914

上記ソースの使い方は、newi2c.c を単純にcc すればコンパイル終了です。私は標準と混ざらないように pi2c という名前で実行ファイルを作って/usr/local/bin に入れています。以下でも標準でないことを強調するため、コマンドライン実行例のコマンド名を pi2c として説明します。

git clone https://github.com/vzaigrin/newi2c
cd newi2c
cc -o pi2c newi2c.c
install -c pi2c /usr/local/bin

#コマンドの使い方実例
コマンドオプションの詳細はお約束の man i2c で。
FreeBSD では i2c コントローラーは /dev/iic? という形で生えていて、i2c コマンドでは -f オプションで渡してあげます。

Raspberry Pi type B(+)や Raspberry Pi2では /dev/iic0 と /dev/iic1 が生えてますが、例の GPIO 端子からI2Cの端子もあるのですが(図のGPIO02=SDA とGPIO03=SCLが i2c用ピン)

図1
Raspberry Pi GPIO

は/dev/iic1です。オプション指定なしだと /dev/iic0 が使われてしまいますので注意してください。
ちなみに Raspberry Pi type B にはこの端子の下に 4 x 2 の穴が空いています。その穴がI2CやSPIの端子で、それが /dev/iic0 なので、ピンをハンダ付けして生やしてやれば、/dev/iic0 もつかえるそうです(まだ試してない)。

実例として、秋月電子で売っていたキャラクター液晶を繋いでみましょう。

8x2 http://akizukidenshi.com/catalog/g/gK-06795/
16x2 http://akizukidenshi.com/catalog/g/gK-08896/

写真では16x2 を使っています。

Raspberry Pi からは
赤 3.3V
青 SDA
緑 SCL
黒 GND

advent-i2c-raspi.jpg

というふうに線を出して、ブレッドボードに刺した液晶につなげます

advent-i2c-lcd.jpg

そして

pi2c -f /dev/iic1 -s

と実行すると、

Scanning I2C devices on /dev/iic1: 3e

と出て、この液晶のアドレスが0x3eだとわかります。
で、文字を出すんですが、

http://akizukidenshi.com/download/ds/xiamen/AQM1602.pdf
にあるデータシートにある初期化手順を踏んで書き込みや、周波数調整など面倒なので

にシェルスクリプトを置きました。

advent-i2c-lcd2.jpg

i2c-lcd.sh -w 16 "Raspberry Pi de I2c"

のような感じで文字が出力できます。「-w」は文字の折り返しで、8x2 に合わせてデフォルトが 8 なので、16 を指定しています。

#問題点
いきなり実例がややこしい例になってしまいました。
もっと簡単な「センサーデーター読みこむだけ」のようなことをやりたかったのですが、実はこの i2c コマンドも問題があって、連続したバイトの読み込みがうまく行きません。
Raspberry Pi 用変更した i2c コマンドは、ioctl() で I2CRDWR コマンドでstruct iic_msg と struct iic_rdwr_data を渡して読み書きを行います。
直接ioctl()で渡すのはstruct iic_rdwr_dataで、その中身 struct iic_msg の配列とその要素数nmsgsです。

   struct iic_rdwr_data {
          struct iic_msg *msgs;
          uint32_t nmsgs;
   };

読み込み時は struct iic_msg の flags とslaveに IIC_M_RDフラグをセットし、len に読み込みサイズ、buf に配列アドレスを渡します。

   struct iic_msg
   {
           uint16_t        slave;
           uint16_t        flags;
   #define IIC_M_WR        0       /* Fake flag for write */
   #define IIC_M_RD        0x0001  /* read vs write */
   #define IIC_M_NOSTOP    0x0002  /* do not send a I2C stop after message */
   #define IIC_M_NOSTART   0x0004  /* do not send a I2C start before message */
           uint16_t        len;    /* msg length */
           uint8_t *       buf;
   };

i2c コマンドでは、struct iic_msg の len を 1 とし、struct iic_rdwr_dataのnmsgs を読み込むバイト数にする形にして読み込んでいるのですが、自分の環境ではstruct iic_msg の len を読み込むバイト数として、nmsgs は1(+書き込み用struct iic_msgの数)としないとうまく読み込めませんでした。
センサーの読み込みを行いたい場合は、i2c コマンドのコードを参考にしつつ、上記に注意しながらプログラムを書けば、読み込めるようになります。

超適当なサンプルですが、温度センサー
http://www.marutsu.co.jp/pc/i/242757/
用の温度取得プログラム(i2cアドレスは0x48を仮定)が参考になるかもしれません。

6
5
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?