« 2023年8月 | トップページ | 2023年11月 »

2023年10月

2023年10月25日 (水)

PIC18FQ MCC で I2C

PIC18FQ MCC で I2C とは

呪文みたいな表題になってしまったが、ちょっと I2C 通信でトラブったので、そのメモ代わりに書いておく。

MCC とは Microchip Code Cpnfigure といったソフトで、 UI でCPUの周辺動作を規定したり、動かすのに必要なドライバーを書き出してくれるます。 MPLAB-X IDE という 最近の開発環境での付加ソフトなのですが、最近まで使っている古い MPLAB IDE というソフトと違って、簡単にソフトが作れるそうなのですが、内部構造が判りにくくて、資料が少ないことから結構難儀しました。

今回は I2C 関連でのおはなし

i2c1_master_example.c というサンプルコードが生成されるので、見てみると

void I2C1_WriteNBytes(i2c1_address_t address, uint8_t* data, size_t len)
{
    while(!I2C1_Open(address));  // バスがBUSYのうちは待っている
    I2C1_SetBuffer(data,len);   // 書き込むデーターの アドレスと長さ
    I2C1_SetAddressNackCallback(NULL,NULL);
                 //反応無いとき "NACK"の場合の処理 ここでは何もしない
    I2C1_MasterWrite();   // 書込処理
    while(I2C1_BUSY == I2C1_Close());  // 完了待って STOP 処理
}

これは大体判る。ここにある xxxxCallback という部分がくせもの
ここでの i2c1_address_t address  は,7ビットなので、実際送信時は シフトされて RW ビットが追加される。

次は EEPROM読み出しなどに使うアドレス指定書込後、RESTART してデーターを読むようなのだが

void I2C1_ReadDataBlock(i2c1_address_t address, uint8_t reg, uint8_t *data, size_t len)
{
    i2c1_buffer_t bufferBlock;         // 結果を書き込むバッファを作成
    bufferBlock.data = data;
    bufferBlock.len = len;

    while(!I2C1_Open(address));  // バス開放待ち
    I2C1_SetDataCompleteCallback
                 rdBlkRegCompleteHandler,&bufferBlock);  //ここがキモ
    I2C1_SetBuffer(&reg,1);          // 送信するデーター 1バイト
    I2C1_SetAddressNackCallback(NULL,NULL);
          //反応無いとき "NACK"の場合の処理 ここでは何もしない
    I2C1_MasterWrite();
    while(I2C1_BUSY == I2C1_Close());  // 完了まで待って STOP 処理
}

ちょっと見ると I2C1_MasterWrite(); だけなので、書き込むだけでどこで読むんだろう?
と思って見てみると I2C1_SetDataCompleteCallback というのがありますね。
DataComplate とあるので、送信が完了した時の動作を指定するところのようです。
この rdBlkRegCompleteHandler というのは、まさに RESTART を送って、データーを読み込む所のようです。

i2c1_buffer_t bufferBlock;  と言う物を作って、アドレスと長さを指定します。

このルーチンは、送信時のレジスタ指定が1バイトなので、256バイト以下ならいいですが、大きな EEPROM などでは足りません。
そこで、

(i2c1_address_t address, uint8_t reg, uint8_t *data, size_t len)
....
I2C1_SetBuffer(&reg,1);  
の部分を

(i2c1_address_t address, uint8_t *reg, uint8_t *data, size_t len)
...
I2C1_SetBuffer( reg,2);  
と2バイトにして ( uint16_t にしてもいいかな?)

新たな関数を作ってみました。

*結局 MCCの作成する I2C ルーチンは、ステータスを定義して

バスは空いているか?
書き込めるか?
書いたら完了したか?
応答はあったか?
完了したら次はどうするか?
全部終了したか?
STOPで終わる

など、順次実行するもので、ソフト上からはあまり良く判らないのが難点ですね。
そのままだと、相手がいなくても、反応がなくても止まることがないので初心者にはいいかな?
エラー処理をきちんとやろうとすると面倒かも?

| | コメント (0)

« 2023年8月 | トップページ | 2023年11月 »