So-net無料ブログ作成
検索選択

I2CでLEDピカピカ完全版 [ColdFire V2]このエントリーを含むはてなブックマーク#

2073158

前回作成した、「I2Cを使ってLEDピカピカ」は、フラグの扱いに不備があることが判明したので、完全版を再度作成しました。

I2Cには、フラグがたくさん

I2Cモジュールには、I2SRというレジスタがあって、フラグビットがぎっしりと詰まっています。 通信の終了を知るには、どのビットを参照したら良いのか、はっきり把握していなかったので、まとめてみました。

I2Cモジュールのフラグレジスタ
ビット名備考
7 ICF 通信中は、クリアされます。 9番目のクロックの立下りでセットされます。
6 IAAS I2ADRレジスタに設定したものと同じアドレスがバス上で検出されたことを示します。 このフラグがセットされたら、マイコンはスレーブ・デバイスとして振舞わなくてはなりません。
5 IBB I2Cバスが使用されている場合にセットされます。 礼儀として、バスが空いていることを確認して通信を始めたほうがよいでしょう。
4 IAL アービトレーション・ロストが発生したことを示します。 アービトレーション・ロストについては、後述します。
2 SRW マイコンがスレーブ・デバイスとして振舞うときに、マスタ・デバイスが指定してきたデータの送受信方向を示します。 スレーブ・デバイスは、マスター・デバイスに完全に従って動作します。
1 IIF I2Cモジュールが割り込みを発生させるためのフラグです。 I2CRレジスタのIIEビットがセットされていたら、割り込みが発生します。 割り込みの発生は、I2Cモジュールが割り込み・サービス・ルーチンに対して何らかの処理を要求している事を示します。
0 RXAK あるデバイスがデータを送信すると、それを受信したデバイスから9ビット目のデータが返却されます。 これをアクノリッジと呼んでいます。 一般に、アクノリッジ・ビットがACK(0)だった場合には、続くデータを送り出しますが、NACK(1)だった場合には、通信が中断されます。 このビットは、ACKが返却された場合にはクリアされ、NACKが返却された場合にはセットされます。 RXAKというレジスタ名から受ける印象と動作が異なっていますので、はまらないように注意が必要です。

で、どのフラグを見て通信の終わりを判断すべきかですが、リファレンス・マニュアルを良く読むと書いてありました。

27.4.3 Post-Transfer Software Response

Software can service the I2C I/O in the main program by monitoring the IIF bit if the interrupt function is disabled. Polling should monitor IIF rather than ICF, because that operation is different when arbitration is lost.

割り込み機能をディセーブルしたうえで、メイン・プログラムでIIFビットを監視することによって、ソフトウェアでI2C入出力を使うことが出来ます。 フラグの監視(ポーリング)には、ICFビットよりもIIFフラグを使用すべきです。 なぜなら、アービトレーション・ロストが発生したときの動作が異なるからです。

アービトレーション・ロストは、ちょっと難しい概念です。

I2Cバスというのは、マルチ・マスタを原則としているプロトコルなので、複数のマスタ・デバイスがバスをドライブしようとします。 そのため、複数のマスタデバイスが同時にバスをドライブする事態も十分に考えられます。 複数のマスタデバイスが同時に通信を始めた場合、マスタ・デバイスはそれを検出して「優先順位のより高いマスタ・デバイス」にバスを譲らなくてはなりません。 このような状態をアービトレーション・ロストと呼びます。

他にも、ノイズなどによって、マスタ・デバイスが出したつもりの無いデータがバス上に出たりした場合にもアービトレーション・ロストが発生します。 このような場合、I2Cモジュールは、即座に通信を中断し、バスを開放し、IALフラグで事態を示します。 同時に、IIFフラグがセットされ、割り込みサービスルーチンに処理を促すのですが、ICFフラグがセットされるとは記述されていません。

つまり、ソフトウェアで対処が必要な場合には、IIFフラグがセットされるので、状況に応じて対処せよということのようです。 今回作り直したプログラムでは、IIFフラグを検出し、RXAKフラグを確認して通信が完了したかどうかを確認しています。

レジスタの設定(再掲)

プログラムで使用したI2Cモジュールの主な設定は、以下の通りです。

I2Cのレジスタ設定
レジスタ備考
I2FDR0x38 (640) I2C通信で使用されるクロックを指定します。 バスクロック(60MHz)を640分周した94kHzの転送レートが使用されます。
I2CR [IEN]1 (enable) I2Cモジュールをイネーブルします。
I2CR [IIEN]0 (disable) I2C割り込みを使用するときにはセットします。 もちろん、割り込みは使いません。
I2CR [MSTA]0 → 1 → 0 マスタ・モードを意味するビットとされているのですが、実際には、マスタとして通信の開始・終了時のSTART状態とSTOP状態を作り出すために使用されます。
I2CR [MTX]1 (TX) I2C通信の方向を示します。 今回は、MCF52233からデータを送り込む方向の通信だけを行っているので、セットしたまま使います。
I2CR [TXAK]0 (ACK) データの受信確認のための符号としてACK/NAKのどちらを返すかを指定します。 前述のように送信方向のみに使用しているので、どちらでもかまいません。
I2CR [RSTA]0 (no Sr) I2C通信の二つのパケットをつなぐリピーテッド・スタートという特殊なSTART状態を作り出すかどうかを指定します。 今回は、リピーテッド・スタートは使用しないので、クリアしておきます。

プログラム

プログラムは、光が流れるように作り直しました。

  int  *pqspar =0x4010006c;
  char *i2adr  =0x40000300;
  char *i2fdr  =0x40000304;
  char *i2cr   =0x40000308;
  char *i2sr   =0x4000030c;
  char *i2dr   =0x40000310;
main(){
  int  i;
  *pqspar =0x00A0; // PQSPAR[3:2]=10 (i2c)
  *i2fdr = 0x38; // (x640)
  *i2cr  = 0x90; // See table
  write(0x03,0x00); // config as OUT
  #stop 0
  i=0;
  for(;;){
    if(Getc(0)=='q')break;
    Sleep(25);
    write(0x01,0xEF<<i);
    i=(i+1)&3;
  }
}
write(char com, char data){
  while ((*i2sr)&0x20) SystemSleep(); // Wait for BUS idle
  *i2sr  = 0x12; // Clear flags
  *i2cr |= 0x20; // START
  do {
    *i2dr  = 0x40; // WRITE for 0100000
    while (!(*i2sr&0x02)); // Wait for IIF
    if (*i2sr&0x01) break; // Quit if no ACK
    *i2sr  = 0x12; // Clear flags
    *i2dr  = com; // command
    while (!(*i2sr&0x02)); // Wait for IIF
    if (*i2sr&0x01) break; // Quit if no ACK
    *i2sr  = 0x12; // Clear flags
    *i2dr  = data; // data
    while (!(*i2sr&0x02)); // Wait for IIF
  } while (0);
  *i2cr &= 0xDF; // STOP
}
このプログラムは、まだバグがあります。 詳細は追記を参照の事。

前回のプログラムでは、全てのフラグのポーリングでSystemSleep()関数を使用していましたが、今回は通信開始前のバスの監視部分だけに使いました。 これは、3バイト分の通信が計算上0.4m秒程度という短時間で完了してしまうと判断したためです。 でも、この時間はインタプリタのオーバ・ヘッドがどのくらいになるか、考慮していません。 この部分だけ、機械語で作り直すかな。

try-finallyは、通信を中断した時に確実にSTOP状態を送り出すためには、ぜひとも欲しい構文なのですが、Cには、try-finally構文はありません。 関数を入れ子にして、returnで脱出する方法もありますが、SilentCでは、むやみにネストを深くしたくはありません。 そこで、do-whileを使って、try-finally構文を実現してみました。 こういう使い方も、アリだよね。

2008-09-18 追記

完全版だったはずなのに、「機械語に移植したら動かない」との知らせを受けました。 調べたところ、IIFビットをクリアする方法がHCS08のI2Cモジュールとは異なっているらしいことがわかりました。

  • HCS08のI2Cモジュールは、1を書いてクリア。
  • MCF52233のI2Cモジュールは、0を書いてクリア。

すると、Interface誌に掲載されているプログラムもフラグをクリアすることなく動作しているという事ですか。 ステータス・レジスタの値を表示させて確認してみなくては。

2008-09-21 追記

フラグの扱い方に問題があることを記事「MCF52233付録基板 - I2CでLEDピカピカ(真)完全版」で確認しました。 また、修正版のプログラムも作成しました。

参考文献

モジュールの使い方は、HCS08もColdFireも変わりないんですよね。 と、思っていたら大間違いでした。

HCS08 Unleashed: Designer's Guide to the Hcs08 Microcontrollers

HCS08 Unleashed: Designer's Guide to the Hcs08 Microcontrollers

  • 作者: Fabio Pereira
  • 出版社/メーカー: Booksurge Llc
  • 発売日: 2007/11/13
  • メディア: ペーパーバック

nice!(0)  コメント(0)  トラックバック(0)  このエントリーを含むはてなブックマーク#

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

トラックバックの受付は締め切りました

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。