次のスニペットは、TimerOneライブラリのソースコードからの抜粋です。
// TimerOne.h:
void (*isrCallback)();
// TimerOne.cpp:
ISR(TIMER1_OVF_vect) // interrupt service routine that wraps a user defined function supplied by attachInterrupt
{
Timer1.isrCallback();
}
// TimerOne.cpp:
void TimerOne::attachInterrupt(void (*isr)(), long microseconds)
{
if(microseconds > 0) setPeriod(microseconds);
isrCallback = isr; // register the user's callback with the real ISR
TIMSK1 = _BV(TOIE1); // sets the timer overflow interrupt enable bit
resume();
}
質問:タイマーが既に実行されていて、メインプログラムがを呼び出しているattachInterrupt()
場合、関数ポインターの割り当て中にタイマー割り込みが発生する可能性がありisrCallback = isr;
ますか?次に、幸運なタイミングで、Timer1.isrCallback();
関数ポインタは古いアドレスと新しいアドレスの一部で構成され、ISRは偽の場所にジャンプしますか?
関数ポインターは確かに1バイトよりも広く、1バイトを超えるデータへのアクセスはアトミックではないため、これが当てはまる可能性があると思います。可能な回避策は次のとおりです。
- を呼び出す前
detachInterrupt()
に、必ずを呼び出して、タイマーが実行されていないことを確認してattachInterrupt()
ください。つまり、Timer1のドキュメントを明確にします。 - または、Timer1を変更して、直前に一時的にタイマーオーバーフロー割り込みを無効にします
isrCallback = isr;
これは理にかなっていますか、それともTimer1
ソースや関数ポインタの割り当てに私が見逃した何かがありますか?