8 votos

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

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

¿Qué ocurre con la pila cuando se produce una interrupción en un microcontrolador AVR y llamo a una función? ¿El compilador inline el código? ¿Guarda la pila en algún lugar y luego restablece el puntero de la pila? ¿Tiene una pila secundaria sólo para las interrupciones?

Según tengo entendido, el vector de la interrupción es un comando GOTO directo en ensamblador. Además, no creo que el microcontrolador se meta automáticamente con la pila, así que probablemente la deje en paz. Sin embargo, eso sigue sin explicar cómo funcionan las funciones durante una ISR.

0 votos

La respuesta de abajo es estupenda, sólo ten en cuenta que el compilador no puede inlinear las llamadas de interrupción porque... Son llamadas de interrupción :D

1 votos

@VladimirCravero Me refería a inline las funciones llamadas dentro de la interrupción (si llamo a foo() en la ISR ¿se inlinea para que no sea realmente una llamada a una función?)

0 votos

Así que la respuesta de abajo no responde a tu pregunta, ¿o sí? caveman explica lo que ocurre cuando se produce una interrupción, pero no lo que ocurre 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 ya está. la magia ocurre cuando se dispara la interrupción, lo que ocurre después (antes del iret) es simplemente código normal, normalmente no interrumpible.

16voto

caveman Puntos 1590

El AVR es una arquitectura RISC, por lo que tiene un manejo bastante básico de las interrupciones por hardware. La mayoría de los procesadores manipulan la pila durante las interrupciones, aunque hay un par, sobre todo ARM y PowerPC, que utilizan métodos diferentes.

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 un simple GOTO:

  1. Termina la instrucción actual.
  2. Desactivar la bandera de interrupción global.
  3. Empuja la dirección de la siguiente instrucción en la pila.
  4. Copiar la dirección en el vector de interrupción correcto (según la interrupción que se produjo) en el contador de programa.

En este punto, el hardware ha hecho todo lo que iba a hacer. El software tiene que ser escrito correctamente para no romper las cosas. Por lo general, los siguientes pasos son a lo largo de estas líneas.

  1. Empuja el registro de estado a la pila. (Esto debe hacerse primero antes de modificarlo).

  2. Coloca en la pila cualquier registro de la CPU que vaya a ser (o pueda ser) modificado. Los registros que deben ser guardados de esta manera son definidos por el modelo de programación. El modelo de programación lo define 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, sólo hace lo que siempre hace, empujar el valor de retorno en la pila, y luego pop de nuevo cuando se hace. Esto no afecta a ninguno de los valores anteriores que hemos guardado en la pila hasta ahora.

  1. Ejecuta 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. Despliega los registros de la CPU que empujamos en el paso 6.
  2. Vuelve a introducir el valor de estado guardado en el registro de estado. Después de esto tenemos que tener cuidado de no ejecutar ninguna instrucción que pueda cambiar el registro de estado.
  3. 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 debe ejecutarse al menos una instrucción antes de que se respete la siguiente interrupción. Esto evita que las interrupciones pesadas bloqueen completamente el trabajo en segundo plano).

    b. Introduzca la dirección de retorno guardada en el PC.

Ahora volvemos al código normal.

Tenga en cuenta que hay algunos puntos en los que tenemos que ser muy cuidadosos, en particular en torno al registro de estado y a los registros de ahorro que podrían ser modificados. Afortunadamente, si estás usando un compilador de C, todo esto se maneja bajo las cubiertas.

Además, hay que vigilar la profundidad de la pila. En cualquier momento en que las interrupciones estén habilitadas, un ISR podría usar más de la pila de lo que es obvio mirando el código local. Por supuesto, esto no se presenta mucho a menos que estés llevando la memoria a sus límites.

Aquí es un enlace que describe este proceso si quieres una referencia.

0 votos

¿Para qué sirven 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.

1 votos

Los pasos 5 y 6 guardan el estado actual (antes de la interrupción) del sistema, para que pueda ser restaurado (pasos 8 y 9) después de que la interrupción se complete, para permitir que el programa principal continúe como si no hubiera sido interrumpido.

1 votos

Este es un excelente resumen.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X