<?xml version="1.0" encoding="utf-8"?><!DOCTYPE article  PUBLIC '-//OASIS//DTD DocBook XML V4.4//EN'  'http://www.docbook.org/xml/4.4/docbookx.dtd'><article><articleinfo><title>WebHome/Hardware/LPC2114/ModuloVIC</title><revhistory><revision><revnumber>3</revnumber><date>2013-10-27 16:09:51</date><authorinitials>GuillermoSteiner</authorinitials><revremark>Se cambia nombre desde &quot;WebHome/HardwareARM2114/ModuloVIC&quot;</revremark></revision><revision><revnumber>2</revnumber><date>2011-08-02 21:18:15</date><authorinitials>GuillermoSteiner</authorinitials></revision><revision><revnumber>1</revnumber><date>2011-08-02 20:55:10</date><authorinitials>GuillermoSteiner</authorinitials></revision></revhistory></articleinfo><section><title>Controlador Vectorizado de Interrupciones (Vectores Interrupt Controller VIC)</title><itemizedlist><listitem override="none"><para>material para la clase:  </para><itemizedlist><listitem><para>Manuales del usuario del lpc21xx version <ulink url="https://ciii.frc.utn.edu.ar/TecnicasDigitalesII/WebHome/Hardware/LPC2114/ModuloVIC/TecnicasDigitalesII/WebHome/Bibliografia?action=AttachFile&amp;do=get&amp;target=UM10114_3.pdf">nueva</ulink> y <ulink url="https://ciii.frc.utn.edu.ar/TecnicasDigitalesII/WebHome/Hardware/LPC2114/ModuloVIC/TecnicasDigitalesII/WebHome/Bibliografia?action=AttachFile&amp;do=get&amp;target=LPC2114_2124_6.pdf">vieja</ulink> capitulo 6 en ambos.  </para></listitem></itemizedlist></listitem></itemizedlist><para>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. </para><section><title>Descripción</title><para>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) </para><itemizedlist><listitem><para>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 &quot;if()&quot; 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. </para></listitem><listitem><para>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. </para></listitem><listitem><para>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 &quot;if()&quot; necesarios para identificar las posibles interrupciones que terminen por atenderse en esta función  </para></listitem></itemizedlist><para>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   </para><para>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 </para><informaltable><tgroup cols="3"><colspec colname="col_0"/><colspec colname="col_1"/><colspec colname="col_2"/><tbody><row rowsep="1"><entry colsep="1" rowsep="1"><para> <emphasis role="strong">Nombre de los Pines</emphasis> </para></entry><entry colsep="1" rowsep="1"><para> <emphasis role="strong">Tipos</emphasis> </para></entry><entry colsep="1" rowsep="1"><para> <emphasis role="strong">Denominación del puerto</emphasis> </para></entry></row><row rowsep="1"><entry colsep="1" rowsep="1"><para> P0.0 a P0.31 </para></entry><entry colsep="1" rowsep="1"><para> I/O </para></entry><entry colsep="1" rowsep="1"><para> GPIO0 </para></entry></row><row rowsep="1"><entry colsep="1" rowsep="1"><para> P1.16 a P1.31 </para></entry><entry colsep="1" rowsep="1"><para> I/O </para></entry><entry colsep="1" rowsep="1"><para> GPIO1 </para></entry></row></tbody></tgroup></informaltable><para>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 </para><para>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. </para><para>Registros de GPIO </para><informaltable><tgroup cols="6"><colspec colname="col_0"/><colspec colname="col_1"/><colspec colname="col_2"/><colspec colname="col_3"/><colspec colname="col_4"/><colspec colname="col_5"/><tbody><row rowsep="1"><entry colsep="1" rowsep="1"><para> Nombre Genérico </para></entry><entry colsep="1" rowsep="1"><para> Descripción </para></entry><entry colsep="1" rowsep="1"><para> Acceso </para></entry><entry colsep="1" rowsep="1"><para> Valor en Reset </para></entry><entry align="center" colsep="1" nameend="col_5" namest="col_4" rowsep="1"><para> Dirección y Nombre </para></entry></row><row rowsep="1"><entry colsep="1" rowsep="1"/><entry colsep="1" rowsep="1"/><entry colsep="1" rowsep="1"/><entry colsep="1" rowsep="1"/><entry colsep="1" rowsep="1"><para> Puerto 0 </para></entry><entry colsep="1" rowsep="1"><para> Puerto 1 </para></entry></row><row rowsep="1"><entry colsep="1" rowsep="1"><para> IOPIN </para></entry><entry colsep="1" rowsep="1"><para> En modo entrada permite leer el valor instantáneo de cada pin, en el modo salida permite determinar la salida lógica </para></entry><entry colsep="1" rowsep="1"><para> R/W </para></entry><entry colsep="1" rowsep="1"><para> NA </para></entry><entry colsep="1" rowsep="1"><para> 0xE0028000 IO0PIN </para></entry><entry colsep="1" rowsep="1"><para> 0xE0028010 IO1PIN </para></entry></row><row rowsep="1"><entry colsep="1" rowsep="1"><para> IOSET </para></entry><entry colsep="1" rowsep="1"><para> 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 </para></entry><entry colsep="1" rowsep="1"><para> R/W </para></entry><entry colsep="1" rowsep="1"><para> 0x0000000 </para></entry><entry colsep="1" rowsep="1"><para> 0xE0028004 IO0SET </para></entry><entry colsep="1" rowsep="1"><para> 0xE0028014 IO1SET </para></entry></row><row rowsep="1"><entry colsep="1" rowsep="1"><para> IODIR </para></entry><entry colsep="1" rowsep="1"><para> Configura individualmente a cada pin como entrada o salida, 1 indica salida 0 entrada  </para></entry><entry colsep="1" rowsep="1"><para> R/W </para></entry><entry colsep="1" rowsep="1"><para> 0x0000000 </para></entry><entry colsep="1" rowsep="1"><para> 0xE0028008 IO0DIR </para></entry><entry colsep="1" rowsep="1"><para> 0xE0028018 IO1DIR </para></entry></row><row rowsep="1"><entry colsep="1" rowsep="1"><para> IOCLR </para></entry><entry colsep="1" rowsep="1"><para> 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 </para></entry><entry colsep="1" rowsep="1"><para> W </para></entry><entry colsep="1" rowsep="1"><para> 0x0000000 </para></entry><entry colsep="1" rowsep="1"><para> 0xE002800C IO0CLR </para></entry><entry colsep="1" rowsep="1"><para> 0xE002801C IO1CLR </para></entry></row></tbody></tgroup></informaltable><para>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. </para><section><title>Uso de la GPIO en modo salida</title><para>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 </para><screen><![CDATA[IO1DIR = 0x00FF0000;]]></screen><para> 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.</para><para>Ahora escribimos en el puerto configurado como salida el valor 0x55, esto lo podemos hacer de dos formas: </para><para>Método 1 </para><screen><![CDATA[unsigned int a;
a = 0x55;
IO1PIN = (a << 16);]]></screen><para>Método 2 </para><screen><![CDATA[unsigned int a;
a = 0x55;
IO1CLR = (~a & 0xFF) <<16;
IO1SET = a <<16;]]></screen><itemizedlist><listitem><para><emphasis role="strong">Método 1</emphasis> 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.  </para></listitem><listitem><para><emphasis role="strong">Método 2</emphasis> 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.  </para></listitem></itemizedlist></section><section><title>Uso de la GPIO en modo entrada</title><para>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. </para><para>Ejemplo Para determinar el estado de un botón que se encuentra en la linea P0.15 se procede de la siguiente forma. </para><screen><![CDATA[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));
      } 
   }
} ]]></screen><para>En el ejemplo realizamos un if(IO1PIN &amp; (1&lt;&lt;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. </para><para>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. </para></section></section></section></article>