13-Mensaje LCD Xilinx CPLD

En este proyecto vamos a manejar un LCD desde el CPLD.
El LCD que vamos a utilizar es el modelo “TAD-9572” que, como todo LCD, tiene su propio microcontrolador y habrá que conocer las instrucciones necesarias para comunicarnos con el .
Características de la pantalla:
-Pantalla de cristal líquido con una matrix de 2x16 caracteres de 5x7 pixeles.
-Microcontrolador propio de gobierno.( Hitacri uC44780).
-Desplazamiento de los caracteres hacia la izquierda o la derecha.
-Proporciona la dirección de la posición absoluta o relativa del carácter.
-Memoria de 40 caracteres por línea de pantalla.
-Movimiento del cursor y cambio de aspecto.
-8 caracteres programables por el usuario.
-Conexión a un procesador usando interfaz de 4/8 bits.

ESQUEMA



VSS.- Patilla de GND de alimentación.
VCC.- Patilla de alimentación de +5V.
VEE.- Patilla de contraste del cristal líquido. Normalmente, se conecta a un potenciómetro a través del cual se aplica una tensión variable entre 0 y +5V que permite regular el contraste del cristal líquido.
RS.- Selección del registro de control/datos:
_-RS=0 Registro de control.
_-RS=1 Registro de datos.
R/W.- Señal de lectura/escritura:
_-R/W= 0 EL módulo LCD es escrito.
_-R/W= 1 EL módulo LCD es leído.
E.- Señal de activación del módulo LCD:
_-E=0 Módulo desconectado. Las líneas D0-D7  quedan                            en  estado de alta impedancia.
_-E=1 Módulo conectado.

D0-D7.- Bus de datos bidireccional. A través de estas líneas se realiza la transferencia de información entre el módulo LCD y el sistema de control.



COMANDOS





El proyecto para escribir un texto en el LCD lo vamos a hacer mediante diagramas de estados en su mayoría , aunque ciertas partes las haremos en el esquemático de Xilinx.
En nuestro caso, al LCD lo vamos a mandar 24 datos y 6 comandos. Utilizaremos la plantilla de “ ABRA Telecom S.L © 2005” para escribir nuestros nombres, en este caso “ Jose Pelayo © 2011”.
La máquina de estados va a necesitar dos contadores, uno de 3 bits y otro de 5 bits, a modo de flag  .
La conexión del LCD estará ubicada en el Banco 2 del CPLD.
La estructura del diagrama de estados será la siguiente:
1-    Secuencia INICIO (3 comandos)
2-    Pantalla ON/OFF (1 comando)
3-    Cursor a casa (1 comando)
4-    Caracteres 1º línea( 16 datos)
5-    Cambio de línea( 1 comando)
6-    Caracteres 2º línea( 8 datos)
Abrimos Xilinx , creamos un nuevo proyecto y configuramos el modelo de nuestro CPLD. En este caso he puesto de nombre “ texto_lcd” .





Una vez creado añadimos una fuente esquemática, en este caso la llamo “esquem_lcd”.



Añadimos  otra fuente como diagrama de estados, llamada “LCD1” , aunque también podemos abrir el StateCAD desde fuera.



Abrimos la fuente de estados y vamos al StateCAD.

Lo primero que hacemos es declarar las variables con las que vamos a trabajar.




El “RESET”  y el  “ THREE_STATE”  van en bajo activo, las salidas con registro.

El LCD realiza automáticamente una secuencia de inicio al aplicarle tensión, también hemos realizado la secuencia por software por si no la hace .  

El “ESTATE 5”  es el encargado de enviar la sencuenca de inicio “00111000” tres veces, pero antes pasaremos por otros estados para preparar el autómata.

En el “STATE0” ponemos el “THREE_STATE” a “0” que al ser de bajo activo pondrá las salidas del autómata en alta impedancia.



Pasamos al “STATE1” sin condiciones.




Ponemos a “1” la salida “RELOJS_REGISTRO” para aumentar la cuenta del contador de comandos.

Pasamos al “STATE2” sin condiciones.

Habilitamos el LCD y lo ponemos en modo lectura.



Pasamos al” STATE3”  sin condiciones.

Mantenemos el “HABILITAR” y también añadimos “READ_WRITE” hasta que el LCD deje de estar ocupado.



Pasamos al “STATE4” si “D7_I=’0’ ”.



Desde el “STATE4” pasamos al “STATE5” tres veces para habilitar el LCD con la secuencia de inicio como mencioné anteriormente.



Al “STATE9” sin condiciones.


Una vez estemos en el 9, sabremos si hemos mandado ya el código de inicio tres veces gracias al contador de 5 bits que vamos a poner en el esquemático, si no ha sido completado volvemos al”STATE0”.





Al “STATE0” 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']

Ahora, desde el “STATE4” , ponemos una nueva transición hacia un estado que deje la pantalla en ON ”D=1”, el cursor en ON  “C=1” y el parpadeo del cursor en ON  “B=1”, este será el “STATE6”.
Del “STATE4”  pasaremos al  “ STATE6”  si : [Q0_R='0' & Q1_R='0' & Q2_R='1'] .




Pasamos del “STATE6” al “STATE9” sin condiciones.
Creamos un nuevo estado seguido del “STATE4” llamado “STATE7” en el cual mandamos el cursor a casa con el código”00000010” .
Pasaremos del “STATE4” al “STATE7”  si : [Q0_R='1' & Q1_R='0' & Q2_R='1'].


Desde el “STATE7” al “STATE9” sin condiciones.
Crearemos un nuevo estado “STATE10” al cual pasaremos desde el “STATE9” con la siguiente condición: [Q0_R='1' & Q1_R='0' & Q2_R='1'].
En el “STATE10”  ponemos la salida “RELOJ_DATO” a 1 para aumentar la cuenta del contador de datos.

Pasamos al “STATE11”  sin condiciones, en el cual habilitamos el LCD y lo ponemos en modo lectura.





Pasamos al “STATE12”  sin condiciones.





En este estado esperamos a que el LCD no esté ocupado, pasaremos al “STATE13” con si : “D7_i=’0’ “ .




En el “STATE13” habilitamos el modo dato y nos vamos comunicando con los estados que contienen todos los caracteres.

Primero vamos a hacer la línea superior:

Al STATE14 si [Q0_D='1' & Q1_D='0' & Q2_D='0' & Q3_D='0' & Q4_D='0']
al STATE15 si [Q0_D='0' & Q1_D='1' & Q2_D='0' & Q3_D='0' & Q4_D='0']
al STATE16 si [Q0_D='1' & Q1_D='1' & Q2_D='0' & Q3_D='0' & Q4_D='0']
al STATE17 si [Q0_D='0' & Q1_D='0' & Q2_D='1' & Q3_D='0' & Q4_D='0']
al STATE18 si [Q0_D='1' & Q1_D='0' & Q2_D='1' & Q3_D='0' & Q4_D='0']
al STATE19 si [Q0_D='0' & Q1_D='1' & Q2_D='1' & Q3_D='0' & Q4_D='0']
al STATE20 si [Q0_D='1' & Q1_D='1' & Q2_D='1' & Q3_D='0' & Q4_D='0']
al STATE21 si [Q0_D='0' & Q1_D='0' & Q2_D='0' & Q3_D='1' & Q4_D='0']
al STATE22 si [Q0_D='1' & Q1_D='0' & Q2_D='0' & Q3_D='1' & Q4_D='0']
al STATE23 si [Q0_D='0' & Q1_D='1' & Q2_D='0' & Q3_D='1' & Q4_D='0']
al STATE24 si [Q0_D='1' & Q1_D='1' & Q2_D='0' & Q3_D='1' & Q4_D='0']
al STATE25 si [Q0_D='0' & Q1_D='0' & Q2_D='1' & Q3_D='1' & Q4_D='0']
al STATE26 si [Q0_D='1’ & Q1_D='0' & Q2_D='1' & Q3_D='1' & Q4_D='0']
al STATE27 si [Q0_D='0' & Q1_D='1' & Q2_D='1' & Q3_D='1' & Q4_D='0']
al STATE28 si [Q0_D='1' & Q1_D='1' & Q2_D='1' & Q3_D='1' & Q4_D='0']
al STATE29 si [Q0_D='0' & Q1_D='0' & Q2_D='0' & Q3_D='0' & Q4_D='1']

En cada uno de estos estados introduciremos los caracteres que queramos en binario, podemos utilizar una tabla como esta:





“D0_O”  será el bit menos significativo.

STATE14 : J
STATE15 : o
STATE16 : s
STATE17 : e
STATE18 :
STATE19 :P
STATE20 :e
STATE21 :l
STATE22 :a
STATE23 :y
STATE24 :o
STATE25 :
STATE26 :
STATE27 :
STATE28 :
STATE29 :





En cada uno de los estados en los que introducimos el caracter  también habilitamos el LCD y dejamos las salidas “Dx_O “ comunicadas .





Después pasamos al ” STATE38” sin condiciones desde cada uno de los 16 
estados .



Pasamos al “STATE39” sin condiciones.




Desde el “STATE4” ahora pasamos a un nuevo estado, el “STATE8” , con la condición de : [Q0_R='0' & Q1_R='1' & Q2_R='1'].


También añadiremos el “STATE40” como @ELSE por si no se cumple ninguna de las condiciones reiniciar los contadores y no perder el flujo del autómata.

En el “STATE8”  habilitamos el LCD y las señales  “Dx_O” para direccionar “ DDRAM”  con “11000000”.




Pasamos del “STATE8” al “STATE9” sin condiciones.
Una vez en el “STATE9” , iremos al “STATE0” 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'] ó [Q0_R='0' & Q1_R='0' & Q2_R='1'].
O al “STATE10” si: [Q0_R='1' & Q1_R='0' & Q2_R='1'] ó [Q0_R='0' & Q1_R='1' & Q2_R='1']. 


Desde el “STATE40” se reinicia la cuenta de los contadores para recuperar el control de flujo en caso de ser necesario, desde este estado pasaremos al “STATE0” sin condiciones.



Ahora mandamos los datos a la 2º línea.

Desde el “STATE13” pasamos a los estados entre “STATE30” y  “STATE37” con las siguientes condiciones:

al STATE30 si [Q0_D='1' & Q1_D='0' & Q2_D='0' & Q3_D='0' & Q4_D='1']
al STATE31 si [Q0_D='0' & Q1_D='1' & Q2_D='0' & Q3_D='0' & Q4_D='1']
al STATE32 si [Q0_D='1' & Q1_D='1' & Q2_D='0' & Q3_D='0' & Q4_D='1']
al STATE33 si [Q0_D='0' & Q1_D='0' & Q2_D='1' & Q3_D='0' & Q4_D='1']
al STATE34 si [Q0_D='1’ & Q1_D='0' & Q2_D='1' & Q3_D='0' & Q4_D='1']
al STATE35 si [Q0_D='0' & Q1_D='1' & Q2_D='1' & Q3_D='0' & Q4_D='1']
al STATE36 si [Q0_D='1' & Q1_D='1' & Q2_D='1' & Q3_D='0' & Q4_D='1']
al STATE37 si [Q0_D='0' & Q1_D='0' & Q2_D='0' & Q3_D='1' & Q4_D='1']

Donde introduciré :

STATE30 : (
STATE31 : c
STATE32 : )
STATE33 :
STATE34 : 2
STATE35 : 0
STATE36 : 1
STATE37 : 1




Desde estos estados también se habilita lo mismo que del “STATE14” al “STATE29” y  también se pasa al “STATE38” sin condiciones.

Desde el “STATE38” se pasa al “STATE39” sin condición.

Una vez en el “STATE39”  hay varias transiciones, se pasa al “STATE10”  hasta introducir todos los caracteres en el LCD, después se vuelve al “STATE38” para dejar la máquina en bucle.

Desde el “STATE39” :

Al STATE10 si [Q0_D='1' & Q1_D='0' & Q2_D='0' & Q3_D='0' & Q4_D='0'] ó
[Q0_D='0' & Q1_D='1' & Q2_D='0' & Q3_D='0' & Q4_D='0'] ó
[Q0_D='1' & Q1_D='1' & Q2_D='0' & Q3_D='0' & Q4_D='0'] ó
[Q0_D='0' & Q1_D='0' & Q2_D='1' & Q3_D='0' & Q4_D='0'] ó
[Q0_D='1' & Q1_D='0' & Q2_D='1' & Q3_D='0' & Q4_D='0'] ó
[Q0_D='0' & Q1_D='1' & Q2_D='1' & Q3_D='0' & Q4_D='0'] ó
[Q0_D='1' & Q1_D='1' & Q2_D='1' & Q3_D='0' & Q4_D='0'] ó
[Q0_D='0' & Q1_D='0' & Q2_D='0' & Q3_D='1' & Q4_D='0'] ó
[Q0_D='1' & Q1_D='0' & Q2_D='0' & Q3_D='1' & Q4_D='0'] ó
[Q0_D='0' & Q1_D='1' & Q2_D='0' & Q3_D='1' & Q4_D='0'] ó
[Q0_D='1' & Q1_D='1' & Q2_D='0' & Q3_D='1' & Q4_D='0'] ó
[Q0_D='0' & Q1_D='0' & Q2_D='1' & Q3_D='1' & Q4_D='0'] ó
[Q0_D='1’ & Q1_D='0' & Q2_D='1' & Q3_D='1' & Q4_D='0'] ó
[Q0_D='0' & Q1_D='1' & Q2_D='1' & Q3_D='1' & Q4_D='0'] ó
[Q0_D='1' & Q1_D='1' & Q2_D='1' & Q3_D='1' & Q4_D='0'] ó
[Q0_D='1' & Q1_D='0' & Q2_D='0' & Q3_D='0' & Q4_D='1'] ó
[Q0_D='0' & Q1_D='1' & Q2_D='0' & Q3_D='0' & Q4_D='1'] ó
[Q0_D='1' & Q1_D='1' & Q2_D='0' & Q3_D='0' & Q4_D='1'] ó
[Q0_D='0' & Q1_D='0' & Q2_D='1' & Q3_D='0' & Q4_D='1'] ó
[Q0_D='1' & Q1_D='0' & Q2_D='1' & Q3_D='0' & Q4_D='1'] ó
[Q0_D='0' & Q1_D='1' & Q2_D='1' & Q3_D='0' & Q4_D='1'] ó
[Q0_D='1' & Q1_D='1' & Q2_D='1' & Q3_D='0' & Q4_D='1']

al STATE0 si [Q0_D='0' & Q1_D='0' & Q2_D='0' & Q3_D='0' & Q4_D='1']

al STATE38 si [Q0_D='0' & Q1_D='0' & Q2_D='0' & Q3_D='1' & Q4_D='1']

al STATE40 si no se cumple ninguna de las condiciones anteriores.



Finalmente quedará algo así.



Ahora, para ver que no tiene fallos de diseño, vamos a “STATE BENCH” para hacer una simulación.




En este caso, debido al tamaño del esquema, vamos a hacer una simulación automática para comprobar si pasa por todos los estados.

Damos a “Automatic Testbench” y comprobamos que llega al 100% y no da errores.



Una vez hecho esto creamos el VHDL en “Generate HDL”.





Nos mostrará una ventana con estadísticas como las líneas de código, la memoria utilizada, el tiempo que ha tardado en compilar, estados, transiciones… y a continuación nos aparecerá el VHDL .




Regresamos a ISE y añadimos en “Add Existing  Sources” el VHDL de la máquina de estados a nuestro proyecto, con el cual creamos un nuevo símbolo en “Create Schematic Symbol ”.






Una vez hemos creado el símbolo de nuestro diagrama de estados lo acompañaremos del siguiente esquema, compuesto por:
1 INV
8 IBUF
8 BUFT
8 OBUFT
1 OR2
1 autómata LCD1
1 contador binario de 4 bit’s CB4CE
1 contador binario de 8 bit’s CB8CE
1 BUFG





Finalmente el símbolo del diseño completo lo podemos ver en “View Synthesis Report”.




Ahora ya solo queda crear la fuente para los pines, el “Implementation Constraints File” , lo abrimos con el PACE y asignamos los siguientes pines:




Terminamos creando el “ .JED “  en “Generate Programming File”.



VIDEO