Los siguientes fragmentos son del código fuente de la biblioteca 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();
}
La pregunta: si el temporizador ya se está ejecutando y el programa principal llama attachInterrupt()
, ¿podría ocurrir la interrupción del temporizador allí durante la asignación del puntero de función isrCallback = isr;
? Entonces, con suerte, el Timer1.isrCallback();
puntero de la función consistiría en parte en la dirección anterior y en la nueva, lo que provocaría que el ISR salte a una ubicación falsa.
Supongo que este podría ser el caso, ya que los punteros de función son ciertamente más anchos que 1 byte, y acceder a datos de> 1 byte no es atómico. Las posibles soluciones podrían ser:
- Siempre llame
detachInterrupt()
para asegurarse de que el temporizador no se esté ejecutandoattachInterrupt()
, es decir, aclare los documentos de Timer1. - O bien, modifique Timer1, deshabilitando las interrupciones de desbordamiento del temporizador temporalmente justo antes
isrCallback = isr;
¿Tiene sentido o hay algo en las Timer1
fuentes o en las asignaciones de puntero de función que me he perdido?
Parece que tienes un punto. Lo lógico sería deshabilitar las interrupciones de tal manera que no las vuelva a habilitar si se deshabilitaron en primer lugar. Por ejemplo:
La intención de esto es permitirle escribir código como este:
Sin esa disposición, podría obtener una interrupción entre esas dos líneas y, por lo tanto, dormir indefinidamente (porque la interrupción que iba a despertar se produjo antes de dormir). La provisión en el procesador de que la siguiente instrucción, después de que las interrupciones se habiliten si no se habilitaron antes, siempre se ejecuta, protege contra esto.
fuente
TIMSK1=0; TIFR1=_BV(TOV1); isrCallback=isr; TIMSK1=_BV(TOIE1);
? Ahorra un registro de CPU y no contribuye a interrumpir la latencia.