バグ

PID 2006-09-24

昨夜、寝ている間に夢の中でバグのことを考えていて、昼過ぎに起きてボーっとした頭でパソコンに向かうこと 1 時間、およそ 2 週間近く悩ませてくれたバグの原因が突如判明した。結論から言ってしまえば、自分のかなりアホなミスが原因だった。悩んでいたのは、PC と PIC(マイクロコントローラ) のシリアル通信の不具合だった。PC が出力する信号の立ち下りのタイミングで PIC が動作するようにプログラムしているのに、数回に一回か、数十回に一回か、かなり不定期に、信号の立ち下がりとは無関係に PIC が動作してしまい、通信が失敗していた。再現性がないので、すげー難しそうなバグかも...と、ちょっとびびっていたw
しかもこの現象は、PIC 側でタイマーや外部割り込みを許可すると発生する。つまり、割り込み禁止状態であれば、期待したとおりに動作する。ここで普通なら割り込み関係のコードを見直すところだが、割り込みルーチンは本やデータシートに載っているとおりに書いており、全く疑う余地がなかった。そこに、解決を長引かせた原因の一端があったように思う。結局、割り込み関係のコードを見直すどころか、割り込みを使うとノイズがのるのかなぁ、とか、シリアル通信用のドライバ・レシーバ IC がうまく動作していないのかなぁ、とか、全く見当違いの方向を思索していた。
それほどまでに執拗だったバグの原因とは、なんてことはなく、割り込みルーチンの入り口で作業用レジスタの値を退避する際の、退避先のレジスタのアドレスを範囲外のアドレス(0x70 あたり)に指定していたことだった。この範囲外のアドレスのレジスタへのライトは常に破棄され、常に 0 としてリードされる。したがって、PIC 側で信号の立ち下がりを待っている最中に割り込みがかかると、割り込みルーチンから帰ってきた時には、作業用のレジスタの値が変わってしまうことになる。嗚呼、なんてアホらしいバグなんだ。恥ずかしすぎて、公衆の面前では絶対、決して、口が裂けても言えないや(←言ってるし...)。なんでこんな変なアドレス(0x70 あたり)に設定したのかというと、0x70 あたりのアドレスであれば、バンクを切り替えても同じアドレスで同じレジスタにマップされて便利らしい、という情報を鵜呑みにしたからだ。結局、それは私が使っている PIC の機種ではなくて、別の機種の仕様だったようで、改めてデータシートを見ると、0x50〜0x7F は "Unimplemented data memory location, read as ’0’." って書いてあるじゃん...orzという具合だった。
というわけで、今日一日で開発スピードが飛躍的に向上。PIC 側はほぼ完成したと言ってよいかも。あとは PC 側のソフトウェアを書くだけ。とか思っていた矢先に、PIC とシリアルケーブルのコネクタを接続していた導線が金属疲労で断線したので、コネクタを基板なりケースなりに固定しないと。