Cika PG24064FRM-E Módulo LCD gráfico inteligente, Rabbit 2000 Módulo Rabbit 2000 Manual de usuario
A continuación, encontrará información breve para Módulo LCD gráfico inteligente PG24064FRM-E, Módulo Rabbit 2000. Este documento le dará una idea del funcionamiento interno del LCD gráfico inteligente Powertip PG24064FRM-E y su conexión con un módulo Rabbit 2000. El documento también proporciona instrucciones para la configuración del LCD y su uso con el módulo Rabbit 2000.
PDF
Descargar
Documento
Anuncio
Anuncio
CAN-011, Utilización de displays LCD gráficos (T6963) con Rabbit 2000 Nota de Aplicación: CAN-011 Título: Utilización de displays LCD gráficos (T6963) con Rabbit 2000 Autor: Sergio R. Caprile, Senior Engineer Revisiones Fecha Comentarios 0 5/9/03 Nos interiorizaremos ahora en el desarrollo de una interfaz para conectar un módulo LCD gráfico inteligente Powertip PG24064FRM-E, a un módulo Rabbit 2000. Se trata de un display de 240x64 pixels basado en chips controladores compatibles con el T6963, de Toshiba. Analizaremos más tarde el software de control y un simple programa demostración, que sirve para comprobar el correcto funcionamiento de los módulos LCD que tengamos en stock, y de paso, demostrar sus capacidades. A fin de probar la mayor parte posible del hardware, la interfaz será de 8 bits y realizará lectura y escritura del controlador LCD. Hardware El T6963 presenta una interfaz tipo Intel, es decir, con líneas de RD y WR separadas. Posee además la línea de selección, CE, y otra para determinar si lo que se escribe es un dato o un comando: C/D. Existe además otro pin que determina el formato de caracteres: 6x8 ú 8x8, llamado FS. A los fines de esta nota de aplicación, conectaremos este último pin a masa, forzando el modo 8x8. Para la interfaz con el micro no es necesario ningún tipo de glue-logic, hacemos una conexión directa entre los ports del Rabbit y el LCD, al igual que con la gran mayoría de los microcontroladores, como puede apreciarse en la tabla a la derecha: El port A, hace las veces de bus de datos, mientras que los ports libres del port E generarán, por software, las señales de control. La señal CE podría conectarse directamente a masa, a criterio del usuario. El único inconveniente es una posible escritura no intencional al momento del arranque, problema que también podemos tener con este esquema, dado que los ports utilizados son entradas al momento de reset. Podrían incluírse sendos pull-ups si esta posibilidad resultara un inconveniente. Rabbit LCD PA.0 PA.1 PA.2 PA.3 PA.4 PA.5 PA.6 PA.7 ------------------------------------------------------------------------- D0 D1 D2 D3 D4 D5 D6 D7 PE.4 PE.3 PE.0 PE.1 ------------------------------------- WR RD CE C/D Otra diferencia es el circuito de contraste; si bien los módulos alfanuméricos funcionan muy bien con una tensión fija cercana a los 0,6V, estos módulos gráficos necesitan de una tensión de aproximadamente -6 a -8V. La misma puede obtenerse de la salida que estos módulos proveen (Vee). El display dispone, además, de un pin de reset, el cual podemos controlar a voluntad o conectar al reset del circuito. Para el desarrollo de esta nota de aplicación, simplemente lo conectamos mediante un pull-up a la tensión de alimentación. Software Breve descripción del display gráfico Estos displays son versátiles, la memoria puede ser dividida en dos áreas: gráfica y de texto, las cuales pueden, a su vez, habilitarse y/o superponerse independientemente. Para el caso del modo texto, el T6963 dispone de un generador de caracteres y una ROM de caracteres de 5x7, aunque es posible utilizar una ROM externa o la misma RAM del display. Al momento de definir cada pantalla, definimos también en qué posición de memoria comienza y cómo se asigna la memoria. Una carcterística interesante es que el área gráfica puede funcionar como memoria de atributos, modificando al área de texto (parpadeo e invertido) La estructura de memoria de pantalla es lineal, tanto para gráficos como para textos. En esta última modalidad, el primer byte corresponde al caracter ubicado arriba a la izquierda, y el último byte corresponde al ubicado abajo a la derecha. Para gráficos, los pixels se agrupan horizontalmente en bytes, correspondiendo el CAN-011 1 CAN-011, Utilización de displays LCD gráficos (T6963) con Rabbit 2000 primer byte de memoria a los primeros ocho pixels1 de la primera línea de arriba a la izquierda, y el último byte a los últimos ocho pixels de la última línea de abajo a la derecha. El bit más significativo del primer byte de memoria corresponde al punto situado en la pantalla arriba a la izquierda, y el bit menos significativo del último byte de memoria corresponde al punto situado en pantalla abajo a la derecha. El direccionamiento del byte a leer o escribir en memoria se hace mediante comandos, especificando la dirección de memoria. Tiene además un contador que puede ser autoincrementado, autodecrementado, o estático; pudiendo apuntar a la dirección siguiente, previa, o no cambiar, luego de una lectura o escritura. Existe además un modo denominado “Auto”, en el cual se envían todos los bytes de datos en bloque, sin su correspondiente comando de escritura asociado. Esto resulta óptimo para enviar los datos byte por byte hasta completar una pantalla. Una característica interesante del display, es que posee un par de instrucciones para setear o resetear directamente un bit en memoria, lo que simplifica las rutinas de dibujo. Otra característica, no tan interesante, es que según definamos el modo (pin FS) en 6x8 ú 8x8, los bytes en modo gráfico serán de 6 ú 8 pixels. Esto significa, que en el modo 6x8, el controlador ignora los bits 6 y 7 de los datos que se le escriben. Por este motivo, elegimos el modo 8x8 para el desarrollo de la nota de aplicación. Algoritmos Para direccionar un punto debemos traducir sus coordenadas a una dirección lineal, para ello, deberemos multiplicar la coordenada vertical y por la cantidad de bytes en sentido horizontal de la pantalla (30 bytes) y sumarle la coordenada horizontal x dividida por 8 (pixels por byte). El resto de dividir x/8 es el número de pixel dentro del byte. Dado que el MSB se halla a la izquierda, el pixel 0 corresponde al bit 7 y el pixel 7 al bit 0, es decir: address=30*y+x/8 ; bit=7-resto(x/8). Para graficar funciones, debemos tener en cuenta que la coordenada (0;0) se halla en el extremo superior izquierdo de la pantalla. Para mostrar pantallas, deberemos agrupar los datos de modo tal de poder enviarlos de forma que aproveche de manera eficiente el contador autoincrementado y la estructura de memoria; dada la estructura lineal, esto se reduce simplemente a enviar todos los bytes corridos. Si comparamos la estructura de memoria del display con la forma de guardar imágenes blanco y negro en formato “Sun raster”2, veríamos que hay una correspondencia perfecta, pudiendo extraer directamente la información de dicho archivo. La única operación a realizar sobre la imagen es que, si disponemos de un display del tipo STN-, como es el caso del desarrollo de esta nota de aplicación, deberemos invertir los colores previamente. El formato utilizado corresponde al modo standard, sin compresión (RLE), y posee un header de 32 bytes que deberá removerse. También es posible procesar un archivo de tipo BMP3, como se ha desarrollado en la CAN-005, dado que el formato de memoria es el mismo para ambos controladores. Para imprimir textos, calculamos simplemente la posición de memoria a partir de fila y columna de modo similar: address=30*fila+columna, para 30 caracteres por fila (matriz de caracteres de 8x8). En el modo atributos, la pantalla gráfica funciona como memoria de atributos, de modo que tenemos dos pantallas de texto, escribiendo en una elegimos el caracter, y escribiendo en la otra seteamos los atributos. Cabe destacar que el set de caracteres no es ASCII, aunque los caracteres están en el mismo orden pero desplazados. Esto se resuelve restando 32 al código ASCII, dado que el set de caracteres comienza con el espacio. Desarrollo Desarrollamos a continuación el software de base para manejo del display. Definiremos dos pantallas: una gráfica de 240x64 y una de texto de 30x8, con caracteres de 8x8, usando el generador interno, por lo que se verán caracteres de 5x7 en una trama de 8x8. Ambas pantallas estarán superpuestas (modo XOR) y podremos superponer texto y gráficos. Dada la cantidad de información a mover hacia el display para la presentación de pantallas, sumado al hecho del constante chequeo del flag de busy, decidimos desarrollar toda la rutina de escritura en assembler. Dado que solamente nuestra rutina accede al port A, prescindimos de su correspondiente shadow register; no obstante, dado que el port E puede compartirse con otra tarea, creemos “buena práctica” el actualizar el shadow register. Esta actualización debe hacerse de forma atómica, para evitar que una interrupción altere el valor en la mitad de la operación. 1 2 3 En modo 6x8 los bytes son de 6 pixels, pero para esta nota utilizamos el modo 8x8. Dicho formato es utilizado en ambiente X11, particularmente en máquinas de la firma Sun Microsystems. Un ejemplo de software gratis que lo utiliza es Gimp (GNU Image Manipulation Program). No se ha incluído ese desarrollo en esta nota dado que a estas resoluciones existen bytes extra en el formato que dificultan la conversión. CAN-011 2 CAN-011, Utilización de displays LCD gráficos (T6963) con Rabbit 2000 Para aprovechar el modo “Auto”, y dado que éste utiliza otro flag de busy diferente, preparamos dos sets de rutinas: uno para modo normal y otro para modo “Auto”, con una 'A' en el nombre. /* LCD control #define LCD_CD #define LCD_CE #define LCD_WR #define LCD_RD signals */ 1 0 4 3 #asm ;Las funciones requiren un parametro: ;@sp+2= dato a escribir ; LCD_WriteCmd:: call LCD_Busy ; Espera a que el controlador esté libre jr Write ; C/D vuelve seteado (comando) LCD_WriteACmd:: ; Modo Auto call LCD_ABusy ; Espera a que el controlador esté libre jr Write ; C/D vuelve seteado (comando) LCD_WriteData:: call LCD_Busy jr WriteData LCD_WriteAData:: call LCD_ABusy WriteData: ld hl,PEDRShadow ld de,PEDR res LCD_CD,(HL) ioi ldd ; Espera a que el controlador esté libre ; Modo Auto ; Espera a que el controlador esté libre ; ; ; ; control port (shadow) control port Baja C/D (data) ahora Write: ld a,0x84 ioi ld (SPCR),a ld hl,(sp+2) ld a,l ioi ld (PADR),a ld hl,PEDRShadow ld de,PEDR res LCD_CE,(HL) res LCD_WR,(HL) ioi ldd ld hl,PEDRShadow ld de,PEDR set LCD_WR,(HL) set LCD_CE,(HL) ioi ldd ret LCD_Busy: ld e',3 jr Busy LCD_ABusy: ld e',8 Busy: ld a,0x80 ioi ld (SPCR),a ld hl,PEDRShadow ld de,PEDR set LCD_CD,(HL) ioi ldd l1: ld hl,PEDRShadow ld de,PEDR res LCD_CE,(HL) res LCD_RD,(HL) CAN-011 ; PA0-7 = Outputs ; escribe ; recupera valor a escribir (parámetro) (LSB) ; ; ; ; ; ; ; ; ; ; ; lo escribe al controlador control port (shadow) control port baja CE baja WR ahora control port (shadow) control port sube WR sube CE ahora ; STA0, STA1 ; Modo Auto ; STA3 ; ; ; ; ; ; PA0-7 = Inputs escribe control port (shadow) control port sube C/D ahora ; ; ; ; control port (shadow) control port baja CE baja RD 3 CAN-011, Utilización de displays LCD gráficos (T6963) con Rabbit 2000 ioi ldd ioi ld a,(PADR) ld hl,PEDRShadow ld de,PEDR set LCD_RD,(HL) set LCD_CE,(HL) ioi ldd ex de',hl and l cp l jr nz,l1 ret ; ; ; ; ; ; ; ; ; ; ; ahora lee al controlador control port (shadow) control port sube RD sube CE ahora HL = DE' (L tiene los bits a chequear) resetea los demás bits chequea flag(s) de busy loop mientras no esté listo #endasm El prefijo ioi es el que nos permite utilizar cualquier instrucción de acceso a memoria como instrucción de I/O. Esta es una de las mayores diferencias entre Rabbit y Z-80, en cuanto a set de instrucciones; descartando, claro está las funciones agregadas. Obsérvese como la operación atómica se realiza mediante la instrucción LDD (LoaD and Decrement), que copia hacia la posición apuntada por DE el contenido de la posición apuntada por HL, decrementando ambos punteros y el contador BC. El inconveniente es que más adelante debemos volver a cargar el mismo valor en los punteros (preferimos esto en vez de salvarlos en el stack porque es más rápido), o incrementarlos nuevamente (más rápido aún). Nos pareció menos confuso para el desarrollo de la nota volver a cargar el mismo valor, sacrificando eficiencia por claridad. También hicimos uso de dos nuevas instrucciones, que no existían en el Z-80: LD E',n, que nos permitió cargar directamente un valor en un registro del set alternativo, y EX DE',HL, que nos permitió recuperar ese valor, ya que sólo algunas operaciones están permitidas sobre registros del set alternativo directamente. Dado que el display dispone de una función para setear un pixel (bit en memoria), no necesitamos funciones de lectura de memoria, al menos para el alcance de esta nota de aplicación. El resto de las funciones se ha escrito en C, dado que con el incremento de velocidad logrado es suficiente para el módulo utilizado y las prestaciones esperadas de una nota de aplicación. void LCD_init () { WrPortI ( PEDR,&PEDRShadow,'\B10011011' ); WrPortI ( PEDDR,&PEDDRShadow,'\B10011011' ); WrPortI ( PEFR, &PEFRShadow, 0 ); MsDelay ( 1000 ); LCD_WriteData(0x0); LCD_WriteData(0x0); LCD_WriteCmd(0x40); LCD_WriteData(0x1e); LCD_WriteData(0x0); LCD_WriteCmd(0x41); LCD_WriteData(0x0); LCD_WriteData(0x10); LCD_WriteCmd(0x42); LCD_WriteData(0x1e); LCD_WriteData(0x0); LCD_WriteCmd(0x43); LCD_WriteCmd(0x81); LCD_WriteCmd(0x9C); } void LCD_address ( int address ) { LCD_WriteData(address&0xFF); LCD_WriteData((address>>8)&0xFF); LCD_WriteCmd(0x24); } // // // // Señales de control inactivas PE0,1,3,4,7 = output PE: no I/O strobe espera reset de LCD // 0x000 // Inicio de área de texto (TXT) // 30x8=240 // Número de columnas // 0x1000 // Inicio de área gráfica/atributos (GFX) // 30x8=240 // Número de columnas // TXT XOR GFX, CG interno // TXT on, GFX on, no cursor, no blink // LO byte // HI byte // set address void LCD_fill(int count,unsigned char pattern) { CAN-011 4 CAN-011, Utilización de displays LCD gráficos (T6963) con Rabbit 2000 int i; LCD_WriteCmd(0xb0); for(i=0;i<count;i++) LCD_WriteAData(pattern); LCD_WriteACmd(0xb2); // Auto data write // llena la pantalla con 'pattern' // reset Auto data write } void LCD_fillblack() { LCD_address(0x1000); LCD_fill(30*64,0); } void LCD_fillwhite() { LCD_address(0x1000); LCD_fill(30*64,0xFF); } // GFX screen // llena con 0's (negro en STN-) // GFX screen // llena con FF's (blanco en STN-) int LCD_print (char *ptr) { char c; int i; i=0; LCD_WriteCmd(0xb0); while (c=*ptr++){ LCD_WriteAData (c-0x20); i++; } LCD_WriteACmd(0xb2); return(i); // Auto data write // convierte ASCII a código controlador // reset Auto data write // devuelve número de caracteres } void LCD_printat (int cpl,unsigned int row, unsigned int col, char *ptr) { LCD_address (cpl*row+col); // set address LCD_print(ptr); } void LCD_printatAtt (int cpl,unsigned int row,unsigned int col,char *ptr,unsigned char attr) { int i; LCD_address (cpl*row+col); i=LCD_print(ptr); LCD_address (0x1000+cpl*row+col); LCD_WriteCmd(0xb0); while (i--) LCD_WriteAData (attr); LCD_WriteACmd(0xb2); // // // // // // // set address imprime, obtiene número de caracteres set address de atributos Auto data write para cada caracter escribe atributos reset Auto data write } void LCD_CLS() { LCD_address(0); LCD_fill(30*64,0); // TXT screen // llena con 0's (borra) } /* Plot image data, 8 pixels per byte, MSB left */ void LCD_plot (int x, int y) { int strip,bit; strip=x>>3; CAN-011 // strip = x/8 5 CAN-011, Utilización de displays LCD gráficos (T6963) con Rabbit 2000 bit=7-x&'\B0111'; y=strip+30*y; LCD_address(0x1000+y); LCD_WriteCmd(0xF8|bit); // bit = resto (MSB a la izquierda) // direcciona strip en GFX screen // set bit } Para mostrar pantallas, podemos, como en la CAN-007, convertirlas a un formato compilable. Afortunadamente, existe un formato binario que coincide con la distribución de memoria, y Dynamic C provee una función que permite, al momento de compilación, leer un archivo y ubicarlo para ocupar un área de memoria en xmem; asociando esa posición de memoria física con un puntero extendido que hace referencia a esa posición. El área apuntada corresponde a una estructura del tipo: puntero (long) -> longitud de los datos ('n', long) datos propiamente dichos (n bytes) De esta forma, resulta muy fácil incluir las imágenes al programa: #ximport "rabbit.im2" rabbit El único inconveniente de trabajar de esta forma, es que acceder a la memoria por su dirección física resulta algo engorroso, por lo que es preferible copiarla al área base y transferirla de allí al display. Dynamic C trae funciones para hacer ésto. Para utilizar poca memoria, partimos la imagen en bloques, movemos estos bloques de una a otra área y copiamos al display. En este caso, serían 8 bloques de 240 bytes c/u. #define IMGCHUNK 240 #define CHUNKS 8 void LCD_dump(long imgdata) { int x,y; unsigned char buffer[IMGCHUNK]; LCD_address(0x1000); // GFX screen LCD_WriteCmd(0xb0); // Auto data write for(y=0;y<CHUNKS;y++){ // lee bloques de xmem xmem2root(&buffer,imgdata+IMGCHUNK*y+sizeof(long),IMGCHUNK); for(x=0;x<IMGCHUNK;x++) LCD_WriteAData(buffer[x]); // escribe bloque en controlador } LCD_WriteACmd(0xb2); // reset Auto data write } El siguiente fragmento de código es un simple ejemplo de la utilización de Dynamic C para escribir un corto y simple programa de control que nos permita corroborar el funcionamiento de un módulo LCD gráfico inteligente. Para observar si todos los pixels funcionan correctamente, pintamos la pantalla de negro y luego la blanqueamos. Luego graficamos una función seno, mostramos un ejemplo del “modo atributos” y finalmente mostramos una pantalla gráfica. /* MAIN PROGRAM */ main() { int i; LCD_init(); while(1){ LCD_CLS(); LCD_fillblack(); MsDelay ( 3000 ); LCD_fillwhite(); MsDelay ( 3000 ); // // // // // borra TXT screen pinta de negro espera 3 segs white screen espera 3 segs LCD_printat(30,4,3,"Cika Electronica S.R.L."); // texto negro fondo blanco MsDelay ( 3000 ); // espera 3 segs CAN-011 6 CAN-011, Utilización de displays LCD gráficos (T6963) con Rabbit 2000 LCD_fillblack(); MsDelay ( 3000 ); LCD_CLS(); // invierte imagen (blanco, fondo negro) // espera 3 segs // borra TXT screen for(i=0;i<240;i++) LCD_plot(i,32); // eje x for(i=0;i<64;i++) LCD_plot(120,i); // eje y for(i=-120;i<120;i++) LCD_plot(120+i,32-(int)(32*(sin(i*3.14159/120)))); LCD_printat(30,0,0,"sin(x)"); MsDelay ( 3000 ); // espera 3 segs LCD_CLS(); // borra TXT screen LCD_fillblack(); // borra GFX screen LCD_WriteCmd(0x84); // modo atributeos, CG interno LCD_printatAtt(30,1,8,"MODO ATRIBUTOS",0); LCD_printatAtt(30,3,8,"Texto Normal",0); LCD_printatAtt(30,4,7,"Texto Invertido",5); LCD_printatAtt(30,5,3,"Texto Normal Parpadeando",8); LCD_printatAtt(30,6,1,"Texto Invertido Parpadeando",13); MsDelay ( 6000 ); // espera 6 segs LCD_CLS(); // borra TXT screen LCD_WriteCmd(0x81); // TXT XOR GFX, CG interno LCD_dump(rabbit); MsDelay ( 6000 ); // muestra logo Rabbit // espera 6 segs } } CAN-011 7 ">
Anuncio
Características clave
- Interfaz tipo Intel
- Controlador compatible con el T6963
- Pantalla de 240x64 pixels
- Memoria gráfica y de texto
- Generador de caracteres
- ROM de caracteres de 5x7
- Modo Auto
- Función para setear un pixel
- Control de contraste
- Control de reset
Preguntas y respuestas frecuentes
El T6963 presenta una interfaz tipo Intel, es decir, con líneas de RD y WR separadas. Posee además la línea de selección, CE, y otra para determinar si lo que se escribe es un dato o un comando: C/D.
La memoria puede ser dividida en dos áreas: gráfica y de texto, las cuales pueden, a su vez, habilitarse y/o superponerse independientemente. Para el caso del modo texto, el T6963 dispone de un generador de caracteres y una ROM de caracteres de 5x7, aunque es posible utilizar una ROM externa o la misma RAM del display.
Los módulos alfanuméricos funcionan muy bien con una tensión fija cercana a los 0,6V, estos módulos gráficos necesitan de una tensión de aproximadamente -6 a -8V. La misma puede obtenerse de la salida que estos módulos proveen (Vee).
El display dispone, además, de un pin de reset, el cual podemos controlar a voluntad o conectar al reset del circuito. Para el desarrollo de esta nota de aplicación, simplemente lo conectamos mediante un pull-up a la tensión de alimentación.