MCC(MPLAB Code Configurator)でI2Cもできるので、Master/SlaveともGenerateさせて試してみた。
両方とも、PIC16F1938を使い、どちらも、I2CとUSARTを有効にして、USBシリアル変換モジュールをつないでMacでモニターできるようにした。
Slave側は128バイトのEEPROMのエミュレータが生成されるので、そのまま動かせる。
Master側は特に機能は生成されないが、生成されるi2c.hに実際のEEPROMのアクセス処理のサンプルコードがコメントに書いてあるので、それをコピペして、アドレス0から16バイトをバッファに読み込むコードと、バッファの内容をUSARTにダンプするコードを書いて動作を確認してみた。
すると、なぜか1バイトずれて読み込まれる現象が…
Slave側でI2Cの処理中にUSARTを使うとI2Cに影響するので、大きめのバッファを用意して、トレース情報を書き込んで後でUSARTに出力させて調べた。
そしたら、Slave側のEEPROMエミュレータはアドレスが1バイトとして処理していて、Master側はアドレスとして2バイト送っているので、アドレスの上位バイト(0)がアドレスとして、下位バイト(0)が書き込みデータとして処理されるので、EEPROMのアドレス0に0が書き込まれて、アドレスが1進められる。で、次のReadリクエストでアドレス1からのデータを返すので1バイトずれて読み込まれるという現象になっていた。
Master側のアドレスを1バイトにしたらちゃんと読み込まれるようになった。
この後、書き込み処理もコピペ&関数化して、16バイト書き込んだ後、同じアドレスから16バイト読み込んでダンプし、書き換えられていることを確認しようとしたら、フリーズしたように進まなくなった。
16バイト書き込みの処理が1バイト毎に書き込んでいるので、どこまで処理が進んでいるのか各所にprintf文を入れて確認したら動いた。
連続してI2Cの関数をコールすると不具合が出るんだろうということで、__delay_xx
を入れたら動くだろうと、怪しそうなところに入れてみた。
I2C_MasterWrite
のコールの後で、ステータスがI2C_MESSAGE_PENDING
の間ループをして処理が終わるのを待っているところに__delay_ms(5);
を入れたら動くようになった。