Controlador Vectorizado de Interrupciones (Vectores Interrupt Controller VIC)
El VIC es un controlador de interrupciones que permite, mediante su configuración, atender a los diferentes dispositivos de hardware del microcontrolador. Esto significa que ante un evento del hardware (finalización de conversión en un ADC, cambio de estado en una pata de entrada, desborde de un contador, etc) el micro procesador detendrá el procedimiento en curso y comenzará a ejecutar la función determinada por el VIC La forma de configurar este controlador, y como asignarle las funciones a realizar para cada caso, será la finalidad del presente texto.
Descripción
El VIC es básicamente un controlador que permite asignar hasta 32 solicitudes de interrupción de 3 formas distintas Interrupción Rápida (FIQ), Interrupción Vectorizada (IRQ) y finalmente la no vectorizada (non-vectored IRQ)
- FIQ, esta interrupción es la mas rápida, posee la mayor prioridad de ejecución, como desventaja, solo puede asignarse una función para atender a todas las FIQ que establezcamos, luego dentro de la función deberemos realizar una serie de "if()" para determinar el origen de la interrupción y actuar en consecuencia, es por ello que para aprovechar su ventaja de velocidad, generalmente se configura una sola solicitud como FIQ.
- IRQ, en caso de que la solicitud no esté configurada como FIQ se pasa a la interrupción vectorizada, en este caso se puede establecer hasta 16 vectores de interrupción, es decir asignar hasta 16 solicitudes de interrupción a 16 funciones diferentes para atenderlas, del numero del vector asignado dependerá la prioridad de esa solicitud, siendo el 0 el de mayor prioridad.
- Non-Vectored IRQs, esta interrupción es la de menor prioridad, y ocurre cuando se configurá el VIC para atender a una solicitud, pero luego no se asigna ni a FIQ ni a un vector de la IRQ, en ese caso por descarte será atendido por una unica función, dentro de ella deberá realizarse los "if()" necesarios para identificar las posibles interrupciones que terminen por atenderse en esta función
Las asignación de cada solicitud a alguna de estas formas de interrupción, la efectuaremos mediante la configuración de los diferentes registros que posee el VIC, pudiendo
El GPIO son lineas que pueden actuar como entrada o salida digital, pudiendo modificar su modo individualmente, estas lineas están agrupadas en puertos, en el caso del microcontrolador LPC2114, son dos
Nombre de los Pines |
Tipos |
Denominación del puerto |
P0.0 a P0.31 |
I/O |
GPIO0 |
P1.16 a P1.31 |
I/O |
GPIO1 |
Como vemos entonces cada linea de entrada salida posee un numero y un puerto, el puerto 0 o GPIO0 agrupa 32 lineas y el puerto 1 o GPIO1 agrupa 16 enumeradas de la 16 a la 31 Cada puerto posee una seria de registros para manejar los mismos, permitiendo configurar cada linea como entrada o salida, leer una entrada en particular o escribir sobre una salida Tendremos entonces registros para distintas acciones por cada puerto, donde cada bits de esos registros representa a cada linea de su puerto
Modo entrada, una linea configurada como entrada, permite leer una señal conectada a la misma, el valor leído es 0 o 1 dependiendo del estado de la linea en el momento de la lectura. Modo Salida, una linea configurada como salida, permite sacar un valor lógico alto o bajo.
Registros de GPIO
Nombre Genérico |
Descripción |
Acceso |
Valor en Reset |
Dirección y Nombre |
|
|
|
|
|
Puerto 0 |
Puerto 1 |
IOPIN |
En modo entrada permite leer el valor instantáneo de cada pin, en el modo salida permite determinar la salida lógica |
R/W |
NA |
0xE0028000 IO0PIN |
0xE0028010 IO1PIN |
IOSET |
Utilizado solo en modo salida, permite pasar a alto una salida escribiendo un 1 en el bit correspondiente, la salida de los bit en 0 no son tocadas |
R/W |
0x0000000 |
0xE0028004 IO0SET |
0xE0028014 IO1SET |
IODIR |
Configura individualmente a cada pin como entrada o salida, 1 indica salida 0 entrada |
R/W |
0x0000000 |
0xE0028008 IO0DIR |
0xE0028018 IO1DIR |
IOCLR |
Utilizado solo en modo salida, permite pasar a bajo una salida escribiendo un 1 en el bit correspondiente, la salida de los bit en 0 no son tocadas |
W |
0x0000000 |
0xE002800C IO0CLR |
0xE002801C IO1CLR |
La denominación dada a cada registro es estándar y puede encontrarse en el archivo de cabecera lp2114.h, en los siguientes ejemplos se usa este nombre en lugar de la dirección física.
Uso de la GPIO en modo salida
El primer paso es configurar cada linea como entrada o salida, esto se realiza con los registro IOxDIR, si queremos configurar por ejemplo las primeras 8 lineas del puerto 1 como salida y dejar al resto como entrada, realizamos lo siguiente
IO1DIR = 0x00FF0000;
Aquí vemos que escribimos 1 en los bits 16 a 23 del registro IO1DIR, registro que configura la dirección del puerto, además como el puerto 1 comienza en el bit 16, efectivamente estamos configurando los 8 bits mas bajos del puerto como salida dejando los 8 mas alto como entrada.
Ahora escribimos en el puerto configurado como salida el valor 0x55, esto lo podemos hacer de dos formas:
Método 1
unsigned int a; a = 0x55; IO1PIN = (a << 16);
Método 2
unsigned int a; a = 0x55; IO1CLR = (~a & 0xFF) <<16; IO1SET = a <<16;
Método 1 es bastante sencillo, asignamos el valor a un entero (32 bits ) lo corremos 16 bits para ponerlo en la posición adecuada dentro del word y establecemos la salida grabando ese valor en el registro IO1PIN.
Método 2 es un poco mas complicado, aquí usamos primero el registro IOCLR, para esto negamos el entero a sacar, hacemos un and con una mascara para dejar solo el byte menos significativo y ahora si corremos los 16 bits y actualizamos el IOCLR, luego corremos el entero sin negar 16 bits y actualizamos el IO1SET.Estos dos pasos tienen un sentido muy importante, de este modo forzamos a 0 escribiendo unos en el IOCLR y forzamos a 1 a los bit que queremos que sean 1 con el IOSET, pero en ningún momento modificamos el estado de cualquier bits fuera de los 8 correspondiente al byte, como vemos en IOCLR cualquier bit fuera de los 8 de nuestra salida nunca tendrán un valor 1, lo mismo que en IOSET, esto permite encapsular estos 8 bits, permitiendo dividir el puerto en sub grupos que no interactúen entre si.El método 1 solo se utilizará cuando no es necesario esta división, permitiendo modificar el estado de los bits con una sola operación.
Uso de la GPIO en modo entrada
En el modo entrada el único registro a usar es el IOxPIN, mediante este registro se puede leer el estado instantáneo de una entrada, generalmente para luego determinar el estado de una señal en particular se enmascara las demás lineas y se compara con 0 el estado final.
Ejemplo Para determinar el estado de un botón que se encuentra en la linea P0.15 se procede de la siguiente forma.
int i; while(true) { if(IO1PIN & (1<<15)) { for(i=0;i<1000;i++); if(IO1PIN & (1<<15)) { /* botón efectivamente apretado */ while(IO1PIN & (1<<15)); } } }
En el ejemplo realizamos un if(IO1PIN & (1<<15)) esto nos da verdadero si y solo si el bit 15 del IO1PIN está en 1, cualquier elemento mecánico (botón, llave, etc) posee un tiempo de establecimiento o rebote durante el cual el microcontrolador puede leer 0 y 1 alternativamente, para evitar esto y para asegurarse de que efectivamente se presionó una tecla y no fue un ruido, se realiza un retardo de un par de milisegundos, luego se lee nuevamente la entrada con otro if(, asegurándose la correcta lectura.
Luego de atender la presión del botón y antes de salir a esperar otro evento, se puede esperar en un bucle hasta que suelte el botón, evitando que entre inmediatamente por continuar el pin P0.15 en 1.