O AVR é uma arquitetura RISC, portanto, possui um gerenciamento bastante básico de interrupções no hardware. A maioria dos processadores mexe com a pilha durante as interrupções, embora existam alguns, principalmente o ARM e o PowerPC, que usam métodos diferentes.
De qualquer forma, é isso que o AVR faz para interrupções:
Quando ocorre uma interrupção, o hardware do processador executa estas etapas, que não são apenas um simples GOTO:
- Conclua a instrução atual.
- Desative o sinalizador de interrupção global.
- Empurre o endereço da próxima instrução na pilha.
- Copie o endereço no vetor de interrupção correto (de acordo com a interrupção que ocorreu) no contador do programa.
Agora, neste momento, o hardware fez tudo o que está fazendo. O software deve ser escrito corretamente para não quebrar as coisas. Normalmente, as próximas etapas são nesse sentido.
Empurre o registro de status para a pilha. (Isso deve ser feito primeiro antes de ser alterado).
Envie todos os registradores da CPU que serão (ou podem ser) alterados para a pilha. Quais registros que precisam ser salvos dessa maneira são definidos pelo modelo de programação. O modelo de programação é definido pelo compilador.
Agora o código de interrupção de trabalho pode ser executado. Para responder ao caso na questão de chamar uma função, ele apenas faz o que sempre faz, pressiona o valor de retorno na pilha e, em seguida, retorna quando terminar. Isso não afeta nenhum desses valores anteriores que salvamos na pilha até agora.
- Execute o código de trabalho do ISR.
Agora terminamos e queremos retornar da interrupção. Primeiro, precisamos fazer a limpeza do software.
- Coloque os registros da CPU que pressionamos na etapa 6.
- Retorne o valor do status salvo para o registro de status. Depois disso, devemos ter cuidado para não executar nenhuma instrução que possa alterar o registro de status.
Execute a instrução RTI. O hardware executa estas etapas para esta instrução:
uma. Habilite o sinalizador de interrupção global. (Observe que pelo menos uma instrução deve ser executada antes que a próxima interrupção seja respeitada. Isso impede que interrupções pesadas bloqueiem totalmente o trabalho em segundo plano.)
b. Coloque o endereço de retorno salvo no PC.
Agora estamos de volta ao código normal.
Observe que há alguns pontos em que precisamos ter muito cuidado, principalmente em torno do registro de status e do salvamento de registros que podem ser alterados. Felizmente, se você estiver usando um compilador C, tudo isso será tratado sob as cobertas.
Além disso, você deve observar a profundidade da pilha. A qualquer momento em que as interrupções são ativadas, um ISR pode usar mais da pilha do que é óbvio, observando o código local. Claro, isso realmente não aparece muito, a menos que você esteja levando a memória ao limite.
Aqui está um link que descreve esse processo, se você desejar uma referência.