USB-101(FT2232H)によるMPSSEを使ったI2C通信例

2010/03/12-

 FTDIデバイスにはMPSSE(Multi-Protocol Synchronous Serial Engine)というモードが用意されています。
このモードを使用することによりシリアル通信(I2C、SPI、JTAG等)をエミュレートし、通信することが可能です。

UTL-015で使用しているSMBus通信温度センサIC TMP401(TI)USB-101を通信させてみました。
USB-102USB-103でも同様の実験が可能です。

◆構成

とても単純です。USB-101UTL-015を直接接続しています。
UTL-015への3.3VはUSB-101から供給しています。



◆ピン割付け

USB-101UTL-015は以下のように接続されています。他は未接続です。

USB-101(FT2232H) 方向 UTL-015 (TMP401)
ピン名 ピン番号 ピン名 ピン番号
ADBUS0 (TCK) 3 ---> SCL 13
ADBUS1 (TDI) 4 <---> SDA 15
ADBUS2 (TDO) 5
ADBUS3 (TMS) 6 -- --
ADBUS4 (GPIOL0) 7 -- --
ADBUS5 (GPIOL1) 8 <--- ALERT#/THERM2# 11
ADBUS6 (GPIOL2) 9 -- --
ADBUS7 (GPIOL3) 10 <--- THERM# 9
3.3V出力
(JP2をショートして出力)
21, 22 ---> V33 1, 2
GND 1, 2 <---> GND 5, 6

◆SMBusとI2C

SMBus (System Management Bus)はI2Cが発展した規格ですので、I2Cインタフェースとして通信できます。
今回の実験ではI2Cとして通信しています。SMBusとして扱ってはおりませんのでご了承ください。

SMBusの詳細は省略致します。詳しくは参考サイト(こちらなど)をご参照ください。

◆I2C通信規格

単純なものは、以下のような手順で通信を行います。

「START」 「デバイスアドレス+(W/R#)」 「レジスタアドレス」 「データ」 「STOP」
>>-------------------------------------------------------------->>

SDAの遷移は、SCLがLowのときに行われる必要があります。
SDAの遷移が、SCLがHighのときに行われると、「START/STOP」シーケンスとなります。

通信波形の例を下図に示します
STARTシーケンスの位置を拡大してみました。SCLがHのときにSDAがLになっているのがわかります。
STOPシーケンスでは逆に、クロックが先にHに上がり、そのあとSDAがHになります。

間に挟まれたデータ8bit毎に、ACKが返ったきたり、ACKを返したりします。


クリックして拡大

詳細はTMP401のデータシートや、他参考サイトをご覧になってください。

◆MPSSEの動かし方

MPSSEモードではコマンドとデータを送信して動作させます。

VCPモードで0x86, 0x01, 0x00をFT_Write()すると、3Byteのデータがポートから出力されますが、
MPSSEモードでは、クロックレート(0x86)を0x0001に変更する、という動作になります。
0x2C, 0x10, 0x00ならばTDOポートから16Byte取得します。

◆MPSSEをI2Cとして動作させる

サンプルプロジェクトよりコードを一部抜粋しました。(ここをクリック
合わせてご覧ください。

まずはじめにUSB-101をMPSSEモードに切り替えます。
MPSSEへの切り替えはFT_SetBitMode関数で行います。APIのみで移行できますので、EEPROMに特別な設定は必要ありません。
第3引数の0x02でMPSSEモードに切り替わります。第2引数はポートの方向で1:OUTPUT、0:INPUTです。

 FT_SetBitMode(ftHandle, (UCHAR)0xFB, (UCHAR)0x02);


 動作設定は以下の配列内容で行います。

 BYTE outBuffer[] = {
  0x85,            //Disconnect TDI to TDO LoopBack
  0x97,            //Turn off Adaptive clocking
  0x8C,            //Enable 3 Phase Data Clocking
  0x86, 0x13, 0x00,    //Set TCK Divisor
 };

 0x86, 0x13, 0x00 にてSCLのレートを設定します。
今回は300kHzを使用します。outBuffer[]はFT_Write()でまとめて送信できます

I2Cの波形とするために「3 Phase Data Clocking (0x8C)」の設定が必要です。

このモードにより、3段階のクロックでデータを出力できます。
「I2C通信規格」でもご説明したように、SDAはSCLがHのときに遷移してもらっては困りますので、このモードが必要となります。

下図に参考波形を示します。
下の波形では、SCLがHのときにデータが遷移してしまっています。(赤線部)
上の波形では、データ遷移用に半周期分のSCLが追加されおり、遷移はこの領域で行われていることがわかります。

ということは実際のレートは2/3と言うことになりそうです。(200kHz)


クリックして拡大


クロックエッジに対するデータの出力タイミングは
・MSBから
・立ち下がりエッジで更新
・バイト単位で出力
という条件から0x11となります。下記は「data」1バイト分の出力コードです。

 BYTE outBuffer[] = {
  0x11, 0x00, 0x00, data,
  ・・・
 };


◆ACKの受け方

8bitのデータ送信毎にACKが返ってきます。(もしくは返します)

FT2232H側のDOとDIをショートしていますので、DOを一時的に入力として、LowByteを読み込みます。

 BYTE outBuffer[] = {
  ・・・
 //Get Ack
  SET_DATA_BITS_LOW_BYTE, 0x00, 0x01,     //SCLK:out, DO:in, DI:in
  MSB_RISING_EDGE_CLOCK_BIT_IN, 0x00,    //Get 1 Byte
  0x87,                            //Send Immediate
  SET_DATA_BITS_LOW_BYTE, 0x00, 0x03,     //SCLK:out, DO:out, DI:in
  };

 FT_Write(ftHandle, outBuffer, sizeof(outBuffer), &dwByteWritten);
 FT_Read(ftHandle, &ret, 1, &dwByteRead);



retの2bit目が0であれば、ACKが返っているということになります。


◆実際の通信例

TMP401のManufacture IDを読み出してみました。


クリックして拡大

@ スタートシーケンス
A スレーブアドレス+Write、Ack応答
B ポインタレジスタバイト
C スタートシーケンス
D スレーブアドレス+Read、Ack送信
E Manufacture ID、Ack送信
F エンドシーケンス

今回は読み出しコマンドですので、まず読み出しアドレスをWriteして、返答データをReadします。
その際スタートシーケンスを再発行する必要があります(4)。

2や5ではスレーブアドレスの後の1bitでWrite/Read#を指定します。
TMP401のスレーブアドレスは0x1001100ですので、Writeの場合0をLSBに付加し0x10011000(0x98)となります。


UTL-015サンプルアプリケーション

今回の実験で作成したサンプルアプリケーションを配布しております。




UTL-015の製品ページよりダウンロードしてご利用ください。

どうぞ皆さんのご参考になさってください。ただし、コードやアプリのご使用は皆さまの責任で(At Your Own Risk!)お願いいたします。
メールでのご質問はこちらへどうぞ
FTDIシリーズTOPへ