I/Oタイミング再来

  • 投稿日:
  • 更新日:2015/02/09
  • by
  • カテゴリ: ,

SDカードインタフェースのハードウェアが出来上がったので、早速実際のSDカード入出力を作り始めています。 まずは、試しにディレクトリ情報を読み出しています。

今回は、AVR側にFATシステムを入れることにより、高速化を狙っていますが、1ポートのインタフェースで通信するのはなかなか難しいことがわかりました。

たとえば、BASICで入出力を組んでやると、特に問題なくSDカードからデータが読めます。 しかし、マシン語になると、処理によってはZ80からの要求がシビアで、AVR側の処理が追いつきません。


PCからのデータ出力時(コマンド)

PCからoutでデータを出力したら、それに反応してAVRが動作するようにしています。 処理中の場合はステータスとしてBUSYを示す信号を出すなどして本体側を待たせればいいわけですが、BUSYを出すまでの時間が問題です。 普通のAVR-GCCではレジスタ退避をするのでとても追いつきません。 そのため、割り込みベクタ部は一部アセンブリで組んでいます。

以前の調査で、割り込みルーチンの開始までの反応時間(ベクタテーブルからのrjmp含む)は8MHzでおよそ8クロックであることがわかっています。

BUSYシグナルを出すためには、アセンブリでも現状で12クロックほどかかるので、合計20クロック。4MHz相当で10クロックです。 out命令終了から次のin命令まで10クロックということは、間に1命令程度挟めば普通に間に合うことになります(in命令自体の入力動作が命令処理の後ろのほうであるため)。

これはほぼうまく動くようになりました。


PCへのデータ入力時(レスポンス)

こいつが問題です。

なるべく入力割り込みの処理を軽くして、連続するin命令に対応できるようにしようとしています。

ディレクトリ情報などは、SRAM内で保持してもたいしたことはないので、コマンド実行時に結果を用意しておいて、1バイトづつ返せば、割り込み処理自体もそれほど時間はかからないでしょう。

ところが実際は、けっこうwaitを入れながらでも、入力データのとりこぼし(というか、ずれ)が生じます。 PCからはINRQ信号で割り込みをかけ、AVRがそれに対し「次のデータ」を返す(でないと間に合わない)のですが、割り込み処理中の多重割り込みはしていないので、完全なハンドシェイクにはなりません。 AVRとZ80がうまく同期していないんですね。

特に、コマンド実行直後のステータス情報を取得する部分(連続するinの最初のバイトの受信)でうまく同期が取れていないようです。 busy状態からデータ入力に変わるところなので、タイミングが微妙なのです。 ステータス情報の確実な受け渡しのために、ステータスにPCからのackを返せばいいかもしれませんが、それに対してまたbusy状態になって...きりがありませんね。

また、セクタデータを読み出す際は、ATmega8では1セクタ分(512バイト)のバッファが取れないので(既にFATで512バイト使っているため)、オンデマンド読み込みをするしかなさそうです。


データもステータスも一つのポートでやり取りしなければならないのが根本原因のひとつなのですが、ここまできた以上なんとかするしかないですね。 完全に1バイトづつハンドシェイクする方法もあるのですが、なんかそれは負けた気がする...。