標準TTLだけ(!)でCPUをつくろう!(組立てキットです!)
(ホントは74HC、CMOSなんだけど…)
[第589回]
●犯人はDMAでした
前回はND80ZVで、[*(I/O)][SI](16進キーの3)を使って、RS232C受信のテストをしようとしたところ、ほとんど受信できずにハングアップしてしまいます、ということを書きました。
Z80BASICで、READ #1命令を使ったテストプログラムを実行させてみますと、全く問題無く、正しく受信できます。
Z80BASICでも、ND80ZVの[*(I/O)][SI]でも、同じことをやっているはずなのですが、なぜかND80ZVのモニタプログラムでのRS232C受信だとハングアップしてしまいます。
どうにも原因がわかりませんでしたから、カメレオンUSB+ロジアナで信号の動きをチェックしてみました。
カメレオンUSB+ロジアナは[第374回]でご紹介いたしました。
すると、怪しいところがみつかりました。
前回の最後にお見せした波形です。
232Cセレクト信号がアクティブ(L)になって、PIC18F14K50に、232C受信データの送出を要求しています。
送信側はまだ送信を開始していませんから、PIC18F14K50は受信バッファエンプティを返します。
RB4(PICSTB)が約15μsecの間LになってからHに戻っています。これが受信バッファエンプティのときの応答です。
ところが奇妙なことに、このPICSTBがLになっている期間の、Z80CPUのIORQとRDとD5がHになっていて、まるで無信号のように見えます。
そしてその後で、232Cセレクト信号がLになりっぱなしになっています。
そしてそして、IORQとRDが繰り返しアクティブになって、まるで無限ループになっているかのように見えます。
なんでもない、正常なときの波形と比べていただければ、その違いは一目瞭然です。
前回、この怪しげな、間延びした波形をご覧になって、あるいはお気づきになられた方もいらっしゃるかと思います。
そうなのです。
犯人は、7セグメントLEDのダイナミック表示を行うためのDMAだったのです。
ND80ZVは(TK80も同じ)、7セグメントLEDをダイナミック点灯させるために、LED表示回路がCPUの動作を一時的にほんのわずかな期間、停止させて、その間にメモリから表示データを読み出してLEDに表示させています。
それがDMA(dynamic memory access)です。
ND80ZVはこのための信号をタイマーICの555で作り出して、それをZ80CPUのBUSRQに入れています。
約1msecに1回、10〜20μsecのパルスがBUSRQに入れられます。
Z80CPUはBUSRQが入力されると、その間は命令の実行を中断して、メモリアクセスやI/Oアクセスに必要な信号や、データバス、アドレスバスをハイインピーダンスにして、BUSAK信号をアクティブにします。
その間はCPU以外の回路が、メモリやI/OをCPUの動作とは関係無くアクセスすることができます。
IORQはともかくRDはメモリアクセスにも使う信号ですから、そのRDが10μsec以上もの間、Hになりっぱなしということは、ちょっと考えられません。
たとえ暴走したとしても、CPUクロック6MHzに見合う間隔でRDはアクティブになるはずです。
とすると、犯人は、DMA以外にはない、ということになります。
DMAは、BUSAK信号がアクティブである期間に実行されます。
そこで、BUSAKを加えて、もう一度カメレオンUSB+ロジアナで観測してみました。
おお。
まさにぴったり。
ビンゴです。
こういうことだったのです。
Z80CPUは、PIC18F14K50にRS232C受信データを要求するために、232Cセレクト信号をアクティブにして、PIC18F14K50からの応答(PICSTBの立下り)を待ちます。
1075μsの少し前のところで、IORQとRDがアクティブになっています。
PICSTBをチェックするためのIN命令の実行です。
ここではまだPICSTBはHのままです。
その直後に、DMAが実行されました。
BUSAKがアクティブ(L)の間は、IN命令は実行されません(プログラムの実行はそこで一時停止しています)。
BUSAKがHになると、プログラムの実行が再開され、再びPICSTBのチェックのためにIN命令が実行されます。
1090μsを過ぎたところで、IORQとRDがアクティブになっています。
ところがちょうどその直前に、PICSTB信号はHになってしまっています。
PIC18F14K50は約束した通りに、15μsecの間、STB信号をアクティブにして、バッファエンプティを出力したのですが、Z80CPU側では、ちょうどその間、DMAのためにいわば瞬間的に目をつぶってしまって、そのPICSTB信号を見逃してしまったのです。
Z80CPUの側では、232Cセレクト信号をアクティブにしましたから、PIC18F14K50からのSTB信号をずっと待ち続けています。
ではPIC18F14K50の方は何をしているのか、といいますと、これがまた悲しいことに、STB信号を出力し終えましたから、Z80CPU側からの232Cセレクト信号がHになるはず、ということで、これまたずっとそれを待ち続けているのです。
実はここのところは、以前はちゃんと動作していたはず、でした。
以前は、PIC18F14K50はSTBをHにすると、232Cセレクト信号がHになることを確認することなくリターンしていました。
そのため、今回のように232Cセレクト信号がアクティブのままになっていると、PIC18F14K50は次のサイクルでふたたびSTBをアクティブにします。
そこで、今度はZ80CPU側もその信号をキャッチすることができていたのです。
しかし、その処理の甘さのせいで、Z80BASICの受信プログラムで、ときどきデータを落としてしまうという現象が発生しました。
そこで、PIC18F14K50のプログラムを修正して、STBをHにしたあと、232Cセレクト信号がHになるまで待ってからリターンするように変更しました([第583回])。
今回は、その修正がかえってアダとなってしまいました。
しかし、それにしても、よくぞここまで見事にすっぽりはまってくれたものです。
狙ったってこうまで見事に当るものじゃありません。
それなのに、毎回必ずと言っていいくらいハングアップしたのですから、これを魔物の仕業と言わずして、なんと言いましょうぞ。
それはともかくとして、これにはまいりました。
ここまできて、土壇場でこんなことになってしまうとは。
実は、Z80BASICはエントリすると、ND80ZVのLED表示のためのDMAを禁止してしまうのです。
Z80BASICでは、表示にはWindowsパソコンのディスプレイを使いますから、もう7セグメントLEDの表示は不要なのです。
それにBASICインタプリタは実行に時間がかかりますから、DMAによって無駄な時間が消費されるのは避けたかったという理由からでもあります。
そのために、Z80BASICの232C受信プログラムはハングアップしなかったのです。
いっそ、ND80Zモニタでも、232C受信のときは、DMAを禁止してLED表示をブランクにしてしまいましょうか?
あるいは、PICSTB信号をもっと長い時間アクティブにして、その間にDMAが発生しても大丈夫なようにする、というテもあります。
いや、いや。
DMAを禁止する、というのはともかくとして、PICSTBを長くする、というのは面白くありません。
それに555の発振はRCですから、ある程度のバラつきは避けられません。
うむ。やっぱり、それは、やりたくありません。
もともと、ここのところは、余り賢くないなあ、と思っていました。
こういうことが明らかになってしまいますと、これはもう、なんとか別の方法にすることを考えなくてはいけません。
しかしPIC18F14K50の端子は全部使い切ってしまっていますから、別の信号線を使って受信バッファエンプティを知らせる、ということができないのですよねえ。
バッファエンプティを知らせるために、STBパルスを利用する、というのは、まあ、ぶっちゃけて言いますと、苦肉の策、だったのです。
信号線が無い?
うう。
待てよ。
なんとかなるのかも…。
昔の人はいいことを言いました。
頭は生きているうちに使え、って。
ま。もっとも、そのうち生きていても使えなくなる日がやってくるかも…。とほほ。
回路図を眺めていましたら、
おお。
ひらめきましたよ、なんとかなりそうな方法を。
本日は時間がなくなってしまいました。この続きは次回にさせていただきます。
2010.8.22upload
前へ
次へ
ホームページトップへ戻る