I2Cは「Inter Integrated Circuit」の略で、機器内、機器間のどちらの通信にも用いられる通信方式です[]。
機器内のセンサー等のインターフェースとして最も普及しています。
また、類似の規格として、DDC(Display Data Channel)やSMBusがあり、I2Cと一部互換性があります。
I2Cには以下のモード[]があります。
本書では、普及している「スタンダードモード」と「ファストモード」の説明を行います。
表5.1 I2Cモード一覧
モード | クロック | Armadillo-640対応 | スタンダードモードとの互換性 |
---|
スタンダードモード | ~100kHz | 〇 | 〇 |
ファストモード | ~400kHz | 〇 | 〇 |
ファストモードプラス | ~1MHz | × | 〇 |
ハイスピードモード | ~3.4MHz | × | 一部互換 |
ウルトラファストモード | ~5MHz | × | 互換性なし |
一般的な接続方法を下図に示します。
なお、Armadillo-640はマスターとして別のデバイスと通信できます。
I2Cの主な特徴を以下に示します。
-
デバイスはマスターとスレーブが存在
-
1つのバス上にマスターとスレーブを複数接続可能[]
-
信号線はSDA(データ)とSCL(クロック)の2本のみ
-
信号線はオープンドレイン(プルアップが必要)
-
データはクロックに合わせて変化
-
スレーブは7ビットもしくは10ビットのアドレスを持つ[]
-
通信は常にマスターが開始し、アドレスでスレーブを選択
-
クロックは最高400kHz(ファストモード)、最高100kHz(スタンダードモード)
I2Cの詳しい仕様は、NXP Semiconductorsから公開されている資料をご覧ください。
I2Cのデータフォーマットは以下のようになっています。
通信はスタートコンディションで開始し、ストップコンディションで終わります。
斜線部分がスレーブの応答です。
1バイトごとに受信側がACKを返すようになっています。なお、マスターが最後のデータを受信したときはNACKを返します。
最初のバイトはアドレスバイトといいます。
2バイト目以降はデータバイトとなり、内容やフォーマットはスレーブのデバイスごとに異なります。
デバイスによっては、以下のように複数バイトの読み出しを連続で行うことも可能です。
アドレスバイトは、スレーブ指定のための7ビットのアドレスとマスターが読み出すか書き込むかをスレーブに伝えるためのR/Wで構成されています。
なお、リスタートやクロックストレッチについては複雑なため、ここでは触れていません。
I2Cの波形は以下のようになっています。
5.2. A/Dコンバーター(PCF8591)を使用する
ここでは、I2CバスにA/Dコンバーターを接続する方法を紹介します。
使用するデバイスは以下のとおりです。
-
PCF8591(NXP Semiconductors製)
今回使用するPCF8591は、以下の特長を持ちます。
-
単電源動作(2.5~6V)
-
I2C接続(スタンダードモード)
-
アドレス 0x48~0x4F(同一バスに8つ接続可能)
-
分解能 8ビット
-
逐次比較型
-
4入力
-
D/A出力あり(8ビット 1出力)
Armadillo-640との接続を示します。
Armadillo-640のCON14から出ているI2C4にPCF8591を接続します。
アドレスを指定するA0~A2は全てGNDに接続しておきます[]。
AIN0~AIN3がアナログ入力ピンです。
AIN0にかかる電圧を、10kΩの可変抵抗で変えられるようにしています。
AIN1~AIN3はそれぞれ固定電圧としています。
リファレンス電圧VREFに電源電圧と同じ3.3Vを入力しているため、
0V~3.3Vの範囲のアナログ入力を8ビット(256段階)のデジタル値に変換します。
PCF8591のドライバを有効にしたLinuxカーネルと、DTBを作成します。
標準状態のカーネルのソースコードを元に変更する手順は次の通りです。
-
Device Treeの編集
-
カーネルコンフィギュレーションでのデバイスドライバの有効化
-
カーネルとDTBをビルドしArmadilloに書き込み
はじめにDevice Treeを作成します。ファイル名は arch/arm/boot/dts/armadillo-640-i2c4.dtsiです(「サンプルソースコード」のページからダウンロードできます)。
|
デバイス名@スレーブアドレス(16進表記)
|
|
スレーブアドレス(16進表記)
|
さきほどのファイルへのincludeをarch/arm/boot/dts/armadillo-640.dtsに追加してください。
続いて、「イメージをカスタマイズする」と同様にmenuconfigを使用してカーネルコンフィギュレーションを変更します。
変更を加え、カーネルコンフィギュレーションを確定してください。
以上の変更後、「イメージをカスタマイズする」と同様にカーネルとDTBをビルドし、Armadilloに書き込んでください。
実際に、PCF8591から値の取得をおこなう手順を説明します。
変換された値の末尾に'0'が追加された文字列が返ります。
PCF8591のデータには3種類あります。
表5.2 PCF8591のデータバイト
データ名 | データ方向 |
---|
コントロールバイト | W |
D/A出力値 | W |
A/D入力値 | R |
コントロールバイトの書き込みは以下のように行います。
D/A出力値を書き込む場合は、コントロールバイトに続けて書き込みます。
A/D入力値の読み出しは以下のように行います。
PCF8591のアドレスバイトのフォーマットを示します。
7ビットアドレスの上位4ビットは固定で1001です。下位3ビットは対応するピン(A2~A0)で設定可能です。
今回の例では全てGNDに接続したので、A2~A0は全て0になります。
コントロールバイトのフォーマットを示します。
AOEを1にするとD/A出力が有効になります。
AISEL1~0はA/D入力のモードを指定します。両方0でシングルエンド入力となります。
AINCは1にするとオートインクリメントが有効になります。
CH1~0はA/D入力のチャンネル0~3を2進数で指定します。
A/D入力値、D/A出力値のフォーマットを示します。
どちらも1バイトに8ビットのデータがそのまま入っています。
| サンプリング・A/D変換が行われるタイミング |
---|
PCF8591では、ACKの後にサンプリングが行われ、データバイトの読み出し中にA/D変換がおこなわれます。
そのため、通信の最初のデータバイトで転送される値は、前回の通信中に変換された値となります。
また、電源投入後の最初のデータバイトで転送される値は0x80となります。
今回使用するドライバでは、対策として電源投入後やコントロールバイト変更後は2回読み出しています。 |
5.3. I/Oエクスパンダー(PCF8574)を使用する
ここでは、I2CバスにI/Oエクスパンダーを接続する方法を紹介します。
使用するデバイスは以下のとおりです。
-
PCF8574(NXP Semiconductors製)
今回使用するPCF8574は、以下の特長を持ちます。
-
単電源動作(2.5~6V)
-
I2C接続(スタンダードモード)
-
アドレス 0x20~0x27(同一バスに8つ接続可能)
-
GPIO数 8
-
入出力方向の設定不要
-
入力変化割り込み機能あり
Armadillo-640との接続を示します。
Armadillo-640のCON14から出ているI2C4にPCF8574を接続します。
アドレスを指定するA0~A2は全てGNDに接続しておきます[]。
例として、スイッチやLEDを接続しています。
スイッチはオンでLow入力になるようにし、LEDはLow出力で点灯するようにします。
PCF8574のドライバを有効にしたLinuxカーネルと、DTBを作成します。
標準状態のカーネルのソースコードを元に変更する手順は次の通りです。
-
Device Treeの編集
-
カーネルコンフィギュレーションでのデバイスドライバの有効化
-
カーネルとDTBをビルドしArmadilloに書き込み
はじめにDevice Treeを作成します。ファイル名は arch/arm/boot/dts/armadillo-640-i2c4.dtsiです(「サンプルソースコード」のページからダウンロードできます)。
|
デバイス名@スレーブアドレス(16進表記)
|
|
スレーブアドレス(16進表記)
|
さきほどのファイルへのincludeをarch/arm/boot/dts/armadillo-640.dtsに追加してください。
続いて「イメージをカスタマイズする」と同様にmenuconfigを使用してカーネルコンフィギュレーションを変更します。
変更を加え、カーネルコンフィギュレーションを確定してください。
以上の変更後、「イメージをカスタマイズする」と同様にカーネルとDTBをビルドし、Armadilloに書き込んでください。
まず、GPIOクラスディレクトリを作成します。
次に、実際にPCF8574のGPIOにアクセスし、LEDを点灯させてみます。
最後に、スイッチの状態を取得してみます。
PCF8574のデータには2種類あります。
表5.3 PCF8574のデータバイト
データ名 | データ方向 |
---|
GPIO出力値 | W |
GPIO入力値 | R |
GPIO出力値の書き込みは以下のように行います。
GPIO入力値の読み出しは以下のように行います。
PCF8574のアドレスバイトのフォーマットを示します。
7ビットアドレスの上位4ビットは固定で0100です。下位3ビットは対応するピン(A2~A0)で設定可能です。
今回の例では全てGNDに接続したので、A2~A0は全て0になります。
GPIO出力値、GPIO入力値のフォーマットを示します。
各ビットはピンP7~P0にそのまま対応します。
GPIO出力値で0を書き込むと、Low出力になり、1を書き込むと、High出力になります。
High出力は弱いプルアップとなっており、入力も兼ねています。
そのため、図5.19「I2C接続I/Oエクスパンダー回路図」のようにスイッチはオンでLow入力になるようにし、
LEDはLow出力で点灯するようにします。
5.4. 温度湿度センサー(HDC1080)を使用する
ここでは、I2Cバスに温度湿度センサーを接続する方法を紹介します。
使用するデバイスは以下のとおりです。
-
HDC1080(Texas Instruments製)
今回使用するHDC1080は、以下の特長を持ちます。
-
単電源動作(2.7~5.5V)
-
I2C接続(ファストモード)
-
アドレス 0x40
-
測定範囲 温度: -40~125℃ 湿度: 0~100%RH
-
精度 温度: 0.2℃ 湿度: 2%RH
-
分解能 温度: 最大14ビット 湿度: 最大14ビット
Armadillo-640との接続を示します。
Armadillo-640のCON14から出ているI2C4にHDC1080を接続します。
HDC1080のドライバを有効にしたLinuxカーネルと、DTBを作成します。
標準状態のカーネルのソースコードを元に変更する手順は次の通りです。
-
Device Treeの編集
-
カーネルコンフィギュレーションでのデバイスドライバの有効化
-
カーネルとDTBをビルドしArmadilloに書き込み
はじめにDevice Treeを作成します。ファイル名は arch/arm/boot/dts/armadillo-640-i2c4.dtsiです(「サンプルソースコード」のページからダウンロードできます)。
さきほどのファイルへのincludeをarch/arm/boot/dts/armadillo-640.dtsに追加してください。
続いて「イメージをカスタマイズする」と同様にmenuconfigを使用してカーネルコンフィギュレーションを変更します。
変更を加え、カーネルコンフィギュレーションを確定してください。
以上の変更後、「イメージをカスタマイズする」と同様にカーネルとDTBをビルドし、Armadilloに書き込んでください。
実際に、HDC1080から値の取得をおこなう手順を説明します。
湿度(%)は以下の式で求められます。
温度(1/1000℃)は以下の式で求められます。
HDC1080のアドレスバイトのフォーマットを示します。
7ビットアドレスは固定で1000000です。
HDC1080には16ビットのレジスタが8個あります。
ポインターの書き込みによってレジスタを指定してアクセスします。
表5.4 HDC1080のレジスタ
ポインター | レジスタ名 | データ方向 |
---|
0x00 | Temperature(温度) | R |
0x01 | Humidity(湿度) | R |
0x02 | Configuration | R/W |
0xFB~FD | Serial ID(40ビット) | R |
0xFE | Manufacturer ID | R |
0xFF | Device ID | R |
温度の読み出しは以下のように行います。
ポインター(0x00)の書き込みで温度の取得が開始されるため、6.5ms以上待ってから読み出しを行います。
データは14ビットなので、下位2ビットが0埋めになっています。湿度も同様に、ポインター(0x01)の書き込み後に読み出します。
コンフィグレーションの書き込みは以下のように行います。
コンフィグレーションレジスタのフォーマットを示します。
デバッグを行う上であまり重要ではないため、各ビットの説明は省きます。
5.5. VOCsセンサー(CCS811)を使用する
ここでは、I2CバスにVOCsセンサーを接続する方法を紹介します。
使用するデバイスは以下のとおりです。
今回使用するCCS811は、以下の特長を持ちます。
-
単電源動作(1.8~3.3V)
-
I2C接続(ファストモード)
-
アドレス 0x5A~0x5B(同一バスに2つ接続可能)
-
VOCs(揮発性有機化合物)、CO2の濃度を測定
-
VOCs: 0~1156ppb[]
-
CO2: 400~7992ppm[]
-
屋内用
Armadillo-640との接続を示します。
Armadillo-640のCON14から出ているI2C4にCCS811を接続します。
アドレスを指定するADDRはGNDに接続しておきます[]。
CCS811のドライバを有効にしたLinuxカーネルと、DTBを作成します。
標準状態のカーネルのソースコードを元に変更する手順は次の通りです。
-
Device Treeの編集
-
カーネルコンフィギュレーションでのデバイスドライバの有効化
-
カーネルとDTBをビルドしArmadilloに書き込み
はじめにDevice Treeを作成します。ファイル名は arch/arm/boot/dts/armadillo-640-i2c4.dtsiです(「サンプルソースコード」のページからダウンロードできます)。
|
デバイス名@スレーブアドレス(16進表記)
|
|
スレーブアドレス(16進表記)
|
さきほどのファイルへのincludeをarch/arm/boot/dts/armadillo-640.dtsに追加してください。
続いて「イメージをカスタマイズする」と同様にmenuconfigを使用してカーネルコンフィギュレーションを変更します。
変更を加え、カーネルコンフィギュレーションを確定してください。
以上の変更後、「イメージをカスタマイズする」と同様にカーネルとDTBをビルドし、Armadilloに書き込んでください。
実際に、CCS811から値の取得をおこなう手順を説明します。
VOCs濃度(ppb)、CO2濃度(ppm)が出力されます。
CCS811のアドレスバイトのフォーマットを示します。
アドレスの上位6ビットは固定で101101です。
CCS811にはレジスタが14個あります。
ポインターの書き込みによってレジスタを指定してアクセスします。
レジスタのバイト数はそれぞれ異なります。
ここでは重要なレジスタのみ紹介します。
表5.5 CCS811のレジスタ
ポインター | レジスタ名 | バイト数 | データ方向 |
---|
0x00 | STATUS | 1 | R |
0x02 | ALG_RESULT_DATA | 8 | R |
STATUSレジスタの読み出しは以下のように行います。
CO2やVOCsの濃度の読み出しは以下のように行います。
STATUSレジスタのフォーマットを示します。
読み出されていないデータがあるとき、DATA_READYが1になります。
今回使用したドライバでは、DATA_READYが1になるまで待ち、新しいデータが用意された後に濃度を読み出します。