È chiaramente documentato che quando i dati globali sono condivisi con un ISR e il programma principale, i dati devono essere dichiarati volatile
per garantire la visibilità della memoria (e ciò è sufficiente solo per i dati a 1 byte; tutto ciò che è più grande ha bisogno di disposizioni speciali per garantire anche l'atomicità) . Qui abbiamo buone regole:
- Le variabili utilizzate solo al di fuori di un ISR non dovrebbero essere volatili.
- Le variabili utilizzate solo all'interno di un ISR non dovrebbero essere volatili.
- Le variabili utilizzate sia all'interno che all'esterno di un ISR dovrebbero essere volatili.
Ma è volatile
necessario quando si accede alla variabile da> 1 ISR, ma non è condiviso al di fuori degli ISR? Ad esempio, ho una funzione che mantiene lo stato interno usando una static
variabile:
void func() {
static volatile long counter; // volatile or not?
// Do stuff with counter etc.
}
Tale funzione viene chiamata in due modi: dall'interruzione dei pin e dalla libreria TimerOne :
attachInterrupt(0, func, CHANGE);
Timer1.attachInterrupt(func);
Non ci sono problemi di atomicità, poiché quando viene inserito un ISR, gli interrupt vengono automaticamente disabilitati , ma questa volatile
è più una domanda del compilatore: cosa viene memorizzato nella cache e cosa no.
Meglio prevenire che curare, ovviamente ...
volatile
, dal momento che non è modificata da qualcosa di diverso dal codice generato; il compilatore può "presumere" che l'ISR viene eseguito in modo lineare, e lo fa, purché gli interrupt non si annidino. Questo ha senso. Grazie!