Les extraits suivants proviennent du code source de la bibliothèque 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 question: si la minuterie est déjà en cours d'exécution et que le programme principal appelle attachInterrupt()
, l'interruption de la minuterie pourrait-elle s'y produire pendant l'affectation du pointeur de fonction isrCallback = isr;
? Ensuite, avec un timing chanceux, le Timer1.isrCallback();
pointeur de fonction serait composé en partie de l'ancienne et en partie de la nouvelle adresse, provoquant le saut ISR vers un faux emplacement?
Je suppose que cela pourrait être le cas, car les pointeurs de fonction sont certainement plus larges que 1 octet, et l'accès aux données> 1 octet n'est pas atomique. Les solutions de contournement possibles pourraient être:
- Appelez toujours
detachInterrupt()
pour vous assurer que le minuteur ne fonctionne pas, avant d'appelerattachInterrupt()
, c'est-à-dire clarifiez les documents Timer1. - Ou, modifiez Timer1, désactivant temporairement les interruptions de dépassement de minuterie juste avant
isrCallback = isr;
Est-ce que cela a du sens, ou y a-t-il quelque chose dans les Timer1
sources ou les affectations de pointeurs de fonction que j'ai manqué?
On dirait que vous avez raison. La chose logique à faire serait de désactiver les interruptions de manière à ne pas les réactiver si elles ont été désactivées en premier lieu. Par exemple:
L'intention est de vous permettre d'écrire du code comme ceci:
Sans cette disposition, vous pourriez obtenir une interruption entre ces deux lignes, et donc dormir indéfiniment (car l'interruption qui allait vous réveiller s'est produite avant de dormir). La disposition dans le processeur selon laquelle l'instruction suivante, après que les interruptions sont activées si elles ne l'ont pas été auparavant, est toujours exécutée, évite cela.
la source
TIMSK1=0; TIFR1=_BV(TOV1); isrCallback=isr; TIMSK1=_BV(TOIE1);
? Il épargne un registre CPU et ne contribue pas à la latence d'interruption.