第40回 I2C通信モジュールとプログラム

PICマイコンのI2C通信のプログラム作成に入ります。

クロック信号の速度

前回の説明で、I2C通信のクロック信号の速度について説明するのを忘れてしまいました。

SPI通信もI2C通信も、データの送受信はクロック信号の変化で読み取る、というルールにしています。クロック信号の速さによらずクロック信号の変化のタイミングでデータ信号を読み取ればいいので、クロック信号の速さは特に決めておく必要はありません。そのためSPI通信ではクロック信号の速度は特に規定はありませんでした。(マスター、スレーブ共に限界値はありますが…)

一方、I2C通信ではクロック信号の速度は標準化されています。I2C通信のバージョンによって異なりますが、以下のように規定されています。単位は、bits/s(1秒あたりに何ビット送信できるか)です。また、それぞれの速度には通称がつけられています。

通称 速度(bits/s)
スタンダードモード 100k
ファストモード 400k
ハイスピードモード 3.4M

このようにクロックの速度は標準化されていますが、これ以外の速度では通信できない、というわけではありません。ただ、実践編では初めてのI2C通信プログラムということで、標準のスタンスダードモード(100k bits/s)でプログラムを作成します。

なお、クロック信号を速くすると当然ながらその分データを早く送ることができますが、あまり速いと電気的な信号は乱れてきますので通常は100k bits/s、速くても400k bits/sあたりがよいと思います。

この後の説明で出てきますが、400k bits/sにする場合、PICマイコンの設定のなかに、波形がなるべく乱れないように、あらかじめクロック信号とデータ信号の波形を調整する機能がありますので、クロックの速度に合わせた設定をするようにします。

 

説明の流れ

I2C通信のプログラムは、PICマイコンに内蔵されているI2C通信機能を使用します。I2C通信のプログラムは今まで出てきた他の機能と同様、最初にピンのデジタル/アナログ設定、入出力設定やその他関連する機能の設定などの初期設定が必要です。

初期設定を行うと、I2C通信ができるようになります。I2C通信の基本的な通信の流れは、スタートコンディションの生成から始まり、スレーブセレクトの送信、データの送受信、ストップコンディションの生成、という順番ですが、I2Cモジュールによってパターンが異なります。そこで、それぞれの通信を関数にして利用することにします。I2C通信を行う際は、I2Cモジュールの仕様に合わせて、これらの関数を呼び出してデータ通信を行うことになります。

今回の記事では、以下の内容、流れで説明することにします。

 

1. ピンの設定

I2C通信に使用するピンはクロック信号ピン(SCLピン)とデータ信号ピン(SDAピン)ですが、これら2ピンは以下の設定にします。

ピン デジタル/アナログ設定
(ANSELレジスタ)
入出力設定
(TRISレジスタ)
クロック信号(SCL) デジタル 入力
データ信号(SDA) デジタル 入力

クロック信号はマスターが出力しますし、データ信号は入出力になりますので、両方とも「入力」に設定するのはちょっと不思議ですが、仕様上このように設定することになっています。ピンの設定をこのようにしておき、I2C通信を有効にすると、それぞれのピンは正しく動作するようになります。

プログラムとしては以下のように設定することにします。

ANSELC = 0b00000000;
TRISC = 0b00001100;

 

2. I2C機能設定(初期設定)

I2C機能の設定に関するレジスタは以下の4個です。

レジスタ名 設定内容
SSP1STAT 信号波形の調整設定、ステータス
SSP1CON1 通信モジュール有効化や通信の種類設定
SSP1CON3 通信モジュール詳細設定
SSP1ADD 通信速度設定

………って、なんだか心が折れそうですが、一つ一つ紐解いてしていきましょう。

まず、レジスタ名をよく見ると、全て「SSP1」で始まっています。設定レジスタ理解のための最初の一歩は、この「SSP1」の意味の解明からです。

すみません、今までの説明で「PICマイコンの中にはI2C通信モジュールが2個あります」という説明をしてきました。

Pic practice 40 i2c modules

実はこれらのモジュールは、一つのモジュールでSPI通信とI2C通信の両方をサポートしているんです。

Pic practice 40 mssp modules

このモジュールことを「MSSPモジュール」と呼んでいます。MSSPは「Master Synchronous Serial Port」の略で、日本語としては「マスター同期型のシリアルポート」という訳になります。今まで説明してきましたSPI通信やI2C通信は、マスターがクロック信号を生成して、全てのスレーブはそのクロック信号に合わせてデータのやり取りを行います。これは、「マスター(のクロック信号に)同期(して通信を行う)型」という意味合いです。また「シリアルポート」とは、以前の記事でシリアル通信を説明しましたが、そのシリアル通信を行うポート、という意味になります。

PIC16F18857には、このMSSPモジュールが2個搭載されています。レジスタ名で表現する場合、これら2個のモジュールに対して「SSP1」「SSP2」という名称がつけられています。「SSP1」は「MSSPモジュール1」に関するレジスタ、ということになります。

また、データシートを調べる場合「SSP1STAT」はこの名称では説明されていません。モジュール1の「SSP1STAT」もモジュール2の「SSP2STAT」も同じ内容になりますので、データシートでは数字の部分を「x」として、「SSPxSTAT」という名称で説明されています。

これから上の表のそれぞれのレジスタの設定内容を説明します。ただ、設定項目が多いですが、一般的なI2C通信を行う場合は一般的な設定がありますので「とりあえずこう設定しておけば動く」という設定値も記載します。

なお、これらのレジスタはSPI通信とI2C通信兼用です。データシートには「SPI通信の時はこういう意味の設定、I2C通信の時はこういう意味の設定になる」と記載されていますが、以下ではI2C通信のみの説明になります。また、PICマイコンのMSSPモジュールは、I2Cのマスターとスレーブ両方に対応していますが、以下の説明はマスターの部分のみの説明になります。もしご自分でPICマイコンを使ってスレーブのデバイスを作る場合は、データシートをご確認いただければと思います。

「SSP1STAT」レジスタ

「SSP1 Status Register」は SSP1モジュールのステータスが格納されるレジスタです。このレジスタを調べると現在の通信状況(通信ステータス)がわかります。また一部のビットは設定にも使用されています。

レジスタの構成は以下のようになっています。それぞれの設定を詳しく説明します。

Pic practice 40 register stat

SMP: SPI Data Input Sample bit
このビットはSPIの名前が付いていますが、I2C通信の場合は以下の設定になります。

設定値 意味
1 信号波形をスタンダードモード(100kHz)用に調整します
0 信号波形をファストモード(400kHz)用に調整します

実践編ではクロック信号を100kHzに設定しますので、SMPは1に設定します。

CKE: SPI Clock Edge Select bit
このビットはSPIの名前が付いていますが、I2C通信の場合は以下の設定になります。

設定値 意味
1 入力回路部をSMBus用に設定する
0 入力回路部は通常用に設定する

突然「SMBus」という用語が出てきました。これはI2C通信の派生仕様の通信方法になります。通常のI2C通信の場合は0に設定します。

D/A: Data/Address bit
このビットは、最後に送受信し値がデータだったのかアドレスだったのかの状態を示すビットです。I2C通信でマスターのプログラムを作成する場合、データの送受信は自分で管理しますので、このビットを見ることはないと思います。

このビットの値を調べると以下のことがわかります。このビットは状態を示すビット(=読み取りビット)ですので値を設定しても無効です。

意味
1 最後に送受信した値はデータ
0 最後に送受信した値はアドレス

P: Stop bit
このビットは、ストップコンディションが検出されたかどうかを示すビットです。I2C通信でマスターのプログラムを作成する場合、データの送受信は自分で管理しますので、このビットを見ることはないと思います。

このビットの値を調べると以下のことがわかります。このビットは状態を示すビット(=読み取りビット)ですので値を設定しても無効です。

意味
1 ストップコンディションが検出された
0 ストップコンディションが検出されていない

S: Start bit
このビットは、スタートコンディションが検出されたかどうかを示すビットです。I2C通信でマスターのプログラムを作成する場合、データの送受信は自分で管理しますので、このビットを見ることはないと思います。

このビットの値を調べると以下のことがわかります。このビットは状態を示すビット(=読み取りビット)ですので値を設定しても無効です。

意味
1 スタートコンディションが検出された
0 スタートコンディションが検出されていない

R/W: Read/Write bit information
このビットはデータ送信中かどうかを示すビットです。I2C通信のマスター場合は以下の意味になります。I2C通信でデータを送受信する場合、送受信が終わったかどうかを判定する方法は別にありますので、通常のI2C通信ブログラムを作る場合、このビットを見ることはそれほどないと思います。このビットは状態を示すビット(=読み取りビット)ですので値を設定しても無効です。

1 データ送信中
0 データ送信中ではない

UA: Update Address bit
このビットはI2C通信でもアドレスを10ビットモードで使用しているときのアドレス状況を示すビットです。10ビットアドレスは使用しませんので説明は省略します。このビットは状態を示すビット(=読み取りビット)ですので値を設定しても無効です。

BF: Buffer Full Status bit
このビットは、データ送受信する一時的なデータ保存場所にデータがあるかないかの状態を示すビットです。I2C通信でデータを送受信する場合、送受信が終わったかどうかを判定する方法は別にありますので、通常のI2C通信ブログラムを作る場合、このビットを見ることはそれほどないと思います。このビットは状態を示すビット(=読み取りビット)ですので値を設定しても無効です。

意味
1 データがまだ残っている(データ送信中)
0 データは残っていない(データ送信完了)

補足として、先ほどのR/Wビットでもデータ送受信完了はわかりますが、BFビットはACK/NACK信号は含んでいません。R/Wビットは、「8ビットのデータ + 1ビットのACK/NACK信号」の送受信が終わったかどうかがわかります。BFは「8ビットのデータの送受信」(ACK/NACK信号は含まない)が終わったかどうかがわかります。

一般的なI2C通信のマスターモードの場合、SSPxSTATレジスタは以下の設定のどちらかになります。

SSP1STAT = 0x80; // クロック信号が100kHzの場合
SSP1STAT = 0x00; // クロック信号が400kHzの場合

 

「SSP1CON1」レジスタ

「SSP1 Control Register 1」: SSP1モジュールの設定を行います。設定項目が多いため、他にもう2つのレジスタ(SSP1CON2とSSP1CON3)があります。

レジスタの構成は以下のようになっています。それぞれの設定を詳しく説明します。

Pic practice 40 register sspxcon1

WCOL: Write Collision Detect bit
この後の説明で出てきますが、I2C通信でデータを送信する場合、特定のレジスタに送信するデータ(値)を代入するとPICマイコンがそのデータを送信してくれます。具体的には、例えば0x12を送信したい場合、以下のように「SSP1BUF」というレジスタに0x12を代入するだけでPICマイコンがクロック信号とデータ信号を制御してI2C通信を行ってくれます。

SSP1BUF = 0x12;

データを複数バイト送信したい場合、SSP1BUFに代入した値が送信完了になるまで、次の値はSSP1BUFに代入できません。

このWCOLビットは、SSP1BUFに代入した値が送信完了したかどうかの状況を示します。このビットの値を調べると以下のことがわかります。このビットは状態を示すビット(=読み取りビット)ですので値を設定しても無効です。

ただ、送信完了したかどうかは別の方法でチェックしますので、実践編ではこのビットはチェックしません。

意味
1 SSP1BUFの値は送信完了していない(=次のデータが代入できない)
0 SSP1BUFの値は送信完了した(=次のデータが代入できる)

SSPOV: Receive Overflow Indicator bit
I2C通信でデータを受信する場合、受信したデータはSSP1BUFレジスタに格納されています。複数バイトを受信する場合、受信するレジスタはSSP1BUFの1バイトしかありませんので、この値を取得しないうちに次のデータを受信すると、取得できないデータが出てきてしまいます。

このビットは、SSP1BUFに受信したデータが保持されているのにも関わらず、次のデータを受信してしまったかどうか(これをオーバーフローと呼びます)の状況を示します。このビットの値を調べると以下のことがわかります。このビットは状態を示すビット(=読み取りビット)ですので値を設定しても無効です。

ただ、実践編ではこのビットはチェックしない方法でプログラムを作成します。

意味
1 受信したデータをSSP1BUFに保持している間に次のデータを受信した(=オーバーフローが発生した)
0 オーバーフローは発生していない

SSPEN: Synchronous Serial Port Enable bit
このビットは非常に重要です。このビットでSSP1モジュールを有効にするかどうかの設定をします。SSP1モジュールはSPI通信やI2C通信のマスター、スレーブモードをサポートしています。このビットでSSP1モジュールを有効にした場合、この後に出てくるSSPMビットで通信の種類を選択します。

以下の意味になります。

意味
1 SPI/I2C通信を有効にする。割り当てたピンはSSP1モジュールに接続される
0 SPI/I2C通信を無効にする。割り当てたピンは通常の入出力ピンとして動作する

CKP: Clock Polarity Select bit
このビットはI2C通信のマスターでは設定する必要はありません。I2C通信のスレーブの場合は、このビットでクロック信号制御(クロックストレッチと呼ばれています)を行います。実践編ではマスターで使用しますので説明を省略します。

PICマイコンがマスターになってI2C通信を行う場合は0を設定しておけばOKです。

SSPM: Synchronous Serial Port Mode Select bit
先ほどのSSPENでSSP1モジュールを有効にした場合、通信の種類はどれにするか、このビットで選択します。一般的なI2C通信(マスター)の場合は「1000」を選択してください。

以下の意味になります。

意味
1111 I2C通信スレーブ(10ビットアドレス)・スタート/ストップ時に割り込み信号発生
1110 I2C通信スレーブ(7ビットアドレス)・スタート/ストップ時に割り込み信号発生
1101 無効
1100 無効
1011 I2C通信マスター(ファームコントロール)
1010 SPI通信マスター
1001 無効
1000 I2C通信マスター
0111 I2C通信スレーブ(10ビットアドレス)
0110 I2C通信スレーブ(7ビットアドレス)
0101 SPI通信スレーブ(スレーブセレクト信号は制御しない)
0100 SPI通信スレーブ(スレーブセレクト信号は制御する)
0011 SPI通信マスター(クロック信号はタイマー使用)
0010 SPI通信マスター(クロック信号は周波数の64分の1を使用)
0001 SPI通信マスター(クロック信号は周波数16分の1を使用)
0000 SPI通信マスター(クロック信号は周波数の4分の1を使用)

ということで、一般的なI2C通信でマスターとなる場合、以下の設定になります。

SSP1CON1 = 0x28;

 

「SSP1CON3」レジスタ

SSP1CON2レジスタを飛ばして、SSP1CON3レジスタです。SSP1CON2レジスタは、実際にI2C通信のデータ通信制御(スタート/ストップコンディションの制御、データ送受信制御)を行うレジスタです。機能設定はSSPCON3に続きます。(なぜそうなっているのかは謎ですが…)

SSP1CON3レジスタの構成は以下のようになっています。それぞれの設定を詳しく説明します。

Pic practice 40 register sspxcon3

ACKTIM: Acknowledge Time Status bit

I2C通信では8ビットデータを送信または受信したあと、1ビットのACK/NACK情報をやりとりします。このビットはそのACK/NACK信号のやり取り中かどうかの状況を示します。状態を示すビットですので、設定は無効です。

以下の意味になります。

意味
1 ACK/NACK信号処理中
0 ACK/NACK信号は処理していない

PCIE: Stop Condition Interrupt Enable bit

SCIE: Start Condition Interrupt Enable bit

PCIEとSCIEは同じような内容の設定になりますのでまとめて説明します。I2C通信では開始はスタートコンディション、終了はストップコンディションの状態を作ります(クロック信号が1の時にデータ信号を変えてしまう)。

PICマイコンをI2C通信のスレーブとして動作させる場合、通信の開始と終了を監視する必要がありますが、プログラムでチェックするのは大変です。そこで、スタート/ストップコンディションが発生した場合、割り込み信号生成してくれる機能があります。これらのビットはその割り込み信号を発生するかどうかの設定です。

以下の意味になります。

意味
1 割り込み信号を発生させる
0 割り込み信号を発生させない

実践編ではPICマイコンはマスターですので、割り込みは設定しません。

BOEN: Buffer Overwrite Enable bit

このビットはスレーブの時に有効なビットで、受信データのレジスタを上書き許可するかどうかの設定になります。実践編ではマスターで使用しますので説明は省略します。マスターの場合は設定は無効になりますので、0を設定します。

SDAHT: SDA Hold Time Selection bit

I2C通信ではデータを送信する際、データ信号線にデータをセットして、クロック信号を変化させてデータを読み取ってもらいます。具体的には、データ信号をセット、クロックを立ち上げて、クロックを立ち下げて次のデータをセット、という流れです。

データ受信側は、クロック信号が変化した瞬間にデータを読み取ることは難しく、クロック信号が変化したことを確認してからデータを読み取ります。そのため、クロック信号を立ち上げて、次にクロック信号を立ち下げたあとに次のデータをセットしますが、データ読み取りがのんびりしているスレーブもあるかもしれません。その場合は、データを保持しておく時間をちょっと長めにしてあげることが必要になるケースもあります。

このビットは、クロック信号を立ち下げてから、どのぐらいの時間データ信号を保持しておくかを設定します。

以下の意味になります。

意味
1 クロック信号を立ち下げてから、少なとも300nsはデータを保持する
0 クロック信号を立ち下げてから、少なとも100nsはデータを保持する

実践編のプログラムのクロック速度は100kHzで作成します。クロック信号の速度が100kHzというのはかなりゆっくりです。この設定は100nsでも問題ありませんので、0に設定することにします。

SBCDE: Slave Mode Bus Collision Detect Enable bit

このビットは、PICマイコンをスレーブにした際のデータ信号の衝突(他のI2Cモジュールと同時にデータ通信を行ってしまう)を検出するかどうかの設定です。マスターの場合設定は無効になりますので説明は省略します。設定は0にします。

AHEN: Address Hold Enable bit / DHEN: Data Hold Enable bit

これらのビットは、I2C通信のスレーブの時に有効な設定で、マスターでは関係ありませんので詳しい説明は省略します。スレーブモードの時に、アドレスを受信してそのアドレスが自分のアドレスであった場合や、データを受信した場合、何か処理する必要があります。マスターは次々にデータを送ってきますが、そのデータ処理が追いつかない場合、マスターに「ちょっと待ってて」と知らせることができます。その「ちょっと待ってて」をするかどうかの設定になります。

マスターの場合は設定は無効になりますので、0を設定しておきます。

ということで、一般的なI2C通信でマスターとなる場合、以下の設定になります。

SSP1CON3 = 0x00;

 

「SSP1ADD」レジスタ

このレジスタは、I2Cのマスターとスレーブで意味が異なります。マスターの場合はクロック信号の速度設定、スレーブの場合はI2Cスレーブアドレスを設定します。

マスターの場合、クロック信号の速度は以下の式で計算される値になります。

クロック信号の速度(=周波数) = PICマイコンの動作周波数 / ((SSP1ADDの値 + 1) x 4)

実践編では、PICマイコンの動作周波数は4MHz、I2Cのクロック信号の速度はスタンダードモードの100kHzにします。SSP1ADDの値を求めると、まずは上の式をSSP1ADD = になるように1次方程式を解くと、

SSP1ADD = (PICマイコン動作周波数 / (I2Cクロック信号周波数 x 4)) – 1

になります。周波数の値を代入すると、

SSP1ADD = 4MHz / (100kHz x 4) – 1 = 10 – 1 = 9

ということで、SSP1ADDの値を9に設定すると、I2Cクロック周波数は100kHzになります。

この値はPICマイコンの動作周波数とI2Cクロック周波数で決まりますので、一般的な設定というものはなく、それぞそれのケースで計算することになります。実践編では以下のように設定します。

SSP1ADD = 0x09;

 

I2C通信機能設定まとめ

今までの設定をまとめます。I2C通信のマスターでクロック信号の速度が100kHzの場合、以下の設定になります。

// ピンの設定
ANSELC = 0b00000000;
TRISC = 0b00001100;

SSP1STAT = 0x80;   // クロック信号は100kHzを使用
SSP1CON1 = 0x28;   // I2C通信のマスターモードを有効化
SSP1CON3 = 0x00;   // CON3はデフォルト設定
SSP1ADD = 0x09;   //クロック信号速度を100kHzに設定

 

3. I2C通信関数の作成

以上でI2C通信の設定(MSSP1モジュールの設定)が終わりましたので、I2C通信の関数を作っていきます。

 

3-1. 概要

以前の記事で、I2C通信でデータ通信を行う例として、マスターからスレーブに2バイトのデータを送信するケースの通信手順を説明しました。

I2C通信のデータ送受信は、必ずスタートコンディションから始まり、ストップコンディションで終わります。またスタートコンディションの後は必ずスレーブアドレス(+読み書き指定)の8ビットデータ送信を行います。選択されたスレーブは、そのスレーブアドレスデータに対してACK信号(了解信号)を返信します。ただ、そのあとのデータ送受信についてはスレーブごとに異なります。

そこで、色々なスレーブに対応できるように、以下のようにそれぞれのやり取りを関数化しておくことにします。関数名は「i2cProtocol」で始まる名前にして、その後はそれぞれの信号制御の名前にしてみました。

Pic practice 40 i2c functions

注意点が2点あります。

まず一つ目は、最初のスレーブアドレス送信とその後のデータ送信は目的は異なるものの、処理としては8ビットのデータ送信です。そのため、スレーブアドレス送信をする関数とデータ送信をする関数というように2つの関数は作成せずに、8ビットデータを送信する関数として作成します。

二つ目は、上のデータ通信はマスターからスレーブに2バイトのデータを送信する例です。実際にはスレーブからマスターにデータを送信するモジュール(実践編で使用する温度センサなど)もあります。スレーブからマスターにデータ送信する関数は温度センサのプログラムを説明する際に作成することにします。

 

3-2. I2C通信制御レジスタ(SSP1CON2)

PICマイコンでI2C通信でデータ通信を実行するには、SSP1CON2レジスタを制御します。そこで、最初にSSP1CON2レジスタの説明をします。

Pic practice 40 register sspxcon2

GCEN: General Call Enable bit

このビットはPICマイコンがスレーブの際の設定ですので詳細な説明は省略します。I2C通信のスレーブアドレス0x00は特殊なアドレスとして定義されていて、マスターからスレーブアドレスとして0x00が指定された場合のスレーブの挙動を設定するビットです。

ACKSTAT: Acknowledge Status bit

このビットは、ACK/NACKの状態を表します。8ビットのデータ送信を行なった後、送信先から「了解信号」、つまりACK/NACK信号が返信されてきますが、その返信されてきた信号がACKかNACKのどちらかかを示すビットです。

以下の意味になります。

意味
1 NACK (了解信号がなかった)
0 ACK (了解信号があった)

 

ACKDT: Acknowledge Data bit

先ほどの「ACKSTAT」ビットは、ACK/NACKの状態を示すビットでした。このビットは、ACK/NACKを返信するビットです。8ビットのデータ受信を行なった後、問題なく受信できた場合は送信先に対して「了解信号」、つまりACK信号を返信する必要があります。返信する信号を設定するビットです。注意点としては、このビットはあくまでACK/NACKの信号を設定するビットです。実際にACK/NACKの返信は次の「ACKEN」ビットを操作することにより行います。

以下の意味になります。

意味
1 NACK (了解できなかった)
0 ACK (了解)

 

ACKEN: Acknowledge Sequence Enable bit

このビットを制御することにより、先ほどのACKDTビットで指定したACK/NACK信号を生成します。

以下の意味になります。

意味
1 このビットを1にすると、SDA信号とSCL信号を制御してACKDTで指定したACK/NACK信号を生成します。処理が終わるとこのビットは自動的に0に設定されます
0 ACK/NACK信号生成を行なっていない時、このビットは0になります

 

RCEN: Receive Enable bit

このビットは、データ受信を行います。このビットを操作してデータ受信を行う関数は、温度センサの制御プログラムを作成する際に出てきます。今回の記事で作成する関数には出てきませんが、後ほど使用しますのでここで確認しておきます。

以下の意味になります。

意味
1 このビットを1にすると、スレーブから返信されてくる8ビットデータを受信します。処理が終わるとこのビットは自動的に0に設定されます
0 データ受信処理を行なっていない時、このビットは0になります

 

PEN: Stop Condition Enable bit

このビットを操作することにより、ストップコンディションを生成します。

以下の意味になります。

意味
1 このビットを1にすると、SCL信号とSDA信号を制御してストップコンディションを生成します。処理が終わるとこのビットは自動的に0に設定されます
0 ストップコンディション生成を行なっていない時、このビットは0になります

 

RSEN: Repeated Start Condition Enable bit

今までの説明では、I2C通信はスタートコンディションから始まり、ストップコンディションで終わる、と説明してきました。一般的な通信はこのような通信方法になりますが、例外があります。

マスターからスレーブにデータを送信して、その後スレーブからマスターにデータを返信する場合、マスターからスレープにデータを送信した後、いったん通信の仕切り直しをします。その仕切り直しとして「リピートスタートコンディション」という信号を発生させます。この信号はスタートコンディションと同じですが、スタートコンディションとは別に用意されています。

このビットを操作することにより、リピートスタートコンディションを生成します。

以下の意味になります。

意味
1 このビットを1にすると、SCL信号とSDA信号を制御してリピートスタートコンディションを生成します。処理が終わるとこのビットは自動的に0に設定されます
0 リピートスタートコンディション生成を行なっていない時、このビットは0になります

 

SEN: Start Condition Enable bit

このビットを操作することにより、スタートコンディションを生成します。

以下の意味になります。

意味
1 このビットを1にすると、SCL信号とSDA信号を制御してスタートコンディションを生成します。処理が終わるとこのビットは自動的に0に設定されます
0 スタートコンディション生成を行なっていない時、このビットは0になります

以下に、これらのレジスタを制御してI2C通信の制御関数を作成します。

 

3-3. スタートコンディション関数

スタートコンディションを生成するには、SSP1CON2レジスタのSENビットを1にします。SENに1を設定すると、(勝手に)PICマイコンがSCL信号とSDA信号を制御してスタートコンディションを生成してくれます。

ただし、SENを1にしてからPICマイコンがスタートコンディションの生成を終えるまで、待ってあげる必要があります(待たずに割り込みで処理する方法もありますが、処理が難しくなるので実践編では待つことにします)。PICマイコンはスタートコンディションの生成を終えると、「SSP1IF」というレジスタを1にしてくれます。

スタートコンディションを生成するには以下の手順になります。

  1. SSP1IFを0にしておく
  2. SSP1CON2のSENを1にする
  3. SSP1IFが1になるのを待つ(=PICマイコンがスタートコンディションの生成を終えるのを待つ)
  4. SSP1IFを0に戻しておく

これをプログラムにすると以下のようになります。なおこの関数は引数、返り値はありません。

// スタートコンディション生成
void i2cProtocolStart() {

// SSP1CON2レジスタのSENビットを1に設定すると
// スタートコンディションが生成される
// 発行が完了するとSSP1IFが1になるのでwhile文で待つ
SSP1IF = 0;
SSP1CON2bits.SEN = 1;
while (SSP1IF == 0) {}
SSP1IF = 0;

return;
}

 

3-4. ストップコンディション関数

ストップコンディションの生成は、スタートコンディションを同様の手順になります。

  1. SSP1IFを0にしておく
  2. SSP1CON2のPENを1にする
  3. SSP1IFが1になるのを待つ(=PICマイコンがスタートコンディションの生成を終えるのを待つ)
  4. SSP1IFを0に戻しておく

これをプログラムにすると以下のようになります。なおこの関数は引数、返り値はありません。

// ストップコンディション生成
void i2cProtocolStop() {

// SSP1CON2レジスタのPENビットを1に設定すると
// ストップコンディションが生成される
// 発行が完了するとSSP1IFが1になるのでwhile文で待つ
SSP1IF = 0;
SSP1CON2bits.PEN = 1;
while (SSP1IF == 0) {}
SSP1IF = 0;

return;
}

 

3-5. データ送信関数

データ送信は「SSP1BUF」レジスタに送りたいデータを代入するだけで、あとはPICマイコンがSCL信号とSDA信号を制御してデータ送信してくれます。

なお、スタート/ストップコンディションと同様に、データ送信が終わるまで待ってあげる必要がありますので、SSP1IFが1になるのを待ちます。データ送信の手順は以下のようになります。

  1. SSP1IFを0にしておく
  2. SSP1BUFに送りたいデータをセットする
  3. SSP1IFが1になるのを待つ(=PICマイコンがスタートコンディションの生成を終えるのを待つ)
  4. SSP1IFを0に戻しておく

これをプログラムにすると以下のようになります。この関数では送信データを引数にしています。

// 1バイトデータ送信
void i2cProtocolSendData(uint8_t data) {

// SSP1BUFに送信したいデータをセットすると、そのデータが送信される
// 発行が完了するとSSP1IFが1になるのでwhile文で待つ
SSP1IF = 0;
SSP1BUF = data;
while (SSP1IF == 0) {}
SSP1IF = 0;

return;
}

 

3-6. ACK/NACK状態確認関数

Ack/Nackの状態は、SSP1CON2レジスタのACKSTATビットにセットされます。ACKの場合が0、NACKの場合が1です。つまり、SSP1CON2bits.ACKSTATの値を調べればすぐにわかるのですが、一連のI2C通信関数を作成していますので、Ack/Nack状態確認も関数にします。

なお、特に意味はありませんが、ACKを0x00、NACKを0xFFに定義して、その値を返り値にすることにしました。(boolean型の方がいいですかね…)

// I2C Ack/Nack定義
#define I2C_ACK  0x00
#define I2C_NACK 0xff

// Ack/Nackチェック
uint8_t i2cProtocolCheckAck() {

uint8_t ackStatus;

if (SSP1CON2bits.ACKSTAT) {
ackStatus = I2C_NACK;
} else {
ackStatus = I2C_ACK;
}

return ackStatus;
}

以上で必要なI2C通信を行う関数ができました。次回から液晶モジュールの制御プログラムの作成に入ります。

 

更新履歴

日付 内容
2018.6.22 新規投稿