È necessaria la volatilità quando si accede alla variabile da> 1 ISR, ma non è condivisa al di fuori degli ISR?


9

È chiaramente documentato che quando i dati globali sono condivisi con un ISR e il programma principale, i dati devono essere dichiarati volatileper 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 è volatilenecessario 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 staticvariabile:

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 :

  1. attachInterrupt(0, func, CHANGE);
  2. 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 ...

Risposte:


9

volatile informa solo il generatore di codice del compilatore che la variabile può essere modificata da qualcosa di diverso dal codice generato, quindi non supporre che una sua copia rimanga accurata.

Il codice ISR deve essere scritto / generato supponendo che non abbia alcun contesto all'ingresso e preservi il contesto della CPU attorno al suo funzionamento (ISR). Quindi, come per l'indivisibilità delle operazioni non atomiche, la volatilità dipende, in questo caso * , dal fatto che gli interrupt possano o meno essere nidificati. Se il non annidamento è garantito, la variabile condivisa non può cambiare da un altro ISR durante la propria esecuzione. Se un giorno il tuo ISR potrebbe essere utilizzato in un ambiente in cui è possibile nidificare gli interrupt, tale vincolo non sarà più valido.

* in questo caso :
suppongo qui una variabile gestita da software. Se stiamo parlando di una variabile che può essere aggiornata da un evento hardware, ad esempio un registro timer, tutte le scommesse sono disattivate: la variabile è volatile, qualunque cosa accada.


Quindi, fintanto che non modifico il comportamento predefinito di "Arduino non annidano", la variabile non ha bisogno di essere 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!
Joonas Pulakka,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.