割り込みから呼び出す関数には何か制限があるのでしょうか?

割り込みプログラムがきちんと動作するには、十分なスタックが確保されていることです。 コンパイラーはmain()関数でスタックのチェックを行いそれ以外のチェックは行われません。 割り込み処理があるとスタックが追加されます。1つの割り込みルーチンで割り込み関数からはSEPARATEコールで呼び出されます。 Main関数でのスタックの最低残量が9以上ある場合、割り込みが有効にできます。 これらの様子はリスト・ファイルの先頭でみることができます。

コンパイラーは再帰呼び出しをサポートしていません。これはプロセッサーがRISC命令を使っているためで旧態的なC言語のスタックではうまくインプリメントできないからです。 関数で必要とされるすべてのRAMのロケーションは、関数がアクティブでなくてもリンク時には決定されていることが必要となります。 例えば、main関数が関数A()をコールし、A()が関数B()をコールしますが。B()はmain関数, A()関数又はB()関数は呼びません。

割り込みが特別な問題を引き起こす状況を良く考えてみると、割り込み関数ISR()が関数A()をコールするということは、main関数がA()をコールすることと変わりはありません。main関数がA()を呼び出し、 A()が実行中に割り込み関数ISR()がイベントによりコールされると再帰的な呼び出し状態が発生します。

ここで、関数A()の呼び出しにプロテクトを行うようにコンパイラーが処理をした場合は、main関数はA()が呼び出される前にすべての割り込みをディセーブルとして、A()の処理が終了したときに再度割り込みをイネーブルとします。 割り込み関数とメイン・プログラムとの間に次に示されるような関係を保つことで割り込みから呼びだせるようになります。

プログラミングには下記の特別な考慮が必要です。:

  1. 上記の例のように、割り込みは関数A()の全実行に対してディスエーブルされますので、関数A()の実行回数によって割り込みが増加します。 従って、関数A()を実行する前に割り込みでこの関数が呼び出されないように設定することです。

  2. 関数A()をENABLE/DISABLE_INTERRUPTで決して再帰的な呼び出しがなされないようINTCONレジスターを操作します。さらにグローバル・インタラプト・フラグがイネーブルだと、関数A()が間違って実行されることがなくなります。

  3. プログラムは割り込みがディセーブルな状態ならどのような状態であっても依存しなくな ります。コンパイラーは割り込みがディセーブルでないなら関数の呼び出しや関数内でローカルなRAMを必要とします。

  4. 割り込みがディセーブルならコンパイラー内部の関数を呼び出しても差し支えありません。 例えば乗算(*)を行う場合でも当てはまります。