Spartan-3A スタータキット

〜PS/2キーボードからの入力〜


2007/04/20

あなたは 人目のお客様です.

LCD表示もできたし,VGA出力もできた.とりあえず出力はオッケーだ. 次は入力だ.手始めに,PS/2キーボードを繋げてみよう.

PS/2のプロトコルについても, こちらで説明した ユーザーガイド(ug330.pdf)に詳細がある. Spartan-3Eスタータキットのユーザーガイドの日本語版(j_ug230.pdf)も参考になる. またネットで検索しても,いくつか情報が見つかる.

ただしSpartan3Aスタータキットでは, PS/2の分岐ケーブルを使って,2入力(マウスとキーボード) にすることができるようになっているようだ(Spartan3Eボードではできない). これは,Spartan3EスタータキットではPS/2コネクタ(6pin)の1番,5番ピンのみ FPGAに接続されているのに対して, Spartan3Aスタータキットでは2番,6番ピンも接続されているため. なのでSpartan3AスタータキットのUCFファイルでは, PS2_CLK1,PS2_DATA1,PS2_CLK2,PS2_DATA2 の4つの信号が定義されている. これらをキーボードとマウスで使用することができる.


PS/2キーボードを接続

あと,PS/2のプロトコルは双方向らしい.

双方向ってどういうことだ?HDLで書くときは,どーいうタイミングで 値を読み取ればいいんだ!? 出力しながら値を読むこともできるのか??? こーいうことってハードやってる人なら誰でも知ってるあたりまえのこと なのかもしれんが, もともとソフトウエア出身で,回路初心者のぼくにはよくわからん.うーん困った.

PS/2のプロトコルは,ネット上で探すとそれなりに見つかる. 要約すると,こんな感じ.

結局のところ,PCとキーボードは1本のデータ線で双方向にデータをやりとりできる. これを「双方向バス」という (PCとキーボードの場合にはPoint-to-Pointな接続になるが, バスの原理的には,多数のノードを接続することができる). またPCとキーボードの間では, 先にクロックにゼロを出力したほうが優先的にデータを送信する. しかし同時の場合には,PC側が優先になる. これを「PCがバスマスタになっている」と表現するらしい.

うーん,プロトコルの内容はわかるんだけど,結局のところ, VerilogHDLではどう書けばいいのだろうか.

「クロックは通常は常に1になっているが,キーボード側からデータを送信したい 場合には0にする」というのは,まあよい.しかし,ということはPC側は 「クロックを通常は1に保ち,キーボード側が0にしたらデータを読み取る」 という動作が必要になる気がする. つまり,1を出力しつつも,0になっていないかどうかを見る必要がある, のだと思う. たとえばVerilogHDLで,あるピンをinoutに定義して

inout CLK;
assign CLK = 1'b1; // 通常はhighを出力

always @(CLK)
begin
    if (CLK == 1'b0) ...
のように書けば,普段は1なのだが,相手が0を出力したときには反応することが できるのだろうか? うーんよくわからん.そもそも線は1本で, 自身は1を出力しているのに,相手が1とか0を出力したことを こちらで読めるもんなのだろうか? (自身が1を出力しているのだから,読み取る値は常に1になるんではないの?)

それとも

inout CLK;
assign CLK = 1'bZ; // ハイインピーダンス

always @(CLK)
begin
    if (CLK == 1'b0) ...
としてハイインピーダンス状態にしておけばいいのだろうか? でもこれだと,PC側もキーボード側も何も出力していないときに, 「何もないときはクロックは1になっている」ということを実現できない. うーん困った.

で,いろいろ調べたのだけど,結論から言うと, PS/2キーボードは「オープンコレクタ」という接続になっていて, 通常は信号線がhighなのだけど,情報を出力したい場合には lowを出力することで,誰かが0を出力したことを感知できるようだ. 詳しくは「プルアップ」「オープンコレクタ」「ワイアードオア」 「トライステート(3ステート)」「ハイインピーダンス」 などのキーワードで検索とかして調べてほしい. Wikipediaの 「デジタル回路」の説明が詳しくて良いと思う.

これにより双方向通信(もしくはバス接続)で,デフォルトでは1だが, 情報送信時には0にする(そして誰かが0を出力したことを,他の相手は感知できる) ということができるらしい. この場合,FPGA側では通常はクロックをハイインピーダンスにしておけばよい. クロックラインがオープンコレクタでプルアップされているならば, PC側もキーボード側も無出力(ハイインピーダンス)のときには, クロックライン自体はhighの状態になる. そしてPCとキーボードは,クロックラインの状態を見ることができる.

問題は,クロックとデータをオープンコレクタにするためには, これらの線をプルアップしなければならないということ. たとえば Interface誌 2006/01月号にはPS/2キーボードの制御についての記事があるが, ここで扱っている回路は回路側でプルアップが行われているので, 回路側でオープンコレクタになっている. しかしSpartan3Aスタータキットのユーザーガイド(ug330.pdf)の回路図では, スタータキットのPS/2コネクタはFPGAに直結されているため, プルアップはされていない.どーすりゃいいのやら. キーボード側でプルアップされていたりするということはないのかしらん.

UCFファイルでPULLUPというキーワードがある. もしかしたら,プルアップされるように設定することができるのかもしれない (それとも「この線は回路側でプルアップされている」という意味かしら. 詳細未調査.間違っていたらごめんなさい). このへんについてはXilinxのホームページ の,マニュアルのダウンロードページで, ソフトウエアマニュアル ISE9.1iソフトウエアマニュアルの 「制約ガイド(日本語版)」(j_cgd.pdf)というのに詳細がある.

まあでもスタータキット標準のUCF(s3astarter.ucf)を見ても, PULLUPはとくに指定されていないようだし, UCFでPULLUP指定しちゃっていいものかどうかよくわからん. 試してみるのが一番手っ取り早いんだけど, FPGA関連の資料って, 「へんなことをすると,チップの破損に繋がる」 みたいなことがいろんなところに書いてあって, 気軽に試すのはちょっとこわい部分がある. とくに今回の「オープンコレクタ」は,失敗すると自分と相手で電圧がぶつかったり, 電流が流れ過ぎたり(そしてこわれたり)するのかなー, などと初心者的に不安になってしまい,十分に調べてから試したい,というのもある.

で,Spartan3Aスタータキットのユーザーガイドをよく読むと, 「キーボードはオープンコレクタ・ドライバを利用するが,キーボードにデータを 送信しないならば,何も考えずにinputで入力してしまってかまわない」 と書いてある (ここでいう「ドライバ」は,「電圧をドライブする回路」という意味ね. いわゆる「デバイスドライバ」ではない.つまりここで言っているのは, 「オープンコレクタにしなけりゃならない」ということ). なので,あまり難しいことは考えずに,ユーザーガイドのとおりに inputで入力することにする. うーん,キーボード側でプルアップされているということなのかなあ... うーん不明.

で,できたのがこんなかんじ.

ps2.v
ps2.ucf

キーボード上で押されたキーのスキャンコードをLEDで表示する. スキャンコードは,キーボードのキーごとに割り当てられているコードのことで, キーボードはキーが押されると,スキャンコードを送信することで どのキーが押されたのかを通知する.まあこのへんはユーザーガイド参照. ちなみにスペースバーのスキャンコードは0x29,Enterキーは0x5aになっている.

ちなみにキーボードからのデータは, スタートビットが1bit, データが8bit, 奇数パリティが1bit, ストップビットが1ビットの合計11ビットが送られてくる. 奇数パリティって,データ中の1の合計が奇数になるように,パリティを追加する ものなのね.データ中の1の合計が奇数のときにパリティが立つものだと勘違いしてた (よって最初に書いたソースでは,パリティの値が逆になって誤動作していた). パリティの処理を修正して実行したら,あっさり動いた.


起動したところ.何も押していないので,LEDは無点灯.ちなみにリセットは下ボタン


スペースバーを押下


LED表示の拡大.スペースバーのスキャンコード(0x29)になっている


Enterを押下


LED表示の拡大.Enterのスキャンコード(0x5a)になっている

今回思ったのは,同じPS/2接続であっても,回路が異なるだけで, HDL記述も変わってくるということ. たとえばInterface誌 2006/01月号のように回路側でプルアップされていたり, 2006/01月号で紹介されている別の回路(実は2005/12月号で説明されている回路らしい) のように入力と出力に2分割されていたり, 今回のスタータキットのように直結されていたりすると, HDLの書き方も変わってくる. つまり文法だけ知っていればいいというものではなく, ディジタル回路の基本的な知識が必要になってくるということだ. あとプロトコルだけ知ればいいのではなく,回路図もちゃんと読まなきゃならん. うーん奥が深い.ちゃんと勉強しなければいかんなあ.
メールは kozos(アットマーク)kozos.jp まで