平成15年1月2日
IEEE1284は、プリンタポートを使ってホスト(PC)とペリフェラル(周辺機器)でデータをやりとりするための規格です。
IEEE1284ではプラグアンドプレイ(PnP)に対応した周辺装置を作成することができます。しかも、マニュファクチャコードやベンダーコードの取得が不要であり、誰でも無料でPnPデバイスを堂々と作ることができます。
IEEE1284を実現するためには、次の機能を実装する必要があります。
上記の機能が実現できれば、Windowsは周辺機器をIEEE1284対応機器として認識します。
このWebページは急いで書いたので、ところどころ不親切だったり、変な個所がありますが、VHDLのバージョンアップとともに文章も更新していきますので、ご了承ください。
高度なFPGAが手軽に使える時代になりました。アマチュアレベルでも、FPGAにデジタル信号処理や画像処理ができる時代になりました。でも、FPGAとPCとのインタフェースは依然として壁が残っています。
私たちが趣味でマイコンやFPGAを使っていろいろ実験するときに、インタフェースにはRS-232Cやプリンタポート、USBなどの選択肢があります。
ポートの種類 | 速度 | 長所 | 短所 |
---|---|---|---|
プリンタポート | 0.1〜16Mbps | プロトコルが任意。外付け部品が少ない。 | NT系のOSでは簡単に使えない。 |
RS-232C | 〜115kbps | ほとんどのPCで使える | 電圧レベルの変換。遅い。 |
USB1.0 | 12Mbps,480Mbps | 速い。現在のトレンド。 | 専用チップが必要。ベンダーID取得。 |
中でも、プリンタポートは外付け部品も少なく、電圧の変換が不要なので手軽にインタフェースできます。なんと言っても、高価なインタフェースチップが不要で、簡単なロジック回路やマイコンがあれば、誰でも自由にインタフェースを自作できます。
自作の装置では、プリンタポートの信号線の本来の役割を無視して、独自の規格のパラレルIOポートとして使えば、プロトコルも自分で勝手に決めることができます。
しかしその反面、遅い、NT系OSで手軽に使えない、信頼性が低いなどの欠点もあります。
そこでプリンタポートをIEEE規格に準拠させようと思っても、ニブルモードやバイトモードなどのレガシー(旧式)の解説はいくつか見つかりますが、ECPモードやEPPモードなどの高度なものを作ろうとしても資料が無く、実現するのはUSBやRS232Cより難しいでしょう。
プリンタポートを使って、高速で高機能なインタフェースを手軽に作りたいけど、資料が無くてわからない。そんな労力を低減するのが本企画の目的です。
この企画では、モルフィー企画様のVirtex300Eボードを使って、IEEE1284に対応した装置を開発することを目的とします。開発に使っている装置を右の写真に載せます。写真のようにVirtex300Eボードを、SRAMと高速ADコンバータのついた万能基板に載せます。
SRAM:HM62W16255HJLP-12(256kword*16bit 12ns)
DAC:TDA8702(ビデオ用8bitDAC)
本IPは、IEEE1284機能を実現するコアの部分と、VirtexEのブロックRAMなどを使用する周辺部分から構成されています。
コアの部分は、使いまわしが効くようにソースを分けてあります。
使用にあたっては、次の点に注意してください。
現在、実現されている機能は次のとおりです。
現在、次の機能がまだ実現されていません。
上記の項目に同意いただければ、次のリンクをクリックしてダウンロードしてください。
●IEEE1284コアのダウンロード(IEEE1284main-ver01.vhd)
IEEE1284main.vhdの入出力ピンを説明します。
種別 | ピン名 | 入出力 | 機能 |
@クロック等 | CLK | in | クロック入力(25MHzを期待) |
RESET | in | リセット入力(実際には未使用) | |
Aユーザ側 | DataAvail | in | 周辺装置→PCへ送信すべきデータが用意できて、送信可能状態であることを示すフラグ |
DataReq | out | PCから読み出し用にデータを要求されたことを示す、1クロック長のパルス | |
DataReceived | out | PCからデータが書きこまれたことを示す、1クロック長のパルス | |
DataWr | in | ユーザのデータが用意できて、PCに送信するための、1クロック長のパルス | |
Busy | in | 周辺装置がビジー状態であることを示す | |
Data_IN[7:0] | in | PCに送信するデータ | |
Data_OUT[7:0] | out | PCから受信したデータ | |
BIEEE1284側 | IEEE1284_DIN[7:0] | in | IEEE1284ポートからのデータ入力 |
IEEE1284_DOUT[7:0] | out | IEEE1284ポートへのデータ出力 | |
IEEE1284_nERROR | out | IEEE1284ポートのnError信号 | |
IEEE1284_Select | out | IEEE1284ポートのSelect信号 | |
IEEE1284_PaperEnd | out | IEEE1284ポートのPaperEnd信号 | |
IEEE1284_nAck | out | IEEE1284ポートのnAck信号 | |
IEEE1284_Busy | out | IEEE1284ポートのBusy信号 | |
IEEE1284_nStrobe | in | IEEE1284ポートのnStrobe信号 | |
IEEE1284_nAutoLF | in | IEEE1284ポートのnAutoLF信号 | |
IEEE1284_nInit | in | IEEE1284ポートのnInit信号 | |
IEEE1284_nSelectIn | in | IEEE1284ポートのnSelectIn信号 | |
CIEEE1284の状態を示す | Mode_Compatible | out | 互換モード |
Mode_Byte | out | バイトモード | |
Mode_Nibble | out | ニブルモード | |
Mode_EPP | out | EPPモード | |
Mode_ECP | out | ECPモード | |
Mode_AutoNego | out | ネゴーシエーションモード | |
ODBuf_En | out | IEEE1284のデータバスをリバース(周辺装置→PC方向)にする。 | |
Debug_Out[7:0] | out | デバッグ用 |
これらの信号線をどのように使えばよいか、少し詳しく解説します。
@クロック等
クロックとリセット信号です。
Aユーザ側信号
ユーザロジックから、IEEE1284へデータを送受信するのに必要な信号です。
■データを受信(PC→周辺装置)する場合
PCからデータを受信すると、Data_OUT[7:0]にそのデータを載せ、DataReceivedに1クロック長の信号を出します。
■データを送信(周辺装置→PC)する場合
周辺装置がビジー状態の時にはBusy信号をHighにします。Busy信号はIEEE1284のハンドシェイク等には無関係です。それを受信したPCがどのように処理するかを任されています。
PCへ送信したいデータが用意できたときには、DataAvailをHighにします。この信号がLowになると、IEEE1284のハンドシェイクにWaitをかけます。
PCから送信要求がされると、DataReqに1クロック長の信号が出ますので、Data_IN[7:0]に送信したデータを載せ、DataWrに1クロック長の信号を入れてください。DataReqからDataWrまでは即答する必要はありませんが、あまり長いとPCがタイムアウトするので、数ミリ秒以内には返すようにしましょう。
BIEEE1284側信号
IEEE1284の対応するピンに接続します。ただし、入力信号には必ず1段以上のD-FFを入れてください。
CIEEE1284の状態を示す信号
ネゴーシエーションの結果、現在どのモードであるかを示します。ODBuf_ENは、データバスを双方向にするための、出力イネーブル信号です。
次の写真は、ECPモードでデバイスIDを読み出した時の波形です。CH1がnAck信号で、CH2がnSelect信号です。
CH1のnAck信号はデータのストローブに使われる信号で、その立下りエッジで、PCはデータを読み込みます。
CH2のnSelect信号は周辺装置が送りたいデータがあることを示す信号で、Lowレベルのとき、送信したいデータがあることを示します。つまり、この信号が立ちあがると、送信完了を意味します。
この写真を見ると、最初の20μ秒はnACKが詰まっていて、後は閑散としています。その理由はFIFOです。
ECPモードで読みこむ最初の20μ秒を拡大した波形を次の写真に載せます。
ECPモードでは、PCのIOチップは、FIFOを使います。周辺装置からFIFOへの読みこみはハードウェアが自動で行います。そのため、約1μ秒に1回データを読み込んでおり、この状態ではとても高速です。
FIFOがフルになると、PC側のECPのハードウェアは自動読みこみを一時停止します。つまり、ウェイト状態です。
この状態で、ソフトウェアがFIFOからデータを取り出してやると、FIFOに1バイトの空きができるので、自動的にIEEE1284へデータを要求します。ソフトウェアは、FIFOのステータスを見ることと、FIFOからデータを取り出すことで、2回inp命令を実行します。
私のPCでは1回のアクセスに約1.5μ秒を要します。これは、Windowsのデバイスドライバを作ったわけではなく、単純なinp命令を使っているため実際の読みこみ動作よりかなり遅いです。ちゃんとデバイスドライバを組めば、もっと速くなるでしょう。
最初の写真から判断すると、私の使っているマザーボードでは、FIFOへの高速読みこみは21回行われています。おそらくFIFOの深さが16バイトです。
PC側のハードウェアが、16バイトをFIFOに読みこむ時間は約16μ秒ですが、この間にもソフトウェアはFIFOから読み出しを行っています。ソフトウェアがFIFOから5バイト読み出す時間は、およそ3.1×5=15μですから、16バイト読みこんだ後には、FIFOのおよそ5バイト分の余裕が空いているはずです。したがって、FIFOがフルになるまでには、あと5バイト読みこめます。
それゆえ、21バイト分が高速に読み出されたのでしょう。
とにかく、ECPモードでは、FIFOが満杯か否かで読み出し速度に差が生じるようです。
各モードがデータを如何に速く読み出せるかを競います。
モード | IOポートへのアクセス回数 | 1バイトの転送時間 | 転送速度 |
ECPモード(FIFO非満杯時) | 2回 | 0.91μ秒 | 1.087MByte/s |
ECPモード(FIFO非満杯時) | 2回 | 3.2μ秒 | 0.312MByte/s |
ニブルモード | 12回 | 22μ秒 | 0.045MByte/s |
バイトモード | 12回 | 21μ秒 | 0.047MByte/s |
私の実験環境(Celeron366MHz自作PC)では、Windows98上でinp、outp命令を使うことによるIOポートへのアクセスには1回あたり1.6μ秒要することがわかっています。ニブルモードとバイトモードの場合、12回のIOアクセスでは19μ秒要しますが、その他にもWindowsのメッセージ処理などが2〜3μ秒加わっているため、上記の結果になったものと思われます。
1回のアクセスに12回というのはいささか多い気がしますが、これはハンドシェイクを厳密に行う上の問題で、プログラミングで頑張れば回数は、もっと減らせるはずです。
オシロスコープを用いて、デバイスIDを読み出すのに必要な時間を計測しました。
モード | 時間 | 平均転送速度 |
ECPモード | 0.22ms | 372kByte/s |
ニブルモード | 1.82ms | 45kByte/s |
バイトモード | 1.74ms | 47kByte/s |
思ったほどECPモードが速くないのは、FIFOが16バイトしかないため、すぐに埋まってしまうからです。また、FIFOからの読み出しにデバイスドライバを作成したわけではなく、inp命令を使用しているため、Windows98のVxDの処理などに要する時間と考えられます。
デバイスドライバを作成すれば、もっと速くなるはずです。
IEEE1284の実験を行うため、次の図のようなソフトウェアを開発しています。近日公開します。
デバイスIDを設定すると、Windowsの起動時にPnPで認識させることができます。どうやら、Windowsの起動時にネゴーシエーションを行って、ニブルモードでID要求するようです。
デバイスIDは、可変長のASCII文字列です。最初の2バイトは、文字列の長さを示します。
その後、キーと値を「:」(コロン)で組み合わせ、「;」(セミコロン)で区切ります。
例) [0x00][0x4a]MFG:Nahitafu;MDL:VIRTEX300E;CLS:Dot4;DES:Nahitafu IEEE1284 FPGA;
次に、各キー名と意味を簡単に説明します。
キー名(省略形) | 内容 | サンプル |
MFG | 周辺機器のメーカを表す | Nahitafu |
CMD | プリンタの対応言語を表す | ESCPL2,BDC,D4 |
MDL | 機種名を表す省略名称 | VIRTEX300E |
CLS | デバイスのクラスを表す | Dot4 ※後述 |
DES | 詳しい解説(PnP時に表示される) | Nahitafu IEEE1284 FPGA |
Windowsのバージョンにもよるのでしょうが、デバイスのクラスはWindows DDKで規定されています。その中から、パラレルポートにつなぐ周辺装置として、意味がありそうなものをいくつか紹介します。
デバイスクラス | CLS | 対象デバイス |
CD-ROM | CDROM | CD-ROM |
ディスクドライブ | DiskDrive | ハードディスク |
フロッピーディスクコントローラ | FDC | フロッピーディスクコントローラ |
フロッピーディスクドライブ | FloppyDisk | フロッピーディスクドライブ |
ハードディスクコントローラ | HDC | ATA/ATAPIを含むが、SCSIやRAIDは含まない |
ヒューマンインターフェースデバイス | HIDClass | キーボードやマウスなど |
IEEE1284.4デバイス | Dot4 | IEEE1284.4に対応したマルチファンクションデバイス |
IEEE1284.4プリンタ | Dot4Print | IEEE1284.4に対応したプリンタ |
イメージングデバイス | Image | デジカメやスキャナなど |
IrDAデバイス | Infrared | IrDAデバイス |
キーボード | Keyboard | キーボード |
メモリテクノロジドライバ | MTD | フラッシュメモリカードなど |
モデム | Modem | モデム |
マウス | Mouse | マウス、トラックボールなど |
マルチファンクションデバイス | Multifunction | 複合デバイス。特に通信関係を意味するらしい。 |
マルチメディア | Media | オーディオデバイスやDVD、ジョイスティック、ビデオキャプチャなど |
ネットワークアダプタ | Net | 高速赤外線以外のNDIS NICデバイス |
プリンタ | Printers | プリンタ |
プロセッサ | Processor | プロセッサ |
SCSI、RAIDコントローラ | SCSIAdapter | SCSI、RAIDコントローラ |
スマートカードリーダ | SmartCardReader | スマートカードリーダ |
テープデバイス | TapeDrive | テープデバイス |
※IEEE1284.4とは、複数のデバイスをパラレルポートにつなぐ技術です。USBでは127台までつなげることができますが、そのIEEE1284ポート版です。
上記のデバイス以外にも、たくさんのデバイスクラスがWindowsで規定されています。しかし、IEEE1284ポート越しに、認識されるかは不明です。特に、マイナーなデバイスほど結果は不明です。
デバイスドライバを作って、INFファイルを記述すればPnPインストールができるかと思います。
IEEE1284には、互換モード、バイトモード、ニブルモード、ECPモード、EPPモードの5つのモードがあります。その機能はいろいろと差があります。中でもEPPとECPは高度なモードで、書きこみ(PC→周辺装置)と読みこみ(周辺装置→PC)の両方ができます。また、ECPとEPPはハンドシェイクをハードウェアで行い、高速です。
読み | 書き | ハンドシェイク | 速度 | 特徴 | |
互換モード | × | ○ | ソフトウェア | 低速 | |
バイトモード | ○ | × | ソフトウェア | 低速 | データバスを入力用に切りかえる |
ニブルモード | ○ | × | ソフトウェア | 低速 | ステータス用の4本の信号線を使って、1バイトを2回に分けて読み込む。 |
EPPモード | ○ | ○ | ハードウェア | 高速 | 同期式 |
ECPモード | ○ | ○ | ハードウェア | 高速 | FIFO、ランレングス圧縮、内部モード |
IEEE1284の信号はとても気まぐれです。モードによって信号の機能も名前も変わるからです。しかし、名前や機能は変わっても、信号の持つ機能の本質はあまり変わりません。
プリンタポートを単純なIOとして使った場合、PCが送ったデータを周辺装置が正しく受け取ったかどうかなどをハンドシェイクして確認することは滅多にありませんでした。いわゆる送りっぱなしの状態でした。
IEEE1284では、どのモードであれ、ハンドシェイクを行うことになっています。PC→周辺装置へのハンドシェイクはnStrobeかnAutoLFをストローブ信号として使います。(モードによっては、名前がHostClkやHostBusyだったりしますが、機能と目的は一緒です)
周辺装置→PCへデータを送る際のハンドシェイクは、ほとんどの場合、nAckを使います。
ハンドシェイクの信号は基本的には負論理ですが、例外もあります。
nDataAvailは、周辺装置からPCへ送りたいデータが存在することを示す信号です。ECPモードではこの信号はnPeriphReqという名前ですが、機能は一緒です。Lowの時に、周辺装置からPCへ送りたいデータが存在します。
周辺装置がバイトモード、ニブルモード、ECP、EPPモードの時に1284ActiveがLowレベルになると、互換モードへ戻ります。ネゴーシエーション中にLowレベルになると、ネゴーシエーションを強制終了し、互換モードへ戻るでしょう。
このように、1284Activeは、IEEE1284のモードを終了させる機能を持ちます。
Select信号は、IEEE1284のモードではXFlagとなります。これは、周辺装置が、要求されたモードに対応しているか否かを示す信号です。
Busy信号の意味は、周辺装置からPCへ、ビジー状態であることを伝えるフラグです。
nInit信号の意味は、PCが周辺装置に初期化を要求する信号です。
BusyとnInitは、多くのモードでは、IEEE1284の機能に影響を与えません。ユーザが任意に使用しても問題はなさそうです。
しかし、ECPではnInitをデータバスの方向切り替えに利用していますので、注意が必要です。また、Busy信号を本来のビジーフラグと時分割で各種制御線として使うこともあります(ニブルとECP)。
プリンタポートから出る信号は、とてもいいかげんな信号です。昔は、オープンコレクタにプルアップ抵抗が基本でした。このため、波形品質はとても低いのが実情です。
昔のように、プリンタポートの信号をマイコンのIOポートで受ける場合には、応答速度がそれほど速くないから問題にはなりませんでしたが、数十MHzで動くようなハードウェアロジックで受けると、波形の汚さを痛感します。
STBなどの信号は、出力がオープンコレクタなので、立下りは鋭い波形ですが、立ちあがりはプルアップ抵抗のお世話になっているので、緩慢な立ちあがりになります。そのため、信号がスレッショルド近傍で何回もHとLを往復し、チャタリングのような波形になることもあります。
それでも数MHzという遅いクロックで、パラレルポートのインタフェースをしていた頃は問題になりませんでした。
本VHDLソースでは、このような現象に対して耐性を持たせております。0.5μ秒以内であれば、信号がばたついても大丈夫です。