項目番号は前回からの続きということで (7) から始まる。
(7) mraa ライブラリでの I2C 通信:Linux の実装における SMBus 通信を使った I2C 通信(書込み)
次に mraa ライブラリでの I2C 通信の処理について見てみよう。 mraa ライブラリでは I2C 通信は,mraa/src/i2c/i2c.c に記載されている。 そこでは,SMBus 通信を使って I2C 通信を行っている。以下具体的に見てみよう。
まずは書込みルーチンについて見てみよう。 下記に mraa/src/i2c/i2c.c の中の書込みルーチンのうちの2個を載せておく。
mraa_result_t mraa_i2c_write_byte(mraa_i2c_context dev, const uint8_t data) { if (mraa_i2c_smbus_access(dev->fh, I2C_SMBUS_WRITE, data, I2C_SMBUS_BYTE, NULL) < 0) { syslog(LOG_ERR, "i2c: Failed to write"); return MRAA_ERROR_INVALID_HANDLE; } return MRAA_SUCCESS; }
mraa_result_t mraa_i2c_write_byte_data(mraa_i2c_context dev, const uint8_t data, const uint8_t command) { i2c_smbus_data_t d; d.byte = data; if (mraa_i2c_smbus_access(dev->fh, I2C_SMBUS_WRITE, command, I2C_SMBUS_BYTE_DATA, &d) < 0) { syslog(LOG_ERR, "i2c: Failed to write"); return MRAA_ERROR_INVALID_HANDLE; } return MRAA_SUCCESS; }これらは共に SMBus を使った I2C 機器への書込み処理を表している。 どちらも mraa_i2c_smbus_access ルーチンを使っている。 違いは,mraa_i2c_write_byte_data ルーチンの方は command と &d の2つある部分が,mraa_i2c_write_byte ルーチンの方は command の代わりに data 1個のみになり,&d の部分は NULL となっている。 また,第4引数が「I2C_SMBUS_BYTE」と「I2C_SMBUS_BYTE_DATA」で異なっている。 これは含まれるデータの数を表しており,/usr/include/linux/i2c-dev-user.h の中で定義されている。
そこで,上記2ルーチンの中で使われている mraa_i2c_smbus_access ルーチンについて見てみよう。 これは mraa/src/i2c/i2c.c の中のはじめの方に記載がある。 ここでは mraa_i2c_smbus_access ルーチン内で使われる i2c_smbus_ioctl_data_t 型についての定義も載せておく。
typedef struct i2c_smbus_ioctl_data_struct { uint8_t read_write; ///< operation direction uint8_t command; ///< ioctl command int size; ///< data size i2c_smbus_data_t *data; ///< data } i2c_smbus_ioctl_data_t; int mraa_i2c_smbus_access(int fh, uint8_t read_write, uint8_t command, int size, i2c_smbus_data_t *data) { i2c_smbus_ioctl_data_t args; args.read_write = read_write; args.command = command; args.size = size; args.data = data; return ioctl(fh, I2C_SMBUS, &args); }
mraa_i2c_smbus_access ルーチンでは,最後に ioctl を呼び出しているが,第2引数が I2C_SMBUS となっており,SMBus を使った書込みということを示している。 また,送り出すデータの構造体は,I2C_RDWR を使う場合とは異なってる。 その構造体 i2c_smbus_ioctl_data_t は,
・read_write
・command
・size
・*data
から成っている。 read_write は書込みか,読込みかの方向を表している。 command はスレーブ機器へのコマンドであり,内部レジスタがある場合は内部レジスタを示すと考えれば良い。 もし内部レジスタの指定がなく,1バイトのみを書込みたい時には,この command の部分にデータを入れれば良い事になる。 size はデータサイズであり,最後に書込みデータがある。
ここで気になるのが,この i2c_smbus_ioctl_data_t 型の中にはスレーブアドレスを入れる部分がない,という点である。 実は,スレーブアドレスの指定は,この mraa_i2c_smbus_access ルーチンを呼び出す直前に別ルーチンを呼び出すことで行う。具体的には,以下のようにして書込みを行う。
mraa_i2c_address(i2c, HMC5883L_I2C_ADDR); // スレーブアドレス指定 mraa_i2c_write_byte(i2c, HMC5883L_DATA_REG); // 書込み処理ここで,mraa_i2c_address ルーチンがスレーブアドレスの指定を行うルーチンである。 つまり SMBus を使う手順では,まず,受け取るスレーブ機器のアドレスを指定し, その直後に対象となるスレーブ機器に対してデータのやりとりをする,という感じである。
言い換えると,I2C では送受信するデータの先頭にアドレスをくっつけるが, Linux の実装の SMBus 通信では受取側アドレスの指定とデータの送受信が別個になっている。
せっかくなので,mraa/src/i2c/i2c.c の中の別の書込みチールンを書いておこう。
mraa_result_t mraa_i2c_write(mraa_i2c_context dev, const uint8_t* data, int length) { i2c_smbus_data_t d; int i; uint8_t command = data[0]; data = &data[1]; length = length-1; if (length > I2C_SMBUS_I2C_BLOCK_MAX) { length = I2C_SMBUS_I2C_BLOCK_MAX; } for (i=1; i<=length; i++) { d.block[i] = data[i-1]; } d.block[0] = length; return mraa_i2c_smbus_access(dev->fh, I2C_SMBUS_WRITE, command, I2C_SMBUS_I2C_BLOCK_DATA, &d); }このルーチンは data 配列を書き込むのだが,内部レジスタがある場合は,data 配列の先頭 data[0] に内部レジスタを入れ,その後に書き込むデータを入れたものを data として渡すようになっている。 しかし,ルーチンの中ではわざわざ data[0] を取り出して,mraa_i2c_smbus_access ルーチンに渡している…。 なんかいまいちな感じやなぁ…。
このルーチンを使った例は以下のようになる。
mraa_i2c_address(i2c, HMC5883L_I2C_ADDR); // スレーブアドレス指定 rx_tx_buf[0] = HMC5883L_MODE_REG; // 内部レジスタの指定 rx_tx_buf[1] = HMC5883L_CONT_MODE; // 書込みたいデータ mraa_i2c_write(i2c, rx_tx_buf, 2); // 書込み処理
(8) mraa ライブラリでの I2C 通信(読込み)
mraa ライブラリでの I2C の読込みルーチンは書込みルーチンとほぼ同じであり, 特に説明の必要はないと思う。 是非,自分で mraa/src/i2c/i2c.c を読んでみて欲しい。 例えば,
・mraa_i2c_read_byte(mraa_i2c_context dev):dev というファイルハンドラを持つデバイスから1バイト読み込む
・mraa_i2c_read_byte_data(mraa_i2c_context dev, uint8_t command):dev に command を書き込んでから1バイト読み出す。
内部レジスタがある場合は,command の部分に内部レジスタ番号を書き込めばよい。
・mraa_i2c_read_word_data(mraa_i2c_context dev, uint8_t command):command の後に dev から2バイト(1ワード)読み込む。
などがある。
多少,趣きが異なる読込みルーチンとして,
・mraa_i2c_read_bytes_data(mraa_i2c_context dev, uint8_t command, uint8_t* data, int length)
がある。これは,I2C_RDWR を使った読み書きのところに書いた「読込みルーチン」とほぼ同じ処理をしている。 つまり,内部レジスタ指定のために1バイトのデータを書込み,通信を切らないままデータを読込む,というルーチンである。 上記に示したルーチンとの違いは,1バイトや1ワードにかぎらず,もっと長いデータも読み込めるルーチン,という点である。
(注意)libmraa0 の ver. 0.6.1には,この mraa_i2c_read_bytes_data ルーチンは含まれていない。 github の mraa の commmit 情報を見ると,このルーチンは 2015/3/4 に追加されている。 しかし libmraa0 の v 0.6.1 のリリースは 2015/2/27 であり,この追加はまだ反映されていない。 今後のリリースで反映されるものと思われる。
(追記) 2015/4/14 付で libmraa0 が ver. 0.6.2 にバージョンアップされていた。 この ver. 0.6.2 には上記の mraa_i2c_read_bytes_data ルーチンが含まれている。
0 件のコメント:
コメントを投稿