O volátil é necessário quando a variável é acessada em> 1 ISRs, mas não é compartilhada fora dos ISRs?

9

Está claramente documentado que, quando os dados globais são compartilhados com um ISR e o programa principal, os dados precisam ser declarados volatilepara garantir a visibilidade da memória (e isso basta apenas para dados de 1 byte; qualquer coisa maior precisa de disposições especiais para garantir também a atomicidade) . Aqui temos boas regras:

  • Variáveis ​​usadas apenas fora de um ISR não devem ser voláteis.
  • Variáveis ​​usadas apenas dentro de um ISR não devem ser voláteis.
  • As variáveis ​​usadas dentro e fora de um ISR devem ser voláteis.

Mas é volatilenecessário quando a variável é acessada em> 1 ISRs, mas não compartilhada fora dos ISRs? Por exemplo, eu tenho uma função que mantém o estado interno usando uma staticvariável:

void func() {
    static volatile long counter; // volatile or not?
    // Do stuff with counter etc.
}

Essa função é chamada de duas maneiras: de interrupção de pinos e da biblioteca TimerOne :

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

Não há problemas de atomicidade, pois quando um ISR é inserido, as interrupções são desativadas automaticamente , mas essa volatileé mais uma pergunta do compilador: o que é armazenado em cache e o que não é.

Melhor prevenir do que remediar, é claro ...

Joonas Pulakka
fonte

Respostas:

9

volatile somente informa ao gerador de código do compilador que a variável pode ser modificada por algo diferente do código que está sendo gerado, para não assumir que nenhuma cópia dela seja precisa.

O código ISR deve ser escrito / gerado sob a suposição de que ele não tem contexto na entrada e preservar o contexto da CPU em torno de sua própria operação (ISR). Assim, como na indivisibilidade de operações não atômicas, a volatilidade depende, neste caso * , de se é permitido ou não interromper as interrupções. Se o não aninhamento for garantido, a variável compartilhada não poderá ser alterada por outro ISR durante sua própria execução. Se algum dia seu ISR for usado em um ambiente em que é permitido aninhar interrupções, essa restrição não será mais válida.

* neste caso :
estou assumindo uma variável mantida por software aqui. Se estamos falando de uma variável que pode ser atualizada por um evento de hardware, por exemplo, um registro temporizado, todas as apostas estão desativadas: a variável é volátil, não importa o quê.

JRobert
fonte
Portanto, desde que eu não mude o comportamento padrão de "interrupções não aninhadas" do Arduino, a variável não precisa ser volatile, pois não é modificada por nada além do código que está sendo gerado; O compilador pode "assumir" que o ISR é executado linearmente e o faz, desde que as interrupções não sejam aninhadas. Isso faz sentido. Obrigado!
Joonas Pulakka