I2C通信とは
I2C通信
クロックに同期させてデータの通信を行う同期式シリアル通信
クロック(SCL)とデータ入出力(SDA)の2本の信号線で通信
I2Cは、2本の線(SCLとSDA)を用いたシリアル通信の一種。
SCLはクロック信号を、SDAはデータ信号を伝送する。
マスター側がSCLを生成し、スレーブ側はそれに同期して通信する。
スレーブ側はアドレスを持ち、マスターはアドレスを指定して通信する。
データはバイト単位でやり取りされ、読み書きの切り替えはACK/NAKで行われる。
マルチマスター構成においては、バス衝突を防ぐために適切な制御が必要。
I2Cの特徴
同じ信号ラインに複数のデバイスを繋げられる。
複数センサーがあっても、同じI2Cに全部つなぐこともできる。
親子関係があり、親1つに対して子をたくさん繋げられる。(親:マスター、子:スレーブ)
スレーブ側はアドレスを持つ。
1バイト転送ごとに、受信側は、ACK信号を返答する必要がある。
相手がいない場合や相手が拒否した場合には送信自体がエラーとなる。
通信速度はSPIなどに比べると遅い。
I2C通信は7ビットアドレスモードと10ビットアドレスモードの2つのモードがあります。
7ビットアドレスモードは最大128のアドレスをサポート
10ビットアドレスモードは最大1024のアドレスをサポート
ただし、10ビットアドレスモードは7ビットアドレスモードよりも複雑で、通信速度も遅くなる傾向がある。
一般的には7ビットアドレスモードが使用されます。
通信速度
table:通信速度
スタンダードモード 100k
ファストモード 400k
ハイスピードモード 3.4M
通信に関して
マスター側は、好きなタイミングで1つのスレーブに対し通信を始める。
書き込みと読み込みがある。
スレーブ側は、マスターの応答に対し返事する。
配線に関して
クロック(SCL)とデータ入出力(SDA)の2本の信号線で通信
双方向通信
オープンドレイン+プルアップ抵抗で配線する必要がある。
外部で、1k~10kΩ程度でプルアップする。
通信距離が長いと使えない。
基本構成:
https://gyazo.com/1ac6680f058c9cc772a127bb40369b70
その他の必要事項
SCLピン、SDAピンともに複数のスレーブを接続
I2Cモードを選択すると両ピンともオープンドレイン構成となる。
スレーブ側は両ピンとも常時は入力モード、ハイインピーダンス状態にする。
アドレスで指定された出力するデバイスだけ出力モードに設定する。
基本的な通信のやり取り方法:
(1) マスター側:Start Condition(スタートコンディション)を出力
(2) マスター側:クロック供給しながら、アドレスとRead/Write要求を出力
(3) スレーブ側(全て):SCLのクロックデータを元に、SDAのデータを受信
(4) スレーブ側(全て):SSPADDレジスタにセットされたアドレスと一致したデバイスのみ、送受信を継続
(5) スレーブ側(個別):データの受信完了後、自動的にACKビットを返送、同時にSSP割り込みを発生
(6) マスター側:Stop Conditionを出力するまで、送受信を行う。
通信タイミング:
(1) スタートコンディション:SCLがHighの時にSDAをLowにする。https://gyazo.com/8cc647bfd11bdecbf0018adc55196ef7
(2) アドレスとRead/Writey要求とSDAデータの受信:
マスター側:SCLがLowの間にSDAのビットを送信し、送信側から順次8ビットのデータを出力
スレーブ側:SCLが立ち上がった時に、SDAのビットを取り込む。
https://gyazo.com/b4c904454e461d374313de355ed54ef2
(3) スレーブ側:8ビットの受信完了後、9ビット目のクロックに合わせて、ACK信号を返送する。
(4) スレーブ側で次のデータ準備が出来るまでマスター側を待たせる場合:
受信側からSCLを強制的にLowにする。
(見かけ状クロックがなくなる為、マスター側からデータの送信が出来なくなる)
(6) ストップコンディション:最後のデータ送信後、ACKを確認する。
スレーブ側:SDAを解放し、Highになる。
マスター側:SCLがHighの間に、SDAをLowする。
マスター側:クロックを停止(SCLがHighにする)。
マスター側:SCLがHighの状態で、SDAをHighにし、ストップコンディション終了。
通信終了
I2Cのデータフォーマット
(1)通信データの開始時のフォーマット:マスター側から送信
7ビットモードと10ビットモードがある。
アドレスの1バイト目の最後のビットが送信、受信を区別するRead/Wireビット (RW)
https://gyazo.com/d4f9ebfd48deacf9716ea6b5f7519d96
(2)全体のフォーマット:
マスター側が送信側か、受信側かでフォーマットが異なる。
マスター側が受信側の場合:アドレスフォーマットでRWを0に設定し、特定のスレーブに送信
指定されたスレーブがデータの送信を開始
マスター側はデータを受信したらACKを返信
マスター側が送信側の場合:アドレスフォーマットでRWを1に設定し、特定のスレーブに送信
指定されたスレーブはACKを返信
マスター側は、データの送信を行う。
スレーブ側は、データを受信したらACKを返信する。
https://gyazo.com/80d1ef2cf25da323a16ded25bb099bd0
参考:
CubeIDEのI2C通信設定
table:I2C設定説明
設定項目 説明
Master Features I2C通信のマスター側の設定項目
I2C Speed Mode I2Cのスピードモード設定。標準モード、Fastモード、FastモードPlusが選択可能
I2C Clock Speed I2Cのクロック速度設定。Hz単位で設定可能
Slave Features I2C通信のスレーブ側の設定項目
Clock No Stretch Mode スレーブデバイスによるクロックのストレッチを禁止するか選択可能。
Primary Address Length selection プライマリアドレスのビット数を7ビットまたは10ビットで設定可能。
Dual Address Acknowledged スレーブデバイスが2つのアドレスを認識するかどうか選択可能。
Primary slave address スレーブデバイスのプライマリアドレスを設定可能。
General Call address detection ジェネラルコールアドレスの受信を有効にするか選択可能。
I2Cには標準モード(Standard-mode)とFastモード(Fast-mode)の2つのスピードモードがあります。以下にそれぞれの特徴をまとめます。
標準モード(Standard-mode):最大100 kbpsまでの通信速度をサポートしています。通常、低速な周辺機器の制御に使われます。
Fastモード(Fast-mode):最大400 kbpsまでの通信速度をサポートしています。通常、高速な周辺機器の制御に使われます。
つまり、Fastモードは標準モードよりも通信速度が速く、高速な周辺機器の制御に適しています。
ただし、通信速度が速い分、ノイズや反射などの影響を受けやすく、適切な回路設計が必要となります。
また、Fastモードは標準モードよりも電力を消費するため、電源や消費電力にも注意が必要です。
I2C_HandleTypeDef *hi2c:I2Cバスのハンドルを指定します。
uint16_t DevAddress:通信先のI2Cスレーブデバイスのアドレスを指定します。
uint8_t *pData:送信するデータのポインタを指定します。
uint16_t Size:送信するデータのサイズをバイト単位で指定します。
uint32_t Timeout:タイムアウト時間をミリ秒単位で指定します。
HAL_I2C_Master_TransmitとHAL_I2C_HAL_I2C_Mem_Write(); 、HAL_I2C_Mem_Read();の違い
HAL_I2C_Mem_Write();
HAL_I2C_Mem_Read();
これは、対象のデバイス(I2C通信先)のレジスタの値を読み取ることが出来る。
HAL_I2C_Master_Transmit
HAL_I2C_Master_Transmitは、通常のI2C通信を送信と受信を行う。
HAL(Hardware Abstraction Layer)ライブラリの一部です。
この関数は、I2C(Inter-Integrated Circuit)通信プロトコルを使用して、STM32マイクロコントローラと外部のI2Cデバイス間でデータを送信するために使用されます。
code:c
HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);
hi2c: I2Cハンドル構造体へのポインタ。これは、I2Cインターフェースを管理するために使用されます。
DevAddress: 通信相手のI2Cデバイスのアドレス。
pData: 送信するデータのバッファへのポインタ。
Size: 送信するデータのバイト数。
Timeout: 通信のタイムアウト時間(ミリ秒)。
この関数を使用すると、指定されたデバイスアドレスに対して指定されたデータを送信することができます。関数は通信の成功またはエラーを示すステータスを返します
送信例
code:c
uint8_t data_to_send2 = {0x12, 0x34}; // 送信するデータ HAL_I2C_Master_Transmit(&hi2c1, 0xA0, data_to_send, 2, HAL_MAX_DELAY);
この例では、I2C1インターフェースを使用して、デバイスアドレス0xA0に対して2バイトのデータを送信しています。通信はタイムアウトまでブロックされます(HAL_MAX_DELAYは無制限のタイムアウトを意味します)。
HAL_I2C_Master_Transmit_IT
HAL_I2C_Master_Transmit_IT は、STM32 HAL(Hardware Abstraction Layer)ライブラリ内の関数の1つで、I2C(Inter-Integrated Circuit)通信を使用してマスターデバイスからスレーブデバイスに対して非同期のデータ送信を行うためのものです。I2C通信は、複数のデバイスが同じバスを共有して通信するための通信プロトコルです。
code:c
HAL_StatusTypeDef HAL_I2C_Master_Transmit_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size);
hi2c: I2Cハンドル(I2C_HandleTypeDef型)。このハンドルには、I2C通信の設定や状態が含まれています。
DevAddress: 通信先デバイスのアドレス(7ビットのアドレス)。通常、スレーブデバイスのアドレスをここに指定します。8ビットアドレスの最上位ビットは読み書きを示すビットで、この関数内で自動的に設定されます。
pData: 送信するデータのバッファへのポインタ。データはこのバッファからスレーブデバイスに送信されます。
Size: 送信するデータのバイト数。
HAL_I2C_Master_Transmit_IT 関数は、非同期モードでデータ送信を行います。これは、関数呼び出し後に送信が完了するまで待機せず、送信がバックグラウンドで行われるためです。送信完了時に割り込みが発生し、コールバック関数が呼び出されることがあります。
使用例
code:c
uint8_t sendData2; // 送信するデータのバッファ HAL_I2C_Master_Transmit_IT(&hi2c, slaveAddress, sendData, sizeof(sendData));
HAL_I2C_Master_Receive
I2C通信プロトコルを使用して、STM32マイクロコントローラから外部のI2Cデバイスへデータを受信するために使用されます。
code:c
HAL_StatusTypeDef HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);
hi2c: I2Cハンドル構造体へのポインタ。これは、I2Cインターフェースを管理するために使用されます。
DevAddress: 通信相手のI2Cデバイスのアドレス。
pData: 受信したデータを格納するためのバッファへのポインタ。
Size: 受信するデータのバイト数。
Timeout: 通信のタイムアウト時間(ミリ秒)。
この関数を使用すると、指定されたデバイスアドレスからデータを受信できます。
関数は通信の成功またはエラーを示すステータスを返します。
code:c
uint8_t received_data2; // 受信したデータを格納するバッファ HAL_I2C_Master_Receive(&hi2c1, slaveAddress, received_data, 2, HAL_MAX_DELAY);
この例では、I2C1インターフェースを使用して、デバイスアドレス0xA0から2バイトのデータを受信しています。
通信はタイムアウトまでブロックされます。
(HAL_MAX_DELAYは無制限のタイムアウトを意味します)。
HAL_I2C_Master_Transmit_IT
HAL_I2C_Master_Seq_Transmit_IT は、STM32 HAL(Hardware Abstraction Layer)ライブラリ内の関数の1つで、I2C(Inter-Integrated Circuit)通信を使用してマスターデバイスからスレーブデバイスに対してシーケンシャルな非同期のデータ送信を行うためのものです。シーケンシャル送信とは、複数のデータバイトを連続して送信する操作です。
code:c
HAL_StatusTypeDef HAL_I2C_Master_Seq_Transmit_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Request, uint8_t *pData, uint16_t Size);
hi2c: I2Cハンドル(I2C_HandleTypeDef型)。このハンドルには、I2C通信の設定や状態が含まれています。
DevAddress: 通信先デバイスのアドレス(7ビットのアドレス)。通常、スレーブデバイスのアドレスをここに指定します。8ビットアドレスの最上位ビットは読み書きを示すビットで、この関数内で自動的に設定されます。
Request: 通信の種類を示すフラグや要求を指定するパラメータ。一般的には0を指定することで、通常の送信操作を行います。
pData: 送信するデータを格納するバッファへのポインタ。送信するデータはこのバッファから取得されます。
Size: 送信するデータのバイト数。
HAL_I2C_Master_Seq_Transmit_IT 関数は、非同期モードでシーケンシャルなデータ送信を行います。関数呼び出し後に送信が完了するまで待機せず、送信がバックグラウンドで行われるためです。送信完了時に割り込みが発生し、コールバック関数が呼び出されることがあります。
使用例:
code:c
uint8_t sendData2; // 送信するデータのバッファ HAL_I2C_Master_Seq_Transmit_IT(&hi2c, slaveAddress, I2C_FIRST_FRAME, sendData, sizeof(sendData));
この例では、I2Cハンドル hi2c を使用して、slaveAddress へ最初のフレームのデータを送信しています。送信データは sendData バッファから取得され、sizeof(sendData) バイト数だけ送信されます。
注意: 実際のプロジェクトでは、エラーチェックや割り込み処理などを適切に実装することが重要です。また、詳細な動作についてはSTM32 HALライブラリのドキュメントやリファレンスを参照してください。
HAL_I2C_Master_Seq_Receive_IT
STM32 HAL(Hardware Abstraction Layer)ライブラリ内の関数の1つで、I2C(Inter-Integrated Circuit)通信を使用してマスターデバイスからスレーブデバイスに対してシーケンシャルな非同期のデータ受信を行うためのものです。シーケンシャル受信とは、複数のデータバイトを連続して受信する操作です。
code:c
HAL_StatusTypeDef HAL_I2C_Master_Seq_Receive_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Request, uint8_t *pData, uint16_t Size);
hi2c: I2Cハンドル(I2C_HandleTypeDef型)。このハンドルには、I2C通信の設定や状態が含まれています。
DevAddress: 通信先デバイスのアドレス(7ビットのアドレス)。通常、スレーブデバイスのアドレスをここに指定します。8ビットアドレスの最上位ビットは読み書きを示すビットで、この関数内で自動的に設定されます。
Request: 通信の種類を示すフラグや要求を指定するパラメータ。一般的には0を指定することで、通常の受信操作を行います。
pData: 受信データを格納するバッファへのポインタ。受信したデータはこのバッファに格納されます。
Size: 受信するデータのバイト数。
HAL_I2C_Master_Seq_Receive_IT 関数は、非同期モードでシーケンシャルなデータ受信を行います。関数呼び出し後に受信が完了するまで待機せず、受信がバックグラウンドで行われるためです。受信完了時に割り込みが発生し、コールバック関数が呼び出されることがあります。
例:
code:c
uint8_t receiveData2; // 受信データを格納するバッファ HAL_I2C_Master_Seq_Receive_IT(&hi2c, slaveAddress, I2C_FIRST_FRAME, receiveData, sizeof(receiveData));
この例では、I2Cハンドル hi2c を使用して、slaveAddress から最初のフレームのデータを受信しています。受信データは receiveData バッファに格納され、sizeof(receiveData) バイト数だけ受信されます。
注意: 実際のプロジェクトでは、エラーチェックや割り込み処理などを適切に実装することが重要です。また、詳細な動作についてはSTM32 HALライブラリのドキュメントやリファレンスを参照してください。
HAL_I2C_Mem_Read
HAL_I2C_Mem_Read は、STM32 HAL(Hardware Abstraction Layer)ライブラリ内の関数の1つで、I2C(Inter-Integrated Circuit)通信を使用してメモリアドレスを指定してデータをスレーブデバイスから非同期で読み取るためのものです。この関数は、特にEEPROMやセンサーデバイスなどのI2Cインターフェースを持つデバイスからデータを読み取る際に便利です。
code:c
HAL_StatusTypeDef HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout);
hi2c: I2Cハンドル(I2C_HandleTypeDef型)。このハンドルには、I2C通信の設定や状態が含まれています。
DevAddress: 通信先デバイスのアドレス(7ビットのアドレス)。通常、スレーブデバイスのアドレスをここに指定します。8ビットアドレスの最上位ビットは読み書きを示すビットで、この関数内で自動的に設定されます。
MemAddress: デバイス内の読み取りを行うメモリアドレス。デバイスによって異なるアドレス体系を持つ場合があります。
MemAddSize: メモリアドレスのサイズ(バイト単位)。通常、1バイトまたは2バイトのアドレスが使用されます。
pData: 読み取ったデータを格納するバッファへのポインタ。
Size: 読み取るデータのバイト数。
Timeout: タイムアウト時間(ミリ秒単位)。
HAL_I2C_Mem_Read 関数は、非同期モードでメモリアドレスを指定してデータを読み取ります。関数呼び出し後に読み取りが完了するまで待機せず、読み取りがバックグラウンドで行われるためです。読み取り完了時に割り込みが発生し、コールバック関数が呼び出されることがあります。
code:c
uint8_t receiveData2; // 読み取ったデータを格納するバッファ HAL_I2C_Mem_Read(&hi2c, slaveAddress, memAddress, I2C_MEMADD_SIZE_8BIT, receiveData, sizeof(receiveData), HAL_MAX_DELAY);
この例では、I2Cハンドル hi2c を使用して、slaveAddress のスレーブデバイスから memAddress で指定されたメモリアドレスからデータを読み取っています。読み取ったデータは receiveData バッファに格納され、sizeof(receiveData) バイト数だけ読み取られます。
HAL_I2C_Mem_Write
STM32 HAL(Hardware Abstraction Layer)ライブラリ内の関数で、I2C(Inter-Integrated Circuit)通信を使用して特定のメモリアドレスにデータを書き込むために使用されます。この関数を使用することで、I2C通信を介してデバイスに対してデータを書き込むことができます。
code:c
HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout);
hi2c: I2Cハンドル(I2C_HandleTypeDef型)。このハンドルには、I2C通信の設定や状態が含まれています。
DevAddress: 通信先デバイスのアドレス(7ビットのアドレス)。通常、スレーブデバイスのアドレスをここに指定します。8ビットアドレスの最上位ビットは書き込みを示すビットで、この関数内で自動的に設定されます。
MemAddress: 書き込むメモリアドレス。
MemAddSize: メモリアドレスのサイズ(バイト単位)。通常、1バイトまたは2バイトのアドレスが使用されます。
pData: 書き込むデータが格納されたバッファへのポインタ。
Size: 書き込むデータのバイト数。
Timeout: タイムアウト時間(ミリ秒単位)。
HAL_I2C_Mem_Write 関数は、指定されたメモリアドレスに対してデータを書き込むための非同期関数です。関数呼び出し後に書き込みが完了するまで待機せず、書き込みがバックグラウンドで行われるためです。書き込み完了時に割り込みが発生し、コールバック関数が呼び出されることがあります。
code:c
uint8_t sendData2; // 書き込むデータを格納するバッファ HAL_I2C_Mem_Write(&hi2c, slaveAddress, memAddress, I2C_MEMADD_SIZE_8BIT, sendData, sizeof(sendData), HAL_MAX_DELAY);
この例では、I2Cハンドル hi2c を使用して、slaveAddress のスレーブデバイスの memAddress で指定されたメモリアドレスに、sendData バッファ内のデータを書き込んでいます。写入が完了すると、指定したデータがデバイスの指定したアドレスに書き込まれます。
注意: 実際のプロジェクトでは、エラーチェックやタイムアウト処理などを適切に実装することが重要です。また、詳細な動作についてはSTM32 HALライブラリのドキュメントやリファレンスを参照してください。
code:c
// レジスタアドレス:TEMPADDR_EMISSIVITY (0x24)の時、放射率補正係数 E2PROMアドレス
#define REG_OBJECT_TEMPERATURE 0x07 // レジスタアドレス:TEMPADDR_TOBJ1 (0x07 )の時、温度(TObj1) RAMアドレス
#define REG_AMBIENT_TEMPERATURE 0x06 // EEPROMのアドレス:TEMPCMD_READ_FLAGS(0xf0 )の時、フラグ読出し
// オブジェクト温度データを読み取る
HAL_I2C_Mem_Read(&hi2c1, MLX90614_ADDRESS << 1, REG_OBJECT_TEMPERATURE, I2C_MEMADD_SIZE_8BIT, buf, 3, HAL_MAX_DELAY);
HAL_I2C_Mem_Read(&hi2c1, MLX90614_ADDRESS << 1, REG_AMBIENT_TEMPERATURE, I2C_MEMADD_SIZE_8BIT, buf, 3, HAL_MAX_DELAY);
HAL_I2C_Mem_Read(&hi2c1, MLX90614_ADDRESS << 1, EEPROM_START_ADDRESS, I2C_MEMADD_SIZE_8BIT, eepromData, sizeof(eepromData), HAL_MAX_DELAY);
table:Opcode
2進数 16進数 アクセス先、コマンド内容
000x xxxx 0x00 RAM Access
0010 0000 0x20 EEPROM Access
1111 0000 0xF0 Read Flags
1111 1111 0xFF Enter SLEEP mode
00100100
問題解決