I2Cドライバ作成中

AVRのI2Cのドライバ作成中。
SPIと違って速度が遅いので、割り込みドリブンで書こうと思ったが微妙に問題が。
AVRのI2Cモジュール(TWIインターフェース)のイベント割り込みビット(TWINT)は他の割り込みビットと違い、割り込みルーチンに入っても"クリアされず"なおかつ、1を書き込んでクリアした時点でTWIがTWCRやTWDRの値および、書き込みを行ったかどうかの状態に合わせてTWIが次の転送を始める仕様になっている。
なので、割り込み待ちでサスペンド→割り込みからリジュームを単純に実装して、割り込みから戻ってから次を設定して動作(TWINTをクリア)とすると、割り込みを抜けた段階で、TWINTがクリアされていないため、TWI割り込みを無限に繰り返して、動作しないことになる。



SPIのようにデータ書き込み=開始というように単純な動作じゃないので、こういう仕様なのはわかるが、ちょっと割り込みで書くのは難しい気がする。
思いつくのは、

  1. グローバル変数の状態レジスタを作って、それを経由してドライバのメイン関数と割り込み関数間で状態の受け渡しを行い、レジスタの設定は割り込み側でやる
  2. サスペンドリジュームを使わずポーリングで行い、代わりに適当な待ち時間のvTaskDelayを使って待ってる間は他のタスクに制御を渡す。

とりあえずシンプルに書けそうな2番を使おうかと思う。


400KHzで動作しているI2Cで待ちが1ワード(8ビット+ACK)の最大速度はKHzで8MHzで動いているプロセッサの180サイクル分に相当(実際にはクロックストレッチなどで伸びる可能性あり)ので、vTaskDelayすらないポーリング待ちでも別に問題ない気もしてきた。
ちなみに、RTOSのTickである1024Hzは7813サイクルでで、1Tickのディレイでも43ワード分待つことになってしまう。
Whileループでいいか…


ここら辺は、DMAがあって転送リストを書いて丸投げできる高機能なマイコンを使えばいい気もする。