¿Cómo se implementan los controladores de interrupción en CMSIS de Cortex M0?

9

Tengo un kit LPC1114. Los últimos días he estado desenterrando la implementación CMSIS de Cortex M0 para descubrir cómo se hacen las cosas en ella. Hasta ahora he entendido cómo se mapean cada registro y cómo puedo acceder a él. Pero aún no sé cómo se implementan las interrupciones en él. Todo lo que sé sobre las interrupciones en CMSIS es que hay algunos nombres de manejadores de interrupciones mencionados en el archivo de inicio. Y puedo escribir mis propios controladores simplemente escribiendo una función C con los mismos nombres mencionados en el archivo de inicio. Lo que me confunde es que en la guía del usuario, se dice que todos los GPIO se pueden usar como fuentes de interrupción externas. Pero solo hay 4 interrupciones PIO mencionadas en el archivo de inicio. Así que dime:

  1. ¿Cómo puedo implementar controladores de interrupción externos para otros GPIOs?
  2. ¿Dónde se asigna la tabla de interrupciones en el CMSIS?
  3. ¿Cuáles son las principales diferencias entre NVIC y la implementación de interrupciones en los AVR / PIC? (excepto NVIC se puede asignar en cualquier lugar en el flash)
pregunta 0xakhil

3 respuestas

14

La siguiente información es adicional a la excelente respuesta de Igor.

Desde una perspectiva de programación en C, los controladores de interrupción se definen en el archivo cr_startup_xxx.c (por ejemplo, el archivo cr_startup_lpc13.c para LPC1343). Todos los controladores de interrupción posibles se definen allí como un alias WEAK. Si no define su propio XXX_Handler () para una fuente de interrupción, se utilizará la función predeterminada del controlador de interrupción definida en este archivo. El enlazador ordenará qué función incluir en el binario final junto con la tabla de vectores de interrupción de cr_startup_xxx.c

El ejemplo de las interrupciones GPIO de los puertos se muestra en los archivos de demostración en gpio.c. Hay una entrada de interrupción al NVIC por puerto GPIO. Cada bit individual en el puerto se puede habilitar / deshabilitar para generar una interrupción en ese puerto. Si necesita interrupciones en los puertos PIO1_4 y PIO1_5, por ejemplo, habilitará los bits de interrupción PIO1_4 y PIO1_5 individuales en GPIO0IE. Cuando su función de controlador de interrupciones PIOINT0_Handler () se dispara, usted puede determinar cuáles de las interrupciones PIO1_4 o PIO1_5 (o ambas) están pendientes leyendo el registro GPIO0RIS y manejando la interrupción adecuadamente.

    
respondido por el Austin Phillips
9

(Tenga en cuenta que los puntos 1 y 2 son detalles de implementación y no limitaciones arquitectónicas).

  1. En chips NXP más grandes (como LPC17xx) hay un par de pines de interrupción dedicados (EINTn) que tienen su propio controlador de interrupción. El resto de los GPIO tienen que usar una interrupción común (EINT3). Luego puede sondear el registro de estado de interrupción para ver qué pines han activado la interrupción.
  2. No estoy muy familiarizado con LPC11xx pero parece que tiene una interrupción por puerto GPIO. De nuevo, tendrá que revisar el registro de estado para averiguar los pines específicos. También hay hasta 12 pines que pueden actuar como fuentes de activación. No estoy seguro de poder secuestrarlos como interrupciones generales (es decir, es probable que solo se activen cuando está en estado de suspensión).
  3. La tabla de manejador predeterminada se coloca en la dirección 0 (que está en flash). La primera entrada es el valor de restablecimiento para el registro SP, la segunda es el vector de restablecimiento y el resto son otras excepciones y vectores de interrupción. Un par de los primeros (como NMI y HardFault) están arreglados por ARM, el resto son específicos del chip. Si necesita cambiar los vectores en tiempo de ejecución, puede volver a asignarlos a la RAM (primero debe copiar la tabla). En LPC11xx, la reasignación se fija al inicio de la SRAM (0x10000000), otros chips pueden ser más flexibles.
  4. El NVIC está optimizado para el manejo eficiente de interrupciones:
    • nivel de prioridad programable de 0-3 para cada interrupción. Una interrupción de prioridad más alta sustituye a las de prioridad más baja (anidamiento). La ejecución de la prioridad más baja se reanuda cuando finaliza la interrupción de prioridad más alta.
    • apilamiento automático del estado del procesador en la entrada de interrupción; esto permite escribir controladores de interrupción directamente en C y elimina la necesidad de envoltorios de ensamblaje.
    • encadenamiento de la cola: en lugar de hacer estallar y presionar el estado nuevamente, la siguiente interrupción pendiente se maneja de inmediato
    • llegada tardía: si llega una interrupción de mayor prioridad mientras se apila el estado del procesador, se ejecuta inmediatamente en lugar de la pendiente anterior.

Ya que está familiarizado con los PIC, eche un vistazo a esta Nota de aplicación: Migración de los microcontroladores PIC a Cortex-M3

Se trata de M3, pero la mayoría de los puntos se aplican a M0 también.

    
respondido por el Igor Skochinsky
8

Las respuestas de Austin e Igor son lo suficientemente detalladas. Sin embargo, quiero responderlo de otra manera, tal vez lo encuentre útil.

El LPC11xx (Cortex-M0) tiene 4 niveles para pines GPIO, todos los pines de GPIO0.0 a GPIO0.n comparten el mismo número de interrupción, y todos los pines de GPIO3.0 a GPIO3.m comparten la misma interrupción número.

Hay seis pasos para inicializar la interrupción GPIO en LPC11xx

  1. Configure la función de pin modificando los registros de bloque de conexión de pin.
  2. Configure la dirección del pin modificando el registro de dirección de datos GPIO (el valor predeterminado es la entrada).
  3. Configure la interrupción para cada pin individual, debe ir al registro GPIOnIE de máscara de interrupción de GPIO y configurar el bit (que corresponde al pin) la lógica 1.
  4. Configure la interrupción para el flanco ascendente o descendente, o ambos modificando los registros de detección de interrupción GPIO GPIOnIBE y GPIOnIS.
  5. Habilite la fuente de interrupción PIO_0 / PIO_1 / PIO_2 / PIO_3 en Control de interrupción de vector anidado usando las funciones de CMSIS.
  6. Establezca la prioridad de interrupción utilizando las funciones CMSIS.

Implementaciones de código. Necesita dos funciones: una inicializa los 6 pasos anteriores y el segundo es el controlador de interrupciones, que debe ser el mismo nombre que el controlador definido en los códigos de inicio , archivo startup_LPC11xx.s . Los nombres son de PIOINT0_IRQHandler a PIOINT3_IRQHandler . Si usa un nombre diferente, tiene que cambiar los nombres en el archivo de inicio.

/*Init the GPIO pin for interrupt control */
void GPIO_Init(){
    LPC_IOCON-> =..              //Pin configuration register
    LPC_GPIO1->FIODIR = ...      //GPIO Data direction register
    LPC_GPIO1->FIOMASK = ..      //GPIO Data mask register - choose  the right pin
    LPC_GPIO1->GPIOnIE = ..      //Set up falling or rising edge 
    NVIC_EnableIRQ(PIO_1);       //Call API to enable interrupt in NVIC
    NVIC_SetPriority(PriorityN); //Set priority if needed
}


/*Must have the same name as listed in start-up file startup_LPC11xx.s */
void PIOINT1_IRQHandler(void){
   //Do something here
}
    
respondido por el Phuong Pham

Lea otras preguntas en las etiquetas