The following snippets are from TimerOne library source code:
// 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();
}
The question: if the timer is already running, and the main program calls attachInterrupt()
, could the timer interrupt occur there during the function pointer assignment isrCallback = isr;
? Then, with lucky timing, Timer1.isrCallback();
function pointer would consist partly of the old and partly of the new address, causing the ISR jump to a bogus location?
I suppose this might be the case, since function pointers are certainly wider than 1 byte, and accessing > 1 byte data isn't atomic. Possible workarounds could be:
- Always call
detachInterrupt()
to make sure the timer isn't running, before callingattachInterrupt()
, i.e. clarify Timer1 docs. - Or, modify Timer1, disabling timer overflow interrupts temporarily just before
isrCallback = isr;
Does this make sense, or is there something in Timer1
sources or function pointer assignments that I've missed?