Diferencia entre revisiones de «ST7920»

De Proyectos
Ir a la navegación Ir a la búsqueda
Línea 303: Línea 303:


Esta dibujando la pantalla entera para cada flush(), pero no lo entiendo porque la función flush() esta preparada para renderizar un AC de una fila concreto
Esta dibujando la pantalla entera para cada flush(), pero no lo entiendo porque la función flush() esta preparada para renderizar un AC de una fila concreto
Modo gráfico
  Relación AC con GDRAM
    Peculiaridad AC
    Peculiaridad Fila
  Proceso de dibujar uno o varios pixeles
    Dibujar un pixel concreto
    Dibujar todos los pixeles

Revisión del 14:00 4 abr 2013

Características

Address Counter (AC)

La AC es una dirección que sirve para poder acceder a la DDRAM, CGRAM y GDRAM. Cuando yo quiero acceder a una posicion de la DDRAM, CGRAM o GDRAM lo hago a traves de una dirección. Mediante el siguiente dibujo explico la relación entre la AC y la DDRAM. La relación con la CGRAM no la explicaré porque no la encuentro necesaria y no me he parado a "jugar" con ella, y la relación con la GDRAM la explico en el apartado de Relación AC con GDRAM.

CGROM

Esta CGROM tiene la particularidad que tiene caracteres chinos de 16x16 puntos. Según el manual tiene 8192 caracteres.

HCGROM

La HCGROM contiene 128 caracteres alfanumericos de 8x16 puntos. Lo que quiere decir que son los caracteres que representan nuestro abecedario. Cada caracter de estos ocupa la mitad que los de la CGROM y necesitas escribir dos caracteres de la HCGROM para completar una dirección AC.


Explicación gráfica:



  • Como se puede ver en el dibujo, en este lcd se pueden mostrar 8 caracteres de la CGROM y 16 de la HCGROM. La CGROM son kanjis chinos y la HCGROM son caracteres alfanumericos (nuestro abecedario mas los signos de puntuación, etc)
  • Cada caracter HCGROM consta de 8bits, y un caracter de CGROM necesita 16bits para ser representado
  • La AC tiene solo 8 posiciones, lo que significa que tengo que escribir los caracteres alfanuméricos de dos en dos porque dos caracteres de la HCGROM equivalen a 1 AC


Peculiaridad al escribir un caracter de la HCGROM

Aqui intento explicar el punto anterior de la AC.


  • Enviamos la instrucción 0x40 que es enviar la AC 0x00 con la instrucción Set CGRAM (0x40)



  • En la imagen se ve la AC 0x00 subrayada de azul, ahora estamos en esa AC
  • Ahora vamos a poner RS a 1 para poder enviar el caracter A (que en hexa es 0x41). Lo que hacemos es escribir la letra A en la primera posición



  • Como vemos en la imagen de arriba la AC 0x00 se ha dividido en dos y la letra A se ha escrito en la primera subcasilla. Esta subcasilla es el espacio que ocupa un caracter de la HCGROM (como hemos visto más arriba)
  • Ahora queremos dejar dos espacios en blanco y escribir B, por lo tanto queremos escribirla en la subcasilla 4. No se puede acceder a esta subcasilla porque la AC 0x01 empieza con la subcasilla 3 y no hay manera de acceder la subcasilla 4 directamente
  • Para poder escribir en la subcasilla 4 tendré que enviar el comando Set CGRAM con la dirección de AC 0x01 y luego enviar el comando Write Ram con el hexadecimal del espacio y otra vez el comando Write Ram con el hexadecimal de B. El código quedaria asi:


  /*La función send envia la instrucción/dato y especifica si es un comando (CMD) o es un dato (DATA). El comando tiene el RS a 0 y el dato tiene el RS a 1*/
  
  send(0x81, CMD);  //Seleccionamos la AC 0x01 con la instrucción básica Set DDRAM Address

  send(0x20, DATA);  //Envio un espacio (en ascci 0x20 es un espacio)
  send(0x42, DATA);  //Envio la letra B

DDRAM

Hay 64x2bytes de espacios para la DDRAM. Son 4 lienas para 16 caracteres de 16x16 puntos o 32 caracteres de 8x16 puntos.
La explicación de que es la DDRAM ya se puede leer en el apartado DDRAM del HD44780U

CGRAM

Esta es la RAM que nos permite crear caracteres personalizados, pero debido a que este lcd es un GLCD lo encuentro poco útil. En la sección de Modo Gráfico (GLCD) hay funciones mucho más interesantes.


Descripción Pines

  • XRESET: Es el pin de reset. Para resetear el lcd desde el hardware se hace con este pin. Tiene que pasar de LOW a HIGH para hacer el reset. Yo no lo utilizo.
  • PSB: Es un pin para seleccionar si usamos la comunicación serie o paralela. LOW es serie y HIGH paralela
  • Vo: Es para el contraste (creo)
  • VSS: GND
  • VDD: +5V

SPI

En el modo serie no se puede leer de la pantalla. Solo se pueden hacer operaciones de escritura.

  • RS: es el pin SS del protocolo SPI
  • RW: es el pin MOSI del protocolo SPI
  • E: es el pin clock del protocolo SPI

Paralelo 8 bits

  • RS: Es el pin Register Select. LOW es para seleccionar las instrucciones de registro (IR) y HIGH es para seleccionar los registros de datos (DR).
  • RW: Es el pin de lectura/escritura. LOW es para indicar escritura y HIGH para indicar lectura.
  • E: Es el pin utilizado para indicar el paso de datos del microcontrolador al st7920. Se ve mejor su utilidad en la sección Como funciona la comunicación paralela 8bits
  • D0-D7: Son los pines de datos.

Funciones Básicas


  • Todas las instrucciones básicas excepto Function Set son muy parecidas o iguales a las de HD44780U


Function Set

  • El bit DL indica si estamos en comunicación paralela de 8 bits(HIGH) o comunicación paralela de 4 bits (LOW)
  • El bit RE es para indicar si estamos en modo extendido(HIGH) o en modo normal(LOW). El modo extendido es en modo GLCD


Funciones Extendidas


De todas las funciones extendidas, de momento, yo solo he "trasteado" con Extended Function Set y Set Graphic Display Ram Address

Extended Function Set

  • DL indica lo mismo que en el apartado anterior, HIGH para comunicacion paralelo 8 bits y LOW para 4 bits.
  • RE indica modo extendido (HIGH) o normal (LOW)
  • G indica lcd encendido (HIGH) o apagado (LOW). Este es el bit importante, porque cada vez que pasemos de modo normal a modo GLCD tenemos que asegurarnos de enviar esta instrucción con este bit en HIGH, sino no se verá nada. Esto lo explico en el apartado de pasos a seguir al dibujar un pixel

Set Graphic Display Ram Address

Esta instrucción es la que se usa para pasar una dirección de memoria a la AC (que recordemos que es la dirección que necesitamos para saber donde dibujar un pixel, es decir las cordenadas X e Y).
En la imagen se ven dos filas porque se tiene que enviar dos veces esta instrucción, una para el eje X y la otra para el eje Y. La primera instrucción se envia para determinar la Y y la segunda para determinar la X.
En el apartado Relación AC con GDRAM hay una imagen explicativa de la relación entre la AC y la GDRAM

Como funciona la comunicación Serial (SPI)

Como funciona la comunicación paralela 8bits

  • El bit RS controla si enviamos operaciones DR o IR (Paralelo 8 bits). El bit lo tenemos que colocar a 1 o 0 antes de activar Enable
  • El bit RW controla si son operaciones de lectura o escritura (Paralelo 8 bits). Igual que con RS se tiene que establecer en 0 o 1 antes de acrtivar Enable
  • Los bits DB0-DB7 son los que llevan los datos. Se tienen que establecer antes de activar Enable
  • El bit E (Enable) es el que utilizamos para transmitir las instrucciones al lcd


Ejemplo:

/*RS, RW, DB0-DB7 y E son pines digitales de Arduino*/

  digitalWrite(RS, LOW);
  digitalWrite(RW, LOW);
  digitalWrite(DB7, LOW);
  digitalWrite(DB6, LOW);
  digitalWrite(DB5, LOW);
  digitalWrite(DB4, LOW);
  digitalWrite(DB3, LOW);
  digitalWrite(DB2, LOW);
  digitalWrite(DB1, LOW);
  digitalWrite(DB0, HIGH);

  digitalWrite(E, HIGH);
  delayMicroseconds(1);
  digitalWrite(E, LOW);
  • En este ejemplo vamos a enviar el comando Display Clear 0x01
  • Como se puede comprobar en la tabla de Funciones Básicas estamos transmitiendo la instrucción IR Display Clear
  • Esta es una forma muy básica de hacerlo, pero es para que quede claro
  • Cuando establecemos todos los pines con su bit correspondiente (0 o 1) pasamos a enviar la instrucción al lcd
    • En el flanco de bajada de Enable es cuando se transmite la instrucción al lcd


Inicialización por software

Modo paralelo 8 bits

Aqui voy a poner el esquema de la inicialización con interfaz de 8 bits. La de 4 bits no la pondré porque trabajar este LCD con 4 bits da errores que no se de donde vienen exactamente pero que con la interfaz de 8 bits o la de serie no pasa.

Al hacer las pruebas he visto como siguiendo este esquema se hace una buena inicialización y el lcd funciona correctamente, pero también he visto en códigos encontrados por internet que no siguen todo el esquema y también se le inicializa correctamente el lcd.

Supongo que de la segunda manera ahorras tiempo en inicializar, pero no se si hay más ventajas o no, ni puedo decir con certeza cual es mejor utilizar.


Modo serie (SPI)

Modo Gráfico (GLCD)

El modo gráfico es en el que tenemos control total sobre todos los pixeles del lcd. con esto podemos dibujar todo tipos de formas, dibujos o incluso tener fuentes de diferentes tamaños y estilos.

Relación AC con GDRAM

Antes he explicado una peculiaridad de la AC en el apartado Peculiaridad al escribir un caracter de la HCGROM. En el modo gráfico también se tiene que tener en cuenta porque cuando se quiere dibujar un pixel se tiene que seleccionar una AC. Esto se verá en más profundidad en el siguiente apartado, Proceso al dibujar uno o varios pixeles

A parte de esta peculiaridad también nos encontramos con otra. Esta tiene que ver con las filas y columnas.

Para poder explicarla primero se ha de explicar como se divide en coordenadas la pantalla:



Esto es una representación gráfica de la pantalla. Esta indicado que hay 128 columnas y 64 filas. Este dibujo también me servirá para explicar como se dibuja un pixel.

Para poder dibujar en el pixel 0 de la fila 0, tengo que indicar unas coordenadas X e Y. La coordenada Y son las filas y la coordenada X es la AC. Si quiero acceder al pixel 0,0 tengo que seleccionar la AC 0x00 y luego dibujar los 16 pixeles que contiene esa AC. Si solo quiero dibujar el primer pixel entonces el primero lo pondré a 1 y los demas a 0.
Excribo el código de ejemplo:

  /*La función send envia la instrucción/dato y especifica si es un comando (CMD) o es un dato (DATA). El comando tiene el RS a 0 y el dato tiene el RS a 1*/

  /*Primero se envia el comando Function Set con RE a 1*/
  send(0x34, CMD);

  /*Luego se envia la Y*/
  send(0x80, CMD); //0x80 equivale a la instrucción extendida Set Graphic Display RAM Address con X = 0

  /*Ahora se envia la X*/
  send(0x80, CMD); //0x80 equivale a la instrucción extendida Set Graphic Display RAM Address con Y = 0

  /*Ahora se dibujan los pixeles con la instrucción básica Write to RAM*/
  /*Como Write to RAM es una instrucción básica antes de poder utilizarla hemos de cambiar a instrucciones básicas*/
  send(0x30, CMD);  //0x30 es la instrucción básica Function Set con RE = 0 (esto se amplia en el siguiente punto)

  send(0x80, DATA);  //Se dibujan los 8 primeros pixeles
  send(0x00, DATA);  //Se dibujan los 8 siguientes pixeles

  /*En la primera instruccion de escritura de 8 bits el bit mas alto estara puesto en 1*/

  /*Volvemos al modo extendido*/
  send(0x34, CMD);

  /*Instrucción extendida Extended Function Set con G en 1 (display on)*/
  send(0x36, CMD);

Con este código lo que tendremos es el pixel 0,0 encendido.

Ahora si queremos por ejemplo encender el pixel 1,0 lo que haremos es lo mismo, pero en vez de poner la fila 0 pondremos la fila 1.

  send(0x34, CMD);  //Primero se envia el comando Function Set con RE a 1

  send(0x81, CMD);  //Esto es la Y
  send(0x80, CMD);  //Esto es la X

  send(0x30, CMD);
  send(0x80, DATA);
  send(0x00, DATA);

  send(0x34, CMD);  //Volvemos al modo extendido
  send(0x36, CMD);  //Instrucción extendida Extended Function Set con G en 1 (display on)


El problema viene cuando llegamos a la fila 32. Hasta este momento para movernos por la X ibamos desde la AC 0x00 hasta la AC 0x07 en cada fila, pero a partir de la 32 la AC empieza en 0x88 hasta 0x8F para cada fila. Y las filas se resetean. Ahora la fila 32 vuelve a valer 0x00 hasta la fila 64 que valdrá 0x9F (que es 31 en decimal).

  /*En este ejemplo dibujaremos el pixel 63,0*/
  send(0x34, CMD);  //Primero se envia el comando Function Set con RE a 1

  send(0x9F, CMD);  //0x9F es 0x80 (instrucción extendida Set Graphic Display Ram Address) + fila 1F (31 en decimal)
  send(0x88, CMD);  //0x88 es la AC = 0

  send(0x30, CMD);
  send(0x80, DATA);
  send(0x00, DATA);

  send(0x34, CMD);  //Volvemos al modo extendido
  send(0x36, CMD);  //Instrucción extendida Extended Function Set con G en 1 (display on)


En este dibujo intento explicarlo de forma gráfica:


Archivo:Coordenadas01.jpg

Proceso al dibujar uno o varios pixeles

Para poder dibujar los pixeles he encontrado dos formas de hacerlo:

  • La primera es dibujando en pantalla cada pixel, es decir si quiero dibujar el pixel 0,0 hago todo el proceso de dibujar un solo pixel y cuando quiero dibujar el pixel 0,1 vuelvo a hacer todo el proceso
  • La segunda, y más eficaz, es tener una matriz en memoria donde se guardan que pixeles estan dibujados y que pixeles no. Entonces luego se dibuja la pantalla entera a partir de la matriz.
    • Hay otra versión aún más optimizada que es dibujar solamente los pixeles que han cambiado, así no estamos redibujando la pantalla todo el rato. Se ahorra mucho tiempo. Este método es el que se usa en la libreria de DC42 <--- aqui poner enlace a esa parte en concreto.


Estas formas de dibujar pixeles estan basadas en ir dibujando un pixel cada vez (un pixel en concreto) o en ir dibujando toda la pantalla de golpe (dibujar todos los pixeles). La forma de dc42 es una unión de las dos.
En los siguientes subapartados explico cada forma.


Dibujar un pixel concreto

Quiero dibujar el pixel 2,3. Es decir el pixel que está en la fila 2 (0x02) y en la AC 0x00. (En la imagen de arriba es el pixel de color azul)


  send(0x34, CMD);  //Primero se envia el comando Function Set con RE a 1

  send(0x82, CMD);  //Este es el comando extendido Set Graphic Display RAM Address con la fila 2
  send(0x80, CMD);  //Este es el comando extendido Set Graphic Display RAM Address con la AC 0

  send(0x30, CMD);  //Se envia el comando Function Set con RE 0

  send(0x10, DATA); //Esto equivale a 00010000, es decir solo el pixel en la posición 3 estará encendido (teniendo en cuenta que el primer pixel está en la posición 0)

  send(0x34, CMD);  //Volvemos al modo extendido
  send(0x36, CMD);  //Instrucción extendida Extended Function Set con G en 1 (display on)


Ahora imaginemos que queremos dibujar el pixel 2,8 (color negro en la imagen de arriba) en otra operación. Si hacemos lo mismo que arriba pero pasandole 0x80 al send de DATA lo que pasará es que se borrará el pixel 2,3 y se dibujará el 2,8. El código de abajo es muestra como se hace:



Dibujar todos los pixeles

Fuentes personalizadas

Documentación

Datasheet ST7920 Cytronix

Notas

  • Hacer una representación gráfica de la disposicion de las filas y columnas, lo del 0x80 y 0x88
    • Explicar como lo soluciona dc42
  • Explicar como soluciona dc42 el problema de que cada AC son 2 bytes y que cada byte representa 8 pixeles (cada pixel corresponde a un bit)
  • Explicar uint8_t *ptr = image + ((16 * r) + (2 * startColNum)); y también la parte (2*startColNum)
  • Explicar sendLcdData(*ptr++);
  • Creo que cada vez que si se hace esto:
setPixel(1,1);
flush();
setPixel(2,1);
flush();

Esta dibujando la pantalla entera para cada flush(), pero no lo entiendo porque la función flush() esta preparada para renderizar un AC de una fila concreto


Modo gráfico

 Relación AC con GDRAM
   Peculiaridad AC
   Peculiaridad Fila
 Proceso de dibujar uno o varios pixeles
   Dibujar un pixel concreto
   Dibujar todos los pixeles