Tamaño: 4126
Comentario:
|
Tamaño: 8765
Comentario:
|
Los textos eliminados se marcan así. | Los textos añadidos se marcan así. |
Línea 2: | Línea 2: |
En el contexto de un sistema con microprocesador, la interrupción es un proceso por el cual ante un evento un determinado periférico suspende momentáneamente la ejecución del programa principal del sistema para ejecutar un código especifico que atienda dicho evento. | |
Línea 3: | Línea 4: |
Nested Vectored Interrupt Controller (NVIC) o Controlador de interrupciones vectorizadas anidadas, es el controlador encargado del manejo de interrupciones del Cortex-M4 Este controlador tiene la particularidad de permitir asociar cada interrupciones del microcontrolador con una dirección de memoria (vector) donde se encuentra la subrutina que atenderá dicha interrupción, permitiendo una respuesta rápida (baja latencia) ante un evento. |
La interrupción se realiza mediante una señal que emite el periférico y que es recibida por un controlador de interrupción que realiza la interrupción del proceso en ejecución dentro del micro y su posterior cambio a el código especifico. == Manejo de eventos por "polling" o "sondeo" == {{attachment:polling.png|"polling.png"|width="35%"}} == Manejo de eventos por interrupción == {{attachment:interrupcion.png|"interrupcion.png"|width="35%"}} == Interrupción en el Cortex M4 == Nested Vectored Interrupt Controller (NVIC) o Controlador de interrupciones vectorizadas anidadas, es el controlador encargado del manejo de interrupciones del Cortex-M4 Este controlador tiene la particularidad de permitir asociar cada interrupciones del microcontrolador con una dirección de memoria (vector) donde se encuentra la subrutina que atenderá dicha interrupción, permitiendo una respuesta rápida (baja latencia) ante un evento. === Registros de la NVIC === ||Dirección ||Nombre ||Tipo ||Desccripción || ||0xE000E100- 0xE000E11C ||NVIC_ISER0- NVIC_ISER7 ||RW ||Interrupt Set-enable Registers || ||0XE000E180- 0xE000E19C ||NVIC_ICER0- NVIC_ICER7 ||RW ||Interrupt Clear-enable Registers || ||0XE000E200- 0xE000E21C ||NVIC_ISPR0- NVIC_ISPR7 ||RW ||Interrupt Set-pending Registers || ||0XE000E280- 0xE000E29C ||NVIC_ICPR0- NVIC_ICPR7 ||RW ||Interrupt Clear-pending Registers || ||0xE000E300- 0xE000E31C ||NVIC_IABR0- NVIC_IABR7 ||RW ||Interrupt Active Bit Registers || ||0xE000E400- 0xE000E4EF ||NVIC_IPR0- NVIC_IPR59 ||RW ||Interrupt Priority Registers || ||0xE000EF00 ||STIR ||WO ||Software Trigger Interrupt Register || === Vectores de Interrupción === Es un vector que contiene la dirección de memoria de la rutina para atender cada uno de las posibles interrupciones, depende específicamente del microcontrolador, debido a que los periféricos que posea serán los listados en este vector. ==== Ejemplo de los primeros 17 vectores en los micros de las familia LPC43xx ==== ||ID ||Numero de excepción ||Offset ||Función || ||0 ||16 ||0x40 ||DAC || ||1 ||17 ||0x44 ||M0APP Cortex-M0APP || ||2 ||18 ||0x48 ||DMA || ||3 ||19 ||0x4C ||Reserved || ||4 ||20 ||0x50 ||FLASHEEPROM || ||5 ||21 ||0x54 ||ETHERNET Ethernet interrupt || ||6 ||22 ||0x58 ||SDIO SD/MMC interrupt || ||7 ||23 ||0x5C ||LCD || ||8 ||24 ||0x60 ||USB0 OTG interrupt || ||9 ||25 ||0x64 ||USB1 || ||10 ||26 ||0x68 ||SCT SCT combined interrupt || ||11 ||27 ||0x6C ||RITIMER || ||12 ||28 ||0x70 ||TIMER0 || ||13 ||29 ||0x74 ||TIMER1 || ||14 ||30 ||0x78 ||TIMER2 || ||15 ||31 ||0x7C ||TIMER3 || ||16 ||32 ||0x80 ||MCPWM Motor control PW || |
Línea 8: | Línea 54: |
== Configuración del periférico == | === Configuración del Periférico === Además de configurar el periférico para su funcionamiento de acuerdo a los requerimientos de la aplicación, se debe definir cuales y cuantos eventos del mismo generarán interrupción, debido a que en general estos periféricos generan mas de un evento. Podemos citar por ejemplo la UART, este periférico generalmente se atiende por interrupción, por tener eventos asíncrono y relativamente lento (configurado a 9600 baudios significa que se recibe o se transmite 1 byte cada aprox. 1 ms o 2x10^5 instrucciones en un micro de 200MHz). |
Línea 10: | Línea 57: |
Además de configurar el periférico para su funcionamiento de acuerdo a los requerimientos de la aplicación, se deberá definir cuales y cuantos eventos del mismo generarán interrupción, debido a que en general estos periféricos generan mas de un evento. Podemos citar por ejemplo la UART, este periférico generalmente se atiende por interrupción, por ser un evento asíncrono y relativamente lento (configurado a 9600 baudios significa que se recibe o se transmite 1 byte cada aprox. 1 ms o 2x10^5 instrucciones en un micro de 200MHz). Este periférico puede generar interrupciones cuando: llego un byte, llego el byte nro n (para un n predefinido), se terminó de enviar un byte, la cola de envíos esta vacía, se detectó un error de trama, etc. Cada uno de estos eventos permite o no generar interrupciones y deben ser configurados. |
Este periférico puede generar interrupciones cuando: |
Línea 14: | Línea 59: |
== Configuración de la NVIC == Una vez definido el periférico, debe configurarse el controlador de interrupciones para que efectivamente atienda a la interrupción, en este paso se define además la prioridad, la NVIC perimite 255 niveles de prioridad siendo el 0 la mas alta, bajando la prioridad cuando subimos el valor. |
* llegó un byte. * llegó el byte nro n (para un n predefinido). * Se terminó de enviar un byte. * La cola de envíos esta vacía. * Se detectó un error de trama. * etc. |
Línea 17: | Línea 66: |
== Vector de Interrupción == | Se debe evaluar entonces al momento de configurar el dispositivo cuales eventos generará interrupciones y cuales no. === Configuración de la NVIC === Una vez definido el periférico, debe configurarse el controlador de interrupciones para que efectivamente atienda a la interrupción, si es requerido en este paso se define además la prioridad, la NVIC permite hasta 255 niveles de prioridad siendo el 0 la mas alta, bajando la prioridad cuando subimos el valor. === Vector de Interrupción === |
Línea 20: | Línea 74: |
== Ejemplo == A continuación se realiza un ejemplo de interrupción, el mismo implementa un retardo de "N" ms para ser utilizado como una retardo mas preciso que un simple bucle. El funcionamiento del mismo será el siguiente: |
=== Ejemplo === A continuación se realiza un ejemplo de interrupción, el mismo implementa un retardo de "N" ms para ser utilizado como una retardo mas preciso que un simple bucle. El funcionamiento del mismo será el siguiente: |
Línea 26: | Línea 79: |
==== Configuración del periférico y NVIC ==== Habilitar el periférico |
|
Línea 27: | Línea 82: |
=== Configuración del periférico y NVIC === Habilitar el periférico |
|
Línea 30: | Línea 83: |
Chip_RIT_Init(LPC_RITIMER); | Chip_RIT_Init(LPC_RITIMER); |
Línea 32: | Línea 85: |
Función de la LPCOpen que configura el periférico para que cuente 1 ms, esta función realiza el cálculo de acuerdo a la frecuencia en que funciona el micro para que la cuenta dé aproximadamente los milisegundos enviados en el 2do parámetro | Función de la LPCOpen que configura el periférico para que cuente 1 ms, esta función realiza el cálculo de acuerdo a la frecuencia en que funciona el micro para que la cuenta dé aproximadamente los milisegundos enviados en el 2do parámetro |
Línea 36: | Línea 90: |
Por último deberíamos configurar el periférico para que el mismo genere interrupción por un evento dado, en el caso particular de RIT, la única interrupción que puede generar es por llegar a la cuenta, por ello no posee configuración de interrupción, la sola habilitación del periférico dentro de la NVIC, ya lo habilita a generar interrupciones. | Por último deberíamos configurar el periférico para que el mismo genere interrupción por un evento dado, en el caso particular de RIT, la única interrupción que puede generar es por llegar a la cuenta, por ello no posee configuración de interrupción, la sola habilitación del periférico dentro de la NVIC, ya lo habilita a generar interrupciones. |
Línea 39: | Línea 93: |
Línea 42: | Línea 97: |
Finalmente se habilita el periférico en la NVIC, Cada periférico tiene asignado un nro dentro de la tabla de vectores de interrupción, en el caso del RIT le corresponde la posición nro 11. | |
Línea 43: | Línea 99: |
Finalmente se habilita el periférico en la NVIC, Cada periferico tiene asignado un nro dentro de la tabla de vectores de interrupción, en el caso del RIT le corresponde la posición nro 11. |
|
Línea 48: | Línea 102: |
=== Vector de Interrupción === En primer lugar se debe realizar la función que atienda a la interrupción, en el caso del ejemplo podemos llamar a la función que atiende a RIT como {{{Timer_IRQ}}} y se codificará de la siguiente manera |
|
Línea 49: | Línea 105: |
{{{ volatile int var_global=0; // variable global }}} {{{ void Timer_IRQ(void) { var_global++; // incrementamos la variable global Timer_Clear_IRQ(); // borramos la bandera de interrupción } }}} Esta función puede ser escrita en una archivo separado del vector.c, para este caso, se deberá escribir el prototipo de la funcion en el .h correspondiente y luego ese .h ser incluido en el archivo que posee el vector de interrupciones ('''vector.c'''), este archivo que acompaña a cada proyecto, en el mismo se encuentra el vector de interrupciones ya inicializado con las funciones para atender las interrupciones principales (15 en total) para luego continuar con los vectores de los periféricos o interrupciones de usuario apuntando todos a la función genérica {{{ISR_NoHandler()}}} Localizada el nro de interrupción (11 en el ejemplo), se debe modificar del nombre genérico {{{ISR_NoHandler}}} al nombre de la función asignada en el ejemplo {{{Timer_IRQ}}} Quedando de la siguiente forma |
|
Línea 50: | Línea 116: |
{{{ ISR_NoHandler, /* 0x17 0x0000005C - No Handler set for ISR LCD (IRQ 7) */ ISR_NoHandler, /* 0x18 0x00000060 - No Handler set for ISR USB0 (IRQ 8) */ ISR_NoHandler, /* 0x19 0x00000064 - No Handler set for ISR USB1 (IRQ 9) */ ISR_NoHandler, /* 0x1a 0x00000068 - No Handler set for ISR SCT (IRQ 10) */ Timer_IRQ, /* 0x1b 0x0000006C - No Handler set for ISR RIT (IRQ 11) */ ISR_NoHandler, /* 0x1c 0x00000070 - No Handler set for ISR TIMER0 (IRQ 12) */ ISR_NoHandler, /* 0x1d 0x00000074 - No Handler set for ISR TIMER1 (IRQ 13) */ ISR_NoHandler, /* 0x1e 0x00000078 - No Handler set for ISR TIMER2 (IRQ 14) */ }}} Finalmente se puede definir la función retardo como sigue: |
|
Línea 53: | Línea 128: |
{{{ void retardo(int ms) { var_global=0; while(var_global<=ms) { } } }}} |
Manejo de Interrupciones (NVIC)
En el contexto de un sistema con microprocesador, la interrupción es un proceso por el cual ante un evento un determinado periférico suspende momentáneamente la ejecución del programa principal del sistema para ejecutar un código especifico que atienda dicho evento.
La interrupción se realiza mediante una señal que emite el periférico y que es recibida por un controlador de interrupción que realiza la interrupción del proceso en ejecución dentro del micro y su posterior cambio a el código especifico.
Manejo de eventos por "polling" o "sondeo"
Manejo de eventos por interrupción
Interrupción en el Cortex M4
Nested Vectored Interrupt Controller (NVIC) o Controlador de interrupciones vectorizadas anidadas, es el controlador encargado del manejo de interrupciones del Cortex-M4 Este controlador tiene la particularidad de permitir asociar cada interrupciones del microcontrolador con una dirección de memoria (vector) donde se encuentra la subrutina que atenderá dicha interrupción, permitiendo una respuesta rápida (baja latencia) ante un evento.
Registros de la NVIC
Dirección |
Nombre |
Tipo |
Desccripción |
0xE000E100- 0xE000E11C |
NVIC_ISER0- NVIC_ISER7 |
RW |
Interrupt Set-enable Registers |
0XE000E180- 0xE000E19C |
NVIC_ICER0- NVIC_ICER7 |
RW |
Interrupt Clear-enable Registers |
0XE000E200- 0xE000E21C |
NVIC_ISPR0- NVIC_ISPR7 |
RW |
Interrupt Set-pending Registers |
0XE000E280- 0xE000E29C |
NVIC_ICPR0- NVIC_ICPR7 |
RW |
Interrupt Clear-pending Registers |
0xE000E300- 0xE000E31C |
NVIC_IABR0- NVIC_IABR7 |
RW |
Interrupt Active Bit Registers |
0xE000E400- 0xE000E4EF |
NVIC_IPR0- NVIC_IPR59 |
RW |
Interrupt Priority Registers |
0xE000EF00 |
STIR |
WO |
Software Trigger Interrupt Register |
Vectores de Interrupción
Es un vector que contiene la dirección de memoria de la rutina para atender cada uno de las posibles interrupciones, depende específicamente del microcontrolador, debido a que los periféricos que posea serán los listados en este vector.
Ejemplo de los primeros 17 vectores en los micros de las familia LPC43xx
ID |
Numero de excepción |
Offset |
Función |
0 |
16 |
0x40 |
DAC |
1 |
17 |
0x44 |
M0APP Cortex-M0APP |
2 |
18 |
0x48 |
DMA |
3 |
19 |
0x4C |
Reserved |
4 |
20 |
0x50 |
FLASHEEPROM |
5 |
21 |
0x54 |
ETHERNET Ethernet interrupt |
6 |
22 |
0x58 |
SDIO SD/MMC interrupt |
7 |
23 |
0x5C |
LCD |
8 |
24 |
0x60 |
USB0 OTG interrupt |
9 |
25 |
0x64 |
USB1 |
10 |
26 |
0x68 |
SCT SCT combined interrupt |
11 |
27 |
0x6C |
RITIMER |
12 |
28 |
0x70 |
TIMER0 |
13 |
29 |
0x74 |
TIMER1 |
14 |
30 |
0x78 |
TIMER2 |
15 |
31 |
0x7C |
TIMER3 |
16 |
32 |
0x80 |
MCPWM Motor control PW |
La configuración de la interrupción requiere de los siguientes pasos
Configuración del Periférico
Además de configurar el periférico para su funcionamiento de acuerdo a los requerimientos de la aplicación, se debe definir cuales y cuantos eventos del mismo generarán interrupción, debido a que en general estos periféricos generan mas de un evento. Podemos citar por ejemplo la UART, este periférico generalmente se atiende por interrupción, por tener eventos asíncrono y relativamente lento (configurado a 9600 baudios significa que se recibe o se transmite 1 byte cada aprox. 1 ms o 2x10^5 instrucciones en un micro de 200MHz).
Este periférico puede generar interrupciones cuando:
- llegó un byte.
- llegó el byte nro n (para un n predefinido).
- Se terminó de enviar un byte.
- La cola de envíos esta vacía.
- Se detectó un error de trama.
- etc.
Se debe evaluar entonces al momento de configurar el dispositivo cuales eventos generará interrupciones y cuales no.
Configuración de la NVIC
Una vez definido el periférico, debe configurarse el controlador de interrupciones para que efectivamente atienda a la interrupción, si es requerido en este paso se define además la prioridad, la NVIC permite hasta 255 niveles de prioridad siendo el 0 la mas alta, bajando la prioridad cuando subimos el valor.
Vector de Interrupción
Una vez configurado el periférico y luego la NVIC, solo resta programar la función que atenderá la interrupción, esta función se escribe de manera análoga a una función estándar con la diferencia que debe cargarse la dirección de la misma en el vector de interrupciones.
Ejemplo
A continuación se realiza un ejemplo de interrupción, el mismo implementa un retardo de "N" ms para ser utilizado como una retardo mas preciso que un simple bucle. El funcionamiento del mismo será el siguiente:
Se utiliza el periférico Repetitive Interrupt Timer (RIT), es un contador muy sencillo que permite realizar cuentas o interrupciones a intervalos definidos sin la necesidad de utilizar los contadores generales que dispone el micro. Se configura este timer para que cuente hasta un valor determinado que implicará un retardo de 1 ms generando una interrupción, dentro de la misma se incrementa una variable global, luego se realizará una función retardo que simplemente colocará a 0 la variable global y un bucle esperará que esa variable se incremente al valor deseado, generando "N" x 1ms = "N" ms de retardo
Configuración del periférico y NVIC
Habilitar el periférico
Chip_RIT_Init(LPC_RITIMER);
Función de la LPCOpen que configura el periférico para que cuente 1 ms, esta función realiza el cálculo de acuerdo a la frecuencia en que funciona el micro para que la cuenta dé aproximadamente los milisegundos enviados en el 2do parámetro
Chip_RIT_SetTimerInterval(LPC_RITIMER,1);
Por último deberíamos configurar el periférico para que el mismo genere interrupción por un evento dado, en el caso particular de RIT, la única interrupción que puede generar es por llegar a la cuenta, por ello no posee configuración de interrupción, la sola habilitación del periférico dentro de la NVIC, ya lo habilita a generar interrupciones.
Antes de concluir la inicialización, se borra la bandera de interrupción
Chip_RIT_ClearInt(LPC_RITIMER);
Finalmente se habilita el periférico en la NVIC, Cada periférico tiene asignado un nro dentro de la tabla de vectores de interrupción, en el caso del RIT le corresponde la posición nro 11.
NVIC_EnableIRQ(11);
Vector de Interrupción
En primer lugar se debe realizar la función que atienda a la interrupción, en el caso del ejemplo podemos llamar a la función que atiende a RIT como Timer_IRQ y se codificará de la siguiente manera
volatile int var_global=0; // variable global
void Timer_IRQ(void) { var_global++; // incrementamos la variable global Timer_Clear_IRQ(); // borramos la bandera de interrupción }
Esta función puede ser escrita en una archivo separado del vector.c, para este caso, se deberá escribir el prototipo de la funcion en el .h correspondiente y luego ese .h ser incluido en el archivo que posee el vector de interrupciones (vector.c), este archivo que acompaña a cada proyecto, en el mismo se encuentra el vector de interrupciones ya inicializado con las funciones para atender las interrupciones principales (15 en total) para luego continuar con los vectores de los periféricos o interrupciones de usuario apuntando todos a la función genérica ISR_NoHandler() Localizada el nro de interrupción (11 en el ejemplo), se debe modificar del nombre genérico ISR_NoHandler al nombre de la función asignada en el ejemplo Timer_IRQ Quedando de la siguiente forma
ISR_NoHandler, /* 0x17 0x0000005C - No Handler set for ISR LCD (IRQ 7) */ ISR_NoHandler, /* 0x18 0x00000060 - No Handler set for ISR USB0 (IRQ 8) */ ISR_NoHandler, /* 0x19 0x00000064 - No Handler set for ISR USB1 (IRQ 9) */ ISR_NoHandler, /* 0x1a 0x00000068 - No Handler set for ISR SCT (IRQ 10) */ Timer_IRQ, /* 0x1b 0x0000006C - No Handler set for ISR RIT (IRQ 11) */ ISR_NoHandler, /* 0x1c 0x00000070 - No Handler set for ISR TIMER0 (IRQ 12) */ ISR_NoHandler, /* 0x1d 0x00000074 - No Handler set for ISR TIMER1 (IRQ 13) */ ISR_NoHandler, /* 0x1e 0x00000078 - No Handler set for ISR TIMER2 (IRQ 14) */
Finalmente se puede definir la función retardo como sigue:
void retardo(int ms) { var_global=0; while(var_global<=ms) { } }