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

●HID送信速度の怪

前回、WriteFileとReadFileをペアにして、64バイトのデータを10000回送受信して、それにかかった時間を測定したところ、約24秒かかりました、という説明をいたしました。
1回の送受信データは64バイト×2=128バイトですから、10000回の繰り返しによって送受信したデータは1280000バイトです。
それを24秒で行ったのですから、1280000/24=53333バイト、約53KB/秒の通信速度である、という結果が得られました。
HIDのインタラプト転送での最高通信速度は64KB/秒ですから、その8割強というパフォーマンスです。
しかし、この数字には、じつはウラがあります、というところまでが、前回のお話でした。

どういうウラなのか、それを説明するために、前回行ったテストプログラムを少し変更して、もう一度実行してみることにします。
どう変更するか、といいますと、前回は最初にWriteFileを、続いてReadFileを実行するという、Write/Readのペアを10000回繰り返しましたが、今回はReadFileは行わず、WriteFileのみ10000回実行するようにしたのです。
WriteFileもReadFileも1回の実行でどちらも64バイトを送っていたところを、WriteFileのみ64バイトを送り、ReadFileは実行しないように変更したのですから、トータルの総通信バイト数は前回の半分になります。
ということは、そのWriteFileのみの10000回の実行時間は、前回の半分、約12秒であることが予想されます。

ところが、ところが、実際に実行してみると、意外な結果になってしまうのです。



画面右のDOS窓が、その実行結果です。
比較のために、先に前回実行したhidtest2f.exeを実行してから、今回のhidtest2g.exeを実行してみました。
hidtest2f.exeは、WriteFileとReadfileを各10000回実行しますが、hidtest2g.exeはWriteFileだけを10000回実行します。
hidtest2f.exeは前回は24秒でしたが今回は23秒です。どういうわけか今回は1秒短縮されています(このあたりもなんだか怪しいなあ、という感じがしますねえ)。
で、肝心の、hidtest2g.exeの結果なのですが、なんと予測を大きくはずれて、20秒もかかってしまいました。
これって、どういうこと?

●HIDの意外な振舞い

3.1からはじまったWindowsも95、98、XP、VISTAと続き、今またWindows7がリリースされました。
その昔と比べれば、ハードもソフトも飛躍的な進歩を遂げた、はずなのですが…。
失ってしまったものもまた大きい、と思います。

上で説明したような状況に直面してしまうと、もうさすがのWindowsもアウトです。
これ以上はなんともなりませぬ。

この局面を打開するには、原始的なレベルでの操作が必要になってきます。
ハードの技術、知識を伴わない、高級言語オンリーの「開発担当者」は、ここで完全にリタイアせざるを得なくなります。
ハードやマシン語レベルの知識、技術を有するものだけが、この先に進むことができます。

ここは、PIC18F4550の側からのアプローチが有効なようです。
まずは、HIDクラスの意外な振舞いを知るための細工をPICに施します。
といっても、おまじないをしよう、というわけではありません。
PIC18F4550に対して、ホストからINトランザクションの開始信号(INトークン)が送られてきたら、特定のポートからHパルスを出力する、というプログラムを仕込んだのです。
すると、こういう結果になりました。



画面がちょっと傾いてしまいました。
きっちり1msごとにパルスが出力されています。

それが、一体どうしたというの?

実は、PIC18F4550をUSBケーブルに接続しただけで、まだホストは何もプログラムは実行していないのです。
つまり、アプリケーションの側からは、何もまだPICに要求していませんし、データの送信も受信も行っていないのです。
もちろんWriteFileもReadFileもまだ実行されてはいません。
それなのに、USBケーブルに接続したPIC18F4550がHIDデバイスとして認識された直後から、1ms間隔で、ホストからは、INトランザクション(PICからホストへのデータ送信)の開始要求(INトークン)が連続して送られるのです。
どうもこのあたりに、ReadFileがうまく実行できなかったカギがあるようです。

つまりHIDでは、たとえばインタラプト転送でトランザクションの実行間隔(インターバル)を1msに設定すると(その設定の方法については、いずれ説明をするつもりです)、実際にReadFileを実行する、しないにかかわらず、1ms間隔で、デバイスに対してINトランザクションが発行される(デバイスに、データを送れという要求、INトークンパケットが、ホストから送られる)、らしいのです。

では、そのことが、さきほどの、WriteFile、ReadFileの実行時間と、WriteFileのみの実行時間との食い違いに、どのように関係してくるのでしょうか?

WebにはUSBについて解説しているサイトもそこそこありますし、HIDについてのサイトはそれほど多くはありませんが、それもまあ、そこそこはあるようです。
しかし、こういう切り口でHIDにせまる、というサイトはほかにはないように思うのですが、いかがでしょうか?
目からウロコ、をご体験いただけますでしょうか?

話をもとに戻します。
そのあたりのことを、もう少しあきらかにするために、今度は、ホストからデータの送信を受けるたびに、ポートの出力をインクリメントするようにしておいて、ホストがWriteFileを連続で実行して、つまりホストからPICに対して連続でデータを送信するようにしてみました。
このPICのプログラムは[第422回]で使ったのと同じものです。
PICは受信するたびにPORTCの出力をインクリメント(+1)します。
そしてそのPORTC出力の下位2ビットをオシロで観測したのが下の写真です。


上側(CH1)がPORTCのビット0(RC0)で下側がビット1(RC1)です。
ホストからデータは1msごとに送られているはず、なのですが、実際にはPORTCの出力は、2msごとに変化しています。
なぜなのでしょうか?

そこで、さきほどお見せした写真が利いてくるのです。
つまり、HIDでは、ホストがアプリケーションでReadFileを実行していなくても、1msごとにINトランザクションが「勝手に」実行されてしまうのです。
そして、そこにWriteFileがやはり1msごとに実行されるために、OUTトランザクションと(ダミーの)INトランザクションが交互に実行される形になるため、写真のように、1回のホストからのデータを受信するのに2msかかってしまう、のだと考えられます。
このことは、最初にお見せした、C++プログラムでのWriteFileのみの10000回の実行結果が20秒であったこととぴったり一致します。

ところで、どうせならば、フレームはがら空き状態のはずなので、同じ1msのフレームにOUTトランザクションとINトランザクションをいっしょにのっけてくれれば、OUTとINをあわせて1msで済んでしまうはずなのに、と思うのですが、そこが、どうも[第427回]でご説明しましたように、「ホストコントローラ様の勝手だよん」のようです。

さて、ではWriteFileとReadFileを実行したときの、PORTCの出力はどのようになるでしょうか。


今度は、2msと3msが交互にあらわれているようです。
ホストの側のプログラムは、WriteFileとReadFileを交互に実行していますから、OUTトランザクションとINトランザクションも交互に実行される、と思うのですけれど、そこにときどきダミーのINトランザクションが入り込むのではないか、と推測しています。
というか、うまくダミーのINトランザクションのタイミングとReadFileの実行により発行されるINトランザクションのタイミングが合うときと、それがずれて両方のINトランザクションが発行されてしまうときが、ちょうど交互に出現しているように思われます。

写真の波形から、OUT2回の実行時間が5msですから、(この間にINも2回実行されているはずなので)、WriteFileとReadFileを合わせた一回の実行時間は平均2.5msということになります。
これは、前回おこなったテストの10000回の実行結果の24秒を裏付けるものといえるでしょう。
また、同じプログラムを実行したのに、今回は23秒であった、ということも、上で説明しましたように、ダミーのINトランザクションとReadFileの実行によるINトランザクションの重なり具合に、パソコン内の資源状態からくる「ゆらぎ」がからんでいる、と考えると納得できる、のではないかと思います。
2010.2.4upload

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