Teclado

From Qi-Hardware
Jump to: navigation, search

Integrantes: Ari Andrés Bejarano 1, Sergio David Sánchez 0.5.

Contents

[edit] Calificación

Porcentaje Presentación 20% Informe 30% Funcionamiento 50%
1 Entrega 10% 0.5 0.5 0.5
2 Entrega 30% 3.0 3.0 3.0
3 Entrega 30% 3 3 3


4 Entrega 30% 5 5 5

[edit] Interfaz de teclado/ratón PS/2

La carpeta del proyecto la puede encontrar aquí

ps2 keyboard.

[edit] Especificaciones del proyecto

Este Proyecto consiste en una PCB hija con puerto PS/2 unida a la tarjeta SIE. Se podrá conectar un teclado ó un ratón (estandar PS/2), La FPGA se encargará de reconocer los dispositivos, funcionar como controlador y hacer puente entre los dispositivos y el procesador con sistema operativo GNU/Linux OpenWrt.

[edit] La interfaz

El protocolo PS/2 es un protocolo serie bidireccional, síncrono, que usa 2 líneas, una de reloj, y otra de datos. Estas líneas son de tipo colector abierto.

[edit] física

Conector hembra de frente.

Los teclados y ratones conectados directamente a la PCB utilizan las conexiones primarias, las conexiones secundarias son accesibles con un cable ps/2 Y-Splitter, pero en este proyecto están desconectados.

1 PS2_DATA1 conexión de datos primaria
2 PS2_DATA2 conexión de datos secundaria
3 GND tierra
4 VCC +5V alimentación
5 PS2_CLK1 conexión de reloj primaria
6 PS2_CLK2 conexión de reloj secundaria

[edit] eléctrica

VCC/GND proporcionan energía al dispositivo. El teclado o el ratón no deberían tomar más de 275 mA y se debe tener cuidado para evitar sobretensiones transitorias. Estas pueden ser causadas por "conexión en caliente" de un teclado/ratón (es decir, conectar/desconectar el dispositivo mientras la alimentación esté encendida). Aunque en mediciones realizadas, la corriente unicamente tiene un pico de 35 mA al inicio y luego se estabiliza en 10 mA (aproximadamente).

Resumen: Especificaciones de potencia
VCC = +4.5V a +5.5V.
Corriente máxima = 275 mA.

Las líneas de datos y reloj son de colector abierto con resistencias de pull-up a VCC. Una interfaz de "colector abierto" tiene dos estados posibles: bajo(valor lógico 0) o alta impedancia. En estado "bajo", un transistor tira la línea a GND. En estado de "alta impedancia", la interfaz actúa como un circuito abierto y no hace que la línea este en bajo o alto. Por otra parte, una resistencia "pull-up" se conecta entre el bus y VCC para tirar el bus a "alto" si ninguno de los dispositivos se activa tirando el bus a "bajo". El valor exacto de esta resistencia no es demasiado importante (1 ~ 10 kohmios); grandes resistencias resultan en un consumo energético menor y menores resistencias resultan en un tiempo de subida más rápido.

El puerto PS/2 es alimentado por 5V. Aunque la FPGA Spartan-3E(FPGA de SIE) no es un dispositivo con tolerancia de 5V, puede comunicarse con dispositivos de 5V utilizando en serie resistencias limitadoras de corriente.

[edit] Tarjeta hija

La tarjeta hija fue diseñada en principio en Orcad, pero posteriormente se hizo una versión en Kicad para utilizar las maquinas de TecnoParque.

Versión en Orcad aquí.
Versión en Kicad aquí.

[edit] Protocolo de Comunicación

[edit] Descripción General

El ratón y teclado PS/2 implementan un protocolo serie síncrono bidireccional. El bus está "inactivo" cuando las dos líneas están en "alto" (colector abierto). Este es el único estado donde el teclado y el ratón se les permite empezar a transmitir datos. El host(en este caso el host es la FPGA) tiene el último control sobre el bus (es el maestro) y puede inhibir la comunicación en cualquier momento, tirando de la línea de reloj a "bajo".

El dispositivo siempre genera la señal de reloj. Si el host desea enviar datos, primero debe inhibir la comunicación desde el dispositivo tirando de la línea de reloj a "bajo". Entonces el host tira de la línea de datos a "bajo" y libera la línea de Reloj. Esta es la "Solicitud para transmitir" que inicia la generación de pulsos de reloj.

Resumen: Estados del Bus
Datos = alto, Reloj = alto: en estado inactivo.
Datos = alto, Reloj = bajo: Comunicación inhibida.
Datos = bajo, Reloj = alto: Solicitud de host para Enviar

Todos los datos se transmiten un byte a la vez y cada byte se envía en un marco consistente de 11-12 bits. Estos bits son los siguientes:

  • 1 bit de arranque. Este es siempre 0.
  • 8 bits de datos, el bit menos significativo primero.
  • 1 bit de paridad (paridad impar).
  • 1 bit de parada. Este es siempre 1.
  • 1 bit de reconocimiento (comunicación host a dispositivo solamente).

El bit de paridad es 1 si existe un número par de 1's en los bits de datos y 0 si hay un número impar de 1's en los bits de datos. El número de 1's en los bits de datos más el bit de paridad siempre suman a un número impar (paridad impar). Esto se utiliza para la detección de errores. El teclado/ratón debe comprobar este bit y si es incorrecto debe responder como si hubiera recibido un comando no válido.

Los datos enviados desde el dispositivo al host se leen en el flanco de bajada de la señal de reloj, los datos enviados desde el host al dispositivo que se leen en el flanco de subida. La frecuencia de reloj debe estar en el rango de 10 a 16,7 kHz. Esto significa que el reloj debe estar en "alto" de 30 a 50 microsegundos y en "bajo" de 30 a 50 microsegundos. Una vez más, el teclado/ratón siempre genera la señal de reloj, pero el host siempre tiene el control final sobre la comunicación.

[edit] dispositivo a FPGA

Las líneas de datos y reloj son de colector abierto. Una resistencia se conecta entre cada línea y +5 V, por lo que el estado de inactividad del bus es "alto". Cuando el teclado o el ratón quieren enviar la información, primero comprueban la línea de reloj para asegurarse que está en un nivel lógico "alto". Si no está, el host tiene la comunicación inhibida y el dispositivo debe almacenar en el búfer cualquier dato a ser enviado hasta que el host libere la línea de Reloj. La línea de reloj debe estar en "alto" durante al menos 50 microsegundos antes de que el dispositivo puede comenzar a transmitir sus datos.

Como se mencionó antes, el teclado y el ratón utilizan un protocolo serie de 11 bits. Estos bits son los siguientes:

  • 1 bit de arranque. Este es siempre 0.
  • 8 bits de datos, el bit menos significativo primero.
  • 1 bit de paridad. (paridad impar).
  • 1 bit de parada. Este es siempre 1.

El teclado/ratón escribe en la línea de datos cuando el reloj está en "alto", y es leído por el host cuando el reloj esta en "bajo".

Ps2 lineas.png

La frecuencia de reloj es de 10-16.7 kHz. El tiempo transcurrido desde el flanco de subida de un pulso de reloj a una transición de datos debe tener al menos 5 microsegundos. El tiempo de una transición de datos para el flanco de bajada del pulso de reloj debe ser de al menos 5 microsegundos y no mayor de 25 microsegundos.

El host puede inhibir la comunicación en cualquier momento, tirando la línea de reloj a "bajo" durante al menos 100 microsegundos. Si la transmisión se inhibe antes del pulso de reloj 11, el dispositivo debe interrumpir la transmisión en curso prepararse para retransmitir el actual "pedazo" de datos cuando host libere el Reloj. Un "pedazo" de datos podría ser un make code, break code, el ID del dispositivo, un paquete del movimiento del ratón, etc. Por ejemplo, si un teclado se interrumpe durante el envío del segundo byte de un break code de dos bytes, tendrá que retransmitir los dos bytes del break code, no sólo el que fue interrumpido.

[edit] FPGA a dispositivo

El paquete se envía un poco diferente en la comunicación FPGA a dispositivo.

En primer lugar, el dispositivo PS/2 siempre genera la señal de reloj. Si el host desea enviar datos, primero debe poner las líneas de reloj y datos en una "Solicitud a enviar" como de indica:

  • Inhibir la comunicación tirando la línea de reloj a "bajo" durante al menos 100 microsegundos.
  • Aplicar la "Solicitar a enviar" tirando la línea de datos a "bajo", y entonces liberar el reloj.

El dispositivo debe comprobar este estado en un intervalo no mayor de 10 milisegundos. Cuando el dispositivo detecta este estado, comenzará a generar señales de reloj, ocho bits de datos y un bit de parada. El host cambia la línea de datos sólo cuando la línea de reloj está en "bajo", y los datos son leídos por el dispositivo cuando el reloj está en "alto". Esto es lo opuesto de lo que ocurría en la comunicación dispositivo a FPGA.

Después de que el bit de parada se recibe, el dispositivo reconoce el byte recibido por traer la línea de datos en "bajo" y la generación de un último pulso de reloj. Si el host no libera la línea de datos después del pulso de reloj 11, el dispositivo continuará generando pulsos de reloj hasta que se libere la línea de datos (el dispositivo generará un error).

Para hacer este proceso un poco más fácil de entender, he aquí los pasos que el host debe seguir para enviar datos a un dispositivo PS/2:

1) Llevar la línea de reloj a "bajo" durante al menos 100 microsegundos.
2) Llevar la línea de datos a "bajo".
3) Soltar la línea de reloj.
4) Esperar a que el dispositivo lleve la línea de reloj a "bajo".
5) Establecer la línea de datos para enviar el primer bit de datos.
6) Esperar a que el dispositivo lleve la línea de reloj a "alto".
7) Esperar a que el dispositivo lleve la línea de reloj a "bajo".
8) Repita los pasos 5-7 para los otros siete bits de datos y el bit de paridad.
9) liberar la línea de datos.
10) Espere a que el dispositivo lleve la línea de datos a "bajo".
11) Espere a que el dispositivo lleve la linea de reloj a "baja".
12) Espere a que el dispositivo libere datos y reloj

A continuacion, se presenta un diagrama de flujo de los diferentes estados del periferico, los cuales serán implementados en la FPGA usando ASM.

[edit] Teclado PS/2

[edit] Scan Codes

El procesador del teclado pasa la mayor parte de su tiempo "escaneando", la matriz de teclas. Si considera que una tecla es presionada, soltada, o se mantiene pulsada, el teclado envía un paquete de información conocido como " "scan code" al host. Hay dos tipos diferentes de cscan codes: "make codes" y "break codes". Un make code se envía cuando se pulsa una tecla o se mantiene presionada. Un break code se envía cuando se suelta una tecla. Cada tecla tiene asignado su propio break code y make code por lo que el host puede determinar exactamente el suceso y la tecla que lo causo mirando un simple scan code. Todos teclados cuentan con un "scan code set". Hay tres estándares de scan code set. Casi todos los teclados modernos tienen por defecto el set dos.

Entonces, ¿cómo saber cuáles son los scan codes corresponden a cada tecla? Desafortunadamente, no hay una forma sencilla de saber esto. Si quiere saber que make code o break code corresponde a una tecla específica, tendrá que mirar en una tabla.

  • Scan Code Set 1 - scan code set XT original; soportado por algunos teclados modernos.
  • Scan Code Set 2 - Casi todos los teclados modernos lo tienen por defecto
  • Scan Code Set 3 - scan code set optional PS/2 -- raramente usado

En este proyecto asumiremos que el teclado que se va a conectar usa el Scan Code Set 2.

[edit] Make Codes, Break Codes, y Typematic:

Cada vez que se pulsa una tecla, el make code se envía al host -. Tenga en cuenta que un código que representa una tecla en un teclado no representa el carácter impreso en esa tecla. Esto significa que no hay relación entre un scan code y un código ASCII. Todo depende del host y de la traducción del scan code en caracter o comando.

Aunque en el set dos la mayoría de los makes codes son sólo de un byte, hay un puñado de "teclas extendidas", esos make codes son de dos a cuatro bytes, y se pueden identificar por el hecho de que su primer byte es E0.

Así como un make code es enviado al host cada vez que se pulsa una tecla, un break code se envía cada vez que se suelta una tecla. y así como cada tecla tiene su propio make code, tambien tienen su propio break code. Afortunadamente, no siempre se tienen que utilizar las tablas de búsqueda para averiguar el break code de una tecla, existen ciertas relaciones entre make codes y break codes. La mayoría de los break codes del set dos son de dos bytes de longitud, donde el primer byte es F0 y el segundo byte es el make code de la tecla. Los break codes para teclas extendidas son usualmente de de tres bytes donde los primeros dos bytes son E0 y F0, y el ultimo byte es el make code de la tecla.

Si se presiona una tecla, el make code es enviado al host. Cuando se presiona y mantiene presionada una tecla, esa tecla se convierte en typematic, lo que significa que el teclado seguirá enviando el make code de la tecla hasta que la tecla se suelte o se pulsa otra tecla, existen dos parámetros importantes aquí, uno es el Retraso typematic (breve retraso entre el primer y segundo carácter)y el otro es la Tasa typematic (cantidad de caracteres por segundo).

[edit] Reset

Al encender o reiniciar el teclado se realiza un autodiagnóstico denominado BAT (Basic Assurance Test) y carga los valores predeterminados siguientes:

  • Retraso typematic de 500 ms. (breve retraso entre el primer y segundo carácter)
  • Tasa typematic de 10,9 cps. (cantidad de caracteres por segundo)
  • Scan code set 2.

Al entrar en BAT, el teclado activa sus tres indicadores LED, y los desactiva cuando BAT se ha completado. En ese momento, un código de terminación, AA(BAT termino con éxito) o FC(error) es enviado al host. Este código debe ser enviado a los 500~750 milisegundos después del encendido del teclado.

[edit] Set de Comandos

Algunas notas sobre los comandos que el host puede enviar al teclado:

  • El teclado se borra el búfer de salida cuando recibe algún comando.
  • Si el teclado recibe un comando o argumento no válido , responde con (FE).
  • El teclado no envía scan codes durante el procesamiento de un comando.
  • Si el teclado está a la espera de un byte de argumento y en su lugar recibe un comando, descarta el comando anterior y procesa el nuevo.

A continuación se presentan todos los comandos que el host puede enviar al teclado:

  • FF (Reset) - El teclado responde con "recibido" (FA), y a continuación, entra en modo "Reset". (Ver la sección Reset).
  • FE (Resend) - El teclado responde reenviando el último byte enviado.

Los siguientes siete comandos pueden ser enviados cuando el teclado está en cualquier modo, pero sólo tienen efecto cuando el teclado se encuentra en "modo 3" (es decir, configurado en scan code set 3).

  • * FD (Set Key Type Make) - Deshabilita break codes y las repeticiones typematic para una tecla específica. El teclado responde con "recibido" (FA), y a continuación, desactiva la exploración (si está habilitada) y lee una lista de teclas del host. Estas teclas son identificadas por su make code en el set 3. El teclado responde a cada make code con "recibido". El host finaliza esta lista mediante el envío de un make code no válido en el set 3 (por ejemplo, un comando). El teclado vuelve a activar la exploración (si previamente estaba desactivada).
  • * FC (Set Key Type Make/Break) - Similar al comando anterior, excepto que este desactiva sólo las repeticiones typematic.
  • * FB (Set Key Type Typematic) - Igual que los dos anteriores, excepto que este desactiva los break codes solamente.
  • * FA (Set All Keys Typematic/Make/Break) - El teclado responde con "recibido" (FA). Y selecciona todas las teclas con su configuración normal (generar scan codes y epeticiones typematic).
  • * F9 (Set All Keys Make) - El teclado responde con "recibido" (FA). Es similar a FD, excepto que se aplica a todas las teclas.
  • * F8 (Set All Keys Make/Break) - El teclado responde con "recibido" (FA). Es similar a FC, excepto que se aplica a todas las teclas.
  • * F7 (Set All Keys Typematic) - El teclado responde con "recibido" (FA). Es similar a FB, excepto que se aplica a todas las teclas.
  • F6 (Set Default) - Carga los parametros por defecto Tasa typematic (10.9cps) retraso typematic (500ms), selecciona el tipo de teclas (todas las teclas a typematic/make/break), y selecciona el scan code set 2.
  • F5 (Disable) - El teclado para la exploración, Carga los valores por defecto (ver el comando F6), y espera futuras instrucciones.
  • F4 (Enable) - Reactiva el teclado después de desactivarlo con el comando anterior.
  • F3 (Set Typematic Rate/Delay) - El host envía después de este comando un argumento de un byte que define la tasa y el retraso typematic de la siguiente manera:

Velocidad de repetición

Bits 0-4 Rate(cps) Bits 0-4 Rate(cps) Bits 0-4 Rate(cps) Bits 0-4 Rate(cps)
00h 30.0 08h 15.0 10h 7.5 18h 3.7
01h 26.7 09h 13.3 11h 6.7 19h 3.3
02h 24.0 0Ah 12.0 12h 6.0 1Ah 3.0
03h 21.8 0Bh 10.9 13h 5.5 1Bh 2.7
04h 20.7 0Ch 10.0 14h 5.0 1Ch 2.5
05h 18.5 0Dh 9.2 15h 4.6 1Dh 2.3
06h 17.1 0Eh 8.6 16h 4.3 1Eh 2.1
07h 16.0 0Fh 8.0 17h 4.0 1Fh 2.0

Retraso

Bits 5-6 Retraso (segundos)
00b 0.25
01b 0.50
10b 0.75
11b 1.00
  • * F2 (Read ID) - El teclado responde enviando dos bytes de ID de dispositivo, AB y 83. (AB se envía en primer lugar, seguido de 83).
  • * 0xF0 (Set Scan Code Set) - El teclado responde con "recibido", y entonces lee el byte de argumento del host. Este argumento puede ser 01, 02 ó 03 para seleccionar el scan Code Set 1, 2, ó 3, respectivamente. El teclado responde a este byte con el argumento de "recibido". Si el argumento es 00, el teclado responde con "recibido", seguido por el scan Code Set actual.
  • EE (Echo) - El teclado responde con "Echo" (EE).
  • ED (Set/Reset LEDs) - El host envía después de este comando un argumento de un byte, que especifica el estado de los leds del teclado: Num Lock, Caps Lock y Scroll Lock. Este byte de argumento se define de la siguiente manera:
0 0 0 0 0 Caps Lock Num Lock Scroll Lock
  • "Scroll Lock" - LED Scroll Lock off(0)/on(1)
  • "Num Lock" - LED Num Lock off(0)/on(1)
  • "Caps Lock" - LED Caps Lock off(0)/on(1)

[edit] Ratón PS/2

La interfaz de MOUSE PS/2 utiliza un protocolo serial bidireccional para transmitir el movimiento (parte del controlador de teclado). El controlador realiza acciones como accionar el mouse, resolucion, reset, deshabilitar, enviar un numero de instrucciones para fijar estado, entre otras funciones. El host, lo alimenta con ~5V y consume una corriente de ~100mA aproximadamente.

[edit] Funcionamiento

El mouse estandar, contiene dos contadores, que mantienen la traza del movimiento, basicamente el contador en X, y el contador en Y. Estos tienen 9 bits (1 byte mas el bit de signo, es decir con rango de -128 a 127) valores complemento a 2 cada uno asociado a una bandera de flujo. Para el envio de informacion de los 3 botones de un mouse estandar, lo que se hace es hacer llegar al host un offset de 3 paquetes de datos de movimiento, es decir 3 bytes a lo largo de los bytes de posicion. El movimiento de los contadores posee un offset relativo a la posicion para saber si el paquete de datos fue enviado al host satisfactoriamente (comando Resend senal 0xFE).

Cuando el mouse lee la entrada los datos de entrada se almacenan en el estado actual de aumento y decremento para los contadores de movimiento de acuerdo al aumento del movimiento que ha ocurrido desde el ultimo muestreo de la entrada. Cuando se reciben senales de sobreflujo, es decir, valores por fuera del rango de movimiento, existe un flag especifico que permite saber cuando se esta en transmision de datos de sobreflujo.

[edit] Resolucion y escalamiento

El parametro que determina la cantidad por la cual los contadores son incrementados o decrementados, esta dado por un parametro conocido como resolucion, y es este presisamente el que se usa para los flags de sobreflujo (Overflow). El valor estandar es de 4 contadores por milimetro aunque el host puede cambiar estos valores con un comando conocido como "Set Resolution" (El valor binario es 0xE8).

Existe adicionalmente adicionalmente un valor que no afecta el movimiento de los contadores, pero que afecta el valor de estos contadores, este es conocido como escalamiento, generalmente es de 1:1 aunque el host puede modificarlo pudiendo ser por ejemplo 2:1 (Comando "Set Scaling 2:1" o su valor Hexadecimal 0xE7). Si el escalamiento 2:1 es activado, el flujo de datos va a ser asi:

ReportmovementPS2.png

Nota: el escalamiento, solo aplica para el reporte automatico de datos, no aplica para reporte de datos enviados en respuesta al comando "Read Data" 0xEB.

[edit] Movimiento de paquetes de datos

El protocolo PS/2 estandar, envia la informacion de la siguiente manera:

Ps2bytes.png

Los valores del movimiento son de 9 bits, con complemento a 2 entero. Donde el bit mas significativo aparece como el bit mas significativo aparece como bit de signo en el byte 1. Sus valores representan el offset relativo a su posicion cuando el paquete previo fue enviado en unidades determinadas por la actual resolucion. Cuando el rango de valores es exedido el bit de overflow es puesto es activado, es decir el flag.

[edit] Set de comandos

0xFF (Reset) - El mouse responde a este comando "acknowledge" (0xFA) then enters reset mode.

0xFE (Resend) - El host envía este comando cada vez que recibe datos no válidos desde el ratón. El mouse responde reenviado el ultimo paquete que fue senviado al host. Si el mouse responde reenviando otro paquete no valido, el host puede reenviar otro comando "Resend" o enviar un comando conocido como "Error" (0xFC), y inhibir la comunicacion con el mouse (haciendo la señal de clock baja) o reestablecer al raton. Este comando esta protegido (no es almacenado) lo que quiere decir que el comando "Resend" nunca será enviado en respuesta a otro comando "Resend".

0xF6 (Set Defaults) - A este comando, el host responde como "acknowledge" (0xFA) ("Reconocido"), despues de eso, carga los valores como son, frecuencia de muestreo (100), resolucion (4 counts/mm), Escalamiento (1:1) y presentación de datos desactivado. Despues el mouse restablece los contadores de su movimiento y entra en modo de secuencia.

0xF6 (Set Defaults) - A este comando, el host responde como "acknowledge" (0xFA) ("Reconocido"), despues de eso, carga los valores como son, frecuencia de muestreo (100), resolucion (4 counts/mm), Escalamiento (1:1) y presentación de datos desactivado. Despues el mouse restablece los contadores de su movimiento y entra en modo de secuencia.

0xF3 (Set Sample Rate) - El mouse responde con reconocimiento 0xFA qntonces lee un byte mas del host. El mouse guarda este byte como la nueva tasa de muestreo. Despues de recibir la tasa de muestreo, el mouse responde con "reconocido" 0xFA y resetea el contador de movimiento. Las tasas de muestreo validas son 10, 20, 40, 60, 80, 100, and 200 muestras por segundo.

0xF2 (Get Device ID) - El mouse responde con "reconocido" 0xFA seguido de su "device ID" o identificador de dispositivo (0x00 estandar para mouse PS/2). El mouse deberia resetear el contador de movimiento.

0xF0 (Set Remote Mode) - El mouse responde con "reconocido" 0xFA entonces, resetea su contador de movimiento y entra en modo remoto.

0xEE (Set Wrap Mode) - El mouse responde con "reconocido" 0xFA entonces, resetea su contador de movimiento y entra en modo "wrap"

0xEC (Reset Wrap Mode) - El mouse responde con "reconocido" 0xFA entonces, resetea su contador de movimiento y entra en el modo en el que estaba antes.

0xEB (Read Data) - El mouse responde con "reconocido" 0xFA entonces, envia un paquete de datos de movimiento. Este es la unica manera de leer datos en modo remoto. Despues de que el mouse ha enviado satosfactoriamente un paquete de datos, el mouse resetea su contador de movimiento.

0xEA (Set Stream Mode) - El mouse responde con "reconocido" 0xFA entonces resetea sus contadores de movimiento y entra en modo stream o modo de cadena.

0xE9 (Status Request) - El mouse responde con "reconocido" 0xFA entonces envia los siguientes 3 bytes (paquete de datos), y resetea los contadores de movimiento.

[edit] Tareas hardware

El teclado y el ratón no se comunicarán directamente con el procesador Ingenic JZ4725, en cambio dos controladores, uno de teclado y otro de ratón proporcionan una interfaz entre los dispositivos y el bus de periféricos. Estos controladores se encargan de los niveles de señal y de los detalles del protocolo.

A continuación se explicará lo más relevante de la arquitectura de hardware, los archivos que la componen los puede ver aquí

El diagrama de bloques general que se muestra a continuacion, muestra a grandes rasgos que es lo que se pretende.

diagrama de bloques general.

[edit] Diagrama de bloques de la FPGA

Diagrama de Bloques.

[edit] Mapa de memoria

kb_ps2 (teclado) : 0x15000010

ms_ps2 (ratón)  : 0x15000020

pic  : 0x15000000

[edit] Controlador PS/2

El Controlador que se describe a continuación es usado para recibir y transmitir los datos del teclado/ratón sin hacer distinción alguna en el hardware, los drivers son los encargados de decodificar los paquetes de datos de 8 bits e interpretarlos.

El siguiente esquema es del controlador PS/2:

Controlador PS/2.

[edit] Descripción de hardware del módulo de recepción ps2_rx

módulo ps2_rx.

El más importante módulo que hace parte del controlador de teclado es el receptor ps2_rx, este es el encargado de recibir los datos seriales del teclado y devolver el scan code correspondiente(dout) y activar la interrupción(rx_done).

El diseño del receptor del controlador PS2 es algo similar al receptor de una UART. Pero en vez de usar sobremuestreo el flanco de bajada de la señal ps2_clk se utiliza como punto de referencia para recuperar los datos. El subsistema incluye un circuito de detección de flanco de bajada, que genera una bandera en el flanco de bajada de la señal ps2_clk.

[edit] Circuito de detección de flanco de bajada
  1.   always @(posedge clk, posedge reset)
  2.     if(reset)
  3.       begin
  4.         filter_reg <= 0;
  5.         f_ps2c_reg <= 0;
  6.       end
  7.     else
  8.       begin
  9.         filter_reg <= filter_next;
  10.         f_ps2c_reg <= f_ps2c_next;
  11.       end
  12.  
  13.   assign filter_next = {ps2_clk, filter_reg[7:1]};
  14.   assign f_ps2c_next = (filter_reg==8'b11111111) ? 1'b1 :
  15.                        (filter_reg==8'b00000000) ? 1'b0 :
  16.                        f_ps2c_reg;
  17.  
  18.   assign fall_edge   = f_ps2c_reg & ~f_ps2c_next;
[edit] Máquina de estados finitos

El módulo ps2_rx se modela como una máquina de estados finitos. Cuando se completa la transmisión de los 11 bits que forman el paquete de información se envía una señal (rx_done) que indica que el bus de datos de salida (dout) contiene un scan code nuevo.

Máquina de estados finitos recepción.
  1.   // state & data registers
  2.   always @(posedge clk, posedge reset)
  3.     if(reset)
  4.       begin
  5.         state_reg <= idle;
  6.         n_reg <= 0;
  7.         b_reg <= 0;
  8.       end
  9.     else
  10.       begin
  11.         state_reg <= state_next;
  12.         n_reg <= n_next;
  13.         b_reg <= b_next;
  14.       end
  1.   // next state logic 
  2.   always @(*)
  3.     begin
  4.       state_next = state_reg;
  5.       rx_done = 1'b0;
  6.       n_next = n_reg;
  7.       b_next = b_reg;
  8.       case(state_reg)
  9.         idle:
  10.              if(fall_edge & rx_en)
  11.                begin
  12.                  //shift in start bit
  13.                  b_next = {ps2_data, b_reg[10:1]};
  14.                  n_next = 4'b1001;
  15.                  state_next = dps;
  16.                end
  17.         dps:  // 8 data + 1 parity + 1 stop
  18.             if(fall_edge)
  19.               begin
  20.                 b_next = {ps2_data, b_reg[10:1]};
  21.                 if(n_reg==0)
  22.                   state_next = load;
  23.                 else
  24.                   n_next = n_reg-1;
  25.               end
  26.         load:  // 1 extra clock to complete the last shift
  27.              begin
  28.                state_next = idle;
  29.                rx_done = 1'b1;
  30.              end
  31.       endcase
  32.     end
  33.  
  34.     //output
  35.     assign dout = b_reg[8:1]; //data bits

[edit] Descripción de hardware del módulo de transmisión ps2_tx

módulo ps2_tx.

El módulo de transmisión también cuenta con el circuito detector de flancos de bajada visto en la sección anterior, el host cambia la línea de datos sólo cuando la línea de reloj está en "bajo" (Ver la sección FPGA a dispositivo). La lógica de transmisión también se modela como una maquina de estados finitos, los pasos que el host debe seguir para enviar datos a un dispositivo PS/2 ya se explico con detalle (Ver la sección FPGA a dispositivo).

[edit] Máquina de estados finitos
Máquina de estados finitos transmisión
  1. // state & data registers
  2.    always @(posedge clk, posedge reset)
  3.       if (reset)
  4.          begin
  5.             state_reg <= idle;
  6.             c_reg <= 0;
  7.             n_reg <= 0;
  8.             b_reg <= 0;
  9.          end
  10.       else
  11.          begin
  12.             state_reg <= state_next;
  13.             c_reg <= c_next;
  14.             n_reg <= n_next;
  15.             b_reg <= b_next;
  16.          end
  17.  
  18.    // odd parity bit
  19.    assign par = ~(^din);
  20.  
  21.    // FSM next-state logic
  22.    always @*
  23.    begin
  24.       state_next = state_reg;
  25.       c_next = c_reg;
  26.       n_next = n_reg;
  27.       b_next = b_reg;
  28.       tx_done = 1'b0;
  29.       ps2c_out = 1'bz;
  30.       ps2d_out = 1'bz;
  31.       tri_c = 1'b0;
  32.       tri_d = 1'b0;
  33.       tx_idle = 1'b0;
  34.       case (state_reg)
  35.          idle:
  36.             begin
  37.                tx_idle = 1'b1;
  38.                if (we_ps2)
  39.                   begin
  40.                      b_next = {par, din};
  41.                      c_next = 13'h1fff; // 2^13-1
  42.                      state_next = rts;
  43.                   end
  44.             end
  45.          rts:   // request to send
  46.             begin
  47.                ps2c_out = 1'b0;
  48.                tri_c = 1'b1;
  49.                c_next = c_reg - 1;
  50.                if (c_reg==0)
  51.                   state_next = start;
  52.             end
  53.          start:  // assert start bit
  54.             begin
  55.                ps2d_out = 1'b0;
  56.                tri_d = 1'b1;
  57.                if (fall_edge)
  58.                   begin
  59.                      n_next = 4'h8;
  60.                      state_next = data;
  61.                   end
  62.             end
  63.          data:   //  8 data + 1 parity
  64.             begin
  65.                ps2d_out = (b_reg[0])? 1'bz : 1'b0;
  66.                tri_d = 1'b1;
  67.                if (fall_edge)
  68.                   begin
  69.                      b_next = {1'b0, b_reg[8:1]};
  70.                      if (n_reg == 0)
  71.                         state_next = stop;
  72.                      else
  73.                         n_next = n_reg - 1;
  74.                   end
  75.             end
  76.          stop:   // assume floating high for ps2_data
  77.             if (fall_edge)
  78.                begin
  79.                   state_next = idle;
  80.                   tx_done = 1'b1;
  81.                end
  82.       endcase
  83.    end
  84.  
  85.    // tri-state buffers
  86.    assign ps2_clk = (tri_c) ? ps2c_out : 1'bz;
  87.    assign ps2_data = (tri_d) ? ps2d_out : 1'bz;

[edit] Simulación de la arquitectura de hardware

Para la simulación de la arquitectura se utilizan las herramientas libres icarus y gtkwave.

El Test bench lo pueden ver aquí. Se puede correr con este script

simulación de la arquitectura de hardware.

[edit] Tareas software

Los driver del proyecto y otros de ejemplo los puede ver aquí

Diagrama básico de drivers y secuencia de ejecucion.

Esquema simple de jerarquía de drivers

[edit] Driver de pruebas

El siguiente es un driver de pruebas que implementa las funciones básicas y permite la comunicación HW/SW a nivel del núcleo: recibe la interrupción de la arquitectura implementada en la FPGA y ejecuta el código asociado, lee y escribe en los dispositivos. En este caso en la FPGA se describe el hardware de un controlador de dispositivos PS/2. El driver completo lo puede ver aquí.

El mapeo de la memoria física de la FPGA se puede realizar con la función:

 void *ioremap_nocache(unsigned long phys_addr, unsigned long size);

Extrayendo una cita de uno de las cabeceras del núcleo: “es útil si algunos registros de control se encuentran en esa área y no se desea combinación de escritura o lectura de almacenamiento en caché”. En este caso utilizamos un equivalente para mips.

  1.   ioaddress = __ioremap(FPGA_BASE_BEGIN, FPGA_BASE_END - FPGA_BASE_BEGIN, _CACHE_UNCACHED);

En algunas plataformas se podría usar el valor devuelto desde ioremap como si de un puntero se tratase. Este uso no se puede trasladar a otros sistemas. El modo correcto de llegar a la memoria de E/S es a través de un conjunto de funciones (definido en <asm/io.h>) proporcionado con este propósito.

La lectura y la escritura en este driver se realiza con las funciones:

 unsigned int ioread32(void *addr);
void iowrite32(u32 value, void *addr);

Si leen diferentes drivers o partes del núcleo se verán muchas llamadas a un antiguo conjunto de funciones(macros) cuando la memoria de E/S está siendo usada. Estas funciones todavía funcionan, pero no se aconseja su inclusión en el nuevo código. Entre otras cosas son menos seguras dado que no realizan la misma comprobación de tipos.

 unsigned readl(address); //equivalente a ioread32
void writel(unsigned value, address); //equivalente a iowrite32

A pesar de las grandes similitudes entre los registros de hardware y la memoria, un programador que acceda a los registros de E/S debe tener cuidado para evitar ser engañado por las optimizaciones del compilador capaces de modificar el comportamiento de E/S esperado.

La principal diferencia entre los registros de E/S y la RAM es que las operaciones de E/S tienen efectos secundarios y las operaciones de memoria no.

Estas optimizaciones son transparentes y favorables cuando se aplican a la memoria convencional, pero estas optimizaciones pueden ser fatales para corregir operaciones de E/S porque interfieren con los “efectos secundarios”, que constituyen la principal razón por la que los controladores acceden a los registros de E/S. El procesador no puede prever una situación en la que otro proceso (ejecutándose en un procesador separado, o que tenga lugar dentro de un controlador de E/S)dependa del orden del acceso a memoria. El compilador tan sólo intenta engañarle y reordenar las operaciones que solicite. El resultado puede tener como resultado errores extraños muy difíciles de depurar. Por tanto, un controlador debe asegurarse de que no se realice almacenamiento en caché ni tengan lugar reordenamientos de escritura o lectura cuando se acceda a los registros.

La solución para la optimización del compilador y el reordenamiento del hardware es situar una barrera de memoria entre las operaciones, en un orden definido y visible para el hardware.

 #include<asm/system.h>
 void rmb(void);
 void wmb(void);
 void mb(void);

Estas funciones introducen barreras de memoria de hardware en el flujo de instrucciones compilado aunque su instanciación real depende de la plataforma. Una rmb (barrera de lectura de memoria) garantiza que cualquier lectura que aparezca antes de la barrera será completada antes de ejecutar cualquier lectura posterior, wmb garantiza el orden de las operaciones de escritura, y la instrucción mb asegura ambas operaciones. Cada una de estas funciones constituye un superconjunto de barrier.

En estos fragmentos de código se puede ver lo que se mencionó antes:

  1.   red=ioread32(ioaddress)& 0XFF;
  2.   rmb();
  3.   printk("%X\n", red);
  1.   printk("%X\n", buff[0]);
  2.   iowrite32(buff[0],ioaddress);
  3.   wmb();

[edit] Driver de Teclado

El driver completo del Teclado PS/2 lo puede ver aquí.

  1. ps2kbd_dev = input_allocate_device();
  2.         if (!ps2kbd_dev)
  3.                 return -ENOMEM;
  4.  
  5.         ps2kbd_dev->name = "PS2 Keyboard";
  6.         ps2kbd_dev->phys = "ps2kbd/input0";
  7.         ps2kbd_dev->id.bustype = BUS_HOST;
  8.         ps2kbd_dev->id.vendor = 0x0001;
  9.         ps2kbd_dev->id.product = 0x0001;
  10.         ps2kbd_dev->id.version = 0x0100;
  11.  
  12.         ps2kbd_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);

En la línea 97 del driver se crea una estructura que representa el teclado ps2kbd_dev con la función input_allocate_device(). Después se verifica que se le asigno memoria, si la respuesta es falsa se retorna el error ENOMEM, si la respuesta es verdadera se prosigue asignando las características que definen la estructura como una entrada de datos de tipo teclado. Algunas de las más relevantes son BIT_MASK(EV_KEY) y BIT_MASK(EV_REP) que habilitan la estructura como entrada de pulsadores(teclas) y repeticiones de la misma tecla hasta que se libere.

  1.         ps2kbd_dev->keycode = atkbd_set2_keycode;
  2.         ps2kbd_dev->keycodesize = sizeof(unsigned short);
  3.         ps2kbd_dev->keycodemax = ARRAY_SIZE(atkbd_set2_keycode);
  4.  
  5.         for (i = 0; i < ATKBD_KEYMAP_SIZE; i++) {
  6.                 set_bit(atkbd_set2_keycode[i], ps2kbd_dev->keybit);
  7.         }
  8.  
  9.         /* error check */
  10.         error = input_register_device(ps2kbd_dev);
  11.         if (error) {
  12.                 input_free_device(ps2kbd_dev);
  13.                 return error;
  14.         }

La línea 109 del driver se selecciona la matriz atkbd_set2_keycode que contiene en este caso los Keycodes correspondientes a un teclado PS/2 en inglés.

  1. #define ATKBD_KEYMAP_SIZE        512
  2.  
  3. static const unsigned short atkbd_set2_keycode[ATKBD_KEYMAP_SIZE] = {
  4.  
  5. #ifdef CONFIG_KEYBOARD_ATKBD_HP_KEYCODES
  6.  
  7.  
  8.  
  9. /* XXX: need a more general approach */
  10.  
  11. #include "hpps2atkbd.h"        /* include the keyboard scancodes */
  12.  
  13. #else
  14.           0, 67, 65, 63, 61, 59, 60, 88,  0, 68, 66, 64, 62, 15, 41,117,
  15.           0, 56, 42, 93, 29, 16,  2,  0,  0,  0, 44, 31, 30, 17,  3,  0,
  16.           0, 46, 45, 32, 18,  5,  4, 95,  0, 57, 47, 33, 20, 19,  6,183,
  17.           0, 49, 48, 35, 34, 21,  7,184,  0,  0, 50, 36, 22,  8,  9,185,
  18.           0, 51, 37, 23, 24, 11, 10,  0,  0, 52, 53, 38, 39, 25, 12,  0,
  19.           0, 89, 40,  0, 26, 13,  0,  0, 58, 54, 28, 27,  0, 43,  0, 85,
  20.           0, 86, 91, 90, 92,  0, 14, 94,  0, 79,124, 75, 71,121,  0,  0,
  21.          82, 83, 80, 76, 77, 72,  1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
  22.  
  23.           0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  24.         217,100,255,  0, 97,165,  0,  0,156,  0,  0,  0,  0,  0,  0,125,
  25.         173,114,  0,113,  0,  0,  0,126,128,  0,  0,140,  0,  0,  0,127,
  26.         159,  0,115,  0,164,  0,  0,116,158,  0,172,166,  0,  0,  0,142,
  27.         157,  0,  0,  0,  0,  0,  0,  0,155,  0, 98,  0,  0,163,  0,  0,
  28.         226,  0,  0,  0,  0,  0,  0,  0,  0,255, 96,  0,  0,  0,143,  0,
  29.           0,  0,  0,  0,  0,  0,  0,  0,  0,107,  0,105,102,  0,  0,112,
  30.         110,111,108,112,106,103,  0,119,  0,118,109,  0, 99,104,119,  0,
  31.  
  32.           0,  0,  0, 65, 99,
  33. #endif
  34. };

En un principio se mira si el macro CONFIG_KEYBOARD_ATKBD_HP_KEYCODES esta definido y se utiliza el archivo "hpps2atkbd.h" esto da flexibilidad al sistema y la posibilidad de cambiar la codificación del teclado, si no esta definida se usa la matriz de keycodes de arriba que por defecto está para un teclado en ingles. (este trozo de código se saco del driver de linux atkbd.c).

Finalmente en la línea 118 se registra la estructura como un dispositivo de entrada y se chequea si hubo error.

  1. static irqreturn_t ps2_keyboard_interrupt(int irq, void *id)
  2. {
  3.         unsigned char scancode, keycode;
  4.  
  5.         scancode = (unsigned char)(ioread32(ioaddress)& 0XFF);
  6.         rmb();
  7.  
  8.         //printk(KERN_INFO "scancode %x\n", scancode);
  9.  
  10.         if      (scancode == 0xAA)printk(KERN_INFO "PS/2 keyboard. ok\n");
  11. 	else if (scancode == 0xFC)printk(KERN_INFO "PS/2 keyboard. error\n");
  12.         else if (scancode == 0xF0)key_p=0;
  13.         else if (scancode == 0xE0)key_e=1;
  14.         else if (scancode <= 0x7E){                /* scancodes < 0xf2 are keys */
  15.  
  16.                 keycode = atkbd_set2_keycode[scancode+0x80*key_e];
  17.  
  18.                 input_report_key(ps2kbd_dev, keycode, key_p);
  19.                 input_sync(ps2kbd_dev);
  20.                 key_p=1;
  21.                 key_e=0;
  22.         } else                                /* scancodes >= 0xf2 are mouse data, most likely */
  23.                 printk(KERN_INFO "ps2kbd: unhandled scancode %x\n", scancode);
  24.  
  25.         return IRQ_HANDLED;
  26. }

En la parte de arriba se muestra el código asociado a la interrupción, lo primero es leer el dato(scancode) de la FPGA, como ya se mensiono en la sección Reset, al encender o reiniciar el teclado se realiza un autodiagnóstico denominado BAT, la respuesta puede ser AA o FC dependiendo del estado del teclado, esto se refleja en el driver en las lineas 71 y 72 respectivamente.

La función input_report_key reporta la tecla cuando es presionada o liberada, en un teclado PS/2 cuando una tecla es liberada se envía un byte F0 seguido del scandode correspondiente a la tecla, esto se ve en la línea 73 del driver.

Debido al número elevado de teclas actualmente utilizadas existen las "teclas extendidas", están formadas por dos bytes y el primero de ellos siempre es E0. Para encontrar su correspondiente keycode en la matriz se le suma el número 0x80 al segundo byte. líneas 74 y 77 del driver.

Es necesario ejecutar el siguiente programa después de cargar un driver para habilitar el CS2.

  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <stdlib.h>
  4.  
  5. #include "jz47xx_gpio.h"
  6.  
  7. #define CS2_PORT JZ_GPIO_PORT_B
  8. #define CS2_PIN  26
  9.  
  10. int main () { 
  11.  
  12.   int i,j;
  13.   JZ_PIO *pio;
  14.  
  15.   // Set GPIOB26 as part of External Memory Controller
  16.   pio = jz_gpio_map (CS2_PORT);
  17.   jz_gpio_as_func (pio, CS2_PIN, 0);
  18.  
  19.   printf ("¬_¬\n");
  20.  
  21.   return 0;
  22. }

[edit] Editor de texto en Qt

Los archivos del editor los puede encontrar aquí.

Este documento no tiene como fin ser un tutorial de Qt por lo tanto no se explicaran los pasos realizados en la creación del programa.

Sim embargo, con conocimientos básicos de linux, se puede observar que cada archivo es bastante intuitivo y sólo basta con modificar algunos paths para poder hacer un diseño como este, teniendo en cuenta que se tuvo que haber instalado previamente las herramientas como el toolchain, qtcreator y demás librerias necesarias. Un preview del mismo, puede observarse en el video al inicio de esta página mostrando el funcionamiento del keyboard.

[edit] Evaluación de costos del proyecto

Dentro de los costos generales, despreciamos materiales, herramientas y trabajo invertido.

Costos de herramientas usadas en el proyecto:

Herramientas invertidas

Qt ps2cost1.png


Costo de materiales por unidad de tarjeta.



Qt ps2cost2.png
Qt ps2cost3.png
Qt ps2cost4.png


.

De lo cúal podemos ver que el costo por tarjeta en etapa de diseño fue de $78370 pesos colombianos M/CTE.

  • NOTA: Para las pruebas de prototipos y demás, se asume que se poseen tanto el teclado como el mouse. Adicionalmente no se tiene en cuenta el costo de la SIE. La tarjeta fue hecha en Tecnoparquecolombia y por eso el precio relativamente economico. El costo del tiempo invertido se establece con un Salario minimo legal vigente por dos personas, y se toma esta referencia para estimar el costo minimo que puede llegar a tener un prototipo de estos en etapa de diseño. Adicionalmente se puede notar que el valor del tiempo invertido es muy grande, si se tiene en cuenta que cada tarjeta es relativamente barata.
  • Dado que es un prototipo, los costos son más elevados de lo que se pensaría, sin embargo, el costo en masa disminuye sustancialmente, teniendo en cuenta el precio de los materiales también se reduce, así como el tiempo invertido en el diseño, se establece que el precio de 100 tarjetas hijas como la hecha costaría al rededor de $22.000 pesos M/CTE Colombiana.
  • Si tenemos en cuenta el costo de la fabricación de la tarjeta al día de hoy, se establece que el costo inicial de materiales por tarjeta, hay que sumarle $30.000 (por tarjeta) por lo tanto el costo por unidad sería de $52.000 por cada tarjeta hija.
Personal tools
Namespaces
Variants
Actions
Navigation
interactive
Toolbox
Print/export