I2C通信モジュールとプログラムPICマイコン入門-実践PICマイコン入門-実践PICマイコンのI2C通信のプログラム作成に入ります。前回の説明で、I2C通信のクロック信号の速度について説明するのを忘れてしまいました。SPI通信もI2C通信も、データの送受信はクロック信号の変化で読み取る、というルールにしています。クロック信号の速さによらずクロック信号の変化のタイミングでデータ信号を読み取ればいいので、クロック信号の速さは特に決めておく必要はありません。そのためSPI通信ではクロック信号の速度は特に規定はありませんでした。(マスター、スレーブ共に限界値はありますが...)一方、I2C通信ではクロック信号の速度は標準化されています。I2C通信のバージョンによって異なりますが、以下のように規定されています。単位は、bits/s(1秒あたりに何ビット送信できるか)です。それぞれの速度には通称がつけられています。3.4Mこのようにクロックの速度は標準化されていますが、これ以外の速度では通信できない、というわけではありません。bits/s)でプログラムを作成します。bits/sあたりがよいと思います。bits/sにする場合、PICマイコンの設定のなかに、波形がなるべく乱れないように、あらかじめクロック信号とデータ信号の波形を調整する機能がありますので、クロックの速度に合わせた設定をするようにします。説明の流れI2C通信のプログラムは、PICマイコンに内蔵されているI2C通信機能を使用します。I2C通信のプログラムは今まで出てきた他の機能と同様、最初にピンのデジタル/アナログ設定、入出力設定やその他関連する機能の設定などの初期設定が必要です。初期設定を行うと、I2C通信ができるようになります。I2C通信の基本的な通信の流れは、スタートコンディションの生成から始まり、スレーブセレクトの送信、データの送受信、ストップコンディションの生成、という順番ですが、I2Cモジュールによってパターンが異なります。そこで、それぞれの通信を関数にして利用することにします。I2C通信を行う際は、I2Cモジュールの仕様に合わせて、これらの関数を呼び出してデータ通信を行うことになります。今回の記事では、以下の内容、流れで説明することにします。ピンの設定I2C通信に使用するピンはクロック信号ピン(SCLピン)とデータ信号ピン(SDAピン)ですが、これら2ピンは以下の設定にします。入力クロック信号はマスターが出力しますし、データ信号は入出力になりますので、両方とも「入力」に設定するのはちょっと不思議ですが、仕様上このように設定することになっています。ピンの設定をこのようにしておき、I2C通信を有効にすると、それぞれのピンは正しく動作するようになります。プログラムとしては以下のように設定することにします。I2C機能設定(初期設定)I2C機能の設定に関するレジスタは以下の4個です。通信速度設定.........って、なんだか心が折れそうですが、一つ一つ紐解いてしていきましょう。レジスタ名をよく見ると、全て「SSP1」で始まっています。設定レジスタ理解のための最初の一歩は、この「SSP1」の意味の解明からです。すみません、今までの説明で「PICマイコンの中にはI2C通信モジュールが2個あります」という説明をしてきました。実はこれらのモジュールは、一つのモジュールでSPI通信とI2C通信の両方をサポートしているんです。このモジュールことを「MSSPモジュール」と呼んでいます。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マイコンを使ってスレーブのデバイスを作る場合は、データシートをご確認いただければと思います。SSP1モジュールのステータスが格納されるレジスタです。このレジスタを調べると現在の通信状況(通信ステータス)がわかります。一部のビットは設定にも使用されています。レジスタの構成は以下のようになっています。それぞれの設定を詳しく説明します。bitこのビットはSPIの名前が付いていますが、I2C通信の場合は以下の設定になります。信号波形をファストモード(400kHz)用に調整します実践編ではクロック信号を100kHzに設定しますので、SMPは1に設定します。bitこのビットはSPIの名前が付いていますが、I2C通信の場合は以下の設定になります。入力回路部は通常用に設定する突然「SMBus」という用語が出てきました。これはI2C通信の派生仕様の通信方法になります。通常のI2C通信の場合は0に設定します。bitこのビットは、最後に送受信し値がデータだったのかアドレスだったのかの状態を示すビットです。I2C通信でマスターのプログラムを作成する場合、データの送受信は自分で管理しますので、このビットを見ることはないと思います。このビットの値を調べると以下のことがわかります。このビットは状態を示すビット(=読み取りビット)ですので値を設定しても無効です。bitこのビットは、ストップコンディションが検出されたかどうかを示すビットです。I2C通信でマスターのプログラムを作成する場合、データの送受信は自分で管理しますので、このビットを見ることはないと思います。このビットの値を調べると以下のことがわかります。このビットは状態を示すビット(=読み取りビット)ですので値を設定しても無効です。bitこのビットは、スタートコンディションが検出されたかどうかを示すビットです。I2C通信でマスターのプログラムを作成する場合、データの送受信は自分で管理しますので、このビットを見ることはないと思います。このビットの値を調べると以下のことがわかります。このビットは状態を示すビット(=読み取りビット)ですので値を設定しても無効です。informationこのビットはデータ送信中かどうかを示すビットです。I2C通信のマスター場合は以下の意味になります。I2C通信でデータを送受信する場合、送受信が終わったかどうかを判定する方法は別にありますので、通常のI2C通信ブログラムを作る場合、このビットを見ることはそれほどないと思います。このビットは状態を示すビット(=読み取りビット)ですので値を設定しても無効です。bitこのビットはI2C通信でもアドレスを10ビットモードで使用しているときのアドレス状況を示すビットです。10ビットアドレスは使用しませんので説明は省略します。このビットは状態を示すビット(=読み取りビット)ですので値を設定しても無効です。bitこのビットは、データ送受信する一時的なデータ保存場所にデータがあるかないかの状態を示すビットです。I2C通信でデータを送受信する場合、送受信が終わったかどうかを判定する方法は別にありますので、通常のI2C通信ブログラムを作る場合、このビットを見ることはそれほどないと思います。このビットは状態を示すビット(=読み取りビット)ですので値を設定しても無効です。データは残っていない(データ送信完了)補足として、先ほどのR/Wビットでもデータ送受信完了はわかりますが、BFビットはACK/NACK信号は含んでいません。1ビットのACK/NACK信号」の送受信が終わったかどうかがわかります。BFは「8ビットのデータの送受信」(ACK/NACK信号は含まない)が終わったかどうかがわかります。一般的なI2C通信のマスターモードの場合、SSPxSTATレジスタは以下の設定のどちらかになります。SSP1モジュールの設定を行います。設定項目が多いため、他にもう2つのレジスタ(SSP1CON2とSSP1CON3)があります。レジスタの構成は以下のようになっています。それぞれの設定を詳しく説明します。bitこの後の説明で出てきますが、I2C通信でデータを送信する場合、特定のレジスタに送信するデータ(値)を代入するとPICマイコンがそのデータを送信してくれます。具体的には、例えば0x12を送信したい場合、以下のように「SSP1BUF」というレジスタに0x12を代入するだけでPICマイコンがクロック信号とデータ信号を制御してI2C通信を行ってくれます。0x12;データを複数バイト送信したい場合、SSP1BUFに代入した値が送信完了になるまで、次の値はSSP1BUFに代入できません。このWCOLビットは、SSP1BUFに代入した値が送信完了したかどうかの状況を示します。このビットの値を調べると以下のことがわかります。このビットは状態を示すビット(=読み取りビット)ですので値を設定しても無効です。送信完了したかどうかは別の方法でチェックしますので、実践編ではこのビットはチェックしません。bitI2C通信でデータを受信する場合、受信したデータはSSP1BUFレジスタに格納されています。複数バイトを受信する場合、受信するレジスタはSSP1BUFの1バイトしかありませんので、この値を取得しないうちに次のデータを受信すると、取得できないデータが出てきてしまいます。このビットは、SSP1BUFに受信したデータが保持されているのにも関わらず、次のデータを受信してしまったかどうか(これをオーバーフローと呼びます)の状況を示します。このビットの値を調べると以下のことがわかります。このビットは状態を示すビット(=読み取りビット)ですので値を設定しても無効です。実践編ではこのビットはチェックしない方法でプログラムを作成します。bitこのビットは非常に重要です。このビットでSSP1モジュールを有効にするかどうかの設定をします。SSP1モジュールはSPI通信やI2C通信のマスター、スレーブモードをサポートしています。このビットでSSP1モジュールを有効にした場合、この後に出てくるSSPMビットで通信の種類を選択します。以下の意味になります。SPI/I2C通信を有効にする。SPI/I2C通信を無効にする。bitこのビットはI2C通信のマスターでは設定する必要はありません。I2C通信のスレーブの場合は、このビットでクロック信号制御(クロックストレッチと呼ばれています)を行います。実践編ではマスターで使用しますので説明を省略します。PICマイコンがマスターになってI2C通信を行う場合は0を設定しておけばOKです。bit先ほどのSSPENでSSP1モジュールを有効にした場合、通信の種類はどれにするか、このビットで選択します。一般的なI2C通信(マスター)の場合は「1000」を選択してください。以下の意味になります。SPI通信マスター(クロック信号は周波数の4分の1を使用)ということで、一般的なI2C通信でマスターとなる場合、以下の設定になります。0x28;「SSP1CON3」レジスタSSP1CON2レジスタを飛ばして、SSP1CON3レジスタです。SSP1CON2レジスタは、実際にI2C通信のデータ通信制御(スタート/ストップコンディションの制御、データ送受信制御)を行うレジスタです。機能設定はSSPCON3に続きます。(なぜそうなっているのかは謎ですが...)SSP1CON3レジスタの構成は以下のようになっています。それぞれの設定を詳しく説明します。bitI2C通信では8ビットデータを送信または受信したあと、1ビットのACK/NACK情報をやりとりします。このビットはそのACK/NACK信号のやり取り中かどうかの状況を示します。状態を示すビットですので、設定は無効です。以下の意味になります。bitPCIEとSCIEは同じような内容の設定になりますのでまとめて説明します。I2C通信では開始はスタートコンディション、終了はストップコンディションの状態を作ります(クロック信号が1の時にデータ信号を変えてしまう)。PICマイコンをI2C通信のスレーブとして動作させる場合、通信の開始と終了を監視する必要がありますが、プログラムでチェックするのは大変です。そこで、スタート/ストップコンディションが発生した場合、割り込み信号生成してくれる機能があります。これらのビットはその割り込み信号を発生するかどうかの設定です。以下の意味になります。割り込み信号を発生させない実践編ではPICマイコンはマスターですので、割り込みは設定しません。bitこのビットはスレーブの時に有効なビットで、受信データのレジスタを上書き許可するかどうかの設定になります。実践編ではマスターで使用しますので説明は省略します。マスターの場合は設定は無効になりますので、0を設定します。bitI2C通信ではデータを送信する際、データ信号線にデータをセットして、クロック信号を変化させてデータを読み取ってもらいます。具体的には、データ信号をセット、クロックを立ち上げて、クロックを立ち下げて次のデータをセット、という流れです。データ受信側は、クロック信号が変化した瞬間にデータを読み取ることは難しく、クロック信号が変化したことを確認してからデータを読み取ります。そのため、クロック信号を立ち上げて、次にクロック信号を立ち下げたあとに次のデータをセットしますが、データ読み取りがのんびりしているスレーブもあるかもしれません。その場合は、データを保持しておく時間をちょっと長めにしてあげることが必要になるケースもあります。このビットは、クロック信号を立ち下げてから、どのぐらいの時間データ信号を保持しておくかを設定します。以下の意味になります。クロック信号を立ち下げてから、少なとも100nsはデータを保持する実践編のプログラムのクロック速度は100kHzで作成します。クロック信号の速度が100kHzというのはかなりゆっくりです。この設定は100nsでも問題ありませんので、0に設定することにします。bitこのビットは、PICマイコンをスレーブにした際のデータ信号の衝突(他のI2Cモジュールと同時にデータ通信を行ってしまう)を検出するかどうかの設定です。マスターの場合設定は無効になりますので説明は省略します。bitこれらのビットは、I2C通信のスレーブの時に有効な設定で、マスターでは関係ありませんので詳しい説明は省略します。スレーブモードの時に、アドレスを受信してそのアドレスが自分のアドレスであった場合や、データを受信した場合、何か処理する必要があります。マスターは次々にデータを送ってきますが、そのデータ処理が追いつかない場合、マスターに「ちょっと待ってて」と知らせることができます。その「ちょっと待ってて」をするかどうかの設定になります。マスターの場合は設定は無効になりますので、0を設定しておきます。いうことで、一般的なI2C通信でマスターとなる場合、以下の設定になります。0x00;「SSP1ADD」レジスタこのレジスタは、I2Cのマスターとスレーブで意味が異なります。マスターの場合はクロック信号の速度設定、スレーブの場合はI2Cスレーブアドレスを設定します。マスターの場合、クロック信号の速度は以下の式で計算される値になります。4)実践編では、PICマイコンの動作周波数は4MHz、I2Cのクロック信号の速度はスタンダードモードの100kHzにします。9ということで、SSP1ADDの値を9に設定すると、I2Cクロック周波数は100kHzになります。この値はPICマイコンの動作周波数とI2Cクロック周波数で決まりますので、一般的な設定というものはなく、それぞそれのケースで計算することになります。実践編では以下のように設定します。0x09;I2C通信機能設定まとめ今までの設定をまとめます。I2C通信のマスターでクロック信号の速度が100kHzの場合、以下の設定になります。以上でI2C通信の設定(MSSP1モジュールの設定)が終わりましたので、I2C通信の関数を作っていきます。以前の記事で、I2C通信でデータ通信を行う例として、マスターからスレーブに2バイトのデータを送信するケースの通信手順を説明しました。I2C通信のデータ送受信は、必ずスタートコンディションから始まり、ストップコンディションで終わります。スタートコンディションの後は必ずスレーブアドレス(+読み書き指定)の8ビットデータ送信を行います。選択されたスレーブは、そのスレーブアドレスデータに対してACK信号(了解信号)を返信します。そのあとのデータ送受信についてはスレーブごとに異なります。そこで、色々なスレーブに対応できるように、以下のようにそれぞれのやり取りを関数化しておくことにします。関数名は「i2cProtocol」で始まる名前にして、その後はそれぞれの信号制御の名前にしてみました。注意点が2点あります。一つ目は、最初のスレーブアドレス送信とその後のデータ送信は目的は異なるものの、処理としては8ビットのデータ送信です。そのため、スレーブアドレス送信をする関数とデータ送信をする関数というように2つの関数は作成せずに、8ビットデータを送信する関数として作成します。二つ目は、上のデータ通信はマスターからスレーブに2バイトのデータを送信する例です。実際にはスレーブからマスターにデータを送信するモジュール(実践編で使用する温度センサなど)もあります。スレーブからマスターにデータ送信する関数は温度センサのプログラムを説明する際に作成することにします。I2C通信制御レジスタ(SSP1CON2)PICマイコンでI2C通信でデータ通信を実行するには、SSP1CON2レジスタを制御します。そこで、最初にSSP1CON2レジスタの説明をします。bitこのビットはPICマイコンがスレーブの際の設定ですので詳細な説明は省略します。I2C通信のスレーブアドレス0x00は特殊なアドレスとして定義されていて、マスターからスレーブアドレスとして0x00が指定された場合のスレーブの挙動を設定するビットです。bitこのビットは、ACK/NACKの状態を表します。8ビットのデータ送信を行なった後、送信先から「了解信号」、つまりACK/NACK信号が返信されてきますが、その返信されてきた信号がACKかNACKのどちらかかを示すビットです。以下の意味になります。bit先ほどの「ACKSTAT」ビットは、ACK/NACKの状態を示すビットでした。このビットは、ACK/NACKを返信するビットです。8ビットのデータ受信を行なった後、問題なく受信できた場合は送信先に対して「了解信号」、つまりACK信号を返信する必要があります。返信する信号を設定するビットです。注意点としては、このビットはあくまでACK/NACKの信号を設定するビットです。実際にACK/NACKの返信は次の「ACKEN」ビットを操作することにより行います。以下の意味になります。bitこのビットを制御することにより、先ほどのACKDTビットで指定したACK/NACK信号を生成します。以下の意味になります。このビットを1にすると、SDA信号とSCL信号を制御してACKDTで指定したACK/NACK信号を生成します。bitこのビットは、データ受信を行います。このビットを操作してデータ受信を行う関数は、温度センサの制御プログラムを作成する際に出てきます。今回の記事で作成する関数には出てきませんが、後ほど使用しますのでここで確認しておきます。以下の意味になります。このビットを1にすると、スレーブから返信されてくる8ビットデータを受信します。bitこのビットを操作することにより、ストップコンディションを生成します。以下の意味になります。このビットを1にすると、SCL信号とSDA信号を制御してストップコンディションを生成します。bit今までの説明では、I2C通信はスタートコンディションから始まり、ストップコンディションで終わる、と説明してきました。一般的な通信はこのような通信方法になりますが、例外があります。マスターからスレーブにデータを送信して、その後スレーブからマスターにデータを返信する場合、マスターからスレープにデータを送信した後、いったん通信の仕切り直しをします。その仕切り直しとして「リピートスタートコンディション」という信号を発生させます。この信号はスタートコンディションと同じですが、スタートコンディションとは別に用意されています。このビットを操作することにより、リピートスタートコンディションを生成します。以下の意味になります。このビットを1にすると、SCL信号とSDA信号を制御してリピートスタートコンディションを生成します。bitこのビットを操作することにより、スタートコンディションを生成します。以下の意味になります。このビットを1にすると、SCL信号とSDA信号を制御してスタートコンディションを生成します。スタートコンディション生成を行なっていない時、このビットは0になります以下に、これらのレジスタを制御してI2C通信の制御関数を作成します。スタートコンディション関数スタートコンディションを生成するには、SSP1CON2レジスタのSENビットを1にします。SENに1を設定すると、(勝手に)PICマイコンがSCL信号とSDA信号を制御してスタートコンディションを生成してくれます。SENを1にしてからPICマイコンがスタートコンディションの生成を終えるまで、待ってあげる必要があります(待たずに割り込みで処理する方法もありますが、処理が難しくなるので実践編では待つことにします)。PICマイコンはスタートコンディションの生成を終えると、「SSP1IF」というレジスタを1にしてくれます。スタートコンディションを生成するには以下の手順になります。SSP1IFを0にしておくSSP1CON2のSENを1にするSSP1IFが1になるのを待つ(=PICマイコンがスタートコンディションの生成を終えるのを待つ)SSP1IFを0に戻しておくこれをプログラムにすると以下のようになります。この関数は引数、返り値はありません。ストップコンディション関数ストップコンディションの生成は、スタートコンディションを同様の手順になります。SSP1IFを0にしておくSSP1CON2のPENを1にするSSP1IFが1になるのを待つ(=PICマイコンがスタートコンディションの生成を終えるのを待つ)SSP1IFを0に戻しておくこれをプログラムにすると以下のようになります。この関数は引数、返り値はありません。データ送信関数データ送信は「SSP1BUF」レジスタに送りたいデータを代入するだけで、あとはPICマイコンがSCL信号とSDA信号を制御してデータ送信してくれます。スタート/ストップコンディションと同様に、データ送信が終わるまで待ってあげる必要がありますので、SSP1IFが1になるのを待ちます。データ送信の手順は以下のようになります。SSP1IFを0にしておくSSP1BUFに送りたいデータをセットするSSP1IFが1になるのを待つ(=PICマイコンがスタートコンディションの生成を終えるのを待つ)SSP1IFを0に戻しておくこれをプログラムにすると以下のようになります。この関数では送信データを引数にしています。ACK/NACK状態確認関数Ack/Nackの状態は、SSP1CON2レジスタのACKSTATビットにセットされます。ACKの場合が0、NACKの場合が1です。SSP1CON2bits.ACKSTATの値を調べればすぐにわかるのですが、一連のI2C通信関数を作成していますので、Ack/Nack状態確認も関数にします。意味はありませんが、ACKを0x00、NACKを0xFFに定義して、その値を返り値にすることにしました。ackStatus;}以上で必要なI2C通信を行う関数ができました。