標準TTLだけ(!)でCPUをつくろう!(組立てキットです!)
(ホントは74HC、CMOSなんだけど…)
[第570回]

●STROBE信号を拡大してみました

前回はZ80BASICのPRINT文の実行に時間がかかっているようなので、Z80CPUからPIC18F14K50にデータを送るときのZ80CPU側からのSTROBE信号出力と、それを受けるPIC18F14K50のREADY/BUSY信号の状態をオシロスコープで見てみました。
するとなんと900msec近くもSTROBE信号が出力されたままになっていることがわかりました。

STROBE信号がHになっている期間はほんのわずかしかありません。
そのSTROBE信号がわずかの間だけHになっているところを、時間軸を拡大してみました。

STROBE信号もREADY/BUSY信号も短い時間に繰り返し出力されています。
このわずかな期間だけCPUからPICへデータの送出が行われ、そのほかの大部分の時間はSTROBE信号がアクティブになったままになっています。
Z80CPUがPIC18F14K50にPRINT文の出力データを送るためにSTROBE信号をアクティブにしているのですが、PIC18F14K50がそれに応答していない、という状態のようです。

しかし、PIC18F14K50はCPUクロックが48MHzと非常に高速ですし、プログラムの流れを確認してみても、そのように長い時間Z80CPUに応答しないなどということは考えられません。
ああ、いや、1つだけ、そのような状態が起こる可能性がありました。

それはPIC18F14K50からWindowsパソコンにデータを送信するためのバッファがバッファフルの状態になっているときです。
しかし、そのようなことがあるでしょうか?

●USB(HID)INトランザクション

USB(HID)でPIC18F14K50からWindowsパソコンへのデータ送信は、WindowsパソコンからPIC18F14K50へINトランザクションを要求して、PIC18F14K50がそれに答えて、データを送出することによって行われます。
前に少し書いたことがあったと思いますが、ホストからのINトランザクションの要求は1msec毎に、機械的に行われます。
この要求にはPIC18F14K50は、機械的にでも応答しなければなりません。
答えないでおくとホスト(Windows)側のプログラムがハングアップしてしまいます。

でもそれならば、INトランザクションに答えるための、PIC18F14K50からの送信バッファがフルになってしまう、ということはありえないのではないか、という気がしますが、実は、そのように簡単ではないのです。

実は、WindowsパソコンからのINトランザクションは、アプリケーションの実行とは全く無関係に(!!!)行われるのです。
HIDというのは、とんでもない仕組みなのですよお。

たとえば、RS232C受信ならば、ファイルをOPENしたときから、受信スタンバイになりますが、もちろんホストが勝手にREADするなどということはありえないので、送信側から送信されてきたときにその送信データを受信バッファに読み込みます。
この読み込みはアプリケーションの実行とは非同期に行われますが、しかし、RS232C受信では、データの受信後にReadFile()を実行すれば、その受信バッファに読み込まれているデータを取り出すことができます。

しかしHIDの場合は、送信側から送信されてくるのを待つのではなくて、ホストの側から勝手に1msecに1回、データを送るように要求し、いわば強制的に、といいますか、無理やりにといいますか、データを送出させてしまうのですが、その後1msec以内にアプリケーションがReadFile()を実行しないときは、その受信データは捨てられてしまうのです。
一方PIC18F14K50の側からは、そのように無理やり送出させられたデータがアプリケーションプログラムに吸い上げられたのか、それとも使われないで捨てられてしまったのかを知ることはできません。

でも、それって、そういうことだと、そのままでは使い物にならないのではありません?
もしも、PRINT文のデータをどんどん送って、でも、それがWindowsパソコンの側で画面に表示されなくて捨てられてしまったら?
ねえ。使い物になりませんでしょう。

●Z80BASICでのHID受信の工夫

そこで、Z80BASICではなかなかに面倒なことをやっているのです。
PIC18F14K50は、USB(HID)の64バイトの送信データの先頭に、シリアルナンバーを1バイトつけるようにしています。
と同時にもう1バイト、送信データのバイト数もつけます。
64バイトの送信データのうち、先頭の2バイトはシリアルナンバーとデータバイト数になりますから、正味のデータ数は最大で62バイトになります。

そしてホストからINトランザクションの要求にそなえて、もし送信データがある場合には、データをセットするとともにシリアルナンバーとデータバイト数も先頭に置きます。
PIC18F14K50では、そのように送信データエリアにデータをセットしたあと、送信レディの状態にしておくと、内蔵のHIDコントローラがホストからINトランザクションを受け取ると、自動的に送信データエリアのデータを送出してくれます。
送信すべきデータがないときは、データ数のところに0をセットしておきます。

さてホスト側なのですが、バックグランドでINトランザクションが1msecごとにオートマチックに実行されているために、アプリケーションプログラムがReadFile()を実行したときに、2つの異なる結果になることが考えられます。
その1つはReadFile()が1msecの間に複数回実行されてしまうことで起きます。
その場合、読み込まれるデータは同じデータになります。
こういうことは、RS232C受信ではありえないのですけれど、HID受信では当然のように起こり得ます。

その対策としてシリアルナンバーが生きてきます。
毎回ReadFile()を実行するたびに、シリアルナンバーをまず確認し、前回実行したときのシリアルナンバーと比較するようにプログラムします。
もしシリアルナンバーが同じならば、受信データは更新されていない、と判断して、その受信データは捨てるようにします。
また、受信データのデータバイト数情報が0ならば、PIC18F14K50にはホストに送信すべきデータがない、という判断ができます。

さてもう1つの別の結果についてです。
今度は上とは逆に、ReadFile()が2msec以上の間隔を空けて実行された場合の結果です。
この場合には、INトランザクションの実行によって受信したデータが、その間で落とされてしまうことになります。

これを防ぐには、INトランザクションの要求によってPIC18F14K50がホストに送信したデータが、アプリケーションソフトウェアに受け取られたのか、それとも間に合わなくて捨てられてしまったのかを、、何らかの方法で、PIC18F14K50に知らせてやることが必要になります。

そこでもシリアルナンバーが生きてきます。
アプリケーションソフトの側は、ReadFile()の実行によって、PIC18F14K50からのUSB(HID)送信データを受け取ると、すぐに、そのシリアルナンバーを、USB(HID)を通じてPIC18F14K50に送信するのです。
このときは通常のデータとは区別するために、先頭にそのための識別マークをつけて、シリアルナンバーを送り返します。

ホストからの送信データも64バイトですが、先頭に識別マークの1バイトと、通常の送信データの場合には、送信データのバイト数情報が必要です。
しかし、INトランザクションと違って、ホストが送信する、OUTトランザクションは、アプリケーションプログラムがWriteFile()を実行しない限り、勝手に空のデータを送信してしまう、などということはありません。

すると、通常の送信データをWriteFile()で送信するときは、必ず送信バイト数は1以上になるはずです。
送信バイト数が0ということはありえません。
ですから、さきほどの、受信したシリアルナンバーを返送するための特別の送信データのときは、普通の送信データと区別するために、そのバイト数情報のところを0にして送ります。
つまり通常のデータを送信するときの最大の送信バイト数は1度に63バイト、ということになります。

一方PIC18F14K50は、ホストから返送されてくるシリアルナンバーをチェックします。
INトランザクションの要求によってホストに送信したデータのシリアルナンバーと同じシリアルナンバーが返送されてくるまで、送出するデータは更新しないで、毎回同じデータ、同じシリアルナンバーをホストに送出し続けるのです。
この間はホストへの送信データは更新されませんから、Z80CPUからPIC18F14K50へのデータの送出も、「送信バッファフル」で待たされることになります。

●なぜ画面表示が遅いのか?

そこで、やっとオシロスコープで観測したSTROBE信号の状態についてのお話に戻ります。
ここまでかかってやっと説明しました、PIC18F14K50からの受信データの処理の仕組みによって、アプリケーションプログラムがReadFile()を実行するのが遅れると、その間、PIC18F14K50の送信バッファがバッファフルになってしまい、そのためにZ80CPUからのSTROBE信号出力がアクティブになったままになる、ということがおわかりいただけたと思います。

それじゃあ、Z80BASICのPRINT文の実行によって、PIC18F14K50からUSB(HID)を通じて送られてきたデータをDOSプロンプト画面に表示するのに、そんなに時間がかかるのか?
と言いますと、ええ、確かにそんなに時間がかかっているのですよねえ。

そりゃあ、普通の画面表示とは違って、スクロールのための処理とか、ページモードのためのデータの処理や、ログファイルの作成などということまでやっているのでありますから、そうとう時間がかかるかもしれない、ということは考えてみました。

そこで、念の為に、スクロールとか、ページモードとかの処理をとりあえず外して試してみたのですが…。
それほど、画面表示は、速くはならなかったのです。

むむ。
いったいぜんたい、どういうことなのでしょう?
2010.8.1upload

前へ
次へ
ホームページトップへ戻る