= Entradas y Salidas Digitales GPIO = material para la clase: * Manuales del usuario del microcontrolador freescale familia KL46 capitulo 42. 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 de esta familia pueden ser hasta 5 dependiendo del modelo || '''Nombre de los Pines''' || '''Tipos''' || '''Denominación del puerto''' || || PORTA31 a PORTA0 || I/O || PORTA || || PORTB31 a PORTB0 || I/O || PORTB || || PORTC31 a PORTC0 || I/O || PORTC || || PORTD31 a PORTD0 || I/O || PORTD || || PORTE31 a PORTE0 || I/O || PORTE || 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.