標準TTLだけ(!)でCPUをつくろう!(組立てキットです!)
(ホントは74HC、CMOSなんだけど…)
[第185回]
●またもや、思わぬトラブルが…
前回、ハイパーターミナルを使って、テストプログラムを送信し、実際にそのプログラムを動作させているところの写真をお見せしました。
やっとこれでALU回路のうちの、論理演算回路の説明が完了し、いよいよこれから、ALU回路の残り、算術演算回路の説明にとりかかります…。
のはずだったのですが、またしても、思わぬトラブルが発生してしまいました。
前々回、[第183回]で、ハイパーターミナルを使っての232C送信について、無事送信テストOK、と書きましたが、じつはスンナリとOKになったのではなくて、当初、送信エラーが発生していたのです。
いろいろ試みるうちに、エラーが出なくなってしまったので、とりあえずは、それでいいか、と思ったのですけれど。
いやいや、やっぱりあいまいにしておくのはよくないぞ。
と思いなおして、あらためて追求してみることにしたのです。
そうしたら、まあ、なんと、とんでもないことが発覚してしまいました。
まあ、ほんとに、好事魔多しといいますか、いやいや好事どころか、そもそも、今年は最初からついていなかった。
これは、きっと、魔物の仕業に違いない。
●サスペンス劇場…衝撃の結末?
調べていくうちに知ってしまった、予想だにしなかった、衝撃の結末とは?
サスペンス劇場の始まりです。
[第183回]で書きましたように、ハイパーターミナルを使うのは初めてです。
そこで、まずは簡単な送信テストをしてみることにしました。
送信先は今回製作した「つくるCPU」試作基板ではなくて、当社のBASICボードです。
いつも製品の動作テストで、232C受信テストに利用しているボードです。
使い慣れているものを使ってテストするのが一番です。そう思って試してみたのです。
これは、なんなくOKになりました。
おお。ハイパーターミナルも、けっこう使えるじゃないか。
これなら、楽勝だ。
と思って、いよいよ本番。
「つくるCPU」試作基板あてに送信テストです。
そうしたら…。
●232C送信でエラー発生
あれっ?受信エラー…?
じつは、こういうこともあろうかと、PICからの出力端子の1本をエラー出力にして、そこにLEDをつけるようにしておいたのです。
すると、ハイパーターミナルからテストプログラムを送信したところ、途中まで受信するとエラーLEDが点灯して、そこで停止してしまうではありませんか?
まさか?
USB−232C変換コネクタでテストしたのですが、念のため、DSUB9pin同士、232Cケーブルを使ってcom1でも試してみました。
結果は全く同じです。
何度試みても、同じアドレスまで受信すると、エラーで停止してしまいます。
最初、BASICボードで受信テストをしたときには、エラーは発生しなかったのに…。
もう一度、BASICボードにつないで、送信してみました。
こちらだと、エラーにはなりません。
当然の結論として、これは、PICの側の問題だ。
最初は、PICが受信したデータをCPUに渡している間に次のデータが来てしまうために、それを落としてしまう、「オーバーランエラー」かと思いました。
ここで、お勉強です。
●オーバーランエラーとは?
PICには受信バッファが2バイト分あって、シリアルデータが送られてくると、プログラムの実行とは関係無く、バックグラウンドでハード的に、そのデータを受信バッファに取り込みます。
受信回路は、シリアル受信したデータがちょうど1バイトそろったところで、「受信データがきましたよ」というフラグをたてて知らせます。
あ。今回は232C受信にPICを使いましたから、PICの動作として説明していますが、「オーバーランエラー」はPICだけの用語ではありません。シリアルデータ受信時のエラーの1種です。
話をもとに戻します。
プログラムの側で、このフラグを見ていて、フラグが立ったら、受信バッファからデータを引き取ります。
この処理を、フラグ発生をトリガとして、割り込みで行う場合には、問題はおこりにくいのですが、そうではなくて、普通のプログラムでフラグの状態を、他の処理の合間にときどき見るようにしていたり、割り込みでも、割り込みを禁止している期間が長すぎたりしていると、データを引き取るのが遅れて、その間に次のデータが到着してしまいます。
PICの場合、受信バッファは2バイト分ありますから、1バイト分だけなら遅れても、エラーにはなりません。
しかし、他の処理に時間を取られてしまい、データを引き取るのがさらに遅れたりすると、バッファに2バイト分のデータが残っていて、バッファフルの状態なのに、そこに次のシリアルデータが到着してしまいます。
でも、それを受け取るスペースは、もうありません。
受信回路は、「もう、だめですぅ」というフラグを出します(だから、早く引き取ってよー、って知らせたのにぃ。恨み節です)。
これが、オーバーランエラーです(早く引き取らなかった、アンタが悪い。ワタシのせいじゃぁ、ないもん)。
オーバーランエラーはタイムアウトになってから出ますから、時すでに遅し、です。
フラグをクリアして、最初から受信をやり直すしかありません。
余談になりますが、オーバーランを防ぐ方法はあります。
最も簡単な方法は、送信してくる相手に、「受信バッファがいっぱいだから、今はもう送らないでよねー」ということを、ハードウェア的に知らせることです。
一般的には、RS232Cの制御線のうちの、RTS(request to send)とCTS(clear to send)を使います。
装置によっては、それに加えてDTR(data terminal ready)とDSR(data set ready)を使うこともあるようです。
互いのRTSとCTS、DTRとDTSを接続することで、送信側と受信側のハンドシェイクが出来て、オーバーランエラーを防ぐことができます。
これらの信号をそのように接続することは、正式のRS232Cのルールにはないことのようで、パソコンの普及に伴って、アマチュア規格的に広まっていったのではないか、と思われます。
ですから、装置によっては、そのような接続になっていないものもあり、接続に際しては、取扱説明書をよく確認する必要があります。
ところで、「つくるCPU」のRS232C回路には、RX(RxD)とTX(TxD)しかなくて、RTS、CTS、DTR、DTSはありません。
それじゃあ、どうするの?
といいますと、こちら側で、RTSとCTS、DTRとDTSをつないでループにしてしまうのです。
下図はRS232Cの9pinDSUBコネクタです。
DOS/Vパソコンについているオス型コネクタを外側から見た図です。
下図は「つくるCPU」基板の232Cコネクタ〜PICの間の回路図です。
コネクタ端子名はパソコン側に合わせてあります。
(この回路図は、ストレートケーブルでの接続をするように、訂正したあとの回路図です)
図のようにDTR−DSR、RTS−CTSをつないでおくと、受信側から送信ストップの信号を送ることはできませんが、RxD、TxD、GNDの3本のラインだけでデータの送受信を行うことができます(今回のように、パソコン→試作基板の向きの送信だけならば、TxDとGNDの結線のみで済みますから、回路が簡単になります)。
その代わりにオーバーランの可能性がゼロではなくなります。
しかし、その可能性は、今回の試作基板では、ちょっと考えられない、のですよ、ねぇ。
なんたって、2400ボーですから…。
●いくらなんでも、オーバーランエラーはありえない…
厳密な言葉の定義によると、ボーレートとビット/秒とは異なる、と何かの解説で読んだ気がしますが、でも計算上はそうなります。
2400ボーは1秒間に2400ビットを送信する速度と考えて間違いありません。
1バイトのデータにスタートビットとストップビットが加わりますから、ちょうど10ビットになります。
2400ビット/秒ということは、すると、240バイト/秒ということになります。
いまどきそれはちょっと遅いのじゃないの?といわれてしまいそうですが、何も10KBや20KBもあるデータを送信しようってんじゃありません。
大きくても、せいぜい1KBか2KBのプログラムです。
2KBだって10秒もあれば終わってしまいます。
それよりも、データを受信してアドレスを表示するLEDがカウントアップされていくさまを眺めているほうが楽しいじゃありませんか。
もう季節も春なのですから、そんなにあくせくしないで、のんびりローカル線の旅を満喫しましょうよぉ。
え?何のお話でしたっけ?
そうそう、そうでした。オーバーランのお話でした。
さきほども書きましたように、PICは受信バッファを2バイト分持っています。
また、今回の受信プログラムでは、PICはASCIIコードで受信した2バイトのデータを16進数1バイトのデータに直してから、CPUに渡します。
当然その換算もPICが行っているのですが、それにしてもそれほど時間がかかるとは思えません。
2バイトのデータを受信するのにかかる時間は、約8.3msecです(1/240×2)。
いくらなんでも、ASCII→16進変換や、CPUへのパラレルデータ送出に、ミリ秒はかかりませんよぉ。
すると?
残る可能性は、フレーミングエラーかぁ?
●フレーミングエラーとは?
フレーミングエラーとは、シリアル伝送経路のノイズや線路の遅れ、またはボーレートの設定ミスなどで、規定時間内にストップビットが受信できなかったり、逆にスタートビットが早く来すぎてしまった場合に発生します。
下図は232Cで、1バイトのデータを送るときのビットデータの様子を模式的に示したものです。
文字”C”のASCIIコード、43(16進数)、2進数では01000011を送信するときの例です。
図のように、最初にスタートビット(1ビットの0)を送り、それからデータをビット0からビット7の順に送ります。
最後にストップビット(ふつうは1ビットの1)を送ります。
受信側はスタートビットの下がりエッジから半ビット過ぎたところから、データのサンプリングを開始します。
それからビット長時間毎にサンプリングし、最後のストップビットのサンプリングで、1バイトのデータの受信を完了します。
最後のストップビットのサンプリングのときに、図の中または下のように、1ではなくて、0が検出されてしまうと、フレーミングエラーになります。
うむむ。
と、とりあえず、ストップビット長を2ビットにしてみよう…。
ハイパーターミナルの設定を変更して、通常1ビットを送るストップビットを2ビットの長さにしてみました。
そうしたら…。
エラーが出なくなってしまいました!
いやぁ。よかった、よかった。
これにて、一件落着。
●でも、それって、おかしくね?
ストップビットを長くするっていうのは、本来は、オーバーランエラー対策のはず。
ストップビットでこける、ということは、その前のビットでも、かなり危ないということになりませんかぁ。
とするならば、ストップビットを長くして、たまたまフレーミングエラーにならなくなったとしても、データの信頼性は、相当に低くなってしまうはず…。
ううう。
ここは、やっぱり、もう少し追求しておかなくては。
PICはクリスタル発振ではなくて、内部発振回路によって、4MHzクロックで動作させています。
もっと高いクロック(8MHz)にもできるのですが、むやみに速くしなくたって、このくらいで十分、と思ったので、そうしたのです。
うむむ。
さては、ボーレートの誤差か?
PIC16F88のデータシートで確認してみました。
[出典]Microchip Technology Inc.PIC16F88datasheet(赤四角は筆者)
今回はクロック4MHzで2400ボーに設定しましたから、表で見ると、誤差は+0.17%ということになっています。
0.17%…?
つうことは、スタートビットから10ビット目でも、誤差はせいぜい1.7%…。
あかん。この線は、完全にシロや。
どうころんだって、これじゃあ、半ビットもズレるのは、どだい無理な話だ。
ホンボシはどこかほかにいる!
ううっ。まてよ。クロックが外付けの水晶発振じゃなくって、内部発振?
そ、それだっ!もう、それしか、ないっ!
ホンボシは、きっとそいつだぁぁ。
[出典]Microchip Technology Inc.PIC16F88datasheet
8MHzだなんて、もっともらしいことを言っているようですが、だまされちゃいけませんぜ、警部。
こいつぁ、きっと、いいかげんにきまってまさぁ。
2009.3.16upload
前へ
次へ
ホームページトップへ戻る