宣言
int I2CTR(I2C_TypeDef* I2Cx, uint8_t Addr, uint8_t*Buff, uint8_t TxLen, uint8_t RxLen)
I2Cx
通信に使用するポート
Addr
デバイスアドレスを使用する 7bit形式ではなく8bit形式で渡す
Buff
送受信のバッファを渡す
TxLen
送信データ数を渡す
RxLen
受信データ数を渡す
この関数では送信バッファと受信バッファを兼用している。そのためレジスタアドレスを指定する引数は取らない。レジスタアドレスを指定したい場合はBuff[0]にアドレスを指定し、TxLenを1にする。ROMのようなレジスタアドレスが複数バイトになる場合はBuffに必要なバイト数を設定し、TxLenにその長さを渡す。
送信だけで、受信する必要が無い場合はRxLenを0にすればいい。RxLenが0の場合は送信が終了した段階でStopを発行し関数を終了する。
手持ちのデバイスの中には「レジスタアドレスを指定せずに読みだす」という物がないため、TxLen==0の場合の動作確認はしていない。だけどたぶん失敗すると思う。
const int timeoutは無限ループに入らないようにしている。ただ0x7FFFFFFFでは明らかに長過ぎるから、もっと短い値に変更しないと意味が無い。例を挙げると72MHzで0xFFFFを指定すると67msecほどでタイムアウトする。大雑把な目安としてだいたい1マイクロ秒くらいの分解能になる。例えば10000を指定すると10msecくらいでタイムアウトするので、5000とか10000くらいがいいと思う。
タイムアウトは1回のループ毎に変数をtimeoutで初期化し、whileで比較、デクリメントを行っているだけ。そのためマイコンの動作クロックが変わると待ち時間も変化する。
/* I2Cx:通信に使用するI2Cポート Addr:デバイスアドレス Buff:データバッファ TxLen:送信バイト数 RxLen:受信バイト数 戻り値:成功した場合は0、失敗した場合は0位外 (戻り値で成功したかの判定は!0を使用すること 失敗時の1は今後変更の可能性がある) */ int I2CTR(I2C_TypeDef* I2Cx, uint8_t Addr, uint8_t*Buff, uint8_t TxLen, uint8_t RxLen) { uint8_t IsSuccess = 0; volatile int to; const int timeout = 0x7FFFFFFF; uint8_t*p1 = Buff, *p2 = Buff; do { // check busy { to = timeout; while (I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY) && --to); if (!to) { break; } } // generate Start condition { I2C_GenerateSTART(I2Cx, ENABLE); to = timeout; while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT) && --to); if (!to) { break; } } // send Slave address { I2C_Send7bitAddress(I2Cx, Addr, I2C_Direction_Transmitter); to = timeout; while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) && --to); if (!to) { break; } } // send Register address / Transmitted mode while (TxLen--) { I2C_SendData(I2Cx, *p1++); to = timeout; while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED) && --to); if (!to) { break; } } if (!to) { break; } if (!RxLen) { I2C_GenerateSTOP(I2Cx, ENABLE); IsSuccess = 1; break; } // generate ReStart condition { I2C_GenerateSTART(I2Cx, ENABLE); to = timeout; while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT) && --to); if (!to) { break; } } // send Slave address / Reciver mode { I2C_Send7bitAddress(I2Cx, Addr, I2C_Direction_Receiver); to = timeout; while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) && --to); if (!to) { break; } } // check One Byte received. ACK Enabe if (RxLen > 1) { I2C_AcknowledgeConfig(I2Cx, ENABLE); } while (RxLen--) { if (!RxLen) { I2C_AcknowledgeConfig(I2Cx, DISABLE); I2C_GenerateSTOP(I2Cx, ENABLE); } to = timeout; while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED) && --to); if (!to) { break; } *p2++ = I2C_ReceiveData(I2Cx); } if (!to) { break; } IsSuccess = 1; } while (0); if (!IsSuccess) { I2C_GenerateSTOP(I2Cx, ENABLE); return(1); } return(0); }
0 件のコメント:
コメントを投稿