lunes, 21 de noviembre de 2011

Creación de un carácter en el LCD



Vamos a visualizar un mensaje en el LCD alfanumérico 2x16, mediante una máquina de estados Moore. El mensaje contendrá un carácter creado por nosotros.
Descargar memoria.
Descargar documentos.


Proceso de trabajo:

Algoritmo de la máquina de estados:
- Secuencia de inicio.
- Enviar instrucción de ‘Pantalla ON/OFF’ de manera que ponemos la pantalla en ON ‘D=1’, el cursor en ON, ‘C=1’ y el parpadeo del cursor en ON ‘B=1’.
- Colocar el cursor en la posición de inicio con la instrucción ‘Cursor a casa’.
- Mandar los datos de la primera línea.

Para la creación del carácter deberemos seguir la siguiente secuencia:
- Mandar la dirección de la DDRAM, en la cual se va a crear el carácter. (Esta dirección se manda como dato).
- Mandar la dirección de la CGRAM para apuntar a la fila. (De la 40h a 47h ).
- Introducir el código de la fila CGRAM direccionada. (Los datos estarán comprendidos entre los valores 00h a 1Fh).
- Direccionar la siguiente posición de la CGRAM e introducir su código, y así hasta completar las 7 filas del carácter.
- Una vez terminado el carácter, mandar una dirección de la DDRAM para que de este modo las siguientes instrucciones apunten a la DDRAM y podamos utilizar el carácter gráfico creado.

La máquina va a necesitar tres contadores: uno de 3 bit’s para contar el número de registros, uno de 3 bit’s que lo usaremos para contar el número de datos, y otro de 5 bit´s para los datos y registros del carácter.

Los puertos bidireccionales van a necesitar buffer´s 3-state para controlar su función, entrada o salida.

Es importante introducir un mensaje corto con el carácter, ya que necesitaríamos más macrocelulas de las que el CPLD contiene, 72. Para que pudiésemos introducir un mensaje largo necesitaríamos usar una FPGA.


Creación de un nuevo proyecto:

Creamos un nuevo proyecto y seleccionamos esquemático.


Seleccionamos las características de nuestro CPLD:
-Seleccionamos la familia del CPLD, XC9500 CPLDs.
-El modelo, XC9572.
-El  encapsulado, PC84.
-La  velocidad de trabajo del CPLD, -7.
-El sintetizador.
-El simulador.
-El lenguaje de programación, VHDL.


En la siguiente ventana añadimos el fichero fuente.


Seleccionamos schematic y damos nombre al archivo


Aceptamos todos los apartados siguientes y se nos crea el proyecto.


Creación del componente:

Añadimos un fichero fuente State Diagram donde crearemos la máquina de estados:


Se nos abrirá un subprograma llamado StateCAD donde creamos la máquina de estados.
En OptionsVariables añadimos los puertos de entrada y salida:


- Escribimos el nombre.
- Seleccionamos el tipo: reloj, entrada o salida; la salida puede ser asíncrona (OUT:COM) o en nuestro caso síncrona (OUT:REG).
- Modo activo.
- Si va a ser un pin o un nodo.


Los pines que debemos agregar son los siguientes:


Control de LCD a través de la máquina de estados:
- RS: Salida. (Control de selección de modo).
- Habilitar: Salida. (Habilitación del módulo).
- Read_write: Salida. (Control de lectura/escritura en el módulo).
- D0_O, D1_O, D2_O, D3_O, D4_O, D5_O, D6_O, D7_O: Salida
- D0_I, D1_I, D2_I, D3_I, D4_I, D5_I, D6_I, D7_I: Entrada
- Three_state: Salida. (Control pines bidireccionales).

Las líneas Dx son bidireccionales y tendrán que tener dos funciones: de entrada y salida. Las controlaremos con un buffer 3-state que trabaja en bajo activo.

Entrada de datos de los contadores:
- Q0_r, Q1_r, Q2_r: Entradas. (Entradas de control del nº de comandos o registros mandados al LCD).
- Q0_d, Q1_d, Q2_d: Entradas. (Entradas de control del nº de datos mandados al LCD).
- Q0_c, Q1_c, Q2_c, Q3_c, Q4_c: Entradas. (Entradas de control del nº de comandos y datos del carácter).
- Puesta_0: Salida. (Salida de inicialización de los contadores).
- Reloj_dato: Salida. (Reloj del contador de datos).
- Reloj_registro: Salida. (Reloj del contador de comandos).
- Reloj_carácter: Salida. (Reloj del contador de datos y comandos para el carácter).


Estos son los pines que agregamos:


Algoritmo:

Vamos a explicar las partes de las que consta el algoritmo:

- Secuencia de inicio:

El LCD necesita recibir al inicio el código 00111000 tres veces seguidas con un intervalo de 5 mS. El LCD queda borrado y el cursor en la primera posición. Además, se configura el interfaz de 8 bit’s ‘DL=1’, dos líneas ‘Líneas=1’ y 5x7 puntos ‘Font=1’.

Así quedaría resuelta la secuencia de inicio:


Estado 0:
Añadimos el reset asíncrono en bajo activo y le damos el valor 0.
- Salidas: tendremos todas las salidas a 0, incluyendo la salida triestado que trabaja en bajo activo y nos deja en alta impedancia las salidas Dx.
- Transiciones: Al estado 1 sin condiciones.


Estado 1:
- Salidas: reloj_registro a 1 para aumentar la cuenta en el contador de comandos. Las demás salidas se quedan por defecto en 0.
- Transiciones: Al estado 2 sin condiciones.


Estado 2:
- Salidas: Habilitamos el LCD y lo ponemos en modo de lectura, así podremos leer el flag ‘BUSY’ para saber si está ocupado.
- Transiciones: Al estado 3 sin condiciones.


Estado 3:
- Salidas: Mantenemos las salidas anteriores y nos quedamos en este estado hasta que el LCD deje de estar ocupado.
- Transiciones: Al estado 4 si D7_I= 0.


Estado 4:
- Salidas: Deshabilitamos el LCD y nos vamos al estado 5, para mandar el comando de inicio.
- Transiciones: Al estado 5 si: (Q0_R='1' & Q1_R='0' & Q2_R='0') ||
(Q0_R='0' & Q1_R='1' & Q2_R='0') ||
(Q0_R='1' & Q1_R='1' & Q2_R='0').


Estado 5:
- Salidas: Habilitamos el LCD y dejamos las señales ‘Dx_O’ del autómata comunicado al puerto ‘Dx’ del LCD, todo ello para mandar el código de la condición de inicio 00111000. Por este estado pasaremos 3 veces.
- Transiciones: Al estado 8 sin condiciones.
Podemos cambiar el color de los estados con la herramienta señalada, nosotros ponemos en verde los estados donde introducimos datos:


Estado 8:
Si no hemos terminado de mandar los códigos de la condición de inicio volvemos al estado 0.
- Transiciones: Al estado 0 si: (Q0_R='1' & Q1_R='0' & Q2_R='0') || (Q0_R='0' & Q1_R='1' & Q2_R='0') || (Q0_R='1' & Q1_R='1' & Q2_R='0').


- Pantalla ON-OFF:

Tras los 3 comandos de la condición de inicio vamos a mandar uno que deje la pantalla en ON ‘D= 1’, el cursor en ON ‘C= 1’ y el parpadeo del cursor en ON ‘B= 1’. Añadiremos un estado (6) para realizar esta instrucción.


Estado 6:
- Salidas: Habilitamos el LCD y dejamos las señales Dx_O del autómata comunicado al puerto ‘Dx’ del LCD, todo ello para mandar el código de pantalla ON/OFF 00001111.
- Transiciones: Del estado 4 si (Q0_R='0' & Q1_R='0' & Q2_R='1').
Al estado 8 sin condiciones.
Debemos agregar la condición del estado 8 para que vuelva al estado 0 tras poner la pantalla en ON:
Al estado 0 si: (Q0_R='0' & Q1_R='0' & Q2_R='1').


- Cursor a casa:

Tras el comando pantalla ON/OFF, mandamos el comando cursor a casa consiguiendo, con ello, que el cursor se coloque en la posición de inicio.
Añadiremos un estado (7) para realizar esta instrucción.


Estado 7:
- Salidas: Habilitamos el LCD y dejamos las señales Dx_O del autómata comunicado al puerto Dx del LCD, todo ello para mandar el código de cursor a casa 00000010.
- Transiciones: Del estado 4 si (Q0_R='1' & Q1_R='0' & Q2_R='1').
Al estado 8 sin condiciones.
Desde el estado 8 pasaremos al estado 10 para comenzar a mandar el mensaje de la primera línea.
Al estado 9 si: (Q0_R='1' & Q1_R='0' & Q2_R='1').


- Mandar los datos de la primera línea:

Mandaremos los datos de uno en uno a la primera línea del LCD, creando el carácter personal. Finalizaremos la máquina de estados.


Estado 9:
- Salidas: Ponemos las salida reloj_dato a 1 para aumentar la cuenta en el contador de datos.
- Transiciones: Al estado 10 sin condiciones.


Estado 10:
- Salidas: Habilitamos el LCD y lo ponemos en modo de lectura, así podremos leer el flag BUSY para saber si está ocupado.
- Transiciones: Al estado 11 sin condiciones.


Estado 11:
- Salidas: Mantenemos las salidas anteriores.
- Transiciones: Nos quedamos en este estado hasta que el LCD deje de estar ocupado.
Al estado 12 si D7_I= 0.


Estado 12:
- Transiciones: Pasamos a los distintos estados que contienen cada uno de los 5 caracteres de la primera línea, dependiendo de cómo se encuentre el contador de datos.
Al estado 13 si (Q0_D='1' & Q1_D='0' & Q2_D='0').
Al estado 14 si (Q0_D='0' & Q1_D='1' & Q2_D='0').
Al estado 15 si (Q0_D='1' & Q1_D='1' & Q2_D='0').
Al estado 16 si (Q0_D='0' & Q1_D='0' & Q2_D='1').
Al estado 17 si (Q0_D='1' & Q1_D='0' & Q2_D='1').


Estados 13-17:
- Salidas: En cada uno de estos 5 estados habilitamos el LCD y dejamos las señales ‘Dx_O’ del autómata comunicado al puerto ‘Dx’ del LCD, mandamos el código de los caracteres. En el estado 17 comenzaremos a crear nuestro carácter personal.
Estado 13: D (01000100).
Estado 14: a  (01100001).
Estado 15: n  (01101110).
Estado 16: i   (01101001).
Estado 17: DDRAM donde creamos el carácter (00000000).
- Transiciones: Al estado 18 sin condiciones salvo el estado 17 que pasará al estado 21 sin condiciones.


Elegí los caracteres basándome en la siguiente tabla:


Estado 18:
- Salidas: Deshabilitamos el LCD y pasamos al estado 10 hasta introducir los 8 caracteres en el LCD. Una vez hecho esto, pasamos al estado 19 para dejar la máquina en un bucle.
- Transiciones: Al estado 19 sin condiciones.


Estado 19:
- Salidas: Deshabilitamos el LCD.
- Transiciones: Pasamos al estado 10 hasta introducir los 5 caracteres en el LCD. Una vez hecho esto, la máquina estará en un bucle.
Al estado 9 si:
(Q0_D='1' & Q1_D='0' & Q2_D='0') ||
(Q0_D='0' & Q1_D='1' & Q2_D='0') ||
(Q0_D='1' & Q1_D='1' & Q2_D='0') ||
(Q0_D='0' & Q1_D='0' & Q2_D='1') ||
(Q0_D='1' & Q1_D='0' & Q2_D='1').
Al estado 18 si: (Q0_D='0' & Q1_D='1' & Q2_D='1').
Al estado 20 si no se cumplen las condiciones anteriores.


Estado 20:
Desde este estado reiniciamos la cuenta de los contadores y volvemos al estado 0 para comenzar de nuevo la visualización. Aquí solo se caerá en el caso de perder el control del flujo de la máquina.
- Transiciones: Del estado 4 si no se cumplen las condiciones.
Del estado 19 si no se cumplen las condiciones.
Al estado 0 sin condiciones.


Creación del carácter:

Para la creación del carácter deberemos seguir la siguiente secuencia:
- Mandar la dirección de la DDRAM, en la cual se va a crear el carácter. (Esta dirección se manda como dato).
- Mandar la dirección de la CGRAM para apuntar a la fila. (De la 40h a 47h ).
- Introducir el código de la fila CGRAM direccionada. (Los datos estarán comprendidos entre los valores 00h a 1Fh).
- Direccionar la siguiente posición de la CGRAM e introducir su código, y así hasta completar las 7 filas del carácter.
- Una vez terminado el carácter, mandar una dirección de la DDRAM para que de este modo las siguientes instrucciones apunten a la DDRAM y podamos utilizar el carácter gráfico creado.


Estado 21:
- Salidas: Ponemos las salida ‘reloj_caracter’ a 1 para aumentar la cuenta en el contador de los datos y direcciones para la creación del carácter.
- Transiciones: Al estado 22 sin condiciones.


Estado 22:
- Salidas: Habilitamos el LCD y lo ponemos en modo de lectura, así podremos leer el flag ‘BUSY’ para saber si está ocupado.
- Transiciones: Al estado 23 sin condiciones.


Estado 23:
- Salidas: Mantenemos las salidas anteriores y nos quedamos en este estado hasta que el LCD deje de estar ocupado.
- Transiciones: Al estado 24 si D7_I='0'.


Estado 24:
Dependiendo de como se encuentre el contador del carácter, apuntamos a la fila o introducimos la secuencia.
- Transiciones:
Al estado 25 si: (Q0_C='1' & Q1_C='0' & Q2_C='0' & Q3_C='0' & Q4_C='0') ||
(Q0_C='1' & Q1_C='1' & Q2_C='0' & Q3_C='0' & Q4_C='0') ||
(Q0_C='1' & Q1_C='0' & Q2_C='1' & Q3_C='0' & Q4_C='0') ||
(Q0_C='1' & Q1_C='1' & Q2_C='1' & Q3_C='0' & Q4_C='0') ||
(Q0_C='1' & Q1_C='0' & Q2_C='0' & Q3_C='1' & Q4_C='0') ||
(Q0_C='1' & Q1_C='1' & Q2_C='0' & Q3_C='1' & Q4_C='0') ||
(Q0_C='1' & Q1_C='0' & Q2_C='1' & Q3_C='1' & Q4_C='0') ||
(Q0_C='1' & Q1_C='1' & Q2_C='1' & Q3_C='1' & Q4_C='0').
Al estado 26 si: (Q0_C='0' & Q1_C='1' & Q2_C='0' & Q3_C='0' & Q4_C='0') ||
(Q0_C='0' & Q1_C='0' & Q2_C='1' & Q3_C='0' & Q4_C='0') ||
(Q0_C='0' & Q1_C='1' & Q2_C='1' & Q3_C='0' & Q4_C='0') ||
(Q0_C='0' & Q1_C='0' & Q2_C='0' & Q3_C='1' & Q4_C='0') ||
(Q0_C='0' & Q1_C='1' & Q2_C='0' & Q3_C='1' & Q4_C='0') ||
(Q0_C='0' & Q1_C='0' & Q2_C='1' & Q3_C='1' & Q4_C='0') ||
(Q0_C='0' & Q1_C='1' & Q2_C='1' & Q3_C='1' & Q4_C='0') ||
(Q0_C='0' & Q1_C='0' & Q2_C='0' & Q3_C='0' & Q4_C='1').


Estado 25:
- Salidas: Ponemos el LCD en modo ‘registro’ y pasamos a los distintos estados que contienen cada una de las 8 direcciones de la CGRAM para apuntar a la fila, dependiendo de cómo se encuentre el contador del carácter.
- Transiciones:
Al estado 27 si: (Q0_C='1' & Q1_C='0' & Q2_C='0' & Q3_C='0' & Q4_C='0').
Al estado 28 si: (Q0_C='1' & Q1_C='1' & Q2_C='0' & Q3_C='0' & Q4_C='0').
Al estado 29 si: (Q0_C='1' & Q1_C='0' & Q2_C='1' & Q3_C='0' & Q4_C='0').
Al estado 30 si: (Q0_C='1' & Q1_C='1' & Q2_C='1' & Q3_C='0' & Q4_C='0').
Al estado 31 si: (Q0_C='1' & Q1_C='0' & Q2_C='0' & Q3_C='1' & Q4_C='0').
Al estado 32 si: (Q0_C='1' & Q1_C='1' & Q2_C='0' & Q3_C='1' & Q4_C='0').
Al estado 33 si: (Q0_C='1' & Q1_C='0' & Q2_C='1' & Q3_C='1' & Q4_C='0').
Al estado 34 si: (Q0_C='1' & Q1_C='1' & Q2_C='1' & Q3_C='1' & Q4_C='0').


Estados 27-34:
- Salidas: En cada uno de estos 8 estados habilitamos el LCD y dejamos las señales ‘Dx_O’ del autómata comunicado al puerto ‘Dx’ del LCD, mandamos la dirección de la CGRAM para apuntar a la fila donde vamos a introducir el código.
Estado 27:   (01000000).
Estado 28:   (01000001).
Estado 29:   (01000010).
Estado 30:   (01000011).
Estado 31:   (01000100).
Estado 32:   (01000101).
Estado 33:   (01000110).
Estado 34:   (01000111).
- Transiciones: Al estado 39 sin condiciones.


Estado 26:
- Salidas: Ponemos el LCD en modo ‘dato’ y pasamos a los distintos estados que contienen cada uno de los 8 códigos, que debemos introducir en cada fila de la CGRAM para formar el carácter, dependiendo de cómo se encuentre el contador del carácter.
- Transiciones:
Al estado 35 si: (Q0_C='0' & Q1_C='1' & Q2_C='0' & Q3_C='0' & Q4_C='0').
Al estado 36 si: (Q0_C='0' & Q1_C='0' & Q2_C='1' & Q3_C='0' & Q4_C='0').
Al estado 37 si: (Q0_C='0' & Q1_C='1' & Q2_C='1' & Q3_C='0' & Q4_C='0').
(Q0_C='0' & Q1_C='0' & Q2_C='0' & Q3_C='1' & Q4_C='0') ||
(Q0_C='0' & Q1_C='1' & Q2_C='0' & Q3_C='1' & Q4_C='0') ||
(Q0_C='0' & Q1_C='0' & Q2_C='1' & Q3_C='1' & Q4_C='0').
Al estado 38 si: (Q0_C='0' & Q1_C='1' & Q2_C='1' & Q3_C='1' & Q4_C='0') ||
(Q0_C='0' & Q1_C='0' & Q2_C='0' & Q3_C='0' & Q4_C='1').


Estados 35-38:
- Salidas: En cada uno de estos 8 estados habilitamos el LCD y dejamos las señales ‘Dx_O’ del autómata comunicado al puerto ‘Dx’ del LCD, mandamos los códigos, que debemos introducir en cada fila de la CGRAM para formar el carácter. Utilizo el mismo estado para varias filas, así simplifico las macrocélulas que el programa me compilará.
Estado 35:   (00000100).
Estado 36:   (00001010).
Estado 37:   (00010001).
Estado 38:   (00011111).
- Transiciones: Al estado 39 sin condiciones.


Estado 39:
- Transiciones: Al estado 40 sin condiciones.


Estado 40:
- Salidas: Deshabilitamos el LCD y pasamos al estado 21 hasta introducir los 8 códigos para la creación del carácter. Una vez hecho esto, pasamos al estado 41 para dejar la máquina en un bucle.
- Transiciones:
Al estado 21 si: (Q0_C='1' & Q1_C='0' & Q2_C='0' & Q3_C='0' & Q4_C='0') ||
(Q0_C='0' & Q1_C='1' & Q2_C='0' & Q3_C='0' & Q4_C='0') ||
(Q0_C='1' & Q1_C='1' & Q2_C='0' & Q3_C='0' & Q4_C='0') ||
(Q0_C='0' & Q1_C='0' & Q2_C='1' & Q3_C='0' & Q4_C='0') ||
(Q0_C='1' & Q1_C='0' & Q2_C='1' & Q3_C='0' & Q4_C='0') ||
(Q0_C='0' & Q1_C='1' & Q2_C='1' & Q3_C='0' & Q4_C='0') ||
(Q0_C='1' & Q1_C='1' & Q2_C='1' & Q3_C='0' & Q4_C='0') ||
(Q0_C='0' & Q1_C='0' & Q2_C='0' & Q3_C='1' & Q4_C='0') ||
(Q0_C='1' & Q1_C='0' & Q2_C='0' & Q3_C='1' & Q4_C='0') ||
(Q0_C='0' & Q1_C='1' & Q2_C='0' & Q3_C='1' & Q4_C='0') ||
(Q0_C='1' & Q1_C='1' & Q2_C='0' & Q3_C='1' & Q4_C='0') ||
(Q0_C='0' & Q1_C='0' & Q2_C='1' & Q3_C='1' & Q4_C='0') ||
(Q0_C='1' & Q1_C='0' & Q2_C='1' & Q3_C='1' & Q4_C='0') ||
(Q0_C='0' & Q1_C='1' & Q2_C='1' & Q3_C='1' & Q4_C='0') ||
(Q0_C='1' & Q1_C='1' & Q2_C='1' & Q3_C='1' & Q4_C='0').
Al estado 41 si: (Q0_C='0' & Q1_C='0' & Q2_C='0' & Q3_C='0' & Q4_C='1').


Estado 41:
- Salidas: Habilitamos el LCD y dejamos las señales ‘Dx_O’ del autómata comunicado al puerto ‘Dx’ del LCD, todo ello para mandar el código de ‘dirección DDRAM’ 11000110.
- Transiciones: Al estado 18 sin condiciones.



Simulación previa:

Podemos probar el funcionamiento de nuestra máquina de estados creando un test bench. Se nos abrirá el simulador de estado, podemos ir simulando estado a estado cambiando las entradas con doble clic y generando un pulso. Se nos ira poniendo en amarillo por el estado o transición que vallamos, y en verde por la que hayamos pasado.


Podemos hacer la simulación completa de la máquina de estados y comprobar que nos pase por todos los estados y transiciones.



Creación del esquema:

Generamos el código VHDL de la máquina en Generate HDL. Nos aparecerá una ventana donde nos pregunta si queremos borrara las entradas no utilizadas. Damos a delete.


Nos aparecerá una ventana donde nos dice que el código se ha generado con éxito.


Añadimos el documento creado a nuestro esquemático. En la ventana processes generamos el símbolo del decodificador para poder utilizarlo en el esquema principal del diseño. En la ventana Sources nos aparecerá la ruta del componente creado para poder utilizarle.


Colocamos el símbolo creado con los siguientes componentes:
1 INV
1 IBUF
8 BUFT
8 OBUFT
1 OR2
2 contador binario de 4 bit’s CB4CE
1 contador binario de 8 bit’s CB8CE
1 BUFG
Colocamos las marcas y las etiquetas correspondientes como en la siguiente imagen:


Compilamos en busca de errores:



Síntesis:

Hacemos la síntesis del esquema.


En View Technology Schematic podemos observar como se ha compilado nuestro esquema:



Asignación de los pines:

Añadimos un nuevo archivo al proyecto de tipo: Implementation Constraints File. Lo asociamos a nuestro esquema principal.


Hacemos doble clic al documento creado y se nos abrirá el PACE donde definimos los pines.



Translate y documentación:

Podemos modificar la configuración de la compilación y que nos compile para espacio o para velocidad. En la ventana processes, con el botón derecho sobre implement design seleccionamos properties.


Convertimos el esquemático en un lenguaje interno NGD. Haciendo doble clic en Translate.


Generamos el archivo Fit y comprobamos que todo esté bien. Podemos observar como hemos usado la mayoría de las macrocélulas y registros.



Programación:

Por último generamos el archivo de programación .JED que le abriremos con el programa IMPACT.
Hacemos doble clic sobre Generate Programming File.


Abrimos el IMPACT, creamos un nuevo proyecto, escribimos el nombre y la dirección de la ruta:


Seleccionamos el modo de trabajo del JTAG, lo dejamos por defecto:


Añadimos el documento de programación .JED en Add Device:


Hacemos doble clic en program


Seleccionamos las siguientes opciones de programación:


Nos aparecerá un mensaje de que la programación a finalizado con éxito.


Finalmente cambiamos la tarjeta a modo ejecución y comprobamos su funcionamiento físico:

No hay comentarios:

Publicar un comentario