¿Se necesita volátil cuando se accede a la variable desde> 1 ISR, pero no se comparte fuera de ISR?

9

Está claramente documentado que cuando los datos globales se comparten con un ISR y el programa principal, los datos deben declararse volatilepara 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 volatilenecesario 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 staticvariable:

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 :

  1. attachInterrupt(0, func, CHANGE);
  2. Timer1.attachInterrupt(func);

No hay problemas de atomicidad, ya que cuando se ingresa un ISR, las interrupciones se deshabilitan automáticamente , pero esta volatilees más una pregunta del compilador: qué se almacena en caché y qué no.

Más vale prevenir que curar, por supuesto ...

Joonas Pulakka
fuente

Respuestas:

9

volatile solo informa al generador de código del compilador que la variable puede ser modificada por algo que no sea el código que se está generando, por lo que no debe suponerse que ninguna copia sea precisa.

El código ISR debe ser escrito / generado bajo el supuesto de que no tiene contexto en la entrada, y preservar el contexto de la CPU alrededor de su propia operación (ISR). Entonces, al igual que con la indivisibilidad de las operaciones no atómicas, la volatilidad depende, en este caso * , de si se permiten o no las interrupciones. Si se garantiza la no anidación, la variable compartida no puede cambiar por otro que no sea este ISR durante su propia ejecución. Si su ISR algún día se puede usar en un entorno donde las interrupciones pueden anidar, entonces esa restricción ya no se mantendrá.

* en este caso :
estoy asumiendo una variable mantenida por software aquí. Si hablamos de una variable que se puede actualizar mediante un evento de hardware, un registro de temporizador, por ejemplo, todas las apuestas están desactivadas: la variable es volátil, pase lo que pase.

JRobert
fuente
Por lo tanto, siempre que no cambie el comportamiento predeterminado de "las interrupciones no anidan" de Arduino, entonces la variable no necesita serlo 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!
Joonas Pulakka