Definir devoluciones de llamada para interrupciones

7

Estoy trabajando con un STM32 y estoy un poco confundido acerca de las interrupciones, específicamente las Interrupciones de Vector Anidado (NVI). Según entiendo, hay un vector NVI (llamado NVIC) donde cada interrupción tiene una prioridad (a veces configurable) y una dirección (consulte la página 157 del manual de referencia ARM aquí ).

Ahora asumo que para cada tipo de interrupción es posible adjuntar una función de devolución de llamada, y sospecho que la dirección adjunta a cada interrupción está relacionada con la dirección de la devolución de llamada.

¿Cuál es exactamente la dirección adjunta a una interrupción dada? ¿Cómo puedo definir (en C, por ejemplo) la función de devolución de llamada para una interrupción dada?

    
pregunta Randomblue

2 respuestas

4

Los ARM implementan una tabla de interrupciones para almacenar la dirección de cada controlador de interrupciones (o devolución de llamada, básicamente lo mismo). Básicamente, todas las direcciones de los controladores de interrupción se almacenan en la memoria del programa en una ubicación predefinida. Cuando ocurre una interrupción, el procesador sabe en qué parte de la tabla está la entrada de la interrupción, la agarra y se bifurca a la dirección almacenada allí.

¿Cómo se rellena esta tabla? Por lo general, toda esta información está contenida en un archivo de inicio. Por lo general, solo define una matriz constante de punteros, rellénelos con las direcciones de las devoluciones de llamada que desea usar. Aquí es un sitio web que detalla cómo crear un archivo de inicio para un Microcontrolador ARM específico. Lo complicado de esto es que casi todos los detalles de la creación del archivo dependen en gran medida del vinculador, el compilador y el chip que está utilizando, por lo que tendrá que encontrar un ejemplo o confundirlo haciendo su propio diseño.

    
respondido por el AngryEE
4

la corteza-m3 es muy fácil de interrumpir. No necesita un trampolín en ASM o necesita agregar una sintaxis de compilador no estándar para que el compilador lo haga por usted. El hardware se ajusta a un abi conservando un cierto número de registros para usted, así como los modos de cambio. El registro de enlace se codifica para que, al regresar de la función, el hardware sepa que en realidad es un retorno de interrupción. Así que no tienes que hacer todas las cosas que tenías que hacer en un brazo y muchos otros procesadores.

Del mismo modo, a un nivel de dolor, la corteza-m (y otros brazos más nuevos) tienen miles de vectores en la tabla de vectores, docenas a cientos de interrupciones, etc., como se menciona en un comentario anterior, vea enlace el ejemplo de blinker05 usa interrupciones con un temporizador, puede ver en vectors.s que todo lo que hace es colocar el nombre de la función:

.word hang
.word tim5_handler
.word hang

Y luego escribe el código C:

//-------------------------------------------------------------------
volatile unsigned int intcounter;
//-------------------------------------------------------------------
// CAREFUL, THIS IS AN INTERRUPT HANDLER
void tim5_handler ( void )
{
    intcounter++;
    PUT32(TIM5BASE+0x10,0x00000000);
}
// CAREFUL, THIS IS AN INTERRUPT HANDLER
//------------------------------------------------------------------

Ahora, como con cualquier interrupción de algún dispositivo / periférico, es probable que tenga que, en el controlador, decirle al dispositivo que borre la interrupción, de lo contrario, podría quedarse atascado constantemente al volver a ingresar al controlador.

Mis ejemplos no usan un IDE, usan herramientas de código abierto (gnu gcc y binutils y el compilador de Clang de llvm). Elimine los archivos binarios de clang de la línea all: en el archivo make si no tiene / quiere usar llvm. Las herramientas gnu son fáciles de conseguir, tanto compilando desde fuentes (tengo instrucciones en algún lugar de github, probablemente en varios lugares) o simplemente obtengo la versión lite de codesourcery (ahora mentores gráficos). Mis ejemplos están desarrollados y probados en Linux, pero eso no debería desalentar a los usuarios de Windows, cambiar algunas cosas como rm -f * .o a del * .o, cosas como esas o simplemente compilar un archivo por lotes desde los comandos ensamblador / compilador / enlazador en el makefile.

Recomiendo encarecidamente desarmar su binario, especialmente si está intentando colocar un controlador en la tabla vectorial, por lo que es muy fácil realizar un error de montaje y no tenerlo en la dirección correcta. Necesita saber la dirección de los documentos del brazo y luego verificar el desmontaje. el ejemplo de blinker05 cuando se desmonta:

 8000100:       0800014f        stmdaeq r0, {r0, r1, r2, r3, r6, r8}
 8000104:       0800014f        stmdaeq r0, {r0, r1, r2, r3, r6, r8}
 8000108:       08000179        stmdaeq r0, {r0, r3, r4, r5, r6, r8}
 800010c:       0800014f        stmdaeq r0, {r0, r1, r2, r3, r6, r8}
 8000110:       0800014f        stmdaeq r0, {r0, r1, r2, r3, r6, r8}

offset 0x108 siendo la entrada apuntada. Tenga en cuenta que las direcciones en la tabla deben ser impares. 0x178 es la dirección real, arm quiere que el conjunto de lsbit indique que es una dirección de conjunto de instrucciones de pulgar (la cortex-m3 solo conoce el pulgar y las extensiones de thumb2 que no puede ejecutar instrucciones de brazo). / p>     

respondido por el old_timer

Lea otras preguntas en las etiquetas