PIC三昧(13) MSSP(I2C)で24LC64に読み書きしてみる、PIC16F18855

Joseph Halfmoon

PIC16Fのペリフェラル回路を経めぐっております。今回はMSSPです。SPIもしくはI2Cとして使用できる同期式シリアルインタフェースのモジュールです。今回は同じマイクロチップ社製の24LC64をI2C接続。MCCが何でも簡単にしてくれるのでこれもチョロイとか思ったらそうでもないっす。I2Cもいろいろあるからね。

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

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

MSSP(Master Synchronous Serial Port)

なんだか重厚なお名前です、MSSP。ぶっちゃけSPIかI2Cとして使用できるシリアルインタフェースであります。どちらも同期式シリアルであるので、1個の回路でどちらにでもなるようにした、って具合なんじゃないかしら。知らんけど。

なお、Masterというから、マスターモードだけなの?と思ったらそんなことはありません。SPIもI2Cもマスターにもスレーブにも変幻自在。

ターゲットのPIC16F18855は2個搭載されているようなので、今回は以下のDevice Resources画面からMSSP1の方を選択してProject Resourcesに加えます。MSSP

例によって、デフォルト設定のままのシステムクロックは遅めの1MHz設定であります。するとI2Cの速度も上げられないみたいです。I2Cの設定画面が以下に。クロックをデフォルト設定のままだと、最大でも62.5kHzなのね。でも指定欄には「アリガチな」100kHzがデフォで書き込まれており。そういうときはActualとかいって上限頭打ちになるのね。まあ、今回はそのままでお楽に行きます。半端だけれど繋がればOKよ。I2Csettings

端子機能の設定が以下に。PortAの0番は例によってのソフトLチカ用です。PortCの0番、1番はボード上でUSBシリアルに接続しているのでそこにEUSARTを接続してます。Printfするためです。肝心のMSSP1(I2C)は、PortCの3番がSCL、4番がSDAです。I2CpinSetting

なおPrintfするための設定などは前回と同じっす。

Generateしてソース書き込み

I2Cの制御用の関数は「ちょっと」メンドかったです。i2c1_master.hの中に関数並んでますが、それみただけだと「ちょっと何言っているか分からない」感が。それもあるのか、examplesというフォルダもできていて以下で黄色でマーカ引いたファイルが出来てました。ProjectSources

黄色のexampleの関数を使わせてもらえば楽勝、と思ったら、24LC64相手だと微妙にフィットしない部分がありました。その心は、exampleの関数はI2Cのデバイス側のレジスタ指定部分が1バイトのつもり(一番アリガチな設定)なのだけれど、24LC64はメモリデバイスなのでアドレス指定だけで2バイト必要な点です。まあ書き込みは、アドレスもデータも一つの入れ物に載せて送ってしまえばOK。でも読み出しは、アドレス2バイト送ってからリードに切り替えて1バイト読む(ランダム・リードの場合、ページ・リードなどはまた異なる)必要があるからです。exampleの関数を「パクらせて」いただき、24LC64に合わせて勝手改変して急場?をしのぎました。

実験に使ったソースが以下に。

#include "mcc_generated_files/mcc.h"
#include "mcc_generated_files/examples/i2c1_master_example.h"
#define ADR24LC64  (0x50)

void writeData(uint8_t *buf)
{
    I2C1_WriteNBytes(ADR24LC64, buf, 3);
     __delay_ms(5);   
}

static i2c1_operations_t rd1RegCompleteHandler(void *ptr)
{
    I2C1_SetBuffer(ptr,1);
    I2C1_SetDataCompleteCallback(NULL,NULL);
    return I2C1_RESTART_READ;
}

uint8_t readData(uint8_t *adr)
{
    uint8_t returnValue = 0x00; 
    while(!I2C1_Open(ADR24LC64));
    I2C1_SetDataCompleteCallback(rd1RegCompleteHandler,&returnValue);
    I2C1_SetBuffer(adr, 2);
    I2C1_SetAddressNackCallback(NULL,NULL);
    I2C1_MasterWrite();
    while(I2C1_BUSY == I2C1_Close());   
    return returnValue;
}

void main(void)
{
    uint8_t buf[4];
    uint8_t work;
    uint8_t temp;
    SYSTEM_Initialize();
    INTERRUPT_GlobalInterruptEnable();
    INTERRUPT_PeripheralInterruptEnable();
    printf("24LC64 W/R test.");
    while (1)
    {
        work = work < 254 ? work + 1 : 0;
        temp = 0;
        buf[0] = 0x01; //ADR12-8
        buf[1] = work; //ADR7-0
        buf[2] = work; //DATA(=ADR7-0)
        writeData(buf);
        RA0 = 1;
        __delay_ms(500);
        temp = readData(buf);
        printf("ADR=0x%02x DATA=0x%02x\n", work, temp);
        RA0 = 0;
        __delay_ms(500);
    }
}
Buildして実行

ビルドしたオブジェクトをPIC16F18855へ書き込みました。以下の写真のように24LC64接続し、メモリへの書き込み、読み出した値を比べてみました。24LC64wPIC16F18855_u

アドレス 0x100番地からアドレス0x1FF番地までにバイトデータを書き込み、読み出してます。書き込んだ値はアドレスの下8ビットと同じです。

Printfで観察した、書き込み、読み出しの結果が以下に。I2Cresults

読み書きできてるみたいね。I2C。

PIC三昧(12) FSM(信号測定タイマ)を使ってみる、PIC16F18855 へ戻る

PIC三昧(14) MSSP(SPI)で23LC512にRWしてみる、PIC16F18855 へ進む