PIC I/O の注意点
昨日、実は PIC で例の工作の続きをやってました。しかし、双方向 I/O のところでハマり、結局寝てしまいました。
そちらは単純なプログラムミスだと思われるのですが、PIC の双方向 I/O って、ビット操作命令と組み合わせて利用するときに注意が必要のようです。ある複数の双方向ポートビットに対して予め出力用ラッチを 0 に固定してから、その後でモードを write に切り替えたくても、ポートが入力モードだと出力用ラッチは読み出せないので、1ビット単位で操作する BSF や BCF では複数の出力用ラッチを 0 に固定できないことがあります。例えば複数のポートビットが外部でプルアップされていると、二回目の BCF では既に 0 に設定したはずのポートが、また 1 に戻ってしまう、ということになります*1。この辺の説明は、PICmicro Mid-Range MCU Family Reference Manual (33023a) の 9.10.1 Bi-directional I/O Ports 辺りに詳しく説明が出ています。
これを避けるためには、レジスタファイルへのビット操作命令 BSF, BCF を避けて、一度レジスタファイルを読み出して論理演算をして、バイト全体を書き戻すという操作が必要になります。この場合はアトミックな操作にならないので、割込禁止などの処置が必要になるかも知れません。
後記 (2009/02/05)
最近はちょっと Atmel AVR マイコンに興味があるのですが、この辺の汎用 I/O ポートの振る舞いは、AVR のほうがよく考えられているようです。もっとも、複雑さは同程度のような気もします。
HI-TECH C が変?
HI-TECH C PRO for the PIC10/12/16 MCU Family 9.60PL3 の LITE モードというのを使っているのですが、アセンブリ出力がなんだか変です。というか仕様なのかなあ。(ターゲットは、ちゃんと PIC16F716 になっています。)
というのは、TRISB レジスタへのビットアクセスをするコードがあるんですが、バンク切替のコードがおかしいのです。なんか、コード出力が 1サイクル遅れているのです。例えばリスティングファイルを見るとこんな感じ。
1417 039B 1803 btfsc status,0 1418 039C 2B9F goto u2281 1419 039D 2BA1 goto u2280 1420 039E 1683 bsf status, 5 ;RP0=1, select bank1 1421 1422 1423 039F u2281: 1424 039F 1606 bsf (1076/8),(1076)&7
本当は、1124行目の bsf で TRISB を操作する前に、status レジスタのビット 5 を立てて欲しいのに、このコードではそんなことはできないような。確かに PIC のマニュアルでは TRISB レジスタをビット操作しないほうが良いって書いてありますが、これはそういう問題ではない気がします。
全体的に見て、このコンパイラの LITE モードでの出力コードは汚いです。いくらフリーだといっても、これでは PRO 版を買う気が起こりません。でも、まあ PRO 版をお試しで使ってみました。上記のコードは次のようになります。これは正しい動きをします。
765 0274 1683 bsf 3,5 ;RP0=1, select bank1 766 0275 1903 btfsc 3,2 767 0276 2A79 goto L3 768 0277 1606 bsf 134,4 769 0278 0008 return
もう、コードのクオリティが違いすぎます。でも、$1500なんて個人じゃ払えんぞ。ちなみに STD 版でも $1000 です。とほほ。(っていうか、こんなしょうもないバグがあるようじゃ、信用できないよねえ。)
今度、CCS のコンパイラも評価してみようっと。
後記
ATU の制御試作ソフト、無事に動きました。ATU の LC ネットワークが切り替わることが確認できました。操作性(使い勝手の部分)に問題があるので、もう少し詰めが必要ですが。
*1:一度、出力用ラッチを 0 に設定しても、次のビット操作で読み出すとポートが 1 に見えてしまうため。