MAXQ2000マイクロコントローラのソフトウェアI²Cドライバ
要約
I2C (inter-integrated circuit)は、デバイス間の双方向通信を可能にする2線式シリアルインタフェースです。このアプリケーションノートでは、マイクロコントローラの任意のGPIOピンを使用して100kHzまたは400kHzでのI²C通信を可能にする、MAXQ2000マイクロコントローラのソフトウェアI2Cドライバについて説明します。MAXQファミリのマイクロコントローラは、高速で、GPIOモジュールに柔軟性があり、さらに個別のI/O供給電圧を備えているため、このようなビットバンギングのアプリケーションに適しています。
はじめに
I2C (inter-integrated circuit)は、デバイス間の双方向通信を可能にする2線式シリアルインタフェースです。このアプリケーションノートでは、MAXQ2000マイクロコントローラ(µC)のソフトウェアI²Cドライバ、maxqi2cライブラリについて説明します。
maxqi2cライブラリは、MAXQ用のIAR Embedded Workbenchを使用してコンパイルされる拡張機能を使用したCで記述されています。このライブラリは、maxqi2c.hおよびmaxqi2c.cという2つのファイルで構成されています。これらのファイルをMAXQ2000のファームウェアプロジェクトに組み込むと、µCのいずれかのGPIOピンを使用して、100kHzまたは400kHzの柔軟性のあるI²C通信が可能になります。
MAXQファミリのマイクロコントローラは、高速で、GPIOモジュールに柔軟性があり、さらに個別のI/O供給電圧を備えているため、このようなビットバンギングのアプリケーションに適しています。
このアプリケーションノートで考察するプロジェクト例のファイルは、Maxim Integratedからダウンロードすることができます。
maxqi2cライブラリの構成
ユーザは、maxqi2cライブラリのファイル(maxqi2c.hとmaxqi2c.c)をMAXQ2000のプロジェクトディレクトリにコピーして、所望のI2Cインタフェースを作成するためのファイルを構成する必要があります。構成はすべて、以下に示すコード(リスト1)を編集することによって行います。このコードは、maxqi2c.hソースファイルの先頭にあります。
リスト1. maxi2c.hのカスタマイズコード
/* USER MUST CUSTOMIZE THE FOLLOWING DEFINE STMTS - START */ // Enter the port used for SDA and SCL #define SDA_PORT 0 #define SCL_PORT 0 // Enter the pin used for SDA and SCL #define SDA_PORT_BIT 0 #define SCL_PORT_BIT 1 // Uncomment one of these define statements to select I²C bus speed #define I2C_400_KHZ //#define I2C_100_KHZ // Comment out the following define statement to disable clock // stretching in i2cRecv() #define I2C_CLOCK_STRETCHING /* USER MUST CUSTOMIZE THE FOLLOWING DEFINE STMTS - END */
注:カスタマイズコードはコンパイル時に実装されるため、ランタイム時に確定されます。
SCLピンとSDAピンの選択
2つのGPIOを選択して、SCLおよびSDAとして使用する必要があります。SCLとSDAのI/Oを選択したら、SDA_PORTとSCL_PORTの定義文を編集して、SDAとSCL用に所望のポートを反映する必要があります。また、SDAとSCL用に所望のピン(選択したポート上のピン)を反映するために、SDA_PORT_BITとSCL_PORT_BITの定義文も編集する必要があります。
上記のリスト1のソースコードでは、I/Oポート0のピン0をSDAとして機能するように割り当てており、またI/Oポート0のピン1をSCLとして機能するように割り当てています。
通信速度の選択
通信速度は、I2C_400_kHZとI2C_100_kHZを定義している2つのステートメントのうちの1つをコメント行にすることによって選択します。
リスト1のソースコードは、400kHzのI²Cバスを使用し、maxqi2cライブラリを初期化して通信しています。I²Cインタフェースがビットバングされるため、通信は実際には400kHz (あるいは100kHz)よりわずかに遅くなります。完全な400kHzの通信を達成するには、ファームウェアの設計者が、maxi2cライブラリを調べて、柔軟性を実現しているライブラリ固有のソースコードのいくつかを削除する必要があります。
注:I²Cの仕様を満たすために、maxqi2cライブラリには遅延が含まれています。maxqi2c.cファイルの先頭にあるこれらの遅延は、MAXQ2000が20MHzのシステムクロックを使用することを想定しており、より遅いクロック速度を使用した場合は、遅延の設定を短縮することができます。
クロックストレッチの使用
maxqi2cライブラリのクロックストレッチは、i2cRecv()関数を呼び出すときの、送信の最初のみ許されます(アドレスが送信される場合はアドレスアクノリッジの後、送信されない場合は送信の開始時)。したがって、以下のフォーマットで、クロックストレッチをI²C送信に使用することができます。
[S] [ADDR] [R] [A] [clock stretch] [DATA0] [A] ... [DATAN-1] [A] or [clock stretch] [DATA0] [A] ... [DATAN-1] [N] [P] or [clock stretch] [DATA0] [A] ... [DATAN-1] [A]
「maxqi2cの使用」の項にあるi2cRecv()の説明、および「maxqi2cライブラリの使用例」の項にあるコード例では、これらのフォーマットを使用してI2Cコマンドを生成する方法を示しています。
クロックストレッチを有効にする場合は、I2C_CLOCK_STRETCHINGの定義文をコメント行にしないでください。クロックストレッチが必要でない場合は、I2C_CLOCK_STRETCHINGの定義文をコメント行にすることでクロックストレッチを無効にしてください。クロックストレッチを無効にすると、maxqi2cライブラリのi2cRecv()関数の処理速度がわずかに増大します。
上記リスト1のソースコードでは、クロックストレッチを有効にしています。
maxqi2cの使用
maxqi2cライブラリを使用してソフトウェアI2Cドライバからデータを送受信するには、4つの関数を使用します。すなわち、i2cInit()、i2cIsAddrPresent()、i2cSend()、およびi2cRecv()です。これらの関数のドキュメント一式もmaxqi2c.hのファイルにあります。
これらの関数は正式なパラメータを必要としません。代わりに4つのグローバル変数を使用して、これらの関数のパラメータを格納します。すなわち、i2cData (符号なしchar *)、i2cDataLen (符号なしint)、i2cDataAddr (符号なしchar)、およびi2cDataTerm (符号なしchar)です。この手法を使えば、関数の呼び出し時にデータをコピーする必要がないため、ファームウェアはより高速に動作することができるようになります。maxqi2cライブラリのパラメータとして使用される4つのグローバル変数は、i2cData (符号なしchar *)、i2cDataLen (符号なしint)、i2cDataAddr (符号なしchar)、およびi2cDataTerm (符号なしchar)です。
i2cInit()
この関数は、他のimaxqi2cの関数よりも先に呼び出す必要があります。この関数は、maxqi2c.hファイルのカスタマイズコードで選択したポートピンを初期化します。この関数は、パラメータ(ローカルあるいはグローバル)を必要とせず、値を返しません。
i2cIsAddrPresent()
この関数によって、MAXQ2000は、I²Cバスに照会を行って、特定のアドレスのデバイスが存在するかどうかを決定することができるようになります。この関数には、クローバル変数i2cDataAddrというパラメータが1つあります。このパラメータには、I²Cバス上でデバイスの存在を照会するときの、そのデバイスのアドレスをロードする必要があります。またこの関数は、値(符号なしchar)を返します。この値は、指定のアドレスのデバイスが検出された場合は、I2C_XMIT_OKとなり、指定のアドレスのデバイスが検出されない場合は、I2C_XMIT_FAILEDとなります。
特定のデバイスがI²Cバスに存在するかどうかを決定するため、i2cIsAddrPresent()は、以下のフォーマットでI²Cコマンドを送信します。
[S] [ADDR] [W] [A] [P]
i2cSend()
この関数によって、MAXQ2000は、ソフトウェアI²Cドライバを使用してデバイスにデータを送信することができるようになります。i2cSend()では、以下の4つのパラメータ(すべてグローバル変数)を初期化する必要があります。
- i2cData (符号なしchar *):送信する一連のバイトの最初のバイトを指すポインタ
- i2cDataLen (符号なしint):I²Cバスに送信するバイト数(デバイスのアドレスは含まれません)
- i2cDataAddr (符号なしchar):データが送信されるデバイスのアドレス。この変数を0に設定した場合、アドレスを送信せずにI²Cデータが送信されますので注意してください。
- i2cDataTerm (符号なしchar):I²C送信を終了する方法。i2cSend()を呼び出すとき、この変数には、2つの値、すなわちI2C_TERM_NONEまたはI2C_TERM_STOPのいずれかを使用することができます。
I²Cバス上のデバイスにデータを送信するために使用するフォーマットは、パラメータとして使用する4つのグローバル変数の値によって異なります。グローバル変数の各値によるI²Cのコマンドフォーマットを表1に示します。
i2cDataLen(hex) | i2cDataAddr(hex) | i2cDataTerm | I²C Command Format |
0x0002 | 0x7E | I2C_TERM_STOP | [S] [ADDR] [W] [A] [DATA0] [A] [DATA1] [P] |
0x0002 | 0x7E | I2C_TERM_NONE | [S] [ADDR] [W] [A] [DATA0] [A] [DATA1] [A] |
0x0002 | 0x00 | I2C_TERM_NONE | [DATA0] [A] [DATA1] [A] |
0x0002 | 0x00 | I2C_TERM_STOP | [DATA0] [A] [DATA1] [A] [P] |
注:表1の最後の3つのフォーマットは、i2cSend()が、I²C上の同じデバイスに連続してデータを送信する方法を示しています。
i2cSend()関数は、アドレス指定したデバイスがあらゆるバイトをアクノリッジした場合、値I2C_XMIT_OK (符号なしchar)を返し、アドレス指定したデバイスが1バイトもアクノリッジしなかった場合には、値I2C_XMIT_FAILEDを返します。この関数は、単一バイトがアクノリッジされなかったときに直ちに返されます。
i2cRecv()
この関数によって、MAXQ2000は、ソフトウェアI²Cドライバを使用してデバイスからデータを受信することができるようになります。i2cRecv()では、以下の4つのパラメータ(すべてグローバル変数)を初期化する必要があります。
- i2cData (符号なしchar *):受信した値を格納する一連のバイトの最初のバイトを示すポインタ
- i2cDataLen (符号なしint):I²Cバスから受信するバイト数(デバイスのアドレスは含まれません)。
- i2cDataAddr (符号なしchar):そこからデータを受信するデバイスのアドレス。この変数を0に設定した場合、アドレスを送信せずにI2Cデータが受信されますので注意してください。
- i2cDataTerm (符号なしchar):I²C送信を終了する方法。i2cRecv()を呼び出すとき、この変数には、3つの値、すなわちI2C_TERM_NONE、I2C_TERM_ACK、またはI2C_TERM_NACK_AND_STOPのいずれかを使用することができます。
I²Cバス上のデバイスからデータを受信するために使用するフォーマットは、パラメータとして使用する4つのグローバル変数の値によって異なります。グローバル変数の各値によるI²Cコマンドフォーマットを表2に示します。
i2cDataLen(hex) | i2cDataAddr(hex) | i2cDataTerm | I²C Command Format |
0x0002 | 0x7E | I2C_TERM_NACK_AND_STOP | [S] [ADDR] [R] [A] [DATA0] [A] [DATA1] [N] [P] |
0x0002 | 0x7E | I2C_TERM_ACK | [S] [ADDR] [R] [A] [DATA0] [A] [DATA1] [A] |
0x0002 | 0x00 | I2C_TERM_ACK | [DATA0] [A] [DATA1] [A] |
0x0002 | 0x00 | I2C_TERM_NACK_AND_STOP | [DATA0] [A] [DATA1] [N] [P] |
注:表2の最後の3つのフォーマットは、i2cRecv()が、I²C上の同じデバイスから連続してデータを受信する方法を示しています。
i2cRecv()関数は、I²Cコマンドの一部として送信されたアドレスがアクノリッジされなかった場合に、値I2C_XMIT_FAILED (符号なしchar)を返します。そうでない場合は、I2C_XMIT_OKを返します。
クロックストレッチを用いたmaxqi2cライブラリの使用例
以下の例は、maxqi2cライブラリを使用して、MAX1169 ADCから16ビットサンプルを受信し、またMAXQのRS-232ポートを介してこれらをPCに送信する方法を示しています。
回路図
この例は、MAX1169 ADC評価キットとMAXQ2000評価キット(Rev B)を使用して実現しました。図1に、両方の評価キットの接続方法を示します。MAXQ2000のI/Oポート0のピン0とピン1 (それぞれJ2-30とJ2-28で利用可能)は、I2Cバス上のSDAとSCLのマスタラインとして機能します。
図1. 回路図は、MAX1169評価キットとMAXQ2000評価キット(Rev B)が接続され、maxqi2cライブラリで使用可能な状態を示しています。
注:MAXQ2000評価キット上のMAXQ2000の高周波水晶(Y1)は、20MHzの水晶に置き換えられています。MAX1169評価キットのジャンパおよびMAXQ2000評価キットのスイッチは、以下の表3と表4に示すとおりに設定する必要があります。
跳接器 | 短路器位置 |
JU1 | 引脚1和2之间安装短路器 |
JU2 | 引脚1和2之间安装短路器 |
JU3 | 引脚1和2之间安装短路器 |
JU4 | 没有短路器 |
JU5 | 没有短路器 |
开关 | 位置 |
SW1-1 | 断开 |
SW1-2 | 断开 |
SW1-3 | 断开 |
SW1-4 | 打开 |
SW1-5 | 断开 |
SW1-6 | 断开 |
SW1-7 | 打开 |
SW1-8 | 断开 |
SW6-1 | 断开 |
SW6-2 | 断开 |
SW6-3 | 断开 |
SW6-4 | 断开 |
SW6-5 | 断开 |
SW6-6 | 断开 |
SW6-7 | 断开 |
SW6-8 | 打开 |
ファームウェア
この例のファームウェアのファイル(max1169.c)は、付録Aに記載されています。プロジェクトの全体は、マキシムMAXQ2000のウェブページからダウンロードすることが可能で、IAR Embedded Workbench for MAXQを使用してコンパイルすることができます。この例では、maxqi2cライブラリのカスタマイズコード(maxqi2c.hファイルの先頭にあります)は、リスト1に示すソースコードとまったく同じです。
max1169.cファイルには、iomaxq200x.hおよびmaxqi2c.hの2つのヘッダファイルが含まれています。この例にあるiomaxq200x.hファイルは、MAXQ 用のIAR Embedded Workbenchのインクルードパスにあるiomaxq200x.hファイルよりも優先されることに留意してください。iomaxq200x.hファイルは、maxqi2cライブラリに必要なあらゆるポートのあらゆるピンの定義を作成します。maxqi2c.hファイルは、ファームウェアでmaxqi2cライブラリの関数を呼び出すことができるようにインクルードされます。
max1169.cファイルでは、ファームウェアは5つのステップに分割されており、コメントが添付されています(付録Aを参照)。
ステップ1は、UART0を初期化し、19200bpsの非同期通信を行います。MAXQ2000のシステムクロックが20MHzでない場合、所望のボーレートを取得するためには、抵抗PR0への割当てを変更する必要があることに留意してください。
ステップ2は、i2cInit()関数を呼び出します。この関数は、MAXQ2000上でI²Cバス用に使用するピンを初期化する役割があります。
ステップ3は、パラメータを初期化して、i2cRecv()関数を呼び出します。パラメータは初期化されて、以下のフォーマットでI²Cコマンドを送信します。
[S] [ADDR] [R] [A] [clock stretch] [DATA0] [A] [DATA1] [A (termination)]
ステップ4は、アドレスのパラメータをゼロに設定します。これによって、i2cRecv()関数は、以下のフォーマットでI2Cコマンドを送信するようになります。
[clock stretch] [DATA0] [A] [DATA1] [A (termination)]
ステップ5は、無期限に繰り返すループです。このループはi2cRecv()を呼び出し(ステップ4で定義したフォーマットを使用)、これによって16ビットのサンプルをMAX1169から受信します。この16ビットのサンプルは、UART0を使用してPCに転送されます(MSBファースト)。終了パラメータi2cDataTermは、常にI2C_TERM_ACKに等しくなるため、ループは無期限に繰り返され、MAX1169で停止条件が検出されることはありません。
付録A:max1169.c
/* * DEMO of maxqi2c Software I²C Driver * (uses evkits for the MAX1169 and MAXQ2000) * * DESC: Test program for the maxqi2c.c/maxqi2c.h I²C * driver for the MAXQ2000. The program reads * 16-bit samples from the MAX1169 (running in * continuous conversion mode) and transmits them * using the UART0 port. * * NOTE - THE FOLLOWING CODE ASSUMES THE MAXQ2000 HAS * A Fsysclk=20MHz. */ #include "iomaxq200x.h" #include "maxqi2c.h" void main() { unsigned char data[2]; // 1. Init UART0 PD7_bit.bit0 = 1; // Set TX0 pin as output SCON0 = 0x42; SMD0 = 0x02; PR0 = 0x07DD; // 19200bps // 2. Init bit-banged I²C port i2cInit(); // 3. Send initial I²C request // [S] [ADDR+R] [A] [clock_stretch] [DATA0] [A] [DATA1] [A (termination)] i2cData = (unsigned char *)(&data); // cast needed! i2cDataAddr = 0x7E; i2cDataLen = 0x0002; i2cDataTerm = I2C_TERM_ACK; i2cRecv(); // 4. Init continuous conversion // [clock_stretch] [DATA0] [A] [DATA1] [A (termination)] i2cDataAddr = 0x00; // 5. Receive a 16-bit sample and transfer it to the UART0 port // one byte at a time. Repeat forever... while (1) { i2cRecv(); while(!SCON0_bit.TI); // Wait for UART0 Buffer to be empty SCON0_bit.TI = 0; // Reset TI flag SBUF0 = data[0]; // Send data byte 0 while(!SCON0_bit.TI); // Wait for UART0 Buffer to be empty SCON0_bit.TI = 0; // reset TI flag SBUF0 = data[1]; // Send data byte 1 } }