まだ ATU をいじってます

ATU コントローラにスリープ機能を付けようと思って作業していました。一応コードは動いたのですが、不可解な現象が出ました。いろいろ調べていたら、long 型の変数の処理が割込処理ルーチンと衝突していました。つまり、PIC16 では char 以外の型は 1サイクルで処理できないので、途中で割り込まれることがある訳です。これは盲点でした。よく考えたら、そんなの Z80 のような時代は当たり前だったのだなあ。最近、32ビット処理くらいアトミックに処理できるプロセッサばかり使っていたので、うっかりしました。
こうなると、割込処理ルーチンと安全に共有できる変数は char (8ビット)しかありません。それ以外は、明示的に割込禁止にする必要があります。よく、割込処理ルーチンの中でカウント処理を入れたくなるんですが、これも 8ビット以外は容易に扱えません。コードを全面的に見直してみるかな。

sleep 機能

最初、PORTB のビット変化割込を使って sleep からの wake-up を試みたのですが、sleep すると同時に起き上がってきてしまいます。これまた悩みました。結論からいうと、sleep する前に RBIF ビットを 0 に落とすのを忘れてました。いくら PORTB をダミーリードしておいても、RBIF が 1 のままだと、sleep した直後に起きてきてしまうのでした。

後記 (メモ)

メイン処理と割込処理の間で変数を共有する場合。

  • メイン側で参照し、かつ、割込処理側で更新する場合は、通常は変数を volatile 宣言すること。
  • 共有変数が char 型の場合: メイン側で参照する場合は制限なし。メイン側で更新する場合、read-modify-write ならば、割込禁止で保護すること (単純代入ならば、その必要なし)。
  • 共有変数が short、int、long などの場合: メイン側で参照、更新、いずれの場合も割込禁止で保護すること。