広告
I2Cとは
I2C(あいすくえあしー)はシリアルの通信規格の一つでセンサーなどに使われている。
より詳しい説明などはネットを調べればたくさん出てくるのでそちらを参考に。
ここでは実際に使う上で知っておいた方が良さそうな情報だけ書いてみる。
細かなこと
デバイスのアドレスが8bitで書かれているものと7bitで書かれているものがある。
デバイスのデータシートを見るとデバイスのアドレスが8bitで書かれているものと7bitで書かれているものがある。
これは、8bitの場合、書き込み読み込みビットがLSBに入っているためで、7bitの場合はその読み書きビットが入っていない。つまりどちらも同じ。
Raspberry Piなどで使うときi2cdetectで表示されるのは最後の読み書きビットは含まないので7bitのアドレスとして表示されている。
10bitアドレスもある
ものによっては10bitアドレスもあるらしいが、見たことはない。
同じアドレスのデバイスを複数使いたい場合
外付けの抵抗などでアドレスを変えられるものもあるが、物によってはアドレスを変えられない。
そこで、SCLのラインを切り替えたりする方法もあるらしいが、切り替えラインを必要とするので面倒である。
世の中にはI2Cのアドレス切り替えデバイスがあるのでそれを使うとよい。
例えばLTC4316やLTC4317など。
注意すべきところはLTC4316/4317の出力のSCL、SDAラインも別途プルアップする必要がある。
また、データシートに載っているアドレス設定用の抵抗値がE48系列(E96系列)なので入手がしにくい。
1MΩと681kΩというのを1MΩと680kΩにすれば良いかと思う。あるいはオープンとショートの組み合わせ。
レベル変換をする時
CPUやFPGAなどによってはロジックが1.8Vだったりと3.3Vで無い場合があって,その時はレベル変換をする必要がある.
ところがレベル変換ICによってはI2C(プルアップ)に対応していないものがあるので注意が必要.
例えば,秋月電子などで売っている「FXMA108」はその一つ.
I2C専用のレベル変換ICPをしようするか秋月電子の4ビット双方向ロジックレベル変換モジュールのようにディスクリートで実現するのがいい
Repeated Start Conditionのデバイスに注意
Repeated Start Condition(エレキジャックの解説)になっているデバイスをRaspberry Piで読み込もうとするとちゃんと読めない(変な値になっている)。
i2cgetなどでうまく読めなかった場合はこれを疑ってみると良いと思う。
Rabbit Noteさんの記事にその対処法が載っている。
この処置をしてからwrite()やread()を使わずにioctlで読み書きするといいみたい。ioctlでI2cの読み書き例
他には「bcm2835」というライブラリを使う方法がある。
これは多分GPIOとして直接ポートを叩いていると思う。そのため、これを使うとi2cdetectやi2cget,i2csetなどが使えなくなる。
- アーカイブを取ってきて解凍、インストールする
tar zxvf bcm2835-1.xx.tar.gz
cd bcm2835-1.xx
./configure
make
sudo make check
sudo make install
- 主要部分
単純には初期化して、スレーブアドレスを指定して、読み書きして、終了する
- ヘッダーのインクルード
#include <bcm2835.h>
- 初期化
if (!bcm2835_init()){
printf("Error initialize\n");
}
bcm2835_i2c_begin();
- スレーブアドレスの設定
uint8_t slave_addr;
bcm2835_i2c_setSlaveAddress(slave_addr);
- レジスタアドレスの指定
char reg; //レジスタアドレス
bcm2835_i2c_write(®,1);
- 単純な読み込み
char reg; //レジスタアドレス
char buf[2]; //読み込んだデータを入れる
int len=1; //読み込み長さ
int ret; //返り値(エラーなど)
bcm2835_i2c_write(®,1);
bcm2835_i2c_read(buf,len);
- Repeated Start Conditionに対応した読み込み
char reg; //レジスタアドレス
char buf[2]; //読み込んだデータを入れる
int len=1; //読み込み長さ
int ret;
ret=bcm2835_i2c_read_register_rs(®,buf,len);
- 書き込み(データを書き込む場合)
int ret;
char write[2]; //レジスタアドレスと書き込むデータを入れる
//例えば,write[0]=reg;write[1]=data;
ret=bcm2835_i2c_write(write,2);
- bcm2835_i2c_write()を2回に分けるとちゃんと書き込めない
- 終了
bcm2835_i2c_end();
bcm2835_close();
- コンパイル(ファイル名が「foo.c」の時)
gcc -o foo foo.c -l bcm2835
- 単純な例(インクルードするヘッダーやアドレス等は適当に設定する)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <bcm2835.h>
#include <stdint.h>
#define slave_addr 0x00
#define reg 0x00
#define write_data 0x00
int main(){
unsigned char buf[2];
uint8_t ret;
char write[2];
char reg_addr=(char) reg;
//Initialize
if (!bcm2835_init()){
printf("Error initialize\n");
}
printf("Program start\n");
bcm2835_i2c_begin();
printf("Send Slave address\n");
bcm2835_i2c_setSlaveAddress(slave_addr);
//Read : Repeated Start Condition
printf("Read data\n");
ret=bcm2835_i2c_read_register_rs(®_addr,buf,1);
if(ret==BCM2835_I2C_REASON_OK){
printf("Read OK:%02x\n",buf[0]);
}else{
printf("Error:%d\n",ret);
return ret;
}
//Read : Normal
ret=bcm2835_i2c_write(®_addr,1);
if(ret!=BCM2835_I2C_REASON_OK){
printf("Write Error:Reg\n");
return ret;
}
ret=bcm2835_i2c_read(buf,1);
if(ret==BCM2835_I2C_REASON_OK){
printf("Read OK:%02x\n",buf[0]);
}else{
printf("Error:%d\n",ret);
return ret;
}
//Write
write[0]=reg_addr;
write[1]=(char) write_data;
ret=bcm2835_i2c_write(write,2);
//End
bcm2835_i2c_end();
bcm2835_close();
}
広告