¿Cómo funciona la pila de llamadas durante una interrupción en AVR?

8

(Específico para el Arduino Uno ...)

¿Qué le sucede a la pila cuando ocurre una interrupción en un microcontrolador AVR y llamo a una función? ¿El compilador incorpora el código? ¿Almacena la pila en algún lugar y luego restablece el puntero de la pila? ¿Tiene una pila secundaria solo para interrupciones?

Según tengo entendido, el vector para la interrupción es un comando GOTO directo en ensamblador. Además, no creo que el microcontrolador se meta automáticamente con la pila, por lo que probablemente se quede solo. Sin embargo, eso todavía no explica cómo funcionan las funciones durante un ISR.

Pingüino anónimo
fuente
La respuesta a continuación es excelente, solo tenga en cuenta que el compilador no puede interrumpir llamadas en línea porque ... Son llamadas de interrupción: D
Vladimir Cravero
1
@VladimirCravero Quise decir en línea las funciones llamadas dentro de la interrupción (si llamo a foo () en el ISR, ¿lo hace en línea para que no sea realmente una llamada a función?)
Anonymous Penguin
Entonces, la respuesta a continuación no responde a su pregunta, ¿o sí? El hombre de las cavernas explica qué sucede cuando se produce una interrupción, pero no qué sucede cuando se llama a una función en un contexto interrumpido. la respuesta a esto último sería: nada especial, se llama a la función y eso es todo. la magia ocurre cuando se dispara la interrupción, lo que sucede después (antes de la iret) es un código normal, generalmente ininterrumpible.
Vladimir Cravero
@VladimirCravero sí, lo hace (indirectamente). Estaba hablando de cómo se modificó la pila para un ISR, pensando que tenía que modificarse para usar funciones en primer lugar. Voy a adivinar que las funciones funcionan exactamente de la misma manera después de configurar el ISR.
Anonymous Penguin
bueno, lo tienes entonces. después del salto al vector de interrupción, todo está bien y puedes ir a donde quieras.
Vladimir Cravero

Respuestas:

16

El AVR es una arquitectura RISC, por lo que tiene un manejo bastante básico del hardware de las interrupciones. La mayoría de los procesadores se meten con la pila durante las interrupciones, aunque hay un par, especialmente 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 simple GOTO:

  1. Terminar la instrucción actual.
  2. Deshabilita la bandera de interrupción global.
  3. Empuje la dirección de la siguiente instrucción en la pila.
  4. Copie la dirección en el vector de interrupción correcto (de acuerdo con 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. Por lo general, los siguientes pasos son a lo largo de estas líneas.

  1. Empuje el registro de estado en la pila. (Esto debe hacerse primero antes de cambiarlo).

  2. Empuje cualquier registro de CPU que se (o pueda) cambiar en la pila. El modelo de programación define qué registros que deben guardarse de esta manera. El modelo de programación lo define el compilador.

Ahora se puede ejecutar el código de interrupción de trabajo. Para responder el caso en la cuestión de llamar a una función, simplemente hace lo que siempre hace, empuja 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.

  1. Ejecute el código de trabajo ISR.

Ahora hemos terminado y queremos volver de la interrupción. Primero tenemos que hacer la limpieza del software.

  1. Pop los registros de la CPU que empujamos en el paso 6.
  2. Vuelva a colocar el valor de estado guardado en el registro de estado. Después de esto, debemos tener cuidado de no ejecutar ninguna instrucción que pueda cambiar el registro de estado.
  3. Ejecute la instrucción RTI. El hardware realiza estos pasos para esta instrucción:

    a. Habilite la bandera de interrupción global. (Tenga en cuenta que al menos una instrucción debe ejecutarse antes de que se cumpla la próxima interrupción. Esto evita que las interrupciones intensas bloqueen completamente el trabajo en segundo plano).

    si. Introduzca 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 debajo de las cubiertas.

Además, debes observar la profundidad de tu stack. 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 mirar el código local. Por supuesto, esto realmente no surge mucho a menos que esté llevando su memoria al límite.

Aquí hay un enlace que describe este proceso si desea una referencia.

cavernícola
fuente
¿Cuál es el propósito de los pasos 5/6? Me parece una tontería no modificar directamente los registros, aunque supongo que jugar con algunos registros durante las interrupciones podría crear algunos resultados desagradables.
Anonymous Penguin
1
Los pasos 5 y 6 guardan el estado actual (antes de la interrupción) del sistema, para que pueda restaurarse (pasos 8 y 9) después de que se complete la interrupción, para permitir que el programa principal continúe como si no se hubiera interrumpido.
Peter Bennett
1
Este es un excelente resumen.
Connor Wolf
3
También vale la pena señalar que si realmente sabe lo que está haciendo, puede deshabilitar el guardado automático del estado y otros registros, con un indicador GCC ( ISR_NAKED). Esto le permite omitir los pasos 5,6,8,9, en un contexto en el que realmente necesita esos ciclos. La desventaja es que debe estar absolutamente seguro de que conservará los registros relevantes o podrá sobrescribirlos sin dañarlos.
Connor Wolf
2
Es interesante saberlo, pero haría la programación de ensamblaje antes de usar esa bandera. Tan peligroso ...
hombre de las cavernas