Está claramente documentado que cuando los datos globales se comparten con un ISR y el programa principal, los datos deben declararse volatile
para garantizar la visibilidad de la memoria (y eso solo es suficiente para los datos de 1 byte; cualquier cosa más grande necesita arreglos especiales para garantizar también la atomicidad) . Aquí tenemos buenas reglas:
- Las variables que solo se usan fuera de un ISR no deben ser volátiles.
- Las variables que solo se usan dentro de un ISR no deben ser volátiles.
- Las variables utilizadas tanto dentro como fuera de un ISR deben ser volátiles.
¿Pero es volatile
necesario cuando se accede a la variable desde> 1 ISR, pero no se comparte fuera de ISR? Por ejemplo, tengo una función que mantiene el estado interno usando una static
variable:
void func() {
static volatile long counter; // volatile or not?
// Do stuff with counter etc.
}
Esa función se llama de dos maneras: desde la interrupción del pin y desde la biblioteca TimerOne :
attachInterrupt(0, func, CHANGE);
Timer1.attachInterrupt(func);
No hay problemas de atomicidad, ya que cuando se ingresa un ISR, las interrupciones se deshabilitan automáticamente , pero esta volatile
es más una pregunta del compilador: qué se almacena en caché y qué no.
Más vale prevenir que curar, por supuesto ...
volatile
, ya que no está modificada por otra cosa que no sea el código generado; el compilador puede "asumir" que el ISR se ejecuta linealmente, y lo hace, siempre que las interrupciones no aniden. Eso tiene sentido. ¡Gracias!