項目番号は前回からの続きということで (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 件のコメント:
コメントを投稿