PIC16系のUSARTとMPLAB/PICCのこと(4)


■ USARTは結構大変


・57600bpsでの通信(USART)は結構シビア。


3.58MHzのセラロックをつけて(USARTの誤差率が少ないので)57600bpsで通信させているのだが、1秒に57600/10bit = 5760回ぐらいの受信割り込みがかかる。


PICは4clockで1命令しか実行できないので895000命令/秒。5760回で割ると155.38命令で1回の受信を完了しなければならない。


PIC/AVRを100個ほど数珠つなぎにする計画なので、受信と送信は同じぐらいの頻度で起こる。よって、実際には、155.38の半分の命令でなければならないし、これ以外にもタイマ割り込みが1msごとにあるのと、それとは別にメインの処理がある。


タイマ割り込みは1msなので895命令に1回。メインの処理も必要であることを考えると実際のところ30〜50命令ぐらいで1回の受信割り込み処理を完了する必要がある。


ここまでシビアとは思わなかった。PIC16シリーズは割り込みベクタは一つしかなく、割り込みハンドラ内で割り込み要因を特定しないといけないので、余計なコードがさらに必要になる。ただ、レジスタが少ないので割り込みハンドラでのレジスタ待避が楽なので(STATUSレジスタとwレジスタだけで済む)そこは助かる。


そんなわけで3.58MHzのクロックでは、割り込みを使ってUSARTの送受信をするなら、USARTで受けたデータをecho backするだけであっても57600bpsが限界。115.2kbpsはおそらくクロック数的に不可能だと思う。(割り込みハンドラをアセンブラで書けばギリギリ間に合うのかも知れないが…)


以前コメントでいただいていたが、割り込みルーチン内で他の関数を呼び出すなんていうのは、その呼び出しのオーバーヘッドが到底許容できないものになるので言語道断だと実感した。


■ 16bit変数に対してはatomic性が無いよ


あと、うっかりしていたのが、PIC16シリーズは8bitレジスタのため、割り込みハンドラからアクセスする16bit変数には対してはatomic性が保証されないということだ。PICのアーキテクチャを考えれば当然なのだが、Cで書いているとそんなことを忘れてしまう。


割り込みハンドラでtimerをインクリメントしていたのだが、この変数の値を割り込みハンドラの外からアクセスすると0x01FF→0x0100→0x0200のように見えることがあって困った。


割り込み自体を禁止するとUSARTで受信している文字を取りこぼすのでタイマ割り込みだけ禁止しようかと思ったが、idle中にタイマを頻繁に確認しにいくプログラムなので、タイマ割り込みをそんなに禁止すると正しく時間計測できなくなってしまう。


そこで、timerの値を2度読みして、それが同じ値であれば、その値を採用し、異なる値であれば、もう一度読み直した値を採用するようにした。


こうして思うと組み込み系は組み込み系の流儀があって、なかなか大変な世界である。
些細なことでハマって、すぐに丸一日潰れてしまう。丸一日かけて書いたのがたった3バイトのコードだけとかね。もう、阿呆かと…。