STM32にはペリフェラルとしてH/WのI2Cインターフェース(I/F)が搭載されていますが、STM32がI2Cのマスターになる場合は、H/W I/Fを使わなくてもS/Wで比較的簡単に制御できます。I2C I/Fは数も限られていますので、GPIOを利用したS/W I2Cは使えるようにしておくと便利です。
STM32F103クラスのマイコンであれば、一般的なI2Cのクロックスピードである100kHzは十分に出せます。デバイスをH/W I2Cで制御する時も、実際にはスレーブデバイスのレジスタにデータが書き込まれるのを待つのが一般的ですので、処理時間もさほどちがいはありません。
また、I2Cはデータ、クロックが何かのトラブルでずれて制御ができなくなる事があります。S/Wで制御しておけばトラブルのトリガを捕まえるのも比較的容易にできます。
なお、スレーブの場合は、マスターからのクロックに同期する必要があるので、H/Wで制御するのが簡単です。(普通のマイコンでは、割り込み使って受信する事になるので)
I2Cについて簡単に説明しておきましょう。I2Cは元々Philips社が開発したものでデータ(SDA)とクロック(SCL)の2線で送受信をサポートし、複数のデバイスを同じデータ、クロックラインに接続できるという優れたものです。最新バージョンではクロックスピードも高速になっていますが、今回は一般的なスタンダードモード(100kHzまで)またはファーストモード(400kHzまで)の仕様で説明したいと思います。
また、複数のマスターデバイスがつながるマルチマスターモードもありますが、今回はマスターが一つしかないシングルマスターモードで説明します。(STM32F103がマスターになります) スレーブデバイスが処理が間に合わない場合にSCLをLに保持して処理を延ばすクロックストレッチも割愛します。
- I2Cの制御線
I2Cは、データ(SDA)とクロック(SDA)の2本のH/Wラインで構成されます。複数のデバイスが通信できるようにSDA,SCLとも出力はオープンドレイン(OD)またはオープンコレクタ(OC)になっています。また、SDAは同じラインで送・受信を切り替えますので、入力もできるようになっています。SCLは基本的にマスターが送出しますので、シングルマスターであればC-MOS出力のみでも構成可能です。(スレーブデバイスがクロックストレッチをしない場合) - I2Cのフォーマット
I2Cは2本の制御線で送・受信を切り替えて通信するために、以下の4つから構成されます。
(1) 通信を開始するスタートコンディション(S)
(2) データ 8bit (D)
(3) データ受信確認のAcknowledge(ACK) ,Not Acknowledge(NACK)ビット
ACKは(3)の8bitに続けて送受信されるため、通信は見かけ上9bit目になります。
(4) 通信の終了を示すストップコンディション(P) - スレーブアドレス(SLAVE ADDRESS)
同じSDA,SCLラインに接続されるスレーブデバイスは各々個別のアドレスを持っています。スレーブアドレスは7bitで最下位ビット(LSB)でデータの方向を示します。スレーブデバイスへ書き込み(Write)する場合はLSB = 0,スレーブデバイスから読み出す(Read)する場合はLSB = 1を指定します。
例えば、スレーブアドレスが0x50(0b1010000)にデータを書き込む場合は、0x50 << 1 | 0 = 0xA0 (0b10100000)、データを読み出す場合は 0x50 << 1 | 1 = 0xA1 (0b10100001)になります。この場合、私はスレーブアドレス0xA0/0xA1と呼んでいます。(正しくは0x50)
スタートコンディションの後には必ずスレーブアドレスを送信します。
ストップコンディションを送信するまでは、このスレーブアドレスのデバイスとの通信になります。 - スタートコンディション(S)、ストップコンディション(P)
I2Cのデータ送信中はSCLがHの時にSDAが変化するシーケンスはありません。SCLがH期間中にSDAが変化するシーケンスでスタートコンディション、ストップコンディションを規定しています。
(1) スタートコンディション SCLがH期間中にSDAをH→Lに変化させる
(2) ストップコンディション SCLがH期間中にSDAをL→Hに変化させる - データ(Data)
I2Cは8bit単位で通信します。データはMSBファーストのシリアルデータです。
送信側はSCLがLの間にSDAを変化させます。つまり、SCLがLになったら次のビットを用意する事になります。 - クロック(SCL)
SDAのビットをセットした後 SCLをL→Hにします。受信の場合はSCLをLにする前にSDA端子のH/Lを読みます。送信の場合は、SCLをH→Lにした後SDAを変化させます。 - Acknowledge(ACK), Not Acknowledge(NACK)
I2Cは8bit単位で通信します。
受信側は8bitを受信した後のクロック(9bit目)でACKを返します。
スレーブデバイスは、自分とのアドレスと一致した場合は、スレーブアドレス(+R/W bit)を受信した後、SDAをLに保持しACKを送信します。
受信側は8bit目を受信したら、次のSCLがLになった後SDAをLにし、送信側に8bit受信したことを伝えます。
送信側は、受信側からACKが送信されたら次の送信データを準備します。ACKが返信されない場合は、相手が受信出来ていないか、他の処理で忙しい場合などです。また、受信側が次のデータを要求しない場合(受信終了)は、ACKを送信しません。NACK(Not Ackloledge)と呼びます。
ACKを送信したデバイスはSCLがH→Lに移行した後、SDAをHに戻します。
通信例として、書き込み(Write)シーケンスを紹介します。
- I2C通信は、必ずスタートコンディションから始まります。
- スタートコンディションの後にはスレーブデバイスのアドレスと(マスター側から見た)送受信(W/R)の方向を送信します(Writeは 0 )。
- スレーブデバイスは、自分のアドレスと一致したらACKを返信します。
- マスターはスレーブからのACKを確認したら、通信を継続します。
- スレーブデバイスに複数のレジスタがある場合は、読み書きするレジスタのアドレス(サブアドレス)を指定します。サブアドレスの指定は、書き込み(W)になります。レジスタが一つしかないようはデバイスではサブアドレスの設定がない場合もあります。
- スレーブデバイスにデータを書き込む場合は、続いてデータを送信しします。
- スレーブデバイスはサブアドレスを自動的にインクリメントしてくれるものが多いですが、そうで無い場合は、毎回サブアドレスを指定する必要があります。
- マスター→スレーブへの書き込みの場合、スレーブデバイスは1バイトを受信したらACKを返します。マスターデバイスはACKを確認したら次のバイトデーターを送信します。
- 書き込みデータの送信とスレーブからのACKを確認したら、通信を完了するためストップコンディションを送信します。
- S-Sa-w-a-Ra-a-D0-a-D1-a—-Dn-a-P となります。
S: Start condition, Sa: Slave Address, w: write, a: ack, Ra: Register Address, D0〜Dn: Data, P: Stop condition
Raは複数バイトの場合もあり、デバイスに依存します。 - サブ(レジスタ)アドレスを一度指定した後、アドレスのオードインクリメント機能がある場合、レジスタが一つしかない場合などは、S-Sa-w-a-D0-a-P でも書き込みができます。(スレーブデバイスの仕様を確認してください)
読込の場合も、スレーブデバイスに読み出しするサブ(レジスタ)アドレスを指定するときは送信(Write)になります。サブ(レジスタ)アドレスを設定した後、リピートスタートコンディション、スレーブアドレスに続いてR(H)ビットを送信します。スレーブデバイスはACKを返した後、読み出しデータをセットします。
- S-Sa-w-a-Ra-a-Sr-Sa-r-D0-a-D1-a—Dn-n-P
S: Start condition, Sa: Slave Address, w: write, r: read, a: ack, n: back, Sr: Repeat start condition, Ra: Register Address, D0〜Dn: Data, P: Stop condition - Sa以降はデータの送受信が逆になります。ackはマスターが送信します。
- マスターがデータ読み出しを終了する場合は、nackを送信してからストップコンディションを送信します。
- リピートスタートコンディション(Re Start)は、ストップコンディションを送らずにスタートコンディションを送信する事です。