PIC三昧(16) MSSP、I2C Slaveモードでデータを送受、PIC16F18855

Joseph Halfmoon

前回はPIC16搭載のMSSPをSPIスレーブとして使用。今回はMSSPをI2Cスレーブとして使ってみます。別シリーズ記事にて前回のSPIスレーブのテスト用の通信相手をMicroPythonで作成しましたが、今回もI2Cスレーブの通信相手を同様に作成して実験したいと思います。両側作らないと実験できないのはメンドイっす。

※『PIC三昧』PIC関係の記事総目次はこちら

※作業はMicroChip社の統合開発環境 MPLAB X IDEと、その上で走るコンフィギュレーションツールMCC Classic を使用して行っています。ターゲット・マイコンはPIC16F18855です。

MSSPをI2Cスレーブとして設定

まずはプロジェクトに含めるリソースです。以下のようにEUSARTとMSSP1を含めてます。EUSARTは標準出力(printf)の宛先用のUARTとしての使用です。ProjectResourceI2Cslave

MSSP1の設定画面が以下に。何時データがくるのか分からないスレーブなので、Interrupt Drivenにチェック、I2C Slave設定デス。I2Csetting

Slave Addressには、通常は7ビットのI2Cアドレス(アドレスの下の最下位ビットにR/Wビットがくる)を設定します。今回やってないですが、10ビットアドレスにも対応可能なようです。

また、Mask Addressには、上記のSlave Addressに対するマスクビットを設定します。各ビット、1ならアドレスとして比較対象となり、0なら比較せずとなります。これを使えば複数のSlave Addressを占有することも可。なお実際のMaskビットは SSPxMSK: SSPx MASK REGISTER に書き込まれるようです。

いつもの通りのprintf用のEUSARTの設定が以下に。UARTsetting

何時も書いてますが、手元のMCC Classicで生成されるコードでは、getchの戻り値型が違うのでエラーになります。いつもコイツをつぶしてビルドを通してます。

ピン配が以下に。PINsettings

RX、TXは使用しているボードのUSBシリアルに接続されているので一択です。肝心のI2CのSCL、SDAは使えるところならばどこでもよいのですが、流れでそこになってます。また、PortAのビット0は吉例Lチカ用です。LEDに接続してます。

I2Cスレーブ、手抜きなテストプログラム

前回のSPIスレーブの場合は、データを割り込み受けするのに簡単なハンドラを自前で書かねばなりませんでした(自動生成されるのは無益なデフォルトハンドラでした。)

今回のI2Cスレーブ用に生成されるコードは、以下のコールバック関数に対して、必要最小限の機能を果たすデフォルトのハンドラが代入済です。簡単なテストならお楽。

    • I2C1_SlaveWrCallBack()
    • I2C1_SlaveRdCallBack()
    • I2C1_SlaveAddrCallBack()
    • I2C1_SlaveReleaseClock()

デフォルトハンドラは、I2Cマスタから到来したアドレスを以下の変数に格納してくれます。

volatile uint8_t i2c1SlaveAddr;

また、I2Cマスタが書き込んだデータ(8ビット)は、以下の変数に代入。

volatile uint8_t i2c1RdData;

I2Cマスタがデータ(8ビット)を読もうとすると以下の変数の値がスレーブから送出されます。

volatile uint8_t i2c1WrData;

1アドレスに対して1バイトのリード、ライトに反応できるだけですが、今回はこれをそのまま利用させてもらいました。もっと複雑な通信をするためには自前で書かねばなりますまい。

実験に使ったmain()関数部分のソースが以下に。自動生成されたソースに書き加えた部分は以下のみであります。

extern volatile uint8_t i2c1WrData;
extern volatile uint8_t i2c1RdData;
extern volatile uint8_t i2c1SlaveAddr;

void main(void)
{
    SYSTEM_Initialize();
    INTERRUPT_GlobalInterruptEnable();
    INTERRUPT_PeripheralInterruptEnable();
    printf("I2C1 slave test.\n");
    I2C1_Initialize();
    I2C1_Open();
    i2c1WrData = 0x34;
    i2c1RdData = 0;
    i2c1SlaveAddr = 0;
    while (1)
    {
        RA0 = 1;
        __delay_ms(1000);
        printf("ADR=0x%02x WR=0x%02x RD=0x%02x\n", (i2c1SlaveAddr >> 1), i2c1WrData, i2c1RdData);
        RA0 = 0;
        __delay_ms(1000);
    }
}
実機動作確認

以下に対向機「ESP32 DevKitC」との接続部分を示します。PIC16F_ESP32

I2Cなので、外付けプルアップ抵抗をアカラサマに接続してみました。

さて、上記プログラムをPIC16F18855へ書き込んでスタートさせ、一方対向機からは7ビットアドレス=0x08へ1バイト0xA5を書き込んでます。また、I2C経由の1バイトリードも実施。

PIC16側の標準出力の結果が以下に。i2cSlaveResult

7ビットアドレス=0x08へ1バイト0xA5は書き込まれているみたい。マスタ側のリードも成功、詳しいことは別件記事へ。

PIC三昧(15) MSSP、SPI Slaveモードでデータを受信、PIC16F18855 へ戻る

PIC三昧(17) EEPROM、データ書き込み&読み出し、PIC16F18855 へ進む