PIC16F1619には、Master Synchronous Serial Port (MSSP) があり、MSSP を使うと周辺機器と簡単にシリアル通信を行うことができます。MSSPは、SPIとI2Cという2種類の方式をサポートしていまが、ここでは、I2Cを利用したLCD表示器とのインターフェースだけを取り上げます。このため、I2C マスターモードが対象です。
Inter-Integrated Circuit(I2C)バスは、マスターデバイスが通信を開始するマスター/スレーブ環境で通信します。スレーブデバイスは、アドレス指定によって制御されます。
I2Cバスは2つの信号接続を指定します。
図24-11に、I2Cモードで動作しているときのMSSPモジュールのブロック図を示します。
注1:SDAピンの選択は、入力と出力を同一にします。
注2:SCLピンの選択は、入力と出力を同一にします。
SCLとSDAの接続はどちらも双方向のオープンドレインラインで、それぞれに電源電圧からのプルアップ抵抗が必要です。ラインを接地することは論理「0」、ラインをフロートさせることは論理「1」と定められています。
I2Cバスは、1つ以上のマスターデバイスと1つ以上のスレーブデバイスで構成され、これらデバイスには、4つの潜在的な動作モードがあります。
通信を始めるには、マスターデバイスがマスター送信モードで開始します。マスターは、スタートビットに続けて、通信先スレーブのアドレスバイトを送信。この後に、R/Wビットが続きます。このビットで、マスターがスレーブデバイスへデータを送信するか、データを受信するかが決定されます。
目的のスレーブがバス上に存在する場合、そのデバイスは、ACKとも呼ばれる Acknowledgeビットで応答します。その後、マスターは送信モードまたは受信モードのいずれかで継続し、スレーブは要求された受信モードまたは送信モードで継続します。
スタートビットは、SCLラインが「1」に保持されている間にSDAラインを「1」から「0」へ遷移させつることで示されます。アドレスバイトとデータバイトがその最上位ビット(MSb)から順に送信されます。R/Wビットは、マスターがスレーブからデータを読み取るときに論理「1」として送信され、スレーブにデータを書き込むときに論理「0」として送信されます。
アクノレッジビット(ACK)は負論理信号なので、SDAラインを「0」に保持すると、スレーブデバイスが送信データを受信し、次の受信準備もできていることを送信側に示します。
データビットの変更は常にSCLラインが「0」の時に実施されます。SCLラインが「1」に保持されている間に発生する遷移は、スタートビットとストップビットを示すために使用されます。
マスターがスレーブに書き込むつもりである場合、マスターは繰り返し1バイトのデータを送信し、スレーブは各バイトの後にACKビットで応答します。この例では、マスターデバイスはマスター送信モードにあり、スレーブはスレーブ受信モードにあります。
マスターがスレーブから読み取るつもりの場合、マスターはスレーブからデータのバイトを繰り返し受信し、各バイトの後にACKビットで応答します。この例では、マスターデバイスはマスター受信モードで、スレーブはスレーブ送信モードです。
通信されたデータの最後のバイトで、マスターデバイスはストップビットを送信して送信を終了できます。マスターデバイスが受信モードの場合、最後のACKビットの代わりにストップビットを送信します。ストップビットは、SCLラインが「1」に保持されている間のSDAラインの「0」から「1」への遷移によって示されます。
場合によっては、マスターがバスの制御を維持し、別の送信を再開したいことがあります。その場合、マスターデバイスは、受信モードのときに、ストップビットまたは最後のACKビットの代わりに別のスタートビットを送信できます。
I2Cバスは3つのメッセージプロトコルを指定します。
1つのデバイスが論理「1」を送信している、またはラインをフロートさせ、2番目のデバイスが論理ゼロを送信している、またはラインを「0」に保持している場合、最初のデバイスはラインが論理「1」ではないことを検出できます。この検出をSCLラインで使用する場合、クロックストレッチと呼ばれます。クロックストレッチは、スレーブデバイスにデータのフ「0」を制御するメカニズムを提供します。この検出がSDAラインで使用される場合、アービトレーションと呼ばれます。アービトレーションにより、一度に通信するマスターデバイスは1つだけになります。
スレーブデバイスがデータの処理を完了していない場合、クロックストレッチのプロセスを通じて、より多くのデータの転送が遅延する可能性があります。アドレス指定されたスレーブデバイスは、ビットを受信または送信した後、SCLクロックラインを「0」に保持する場合があり、継続する準備がまだ整っていないことを示します。スレーブと通信しているマスターは、次のビットを転送するためにSCLラインを上げようとしますが、クロックラインがまだ解放されていないことを検出します。SCL接続はオープンドレインであるため、スレーブは通信を継続する準備ができるまでそのラインを「0」に保持することができます。
クロックストレッチにより、トランスミッターに追いつけないレシーバーが着信データのフ「0」を制御できます。
各マスターデバイスは、スタートビットとストップビットについてバスを監視する必要があります。デバイスは、バスがビジーであることを検出すると、バスがアイドル状態に戻るまで新しいメッセージを開始できません。
ただし、2つのマスターデバイスがほぼ同時に送信を開始しようとする場合があります。これが発生すると、仲裁のプロセスが始まります。各トランスミッターは、SDAデータラインのレベルをチェックし、検出することを期待しているレベルと比較します。2つのレベルが一致しないことを確認する最初のトランスミッターは、調停を失い、SDAラインでの送信を停止する必要があります。
たとえば、1つのトランスミッターがSDAラインに論理「1」を出力(フロートさせる)し、2番目のトランスミッターが論理「0」を出力(「0」にプルダウン)した場合、結果はSDAラインは「0」になります。最初のトランスミッターは、回線のレベルが予想とは異なることを検知し、別のトランスミッターも通信していると認知します。
この違いを最初に検知したトランスミッターは、アービトレーションを失い、SDAラインの駆動を停止する必要があるトランスミッターです。このトランスミッターがマスターデバイスでもある場合は、SCLラインの駆動も停止する必要があります。次に、再送信をする前に、ストップビットを監視できます。その間、SDAラインの期待されるレベルと実際のレベルの違いを検出しなかった他のデバイスは、元の送信を続行します。このように、他のトランスミッターがメッセージを妨害しないので、送信が期待どおりに伝送され問題は発生しません。
マスターが複数のスレーブをアドレス指定する場合、スレーブ送信モードも調停できますが、これはあまり一般的ではありません。
2つのマスターデバイスがアドレスステージで2つの異なるスレーブデバイスにメッセージを送信している場合、下位のスレーブアドレスを送信しているマスターが常に調停に勝ちます。2つのマスターデバイスが同じスレーブアドレスにメッセージを送信し、アドレスが複数のスレーブを参照する場合がある場合、アービトレーションプロセスはデータステージに進む必要があります。
仲裁は通常非常にまれに発生しますが、適切なマルチマスターサポートに必要なプロセスです。
すべてのMSSP I2C通信はバイト指向で、MSbが最初にシフトアウトされます。6つのSFRレジスタと2つの割り込みフラグが、モジュールとPICマイクロコントローラーおよびユーザーソフトウェアとのインターフェースをとります。SDAおよびSCLの2つのピンは、モジュールによって実行され、他の外部I2Cデバイスと通信します。
I2Cのすべての通信は9ビット単位で行われます。バイトはマスターからスレーブに、またはその逆に送信され、その後に返されるACKビットが続きます。SCLラインの8番目の立ち下がりエッジの後、SDAにデータを出力するデバイスはそのピンを入力に変更し、次のクロックパルスでACK値を読み込みます。
クロック信号SCLはマスターによって供給されます。データはSCL信号が「0」の間に変化し、クロックの立ち上がりエッジでサンプリングされて有効です。SCLラインが「1」のときのSDAラインの変化は、以下で説明するバス上の特別な状態を定義します。
I2C通信の説明には、I2Cに固有の定義を持つ言語と用語があります。その単語の使用法は以下に定義されており、このドキュメントの残りの部分では説明なしに使用される場合があります。この表は、Philips I2C仕様に基づいています。
用語 | 説明文 |
---|---|
トランスミッター | データをバスにシフトアウトするデバイス |
レシーバー | バスからデータをシフトインするデバイス |
マスター | 転送を開始し、クロック信号を生成し、転送を終了するデバイス |
スレーブ | マスターによってアドレス指定されたデバイス |
マルチマスター | データ転送を開始できる複数のデバイスを備えたバス |
アービトレーション Arbitration (仲裁) | 一度に1つのマスターのみがバスを制御するよう調整する手順。調整がつくと選ばれたメッセージは破損しないことが保証される |
同期 | バス上の2つ以上のデバイスのクロックを同期する手順 |
アイドル | マスターがバスを制御しておらず、SDAとSCLラインの両方が「1」の状態 |
アクティブ | 1つ以上のマスターデバイスがバスを制御している状態 |
指定スレーブ | 一致するアドレスを受信し、マスターによってアクティブに通信されているスレーブデバイス |
一致アドレス | スレーブに送信されるSSPxADDに格納されている値と一致するアドレスバイト |
書込み要求 | スレーブは、R/Wビットがクリアされた一致アドレスを受信し、データを入力する準備ができる状態 |
読出し要求 | マスターは、R/Wビットをセットしたアドレスバイトを送信し、スレーブにデータを送信するよう要求する。リスタートまたはストップまでのすべてのバイトが要求されたデータである |
クロックストレッチ | バス上のデバイスがSCLを「0」に保持して通信を停止した状態 |
バス衝突 | モジュールがSDAラインに「1」状態を出力しているときに、モジュールが「0」を検知した状態 |
SSPENビットがセットされ、I2Cモードが選択されると、SCLおよびSDAピンは強制的にオープンドレインになります。これらのピンのTRISビットは、ユーザーがプログラムにより「入力」に設定する必要があります。
PPS機能により、SDAおよびSCLは任意のピンに割り当てることができます。SDA入力はSSPDATPPSレジスタ、SCL入力は、SSPCLKPPSレジスタで、出力は、RxyPPSレジスタで選択します。これらの機能は双方向性のため、ユーザーは、各機能の入出力の両方が同じピンに配置されるようプログラムにする必要があります。
SDAピンのホールドタイムは、SSPxCON3レジスタのSDAHTビットで選択します。ホールドタイムは、SCLの立ち下がりエッジ後のSDAが有効に保持される時間です。SDAHTビットを設定すると、最小300 ns以上のホールドタイムが選択され、大きな容量性のバスで効果のあります。
I2C仕様では、スタートビットをSCLラインが「1」の間にSDAが「1」から「0」に遷移すると定義しています。スタートビットは常にマスターによって生成され、アイドル状態からアクティブ状態へのバスの遷移を示します。図24-12は、スタートビットとストップビットの波形を示しています。
モジュールがSDAラインを「0」にアサートする前に「0」をサンプリングすると、Start条件でバス衝突が発生する可能性があります。これはI2C仕様に準拠していません。これは、スタートでバス衝突が発生する可能性がないことを示しています。
ストップビットは、SCLラインが「1」の間にSDAラインが「0」から「1」に遷移することです。
注:ストップが有効になる前に、少なくとも1つのSCL「0」タイムが必要です。があるため、SCLラインが「1」の間にSDAラインが「0」になり、再び「1」になる場合は、スタートビットとして検出されます。
図24-12:
リスタートは、ストップが有効な場合はいつでも有効です。現在の転送の終了後にバスを保持したい場合、マスターはリスタートを発行します。スレーブにとってリスタートは、スタートと同じ働きをし、すべてのスレーブロジックをリセットして、アドレスバイトを入力する準備をします。マスターは、同じスレーブまたは別のスレーブをアドレス指定することができます。図24-13は、リスタートビットの波形を示しています。
10ビットアドレス指定スレーブモードでは、マスターがアドレス指定されたスレーブからデータをクロック出力するには、リスタートが必要です。スレーブが完全にアドレス指定され、上位アドレスバイトと下位アドレスバイトの両方が一致すると、マスターはリスタートとR/Wビットが設定された上位アドレスバイトを発行できます。その後、スレーブロジックはクロックを保持し、データをクロックアウトする準備をします。
10ビットモードでR/Wクリアとの完全一致の後、以前の一致フラグが設定され、ストップビット、R/Wクリアを伴う上位アドレス、または上位アドレス一致が失敗するまで維持されます。
SSPxCON3レジスタのSCIEおよびPCIEビットを使用すると、通常この機能をサポートしないスレーブモードでの割り込みの生成が可能になります。スタートおよびストップビット検出時の割り込みがすでに有効になっているスレーブモードでは、これらのビットは効果がありません。
I2Cスタートおよびストップビット
I2Cで転送されたバイトの9番目のSCLパルスは、ACK専用です。これにより、SDAラインを「0」にプルダウンすることにより、受信デバイスがトランスミッターに応答することができます。トランスミッターは、応答をシフトするために、この時間中にラインの制御を解放する必要があります。アクノレッジ(ACK)はアクティブ「0」信号であり、SDAラインを「0」にすると、デバイスが送信データを受信し、さらに受信する準備ができていることをトランスミッターに示します。
ACKの結果は、SSPxCON2レジスタのACKSTATビットに格納されます。
スレーブソフトウェアでは、AHENおよびDHENビットが設定されている場合、ユーザーはトランスミッターに返送されるACK値を設定できます。SSPxCON2レジスタのACKDTビットは、応答を決定するためにセット/クリアされます。
SSPxCON3レジスタのAHENおよびDHENビットがクリアされている場合、スレーブハードウェアはACK応答を生成します。
スレーブがACKを送信しない特定の条件があります。バイトの受信時に、SSPxSTATレジスタのBFビットまたはSSPxCON1レジスタのSSPOVビットがセットされている場合。
モジュールがアドレス指定されると、バス上のSCLの8番目の立ち下がりエッジの後に、SSPxCON3レジスタのACKTIMビットが設定されます。ACKTIMビットは、アクティブバスのACK時間を示します。ACKTIMステータスビットは、AHENビットまたはDHENビットが有効な場合にのみアクティブになります。
マスターモードを有効にするには、SSPxCON1レジスタの適切なSSPMビットを設定およびクリアし、SSPENビットを設定します。マスターモードでは、SDAおよびSCKピンを入力として設定する必要があります。MSSPペリフェラルハードウェアは、ピンを「0」に駆動する必要がある場合、出力ドライバーTRIS制御をオーバーライドします。
マスター動作モードは、スタートビットとストップビットの検出時の割り込み生成によってサポートされます。ストップ(P)およびスタート(S)ビットは、リセットから、またはMSSPモジュールが無効になるとクリアされます。I2Cバスの制御は、Pビットが設定されているとき、またはバスがアイドル状態のときに行われます。
ファームウェア制御マスターモードでは、ユーザーコードはすべてのI2Cバス操作をスタートおよびストップビット条件検出に基づいて実行します。このモードでは、スタートビットとストップビットの検出が唯一のアクティブな回路です。他のすべての通信は、SDAおよびSCLラインを直接操作するユーザーソフトウェアによって行われます。
次のイベントにより、SSP割り込みフラグビットSSPxIFが設定されます(有効になっている場合はSSP割り込み)。
マスターデバイスは、すべてのシリアルクロックパルスとスタートおよびストップビットを生成します。転送は、ストップビットまたはリピートスタートビットで終了します。リピートスタートビットは次のシリアル転送の開始でもあるため、I2Cバスは解放されません。
マスタートランスミッターモードでは、シリアルデータはSDAを通じて出力され、SCLはシリアルクロックを出力します。送信される最初のバイトには、受信デバイスのスレーブアドレス(7ビット)と読み取り/書き込み(R/W)ビットが含まれます。この場合、R/Wビットは論理「0」になります。シリアルデータは一度に8ビット送信されます。各バイトが送信された後、Acknowledgeビットが受信されます。シリアル転送の開始と終了を示すスタートビットとストップビットが出力されます。
マスター受信モードでは、送信される最初のバイトには、送信デバイスのスレーブアドレス(7ビット)とR/Wビットが含まれます。この場合、R/Wビットは論理「1」になります。したがって、送信される最初のバイトは7ビットのスレーブアドレスで、その後に受信ビットを示す「1」が続きます。シリアルデータはSDA経由で受信され、SCLはシリアルクロックを出力します。シリアルデータは一度に8ビット受信されます。各バイトが受信されると、Acknowledgeビットが送信されます。スタートビットとストップビットは、送信の開始と終了を示します。
ボーレートジェネレータを使用して、SCLのクロック周波数出力を設定します。セクションを参照
詳細については、24.7「ボーレートジェネレータ」を参照してください。
注1:MSSPモジュールは、I2Cマスターモードで構成されている場合、イベントのキューイングを許可しません。たとえば、ユーザーはスタートビットを開始して、スタートビットが完了する前にSSPxBUFレジスタに書き込んで送信を開始することはできません。この場合、SSPxBUFへの書き込みは行われず、WCOLビットが設定され、SSPxBUFへの書き込みが発生しなかったことを示します。
2:マスターモードでは、SEN / PENビットがクリアされて生成が完了すると、スタート/ストップビット検出がマスクされ、割り込みが生成されます。
クロックアービトレーションは、マスターが、受信、送信、またはリピートスタート/ストップの条件の間にSCLピンを解放すると発生します(SCLは「1」にフロートできます)。SCLピンが「1」にフロートできる場合、ボーレートジェネレータ(BRG)は、SCLピンが実際に「1」にサンプリングされるまでカウントを停止します。SCLピンが「1」でサンプルされると、ボーレートジェネレータにSSPxADD <7:0>の内容が再ロードされ、カウントを開始します。これにより、外部デバイスによってクロックが「0」に保持されている場合、SCLの「1」時間は常に少なくとも1つのBRG「0」ルオーバーカウントになります(図24-25)。
図24-25:クロックアービトレーションによるボーレートジェネレーターのタイミング
注:イベントのキューイングは許可されていないため、スタートビットが完了するまで、SSPxCON2の下位5ビットへの書き込みは無効です。
スタート、リスタート、停止、受信、または送信シーケンスの進行中にユーザーがSSPxBUFを書き込むと、WCOLビットが設定され、バッファーの内容は変更されません(書き込みは行われません)。WCOLビットが設定されている場合は常に、モジュールがアイドル状態ではないときにSSPxBUFでアクションが試行されたことを示します。
スタートビット(図24-26)を開始するには、ユーザーはSSPxCON2レジスタのスタートイネーブルビット、SENビットをセットします。SDAピンとSCLピンが「1」でサンプリングされると、baudレートジェネレータにSSPxADD <7:0>の内容がリロードされ、カウントが開始されます。ボーレートジェネレータ(TBRG)がタイムアウトしたときにSCLとSDAの両方が「1」でサンプリングされる場合、SDAピンは「0」に駆動されます。SCLが「1」のときにSDAが「0」に駆動される動作はスタートビットであり、SSPxSTAT1レジスタのSビットがセットされます。その後、ボーレートジェネレータにSSPxADD <7:0>の内容がリロードされ、カウントが再開されます。ボーレートジェネレータがタイムアウトすると(TBRG)、SSPxCON2レジスタのSENビットが自動的にクリアされます
図24-26:最初のスタートビットのタイミング
ハードウェアによって; baudレートジェネレータが一時停止され、SDAラインが「0」に保持され、スタートビットが完了します。
注1:スタートビットの初めに、SDAピンとSCLピンが既に「0」にサンプリングされている場合、またはスタートビットの間に、SDAラインが「0」に駆動される前にSCLラインが「0」にサンプリングされると、バス衝突が発生します。バス衝突割り込みフラグBCL1IFが設定され、スタートビットが中止され、I2Cモジュールがアイドル状態にリセットされます。
2:Philips I2C仕様では、スタート時にバス衝突は発生しないと規定されています。
SENビットへの書き込みはここで発生SDA = 1
SSPxCON2レジスタのRSENビットが「1」にプログラムされていて、マスタステートマシンがアクティブではない場合、リピートスタートビット(図24-27)が発生します。RSENビットがセットされると、SCLピンが「0」にアサートされます。SCLピンが「0」でサンプリングされると、baudレートジェネレータがロードされ、カウントを開始します。1つのボーレートジェネレータカウント(TBRG)でSDAピンが解放(「1」)されます。ボーレートジェネレータがタイムアウトすると、SDAが「1」でサンプリングされると、SCLピンがディアサートされます(「1」になります)。SCLが「1」でサンプリングされると、baudレートジェネレータがリロードされ、カウントを開始します。SDAとSCLは、1つのTBRGに対して高い値でサンプリングする必要があります。この動作の後に、SCLが「1」の間に1つのTBRGのSDAピン(SDA = 0)がアサートされます。SCLが「0」にアサートされます。これに続いて、SSPxCON2レジスタのRSENビットが自動化されます。
コールはクリアされ、ボーレートジェネレータはリロードされず、SDAピンは「0」のままになります。SDAピンとSCLピンでスタートビットが検出されるとすぐに、SSPxSTATレジスタのSビットがセットされます。SSPxIFビットは、ボーレートジェネレータがタイムアウトするまでセットされません。
注1:2:
他のイベントの進行中にRSENがプログラムされた場合、RSENは有効になりません。
リピートスタートビットの間のバス衝突は、次の場合に発生します。
図24-27:繰り返されるスタートビットの波形
SSPxCON2への書き込みはここで行われます
データバイト、7ビットアドレス、または10ビットアドレスの残りの半分の送信は、SSPxBUFレジスタに値を書き込むだけで実行できます。この動作により、Buffer FullフラグビットBFが設定され、baudレートジェネレータがカウントを開始して次の送信を開始できるようになります。SCLの立ち下がりエッジがアサートされた後、アドレス/データの各ビットがSDAピンにシフトアウトされます。SCLは、1つのボーレートジェネレータ「0」ルオーバーカウント(TBRG)の間、「0」に保持されます。SCLが「1」に解放される前に、データは有効である必要があります。SCLピンが「1」に解放されると、TBRGに対してその方法で保持されます。SDAピンのデータは、その期間、およびSCLの次の立ち下がりエッジ後のホールド時間の間、安定したままである必要があります。8番目のビットがシフトアウトされた後(8番目のクロックの立ち下がりエッジ)、BFフラグがクリアされ、マスターがSDAを解放します。これにより、アドレスが一致した場合、またはデータが正しく受信された場合、アドレス指定されているスレーブデバイスは、9番目のビット時間中にACKビットで応答できます。ACKのステータスは、9番目のクロックの立ち上がりエッジでACKSTATビットに書き込まれます。マスターがACKを受信すると、確認ステータスビットACKSTATがクリアされます。そうでない場合、ビットが設定されます。9番目のクロックの後、SSPxIFビットがセットされ、マスタークロック(ボーレートジェネレーター)は、次のデータバイトがSSPxBUFにロードされるまで中断され、SCLは「0」のまま、SDAは変更されません(図24-28)。クリアされます。そうでない場合、ビットが設定されます。9番目のクロックの後、SSPxIFビットがセットされ、マスタークロック(ボーレートジェネレーター)は、次のデータバイトがSSPxBUFにロードされるまで中断され、SCLは「0」のまま、SDAは変更されません(図24-28)。クリアされます。そうでない場合、ビットが設定されます。9番目のクロックの後、SSPxIFビットがセットされ、マスタークロック(ボーレートジェネレーター)は、次のデータバイトがSSPxBUFにロードされるまで中断され、SCLは「0」のまま、SDAは変更されません(図24-28)。
SSPxBUFへの書き込み後、7つのアドレスビットすべてとR/Wビットが完了するまで、SCLの立ち下がりエッジでアドレスの各ビットがシフトアウトされます。8番目のクロックの立ち下がりエッジで、マスターがSDAピンを解放し、スレーブがACKで応答できるようにします。9番目のクロックの立ち下がりエッジで、マスターはSDAピンをサンプリングして、アドレスがスレーブによって認識されたかどうかを確認します。ACKビットのステータスは、SSPxCON2レジスタのACKSTATステータスビットにロードされます。アドレスの9番目のクロック送信の立ち下がりエッジに続いて、SSPxIFがセットされ、BFフラグがクリアされ、SSPxBUFへの別の書き込みが行われるまでボーレートジェネレーターがオフになり、SCLを「0」に保持してSDAをフロートさせます。
送信モードでは、CPUがSSPxBUFに書き込むとSSPxSTATレジスタのBFビットがセットされ、8ビットすべてがシフトアウトされるとクリアされます。
送信がすでに進行しているときにユーザーがSSPxBUFを書き込んだ場合(つまり、SSPSRがまだデータバイトをシフトアウトしている場合)、WCOLビットが設定され、バッファーの内容は変更されません(書き込みは発生しません)。
次の送信の前に、WCOLをソフトウェアでクリアする必要があります。
送信モードでは、SSPxCON2レジスタのACKSTATビットは、スレーブがアクノウルエッジ(ACK = 0)を送信するとクリアされ、スレーブがACKしない(ACK = 1)とセットされます。スレーブは、アドレス(一般的な呼び出しを含む)を認識したとき、またはスレーブがデータを正しく受信したときに、Acknowl-edgeを送信します。
図24-28:I2Cマスターモードの波形(送信、7または10ビットアドレス)
マスターモード受信(図24-29)は、SSPxCON2レジスタの受信イネーブルビット、RCENビットをプログラミングすることで有効になります。
ボーレートジェネレータがカウントを開始し、「0」ルオーバーごとにSCLピンの状態が変化し(「1」から「0」/「0」から「1」)、データがSSPSRにシフトインされます。8番目のクロックの立ち下がりエッジの後、受信イネーブルフラグが自動的にクリアされ、SSPSRの内容がSSPxBUFにロードされ、BFフラグビットが設定され、SSPxIFフラグビットが設定され、ボーレートジェネレータが一時停止されます。カウントから、SCLを「0」に保持。MSSPは現在、アイドル状態にあり、次のコマンドを待機しています。バッファがCPUによって読み取られると、BFフラグビットは自動的にクリアされます。ユーザーは、SSPxCON2レジスタのAcknowledge Sequence Enable、ACKENビットを設定することにより、受信の最後にAcknowledgeビットを送信できます。
受信動作では、アドレスまたはデータバイトがSSPSRからSSPxBUFにロードされると、BFビットがセットされます。SSPxBUFレジスタが読み取られるとクリアされます。
受信動作では、8ビットがSSPSRに受信され、BFフラグビットが前の受信からすでに設定されている場合、SSPOVビットがセットされます。
受信がすでに進行しているときにユーザーがSSPxBUFを書き込んだ場合(つまり、SSPSRがまだデータバイトをシフトしている場合)、WCOLビットが設定され、バッファーの内容は変更されません(書き込みは行われません)。
注:MSENモジュールは、RCENビットが設定される前にアイドル状態でなければなりません。そうでない場合、RCENビットは無視されます。
図24-29:I2Cマスターモードの波形(受信、7ビットアドレス)
確認シーケンスを有効にするには、SSPxCON2レジスタの確認シーケンスイネーブルビット、ACKENビットを設定します。このビットが設定されると、SCLピンが「0」になり、Acknowledgeデータビットの内容がSDAピンに表示されます。ユーザーが確認を生成したい場合は、ACKDTビットをクリアする必要があります。そうでない場合、ユーザーは確認シーケンスを開始する前にACKDTビットを設定する必要があります。次に、ボーレートジェネレータが1「0」ルオーバー期間(TBRG)をカウントし、SCLピンがディアサートされます(「1」にプルされます)。SCLピンが「1」にサンプリングされると(クロックアービトレーション)、ボーレートジェネレータはTBRGをカウントします。次に、SCLピンが「0」にプルダウンされます。これに続いて、ACKENビットが自動的にクリアされ、ボーレートジェネレータがオフになり、MSSPモジュールがアイドルモードになります(図24-30)。
確認シーケンスの進行中にユーザーがSSPxBUFを書き込むと、WCOLビットが設定され、バッファーの内容は変更されません(書き込みは行われません)。
ストップビットは、SSPxCON2レジスタのストップシーケンスイネーブルビット、PENビットを設定することにより、送受信の最後にSDAピンでアサートされます。受信/送信の終わりに、9番目のクロックの立ち下がりエッジの後にSCLラインが「0」に保持されます。PENビットがセットされると、マスターはSDAラインを「0」にアサートします。SDAラインが「0」でサンプリングされると、baudレートジェネレータがリロードされ、「0」までカウントダウンします。ボーレートジェネレーターがタイムアウトすると、SCLピンが「1」になり、TBRG(ボーレートジェネレーターの「0」ルオーバーカウント)の1つ後に、SDAピンがディアサートされます。SCLが「1」の間にSDAピンが「1」でサンプルされると、SSPxSTATレジスタのPビットがセットされます。TBRGの後で、PENビットがクリアされ、SSPxIFビットがセットされます(図24-31)。
ストップシーケンスの進行中にユーザーがSSPxBUFを書き込むと、WCOLビットが設定され、バッファーの内容は変更されません(書き込みは行われません)。
図24-30:確認シーケンスの波形
注:TBRG = 1ボーレートジェネレータ期間。
ソフトウェアでクリア
注:TBRG = 1ボーレートジェネレータ期間。
図24-32:
仲裁
マルチマスターモードのサポートは、バスの調停によって実現されます。マスターがアドレス/データビットをSDAピンに出力するとき、マスターがSDAに「1」を出力すると、SDAを「1」にフロートさせ、別のマスターが「0」をアサートすることにより、調停が行われます。SCLピンが「1」にフロートすると、データは安定しているはずです。SDAの予想データが「1」で、SDAピンでサンプリングされたデータが「0」の場合、バス衝突が発生しています。マスターはバス衝突割り込みフラグBCL1IFを設定し、I2Cポートをそのアイドル状態にリセットします(図24-32)。
バス衝突が発生したときに送信が進行中だった場合、送信は停止され、BFフラグがクリアされ、SDAおよびSCLラインがディアサートされ、SSPxBUFに書き込むことができます。ユーザーがバス衝突割り込みサービスルーチンを処理し、I2Cバスが空いている場合、ユーザーはスタートビットをアサートすることで通信を再開できます。
バスの衝突が発生したときにスタート、リピートスタート、ストップ、または確認条件が進行中だった場合、条件は打ち切られ、SDAおよびSCLラインがディアサートされ、SSPxCON2レジスタのそれぞれの制御ビットがクリアされます。ユーザーがバス衝突割り込みサービスルーチンを処理し、I2Cバスが空いている場合、ユーザーはスタートビットをアサートすることで通信を再開できます。
マスターは引き続きSDAおよびSCLピンを監視します。ストップビットが発生すると、SSPxIFビットがセットされます。
SSPxBUFへの書き込みは、バスの衝突が発生したときにトランスミッターが中断した場所に関係なく、最初のデータビットからデータの送信を開始します。
マルチマスターモードでは、スタートビットとストップビットの検出時に割り込みが生成されるため、バスが空いているときを判断できます。I2Cバスの制御は、SSPxSTATレジスタのPビットが設定されているか、バスがアイドルでSビットとPビットがクリアされているときに取得できます。
送信および確認のためのバス衝突タイミング
スリープモードの間、I2Cスレーブモジュールはアドレスまたはデータを受信でき、アドレス一致または完全なバイト転送が発生すると、プロセッサをスリープ状態から復帰させます(MSSP割り込みが有効な場合)。
リセットはMSSPモジュールを無効にし、現在の転送を終了します。
マルチマスターモードでは、スタートビットとストップビットの検出時に割り込みを生成することで、バスが空いているときを判断できます。ストップ(P)およびスタート(S)ビットは、リセットから、またはMSSPモジュールが無効になるとクリアされます。S2xバスの制御は、SSPxSTATレジスタのPビットが設定されているとき、またはバスがアイドル状態で、SビットとPビットの両方がクリアされているときに行われます。バスがビジーの場合、SSP割り込みを有効にすると、ストップビットが発生したときに割り込みが生成されます。
マルチマスター動作では、調停についてSDAラインを監視して、信号レベルが期待される出力レベルであるかどうかを確認する必要があります。このチェックはハードウェアによって実行され、結果はBCL1IFビットに格納されます。
仲裁が失われる可能性のある状態は次のとおりです。
SCL = 0の間のデータ変更
SDAラインが別のソースによって「0」にプルされました
マスターによってリリースされたSDA
サンプルSDA。SCLが高い間、データはマスターによって駆動されるものと一致しません。
バス衝突が発生しました。
バス衝突割り込みの設定(BCL1IF)
SDA
SCL BCL1IF
スタートビットの間、次の場合にバス衝突が発生します。
a)SDAまたはSCLは、スタートビットの開始時に「0」でサンプリングされます(図24-33)。
b)SDAが「0」にアサートされる前にSCLが「0」にサンプリングされます(図24-34)。
スタートビットの間、SDAピンとSCLピンの両方が監視されます。
SDAピンがすでに「0」であるか、SCLピンがすでに「0」である場合、次のすべてが発生します。
スタートビットは、SDAピンとSCLピンがディアサートされることで始まります。SDAピンが「1」でサンプリングされると、baudレートジェネレータがロードされ、カウントダウンします。SDAが「1」のときにSCLピンが「0」でサンプリングされると、別のマスターがスタートビットの間にデータ「1」を駆動しようとしていると想定されるため、バス衝突が発生します。
図24-33:スタート状態中のバス衝突(SDAのみ)
このカウント中にSDAピンが「0」でサンプルされると、BRGがリセットされ、SDAラインが早期にアサートされます(図24-35)。ただし、SDAピンで「1」がサンプリングされた場合、SDAピンはBRGカウントの最後に「0」にアサートされます。ボーレートジェネレーターがリロードされ、ゼロまでカウントダウンします。この間にSCLピンが「0」としてサンプリングされた場合、バス衝突は発生しません。BRGカウントの最後に、SCLピンが「0」にアサートされます。
注意:
スタートビットの間にバス衝突が要因にならない理由は、2つのバスマスターが同時にスタートビットをアサートできないためです。したがって、一方のマスターは常に他方の前にSDAをアサートします。スタートビットに続く最初のアドレスを2つのマスターが調停できるようにする必要があるため、この条件はバスの衝突を引き起こしません。アドレスが同じである場合は、データ部分の繰り返しスタートまたはストップビットに継続するためにアービトレーションを許可する必要があります。
SENビットがセットされる前にSDAが「0」になります。BCL1IFを設定し、
SビットとSSPxIFセット
SDA = 0、SCL = 1。
SDA
SCL
SEN
BCL1IF
S
SSPxIF
SENを設定し、SDA = 1、SCL = 1の場合はスタートビットを有効にする
スタートビットの前にSDAが「0」にサンプリングされました。BCL1IFを設定します。
SDA = 0、SCL = 1であるため、SビットとSSPxIFがセット。
バスの衝突によりSENは自動的にクリアされました。SSPモジュールがアイドル状態にリセットされました。
SSPxIFおよびBCL1IFはソフトウェアによってクリアされます
SSPxIFおよびBCL1IFはソフトウェアによってクリアされます
図24-34:スタートビット中のバス衝突(SCL = 0)
リピーテッドスタートビットの間、次の場合にバス衝突が発生します。
a)SCLが低レベルから高レベルに変化すると、SDAで低レベルがサンプリングされます(ケース1)。
b)SDAが「0」にアサートされる前にSCLが「0」になり、別のマスターがデータ「1」を送信しようとしていることを示している(ケース2)。
ユーザーがSDAを解放し、ピンを「1」にフロートさせると、BRGにSSPxADDがロードされ、ゼロまでカウントダウンします。次にSCLピンがディアサートされ、「1」にサンプリングされると、SDAピンがサンプリングされます。
SDAが低い場合、バス衝突が発生しています(つまり、別のマスターがデータ「0」を送信しようとしています(図24-36))。SDAが「1」でサンプリングされると、BRGがリロードされ、カウントを開始します。BRGがタイムアウトする前にSDAが「1」から「0」に移行した場合、2つのマスターが同時にSDAをアサートできないため、バス衝突は発生しません。
BRGがタイムアウトする前にSCLが「1」から「0」になり、SDAがまだアサートされていない場合、バス衝突が発生します。この場合、リピートスタートビットの間に別のマスターがデータ「1」を送信しようとしています。図24-37を参照してください。
BRGタイムアウトの終了時にSCLとSDAの両方がまだ「1」である場合、SDAピンが「0」に駆動され、BRGがリロードされてカウントを開始します。カウントの最後に、SCLピンのステータスに関係なく、SCLピンが「0」に駆動され、リピートスタートビットが完了します。
図24-36:
次の場合、ストップビット中にバス衝突が発生します。
a)SDAピンがディアサートされて「1」にフロートされた後、BRGがタイムアウトした後(ケース1)、SDAが「0」にサンプリングされます。
b)SCLピンがディアサートされた後、SDAが「1」になる前にSCLが「0」にサンプリングされます(ケース2)。
ストップビットは、SDAが「0」にアサートされることで始まります。SDAが「0」でサンプリングされると、SCLピンはフロート状態になります。ピンが「1」でサンプリングされると(クロックアービトレーション)、ボーレートジェネレーターにSSPxADDがロードされ、ゼロまでカウントダウンします。BRGがタイムアウトした後、SDAがサンプリングされます。SDAが「0」でサンプリングされた場合、バス衝突が発生しています。これは、別のマスターがデータ「0」を駆動しようとしたためです(図24-38)。SDAが「1」にフロートされる前にSCLピンが「0」にサンプリングされると、バス衝突が発生します。これは、別のマスターがデータ「0」を駆動しようとした別のケースです(図24-39)。
図24-38:ストップビット中のバス衝突(ケース1)
表24-3:I2C動作に関連するレジスタの概要
凡例:— =未実装の場所。「0」として読み取られます。網掛けのセルは、I2CモードのMSSPモジュールでは使用されません。*ページは登録情報を提供します。
注1:
2:未実装。「1」として読み取られます。
PIC16(L)F1619のみ。
MSSPモジュールには、I2CとSPIマスターモードの両方でクロックを生成できるボーレートジェネレーターがあります。ボーレートジェネレータ(BRG)のリロード値は、SSPxADDレジスタ(レジスタ24-6)に格納されます。SSPxBUFへの書き込みが発生すると、ボーレートジェネレーターは自動的にカウントダウンを開始します。
所定の操作が完了すると、内部クロックは自動的にカウントを停止し、クロックピンは最後の状態のままになります。
図24-40の内部信号「Reload」は、SSPxADDからの値がBRGカウンターにロードされるようにトリガーします。これは、
モジュールクロックライン。リロード信号がアサートされるタイミングを決定するロジックは、MSSPが動作しているモードによって異なります。
表24-4は、命令サイクルとSSPxADDにロードされたBRG値に基づくクロックレートを示しています。
式24-1:
Fclock = | Fosc |
( SSPxADD + 1 ) x 4 |
図24-40:ボーレートジェネレーターのブロック図
注:I2Cのボーレートジェネレーターとして使用する場合、0x00、0x01、0x02の値はSSPxADDでは無効です。これは実装上の制限です。
表24-4:BSPを使用したMSSPクロックレート
注:システムがIOL要件をサポートするように設計されていることを確認するには、表35-4のI / Oポートの電気的仕様を参照してください。
レジスタ24-2:SSP1CON1:SSP制御レジスタ1
<回路図>
PI2Cを利用したLCD表示器(LCD-AQM0802A)「LCD Test / I2C com」と表示するプログラムを作成しました。通常 I2Cラインに取り付けるプルアップ抵抗は、PIC内の弱プルアップを利用しています。雑音の大きい環境で使用するときは、別途プルアップ抵抗を回路に取り付けてください。
<プログラム>
/********************************************************************* * データをLCDに表示する。 * 秋月(ACM1602NI)I2C LCD表示器を使用 * 1MHz (内部クロック) * RB6 SCL * RB4 SDA * * PIC16F1619 MPLAB X IDE with XC8 * Copyright (c) 2017 iwamoto All Rights Reserved * *******************************************************************/ #include <xc.h> #define _XTAL_FREQ 1000000 //********************************************************************* // 調整用定数 //********************************************************************* #define CONTRAST 0x28 // for 3.3V // #define CONTRAST 0x18 // for 5.0V #define slaveDeviceAddress 0x7C // CONFIG1 #pragma config FOSC = INTOSC #pragma config PWRTE = OFF #pragma config MCLRE = ON #pragma config CP = OFF #pragma config BOREN = ON #pragma config CLKOUTEN = OFF #pragma config IESO = ON #pragma config FCMEN = ON // CONFIG2 #pragma config WRT = OFF #pragma config PPS1WAY = ON #pragma config ZCD = OFF #pragma config PLLEN = OFF #pragma config STVREN = ON #pragma config BORV = LO #pragma config LPBOR = OFF #pragma config LVP = ON // CONFIG3 #pragma config WDTCPS = WDTCPS1F #pragma config WDTE = OFF #pragma config WDTCWS = WDTCWSSW #pragma config WDTCCS = SWC //******************* プロトタイプ ******************************* void i2cByteWrite(char, char, char); void i2cTxData(char); void LCD_dat(char); void LCD_cmd(char); void LCD_clr(void); void LCD_posyx(char,char); void LCD_int(void); void LCD_put(char); void LCD_str(char *); void LCD_ROMstr(const char *); /********************************************************* Main application *********************************************************/ void main(void) { OSCCON = 0x58; // FOSC; PLL disabled; 1MHz_HF; TRISB4 = 1; // RB4,RB6をデジタル入力に指定 TRISB6 = 1; ANSB4 = 0; ANSB6 = 0; // ANSB6は不要のはずだがないど動作しない SSPCLKPPS = 0b00001110; // RB6をCLK入力に指定 RB6PPS = 0b00010000; // RB6をCLK出力に指定 SSPDATPPS = 0b00001100; // RB4をDATに入力指定 RB4PPS = 0b00010001; // RB4をDAT出力に指定 // SSP1設定 ----------------------------------------------- SSP1STAT = 0b10000000; // スルーレート制御はOff SSP1ADD = 3; // クロック設定 65k@1MHz SSP1CON1 = 0b00101000; // I2C Master modeにする // -------------------------------------------------------- char msgStart[] ="LCD Test"; LCD_int(); // LCDを初期化 LCD_str(msgStart); // LCD上段に"LCD Disp Test" LCD_posyx(1,1); // 下段にカーソル移動 LCD_ROMstr("I2C com"); // 下段に追記 while (1) { // Add your application code } } //******************************************************************** // I2C 関連 //******************************************************************** //-------- ByteI2C送信 void i2cByteWrite(char addr, char cont, char data){ SSP1CON2bits.SEN = 1; // Start condition 開始 while(SSP1CON2bits.SEN); // Start condition 確認 i2cTxData(addr); // アドレス送信 i2cTxData(cont); // 制御コード送信 i2cTxData(data); // データ送信 SSP1CON2bits.PEN = 1; // Stop condition 開始 while(SSP1CON2bits.PEN); // Stop condition 確認 } //-------- Data送信 void i2cTxData(char data){ PIR1bits.SSP1IF = 0; // 終了フラグクリア SSP1BUF = data; // データセット while(!PIR1bits.SSP1IF); // 送信終了待ち } //******************************************************************** // LCD 関連 //******************************************************************** //-------- 1文字表示 void LCD_dat(char chr){ i2cByteWrite(0x7C, 0x40, chr); __delay_us(50); // 50μsec } //-------- コマンド出力 void LCD_cmd(char cmd){ i2cByteWrite(0x7C, 0x00, cmd); if(cmd & 0xFC) // 上位6ビットに1がある命令 __delay_us(50); // 50usec else __delay_ms(2); // 2msec ClearおよびHomeコマンド } //-------- 全消去 void LCD_clr(void){ LCD_cmd(0x01); //Clearコマンド出力 } //-------- カーソル位置指定 void LCD_posyx(char ypos, char xpos){ unsigned char pcode; switch(ypos & 0x03){ case 0: pcode=0x80;break; case 1: pcode=0xC0;break; } LCD_cmd(pcode += xpos); } //-------- 初期化 void LCD_int(void){ __delay_ms(100); LCD_cmd(0x38); // 8bit 2行 表示命令モード LCD_cmd(0x39); // 8bit 2行 拡張命令モード LCD_cmd(0x14); // OSC BIAS 設定1/5 // コントラスト設定 LCD_cmd(0x70 + (CONTRAST & 0x0F)); LCD_cmd(0x5C + (CONTRAST >> 4)); LCD_cmd(0x6B); // Ffollwer __delay_ms(100); __delay_ms(100); LCD_cmd(0x38); // 表示命令モード LCD_cmd(0x0C); // Display On LCD_cmd(0x01); // Clear Display } //-------- 文字列出力 void LCD_str(char *str){ while(*str) //文字列の終わり(00)まで継続 LCD_dat(*str++); //文字出力しポインタ+1 } //-------- Rom 文字列出力 void LCD_ROMstr(const char *str){ while(*str) //文字列の終わり(00)まで継続 LCD_dat(*str++); //文字出力しポインタ+1 }