24CW320とのI2C通信について

RX71Mを使ったボードを開発しているのですが、EEPROM(Microchip 24CW320)とのI2C通信で困っており投稿しました。

エミュレータはE2 Lite、コンパイラはCC-RX、開発環境は 2s studio(2020-10)を使っています。

SCI0(簡易I2C、100kHz)を使ってEEPROMと通信の際、デバッグ実行をしてwriteおよびreadするところで一旦ブレークし、実行を再開すると期待通りの通信波形が得られます。

 a1.EEPROMに書き込みアドレスと値をwriteする

 a2.EEPROMに読み出しアドレスをwriteする

 a3.ブレークして再開

 a4.EEPROMからreadする

しかし、同じソースコード(&バイナリ)をブレークをせずにwriteとreadを連続して実行すると通信データの一部が欠落します(出力されない)。ウェイト(100us~5ms)を入れてもみたのですが問題が解消しません。

 b1.EEPROMに書き込みアドレスと値をwriteする

 b2.EEPROMに読み出しアドレスをwriteする

 b3.ウェイト(5ms)

 b4.EEPROMからreadする

上記 b2 の通信内容は本当は3バイト(I2Cアドレス:1バイト+EEPROMアドレス:2バイト)なのですが、最初の1バイトしか出力されません。

  注:左の図は、100usのウェイトを入れた場合

上図と説明をまとめたExcelファイル → ブレークしないで write&readすると波形が欠落する_1.xlsx

問題のソースコード → 

ソースコード.txt
void testEeprom(void)
{
	uint8_t adr = 0;	// 7bit address
	uint8_t dir = 0;	// 0:Write 1:Read
	uint8_t buf_txd[4];
	uint8_t buf_rxd[4];

	R_Config_SCI0_Create();
	R_Config_SCI0_Start();
	
	for (uint16_t a=0; a<0x1000; a++){	// EEPROM 24CW320�A�e�ʁF4KB
		// write EEPROM

		// make device address byte
		adr = 0x0A;	// magic number
		adr <<= 3;	// 7bit address (000)
		dir = 0x00;	// 0:Write 1:Read
		adr = (adr << 1) | (dir & 0x01);

		buf_txd[0] = (a>>8) & 0x00FF;	// word address: byte 0
		buf_txd[1] = a & 0x00FF;		// word address: byte 1
		buf_txd[2] = 0xA5;

		// byte write operation
		R_Config_SCI0_ClearTxdEnd();
		R_Config_SCI0_IIC_Master_Send(adr, buf_txd, 3);
		while (false == R_Config_SCI0_GetIsTxdEnd());	// ���M���������ݑ҂�
		
		// wait
		for (uint16_t w=0; w<2500; w++) nop();	// ��100us

		// read EEPROM

		// write address
		R_Config_SCI0_ClearTxdEnd();	// �����ň�U�u���[�N���Ď��s�A������͘A�����s
		R_Config_SCI0_IIC_Master_Send(adr, buf_txd, 2);
		while (false == R_Config_SCI0_GetIsTxdEnd());	// ���M���������ݑ҂�
		
		// wait
		for (uint16_t w=0; w<2500; w++) nop();	// ��100us

		// make device address byte
		adr = 0x0A;	// magic number
		adr <<= 3;	// 7bit address (000)
		dir = 0x01;	// 0:Write 1:Read
		adr = (adr << 1) | (dir & 0x01);

		// current address read
		R_Config_SCI0_ClearRxdEnd();
		R_Config_SCI0_IIC_Master_Receive(adr, buf_rxd, 1);
		while (false == R_Config_SCI0_GetIsRxdEnd());	// ��M���������ݑ҂�
		
		// wait
		for (uint16_t w=0; w<2500; w++) nop();	// ��100us
	}

	R_Config_SCI0_Stop();
}
注:ソース中の完了待ちでは、送受信完了callback関数で更新するフラグをみています。

可能性としては

 a. CPUがそもそも出そうとしていない

 b. EEPROMが応答しないので CPUが出すのをやめた

 c. EEPROMにアクセスするためのタイミングが間違っている(さらにウェイトが必要?)

等があるかと思いますが、意見をお聞かせください。よろしくお願いいたします。

  • 追記修正:

     説明文が間違っていましたので、ここに修正します。

     a1.EEPROMに書き込みアドレスと値をwriteする
     a2.ブレークして再開
     a3.EEPROMに読み出しアドレスをwriteする
     a4.ブレークして再開
     a5.EEPROMからreadする

     b1.EEPROMに書き込みアドレスと値をwriteする
     b2.ウェイト(5ms)
     b3.EEPROMに読み出しアドレスをwriteする
     b4.ウェイト(5ms)
     b5.EEPROMからreadする

  • チョコです。

    RXも24CWxxも使ったことはありません。しかし、RL78で24C32は使ったことはあります。
    24CWxxのデータシートの「6.4 Acknowledge Polling」及び「FIGURE 6-4: ACKNOWLEDGE POLLING FLOW」をよくまれることをお勧めします。
    ここには、受信した書き込みデータはストップコンディションでEEPROMに書き込むとあり、書き込んでいる最中はR/Wビットが0のスレーブアドレスに対してACK応答はしないと書かれています。
    つまり、書き込みが完了していない状態でのa3に対してはNACK応答となるので、マスタ側のSCI0は(ACK応答した)スレーブがないとして通信を止めてしまいます。
    おそらく、24CW320の書き込み時間は最大5msのはずなので、a1の後に5ms以上のウエイト時間を追加してやれば動作するのではないかと思われます。

    以上

    追記

    ACK応答のポーリングを行う場合、書き込み後直ぐに開始すると、いつまでもACK応答にならなかったようなEEPROMもありました。ACKポーリングを行う場合には、数十~数百マイクロ秒待ってからACKポーリングを開始した方がいいかもしれません。

  • チョコさん、ご助言ありがとうございます!

    a1の後に 5.2msのウェイトを入れると動くようになりました。ウェイト5msではちょうど過ぎて間に合っていなかったようです。

    ACKポーリングですが、スマートコンフィグレータが自動生成するコードを使う限りはできそうにないので、時間はかかるのですがウェイト5.2msを毎回入れることにします。

    ありがとうございました。

  • 8251と言う通信LSIもどうような現象が有りました。

     レディ状態で書き込んで、フラグがビジーに変化するまでの時間が長いため矢継ぎ早に書き込んで動作しないと言うトラブルが有りました。

     こういうのは、1ステップづつ実行すると動くのに、連続実行で動かない。「不思議だなぁ」と言う現象になります。

     高速化すると波形の乱れで誤動作する事が有ります。CPUのクロック周波数を下げて動くようになれば、解決のヒントになります。

  • リカルドさん、ありがとうございます。

    > 1ステップづつ実行すると動くのに、連続実行で動かない。

    相手がデバイスだと、デバッグが難しいですね。色々と勉強になります。

  • チョコです。

    8251ですか。USARTは懐かしいですね。

    8251には、ライト・リカバリー・タイム(書き込み回復時間)の規格があったのではないでしょうか。

    当時のCPUはクロックが2MHzで、通信のボーレートはせいぜい4.8kbpsや9.6kbps程度だと思います。シリアル通信ではCPUの動作クロックよりシリアル部のクロックがはるかに遅いので、そこらで待ち合わせが発生します。そこの部分の影響でしょうね。

    それよりは、8251では、モードを切り替えるときのシーケンスが結構トリッキーだった記憶があります。

    以上

  • チョコさん、こんにちは

    >それよりは、8251では、モードを切り替えるときのシーケンスが結構トリッキーだった記憶があります。

     同期式に設定した後、同期パターンを2バイト書いたと思います。

     モード設定と思って書き込んだとき、それが同期パターンの1バイト目か2バイト目の可能性が有ります。

     そう言った事を防ぐためのテクニックですね。

     秋月電子で売っているLCDなんかも同様のテクニックが有ります。

     データ幅が4ビットと8ビットの切り替えが出来るので、現在がどっちのモードであっても思うようにプログラムするためのテクニックですね。

     

     外部のI/O装置は読み書きのパルス幅が長かったり、リセットコマンドを出してリセットが終了するまでの時間が長いなどの問題で引っ掛かる事が有ります。

     これも、「ワンステップづつなら動くけど、連続実行で動かない」と言う症状で悩まされる事になります。

  • チョコです。

    8251は調歩同期でしか使用しなかったので、エンターハントしないようにして、リセットをかけて初期化していましたね。

    LCDと違って、8251はリセット解除後からの初期化手順しか書かれていなかったと思います(少なくとも私が使っていたころは)。一部に、理由もわからないで、おまじないだとか言っている人が結構いましたね。

    LCDは手順は割ときちんと書かれているのですが、動作クロックが不明で、待ち時間をどこまで確保すればいいのか読み取れず、めいっぱいマージンをもってやりましたね。

    オリジナルのスレッドからはずれてしまいましたね。