El AVR es una arquitectura RISC, por lo que tiene un manejo bastante básico de hardware de interrupciones. La mayoría de los procesadores se meten con la pila durante las interrupciones, aunque hay un par, sobre todo ARM y PowerPC, que utilizan diferentes métodos.
En cualquier caso, esto es lo que hace el AVR para las interrupciones:
Cuando se produce una interrupción, el hardware del procesador realiza estos pasos, que no son solo un GOTO simple:
- Termina la instrucción actual.
- Deshabilitar el indicador de interrupción global.
- Presione la dirección de la siguiente instrucción en la pila.
- Copie la dirección en el vector de interrupción correcto (según la interrupción que ocurrió) en el contador del programa.
Ahora en este punto, el hardware ha hecho todo lo que va a hacer. El software tiene que estar escrito correctamente para no romper cosas. Normalmente, los siguientes pasos son en esta línea.
-
Empuje el registro de estado en la pila. (Esto debe hacerse primero antes de cambiarlo).
-
Inserte cualquier registro de CPU que se cambie (o se pueda cambiar) en la pila. Los registros que deben guardarse de esta manera están definidos por el modelo de programación. El modelo de programación está definido por el compilador.
Ahora se puede ejecutar el código de interrupción de trabajo. Para responder al caso en la pregunta de llamar a una función, simplemente hace lo que siempre hace, presiona el valor de retorno en la pila y luego lo vuelve a abrir cuando termina. Esto no afecta a ninguno de estos valores anteriores que guardamos en la pila hasta ahora.
- Ejecutar código de trabajo ISR.
Ahora hemos terminado y queremos volver de la interrupción. Primero tenemos que hacer la limpieza del software.
- Pop de los registros de CPU que empujamos en el paso 6.
- Devuelve el valor del estado guardado al registro de estado. Después de esto, debemos tener cuidado de no ejecutar ninguna instrucción que pueda cambiar el registro de estado.
-
Ejecuta la instrucción RTI. El hardware realiza estos pasos para esta instrucción:
a. Habilitar la bandera de interrupción global. (Tenga en cuenta que al menos una instrucción debe ejecutarse antes de que se cumpla la siguiente interrupción. Esto evita que las interrupciones pesadas bloqueen completamente el trabajo en segundo plano).
b. Pop la dirección de retorno guardada en la PC.
Ahora volvemos al código normal.
Tenga en cuenta que hay algunos puntos en los que debemos ser muy cuidadosos, especialmente en relación con el registro de estado y guardar registros que podrían modificarse. Afortunadamente, si está utilizando un compilador de C, todo esto se maneja bajo las cubiertas.
Además, debes observar la profundidad de tu pila. En cualquier momento cuando las interrupciones están habilitadas, un ISR podría usar más de la pila de lo que es obvio al observar el código local. Por supuesto, esto realmente no aparece mucho a menos que estés llevando tu memoria al límite.
Aquí es un enlace que describe este proceso si desea una referencia.