FT232Rモジュール活用 #1 ドライバのインストールからソフト開発まで
2011年9月 電子工作をやっていると一度は「自作機器をPCにつないで制御したい」と夢見ます。 一昔前のPCにはシリアルポートが備わっていて、比較的簡単に実現できました。 今時のPCならUSBですが、自作機器を接続するのはちょっと簡単ではありません。 そこで「USB-シリアル変換モジュール」の登場です。これで実現できます。 この記事の内容 ・USB-シリアル変換モジュール各種。FT232Rについて。 ・ドライバのインストール。VCPモード/ビットバンモードのソフト開発例。 ・補足説明。ドキュメントへのリンク集。 シリーズ記事 #1 ドライバのインストールからソフト開発まで #2 ビットバンモードでLCDモジュールを制御する #3 FT232-AVRライター とにかく導入が簡単 #4 ビットバンモードで7セグを制御する |
USB-シリアル変換モジュール | |
PCと周辺機器を接続するインターフェイスといえばUSB(Universal Serial Bus)がお馴染みです。その名の通りシリアル通信で機器を制御します。しかし趣味の電子工作で作った物をUSB機器としてPCに接続するのは簡単ではありません。自作機器側でUSBの規格に合わせた信号を作り、送受信することが難しいのです。 PCはUSBの他に、比較的簡単に周辺機器を制御する手段を備えています。シリアルポート(COMポート)です。 …という話が最近は通じなくなりました。時代の流れでPCからCOMポートは失われつつあります。そして今、USBを仮想的なCOMポートに変換するICがあります。USBコネクタにCOMポートを増設する感覚で使えます。 COMポートを置き換える目的で普及したUSBをCOMポートに変換する。ときには時代を逆行することも必要です。 USB-シリアル変換ICは、メーカーサイトでは「USB to Serial Bridge」と表記されています。 FTDI社:FT232R、Silicon Laboratories社:CP2103、Prolific社:PL-2303HXD などがあります。これらは通信速度(USB1.1/2.0の対応やボーレート)や送受信バッファサイズに違いがあるものの、どれも同じように使えます。 またそれぞれ、変換後のシリアルポートとは別に何個かの汎用I/Oポート(GPIO)を持っています。FT232Rはさらに、シリアルポートを8個の汎用I/Oとして使うこともでき、応用が広がります。 ※GPIOを使ったアプリを作るにはAPIリファレンスや開発ガイドが必要です。FT232Rはドキュメントが充実しています。次いでCP210x、必要なドキュメントは公開されています。PL-2303HXDは、サンプルコードは公開されているものの、開発キットの入手はサポート窓口へ申し込みのようです。 電子パーツショップではこれらのICを使いやすくモジュール化したものを取り扱っています。 このシリーズ記事では秋月電子のFT232Rモジュールの活用方法を紹介します。 ※aitendoがCP2102とPL-2303HXのモジュールを、ストロベリー・リナックスがCP2103のモジュールを取り扱っています。(2011/09現在) ※aitendoがCP2103モジュールを取り扱い始めました。(2012/01現在)
【参考】汎用I/Oポート(GPIO)の個数 FT232Rには4個(4pin)あります(実装5pinのうち4pin使えます)。ちなみに同シリーズのFT245Rには2pinあります。 CP2103/04には4pinあります。CP2101/02にはGPIOがありません。 PL-2303HXD(HX rev.D)には4pinあります。rev.DではないPL-2303HX(HX rev.A)は2pinです。 GPIO使用にあたり GPIOはTXD/RXDなどのインジケータ(LED点灯)として備わっており、大抵は入力方向に設定されています。 これを開発者が独自に使えるようにするには、デバイス内蔵のEEPROMで保持されている設定を書き換えねばなりません。設定方法の説明や書き換えツールはメーカーサイトで公開されています。 各デバイスで使い勝手や性能の違いは様々です。あれこれ使おうと過剰な期待はしない方がよいでしょう。 |
FT232Rの動作モード |
FT232Rには2つの動作モードがあります。 VCP (Virtual COM Port/仮想COMポート) USB-シリアル変換動作です。PCにあたかもCOMポートが増設されたかのようになります。信号電圧はTTLレベルなのでマイコン機器と通信するには都合がよいです。基本的にRXD/TXD(受信/送信)の2線で接続機器を制御します。 もちろんPCにD-SUB 9ピンコネクタが増えるわけではないので、機器との物理的な接続問題はあります。 また、真にRS-232C規格の信号電圧が必要な場合はレベル変換ICも必要になります。 ※仮想でない本物のCOMポートは最大-15V/+15Vの範囲でロジック1/0を表します(負論理)。TTLレベルは5V/0Vでロジック1/0を表します(正論理)。これらを接続するにはMAX232等の専用ICを使い、互いにレベル変換/論理反転する必要があります。 Bit Bang Mode (ビットバンモード) FT232RはCOMポート的な動作をせず、代わりに8bitパラレルのI/O線が使えるようになります。ソフト開発者はこのI/O線を操作するプログラムを組み、同期通信/非同期通信で接続機器を制御します。 |
ドライバの入手とインストール | |
FT232Rを使うにはPCにドライバをインストールする必要があります。FTDI社のサイトで無償公開されています。 VCP動作には「VCPドライバ」が、ビットバンモードには「D2XXダイレクトドライバ」が必要です。
ZIP版よりインストーラ版(xxxxx_setup.exe)をお勧めします。一度に両方インストールできます。xxxxx_setup.exeを実行するとコマンドプロンプトが2回パカパカ開き、インストールが完了します。※WindowsXP/SP3の例。 FT232RモジュールをUSBコネクタに挿し、デバイスマネージャで確認すると「USB Serial Port」が出現しています。 この状態でFT232Rモジュールはもうシリアルポート(COMポート)として使えます。 COMポート何番になるかはPC環境によります。※「通信ポート(COM1)」は、もともとこのPCが備えている本物のCOMポート。 |
ソフト開発に必要なもの | |||
VCPとビットバンモードのソフト開発について、以降、次の開発環境として話を進めます。 ・WindowsXP(32bit)/SP3 ・Visual Studio 2008 Express Edition - C# VCPとビットバンモードにおけるソフト開発の違い VCP(仮想COMポート)のソフトを開発する際、FT232Rの存在を意識する必要はありません。C#ではSerialPortクラスを使い、あくまでもCOMポートを操作するプログラムとして組みます。 一方で専用APIも用意されています。SerialPortクラスと同等の処理の他、製造番号などデバイス固有情報を取得することができます。例えばPCに接続した複数のデバイスを判別するのに使ったりします。 まとめると、 ◆COMポート制御のソフトを開発するにはSerialPortクラスを使う。基本的に専用APIは使わなくてよい。 ◆ビットバンモードのソフトを開発するには専用APIを使う。SerialPortクラスは動作内容が違うので使えない。 C#で専用APIを使うために必要なもの 専用APIはDLLの形で提供されています(FTD2XX.dll)。中身はC/C++用の関数群なのでC#から呼び出すのは面倒くさそうです。ところが嬉しいことにC#用ラッパーDLLが用意されていて、簡単に専用APIが利用できます。
解凍したファイルの説明 【FTD2XX_NET_xxxx.zip】 → FTD2XX_NET.dll, FTD2XX_NET.XML FTD2XX_NET.dll FTD2XX.dllをC#から使うためのラッパーDLL。任意のフォルダに配置します。 C#アプリ作成ごとに(新規プロジェクトごとに)、プロジェクトの「参照設定」へ追加します。 ※FTD2XX.dllの方はドライバインストール時に配置されている。WindowsXPの場合 C:\Windows\system32\FTD2XX.dll FTD2XX_NET.XML FTD2XX_NET.dllのドキュメント。アプリ開発には不要です。別途XMLリーダー(Visual Studioのオブジェクトリーダー)で見てDLL内関数のリファレンス代わりにどうぞ、というものです。※ちなみにVisual Studioの機能を使って自動生成されている。 【FTD2XX_NETclass.zip】 → FTD2XX_NETclass.cs FTD2XX_NETclass.cs FTD2XX_NET.dllのソースコード。アプリ開発には不要です。※FTD2XX_NETclass.csをプロジェクトに加える必要はない。 「XMLファイルよりむしろこちらがドキュメント」くらいのつもりで利用するので(ソースを読む)、あると便利です。 |
仮想COMポートのソフト開発について | |||
VCP(仮想COMポート)のソフト開発は、通常のSerialPortクラスを使ったソフト開発と同じです。 Visual Studioのプロジェクト上、VCPのためにインポートしたり参照を追加するモジュールはありません。 ですが、サンプルコード「Example3」のようにデバイス固有の情報を取得するには専用APIが必要です。 ※専用APIの使い方は次節「ビットバンモードのソフト開発について」で説明します。 専用APIはSerialPortクラスと同等の機能を備えています。ゆえに… どうせ専用APIを使うことになるなら、SerialPortクラスを使わずに専用APIだけで組んでしまおうか? それとも、なるべく標準的なSerialPortクラスを使い、足りない機能だけ専用APIを使おうか? 悩むかもしれませんが、開発者が好きに決めてください。 両方を使うときは注意が必要です。SerialPortオブジェクトからデバイスをOpen()した状態で、FTDIオブジェクトからも同じデバイスをOpen()することはできません。もちろん逆の手順でもダメです。 ※FTDIオブジェクト…専用APIをまとめたFTDIクラスのオブジェクト。 デバイス固有情報を取得するときは、SerialPortオブジェクトでデバイスをOpen()していたらそれをClose()して、FTDIオブジェクトから改めてOpen()して、目的の情報を取得して、FTDIオブジェクトでClose()します。 取得した情報自体は文字列や整数なのでプログラム内で自由に使えます。
例外発生の対策をする FT232Rモジュールを使用した仮想COMポートならではの、アプリケーションの例外エラーが発生し得ます。 それは、「Open()した状態のデバイスをPCから引っこ抜いて、Close()またはアプリを終了した」場合です。 発生する例外 SerialPortをOpen()したあと、デバイス(FT232Rに限らずどのUSB-シリアル変換モジュールでも)を引っこ抜くと、その後挿し直そうが、アプリ終了時に(Main()を抜けるときに)UnauthorizedAccessException例外が発生します。Open()したBaseStreamがClose()されていないので実行環境がClose()/Dispose()しに行きますが、デバイスが無くなってそのBaseStreamにアクセスできないので例外発生、というメカニズムです。
対策案 その1 Main()を抜けるときに実行環境からSerialPort.Dispose()が呼ばれる。そのタイミングで例外をキャッチする方法。 ※詳細は「ThreadException」「UnhandledException」で検索してください。 ・例外キャッチ後、ダイアログを表示するなど何らかの処理が必須。例外発生を「無かったこと」にできない。 ・ダイアログを表示しても、Main()終了時のことなので結局アプリはそのまま終了するしかない。 対策案 その2 SerialPort.Dispose()をオーバーライドし、そこでキャッチする方法。 ソースファイル: MySerialPort.cs ←拡張子を.txtにしてあります。 7行目 SerialPortの派生クラスを作り、それを使うようにします。 9行目 デバイス引っこ抜き対策のために一時保存しておくBaseStream。コンストラクタ(11-14行目)で初期化しています。 16-20行目 デバイス引っこ抜き対策のため、オープンしたストリームを保存しておきます。 22-29行目 この対策のポイントとなるDispose()のoverrideです。 24-28行目のtry。デバイスをオープンしていなければopenedBaseStreamはnullなので素通りします。 デバイスをオープンしても引っこ抜いていなければ26行目で正しくClose()され、例外は発生しません。 デバイスをオープンして、それを引っこ抜いていると26行目のClose()でUnauthorizedAccessException例外発生、29行目でcatchされます。特に後始末の処理はありません。※「デバイスを抜きましたね?」などとダイアログを表示してもしょうがない。 31行目 MySerialPort.Dispose()は実行環境がオブジェクトを破棄するときだけでなく、MySerialPort.Close()からも呼ばれます。その判定のためのフラグ処理を無視してはいけません。 |
ビットバンモードのソフト開発について:送信処理 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ビットバンモードで接続機器を制御するコンソールアプリの開発例です。専用APIを使います。 例としたアプリは、8bitのI/O各線に接続したLEDを点灯させる内容です。 【注意】説明は全てVisual Studio 2008 Express Edition - C# におけるものです。
5行目 名前空間「FTD2XX_NET」を追加します。専用APIは全てこの名前空間にまとめられています。 13行目 デバイスを操作するためのFTDIオブジェクトを生成します。 14行目 デバイスをオープンします。 オープン方法はいくつかあり、自動的に割り振られたインデックスや、デバイスに埋め込まれている固有番号を指定します。例はインデックスを指定する方法です。PCにデバイスが1つしか接続されていない場合はインデックス0番に確定しているので、このオープン方法が簡単です。 15行目 8bit I/Oの入出力方向(第1引数)と、通信制御の方法(第2引数)を指定します。 方向は出力:1、入力:0として1byteの値で指定します。例は全部出力方向にしています。bit:7〜0 = 11111111 = 0xFF 通信制御は「ビットバンモード」を指定するのですが、さらに同期制御/非同期制御の区別があります。例では非同期制御(Asynchronous Bit Bang mode)を指定しています。 16行目 ボーレートを設定します。デフォルトは9600bpsです。 デフォルト値でよければ記述を省略できますが、明示的に設定した方がよいでしょう。 17-19行目 送信するデータを準備し(18行目)、送信処理を実行しています(19行目)。 例では3個の8bitパラレルデータを出力します。出力タイミング(通信速度)は設定したボーレートの通りです。 入出力方向が入力に指定された線にはマスクがかかり、Write()関数を実行してもその線の電圧状態は変化しません。送信データを作るときに入力線のビット位置を意識しなくてよいので楽です。※今回の例では入力方向の線はありませんが。 何らかの影響により、引数のデータが途中までしか送信できないことが起こり得ます。そのため第3引数に、実際に送信されたバイト数が返されてきます。この値を見て全部のデータが送信されたかどうか判断します。送信バッファがあふれるような通信内容でなければ大丈夫のハズです。※FT232R内蔵の送信バッファは256byte. ドライバ側では4096byte持てる。 Write()関数の戻り値は、関数の実行自体が成功したかどうかです。通信事情により送信されなかったデータがあったとしても、関数内部でDLL呼び出しエラーなどが発生していなければ、戻り値は「成功」となります。 20行目 デバイスをクローズします。 入力方向を設定する場合 例では15行目で8bit I/O線を全て出力方向に設定しました。ここで仮に上位4bitを入力方向に設定するとしましょう。 出力ビット:1、入力ビット:0なので、第1引数は0x0Fとなります。
Write()関数の動作 Write()関数の動作は、厳密には「デバイスに対する送信要求」です。具体的には送信データをデバイス内蔵の送信バッファに書き込み、デバイスに送信実行を要求します。デバイスはアプリケーションから送信要求を受け、送信バッファ内のデータを実際に送出し始めます。※それでSend()ではなくWrite()と名付けられたのでしょう。 もしこの瞬間にデバイスの送信準備ができていなかったら、デバイスは送信バッファの内容を保留し、準備完了してから送出し始めます。このような状況でさらに次々と送信要求が繰り返されると送信実行が追いつかなくなり…、というわけでWrite()関数の引数のデータと実際に送信されたデータのバイト数にズレが生じることが起こり得るのです。 デバイスの送信準備とは、I/Oポートの状態確認や、直前の送信処理が完了しているかの確認といったことです。 データ送信の勘違いに注意 18行目で挙げた値(0xF0, 0x0F, 0xAA)について、1つの値は8bit I/O線全体の1回分の出力データを表します。 つまり例では、1回目の出力で通信線8本の電圧状態が「11110000」になり、2回目の出力で「00001111」になり、3回目の出力で「10101010」となります。(○の説明表) 勘違い例:3本の線でそれぞれの値(0xF0, 0x0F, 0xAA)を1ビットずつ8回出力し、残り5本の線は出力0で待ち状態、という動作ではありません。(×の説明表)
シリアル通信(TXD/RXDの制御)では、1byteのデータを指定すると1本の送信線(TXD)から1byte分のビット列(8個の0/1)がズラララッと出力されます。そのイメージで勘違いしそうになるのですが、ビットバンモードは違います。こちらはパラレル線なのです。1byteのデータを指定すると8本の通信線にビット(0/1)がセットされ、同時にバッと1回出力してお終いです。 |
ビットバンモードのソフト開発について:受信処理 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
送信処理のWrite()関数と対になるRead()関数を説明します。 送信処理の説明の続きで、8bit I/O線のうち上位4bitが入力方向、下位4bitが出力方向だとします。 受信データを読み込むプログラムの例 受信データはRead()関数で読み取ります。デバイス内蔵の受信バッファに格納されているデータが取得できます。
1-2行目 デバイスの受信バッファに何バイト貯まっているか調べます。値は引数に返されてきます。 GetRxBytesAvailable()の戻り値は、関数の実行自体が成功したかどうかです。 3行目 受信データを取り込めるだけのバッファ(byte型配列)を用意します。 ※FT232R内蔵の受信バッファは128byte. ドライバ側では4096byte持てる。 4行目 受信処理(バッファからの読み取り処理)を実行します。 第1引数は読み取った値を格納するバッファ。第2引数は読み取りたいデータサイズ(バイト数)。 第3引数には実際に読み込めた長さ(バイト数)が返されてきます。 受信データの内容 接続機器からデバイス(FT232R)の8本のI/O線に対して、bit7〜0 = '01101010' というデータが送られてきたとします。 デバイスは送信線4bit分を特にマスクせず、そのときの8bit I/O線の状態をそのままデバイス内蔵の受信バッファに格納します。従って内蔵受信バッファには'0x6A' (01101010 = 0x6A)が格納されます。 プログラムでは4行目Read()の実行により、rbuf[0]に '0x6A'が代入されます。
データ受信時の注意事項 Read()関数も、Write()関数と同様に必ずしも1回で要求通りのデータが読み取れるわけではありません。従って、要求するデータサイズに達するまでRead()関数を繰り返し実行することになります。 GetRxBytesAvailable()で読み取り可能サイズを調べずに、「nnバイト受信しているはずだ」と決め打ちでRead()関数を繰り返すのは危険です。 while (totalLength < nn) { Read(rbuf, nn - totalLength, readLength); RsvData(rbuf); totalLength += readLength; } …などとしてはいけません。※RsvData()は適当な自作関数とする。 なぜなら、接続機器のトラブルでこちらにデータを送ってこないことがあり得るからです。読み取り処理をするときはタイムアウトを設定したり、一定回数繰り返したらあきらめる処理を入れてください。※送信処理もそうなのですが。 これはFT232Rモジュール操作のことだけでなく、通信処理一般における注意事項です。 |
参考(プログラム改造) |
LEDが変化する様子が目で見て分かるよう改造しました。0.5秒間隔でLEDの点灯が変化します。 1回に送信するデータが1byteでも、Write()関数にはbyte型で送信データを与える書式がありません。byte配列の形に合わせるため、要素が1個だけの配列を用意します。 ソースファイル: Program.cs ←拡張子を.2.txtにしてあります。 |
補足説明 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
同期制御/非同期制御 FT232Rの動作モードはVCPとビットバンモードがあり、ビットバンモードはさらに同期制御と非同期制御の区別があります。詳細は「AN_232R-01_Bit_Bang_Mode_Available_For_FT232R_and_Ft245R.pdf」を読んでください(下記ドキュメントリンク)。一般的な通信制御の仕組みについては適当な参考書を読んでください。 同期制御 Write()でbyte配列を送信するとき、1byte送信するごとにその瞬間のI/Oポートの電圧状態をデバイス内蔵の受信バッファへ格納します。送受信のタイミングはボーレートの設定によります。 こちらが1byte送信すると、相手機器が受信して応答を返してきます。こちらが次の1byteを送信するとき、直前の送信に対する相手の応答を受信するわけです。と同時にこちらからの1byteは送信されています。この繰り返し動作です。 注意点として、相手機器が何個データを送ってきても、こちらは送信した瞬間のデータしか受け取れません。こちらが1byte送信するごとに、受信バッファに格納されるデータは常に1byteずつです。 ※送信を実行するまで受信データは無視。受信バッファは勝手にオーバーフローしません。 非同期制御 Write()実行のタイミングとは関係なく、相手機器が送ってきたデータをデバイス内蔵の受信バッファに格納して行く動作です。送受信のタイミングはボーレートの設定によります。 注意点として、こちらと相手機器の通信速度(ボーレート)が一致していないと、データの送受信が互いに失敗します。 また、受信バッファがオーバーフローする前に受信データを読み込まなくてはなりません。 I/Oポートの状態は維持される SetBitMode()で送信方向に設定した線では、Write()した最後の値が、次にWrite()するまで維持されます。 例えば8bit全部送信方向として、Write({0xAA, 0xBB})→1秒待機→Write(0xCC) と実行すると、この1秒間、I/Oポートの電圧状態は0xBBのままです。勝手に0x00にリセットされたりしません。 I/Oポートの状態を取得する方法 Read()は受信データを読み取りますが、あくまでデバイス内蔵の受信バッファから読み出すのであり、I/Oポートの電圧状態を直接見ているわけではありません。現在のI/Oポートの電圧状態を取得するにはGetPinStates()関数を使います。もちろん受信バッファの中身は影響を受けません。 GetPinStates()は、I/Oポートの特定のビットを、他のビットに影響を与えず変更したいときに役立ちます。 【例】bit:76543210のうちbit:3を'1'にする(他のbitの値を変化させてはならない) → byte pinState = GetPinStates(); pinState |= 0x08; Write(pinState); レイテンシ デバイスは関数がコールされた瞬間に実行するわけではありません。安定動作のためにレイテンシ(応答遅延時間)が設けられています。デフォルトで16msです。通常はボーレートの設定値に隠れてレイテンシは気になりません。 しかし実行速度がシビアに求められるような内容のソフト開発では、レイテンシの影響が無視できなくなります。 レイテンシはSetLatency()関数で設定できます。FT232Rは0msにまで設定できますが、無闇に小さくすると動作が不安定になる可能性があります。FT232Rと同じシリーズの別ICでは「2ms以上であること」といったものもありますし、カツカツに切り詰めるなら動作テストで安定性をよく確認しましょう。 FT232R ビットバンモードの信号名
秋月電子FT232Rモジュールのピンアサイン
ドキュメント (画像と下記リンクは 2011/09現在) サイト左メニュー Support→Documents→ [Data Sheets] FT232R USB UART IC Data Sheet http://www.ftdichip.com/Support/Documents/DataSheets/ICs/DS_FT232R.pdf [Application Notes] AN232R-01 Bit Bang Modes for the FT232R and FT245R 2.02 FT232R, FT245R http://www.ftdichip.com/Support/Documents/AppNotes/ AN_232R-01_Bit_Bang_Mode_Available_For_FT232R_and_Ft245R.pdf [Programming Guides] D2XX Programmer's Guide http://www.ftdichip.com/Support/Documents/ProgramGuides/D2XX_Programmer's_Guide(FT_000071).pdf |
◆ ◆ ◆ |
COMポートがないPCでも、USB-シリアル変換モジュールを使えば シリアル通信による機器の制御が簡単にできるようになります。 さらにFT232R ビットバンモードを使えば、シリアル通信にとらわれず より様々な機器を制御できるようになります。 今回はそれらのソフト開発について解説し、サンプルコードを示しました。 次回は具体的な活用例として、ビットバンモードでLCDモジュールを制御します。 |
(C) 『昼夜逆転』工作室 | [トップページへ戻る] |