Skip to content

Log:Fundamentos de Vídeo. Matriz 4x4 de LEDs

Juan Gonzalez-Gomez edited this page Sep 12, 2024 · 38 revisions

Ideas previas para CT20: Fundamentos de vídeo. Matrices de 4x4 LEDs

  • Fundamentos de video: Raster, refresco
  • Utilizar el sistema unario para la implementación del raster
  • Circuito aplicación último: Pintar leds con pulsadores: pintar/borrar pixeles manualmente
  • Si matriz de 5x3, se pueden pintar números... tal vez se pueda mostrar... Concepto de memoria ROM de caracteres
  • No tengo claro si hacer además los controladores optimizados (en binario en vez de unario...)

Primera pasada

  • Raster horizontal en display 1x4 LEDs
  • Justificar por qué rasterización bit a bit: transmisión de información. Ahorro de consumo
  • Añadir bit de habilitación de fila
  • Pasar a matrix de 2x2 leds
  • Dato a escribir: en forma lineal 4 bits. Pero se renderiza como 2x2
  • Pasar a matriz de 3x3
  • Idea de cursor
  • Pasar a matrix de 4x4
  • Optimizar??

Pruebas

Contenido

Display 1x4

  • Rasterizado: Señal de vídeo

Matrix 2x2

  • Lineal
  • 2 filas y 2 columnas (A partir de más leds hay ahorro usando filas y columnas)
  • Envío serie de información, desde registro de 4 bits
  • Envío serie de información desde 2 registros de 2 bits (uno por fila): Más fácil introducir los datos
  • Raster propio de escritura? Pensar
  • Concpto de cursor
  • hacer animaciones....

Matrix 3x3

  • Dibujo directo por hacer, usando la posición del raster

Matriz 4x4

  • Aplicación de dibujo
  • Optimización?

Referencias

Introducción

  • Si algo transita con la suficiente velocidad, dejamos de percibir esa transición. A partir de 50Hz ya no percibimos la transición

Imagen rasterizada y refresco

Abordamos primero el problema del consumo. Lo vamos a hacer con el display 1x4, que ya sabemos que en realidad no importa, porque el consumo sigue siendo muy bajo... pero lo utilizamos para presentar la solución que sí escala

El caso peor es el de mayor consumo: TODOS los LEDs encendidos. Si solucionamos este caso peor, entonces tenemos la solución para todos los casos (esta es una estrategia muy típica en ingeniería: encontrar el caso peor y solucionarlo!)

El consumo que tenemos en el caso peor es de 4 u (4 unidades de consumo). La solución consiste en encender sólo 1 led cada vez. Nunca tener encendidos más de 1 LED a la vez... ¿What?

Para entender vamos a ir poco a poco creando circuitos y haciendo experimentos hasta llegar a la solución

En este primer circuito, en vez de utilizar un registro vamos a descomponerlo en sus biestables. Usamos un biestable D para cada pixel, explícitamente. El circuito es equivalente, pero lo mostramos aquí porque le iremos añadiendo cosas:

(Ejemplo 2: 2024-09-6-Disp-1x4-02-disable)

Añadimos 4 puertas AND de habilitación, una por LED, para tener el control de qué leds queremos que estén encendidos y qué apagados. Para hacer una prueba partimos del circuito anterior y usamos el pulsador SW2 para habilitar la visualización o no de los LEDs

(Ejemplo 3: 2024-09-6-Disp-1x4-03-disable)

Con este hemos hecho un enable/disable global del display. Pero ahora vamos a separarlo también, de manera que dada pixel lo podamos habilitar/deshabilitar INDIVIDUALMENTE. Para ello añadimos las etiquetas ena3, ena2, ena1 y ena0

Usamos un CONTADOR UNIARIO ONE-HOT de 4 bits, Cada biestable lo conectamos a la entrada de habilitación correspondiente. El dato a grabar en la memoria de video lo ponemos a 1111 (ya que queremos encender TODOS los leds). Usamos el pulsador sw2 para incrementar manualmente el contador unario one-hot, y poder así habilitar cada LED secuencialmente: Primero el LED3, luego el LED2, luego el LED1 y por último el LED0. Despues se vuelve a comenzar. Usamos un bucle espacial (contador módulo 4 unario one-hot)

(Ejemplo 4: 2024-09-6-Disp-1x4-04-disable)

Ahora lo que estamos visualizando es sólo 1 de los 4 píxeles. Es como si sólo tuviesemos un ojo con capacidad para ver sólo 1 pixel. Al darle al botón SW2 visualizamos el siguiente, y así sucesivamente......

Vémos como el LED "se mueve" de izquierda a derecha. Es por efecto del contador. Este contador que nos indica QUE LED VISUALIZAR (sólo 1 de los 4 cada vez). Nos indica el LED ACTUAL. En el que tenemos puesto el FOCO. Este foco lo movemos con el pulsador SW2

Este contador que indica el LED ACTUAL y que tiene la capacidad de moverse hacia la derecha, lo denominamos raster, porque va "rastreando" cada uno de los leds, los va recorriendo uno a uno y permitiendo que se muestre su valor

La línea formada por LEDs, una vez recorrida entera, se llama scanline

Ahora hacemos que este proceso de escaneado del valor y su visualización en cada led se haga automáticamente. En vez del pulsador sw2 hacemos que se muestre un pixel cada vez, a la velocidad de 1Hz (un pixel/segundo)

(Ejemplo 5: 2024-09-6-Disp-1x4-05-scanline)

Sabemos que en la línea completa están todos los leds encendidos, pero que debido al raster sólo vemos 1 led cada vez
Ahora incrementamos la velcoidad del raster, para que se mueve a la derecha más rápidamente

(Ejemplo 6: 2024-09-6-Disp-1x4-06-scanline2)

A la frecuencia de 10Hz vemos que el led va mucho más rápido. Todavía seguimos viendo LEDs aislados...Subamos más la frecuencia.... por ejemplo a 20Hz!

(Ejemplo 7: 2024-09-6-Disp-1x4-07-scanline3)

Va más rápido, pero se sigue viendo.... Subimos a ....

(Ejemplo 8: 2024-09-6-Disp-1x4-08-scanline4)

Si metemos ahora 50*4 = 200Hz, lo que observamos es que.... NO HAY PARPADEO! NO VEMOS EL RASTER! AHORA VEMOS TODOS los LEDS encendidos!!!!!! PERO EN REALIDAD, sólo hay 1 cada vez!!!!!!!! Es un efecto nuestro el verlos todos encendidos!! NUESTROS SENTIDOS NOS ENGAÑAN!!!!!

EXPERIMENTO: Mirad los LEDs a través de la cámara del móvil..... SÍ QUE SE VE MOVIMIENTO O PARPADEO!!

Ahora simos la frecuencia al máximo.... Eso se consigue poniendo un 1 en Next: es decir, que en cada ciclo de reloj el raster se desplaza (a 12Mhz!).

(Ejemplo 9: 2024-09-6-Disp-1x4-09-scanline5)

Si ahora usamos el móvil... ¡YA NO VEMOS NINGUN PARPADEO NI MOVIMEINTO! Va tan rápido que ni siquiera la cámara del móvil lo detecta

A partir de ahora vamos a trabajar siempre con la máxima frecuencia...

Lo que tenemos ahora es un controlador de diplay que NO muestra la información en paralelo en los LEDs, sino que lo hace multiplexando los LEDs. Seleccionando sólo 1 led cada vez, usando el raster. Este controlador ahora se comportante EXACTAMENTE IGUAL QUE un Registro, es decir, que el ejemplo 1, PERO consumiendo muchísimo menos. De hecho, su consumo se aproxima al de 1 led encendido (ya que cada vez sólo hay 1 led encendido). NUNCA hay dos leds encendidos a la vez. Tenemos un controlador de bajo consumo!

(Ejemplo 10: 2024-09-6j-1x4-10-controlador)

Este es el mismo ejemplo que el original, pero usando este nuevo controlador LOW cost. Es un controlador más complejo, pero consume menos. Y en los casos de displays grandes no sería viable de otra manera. Si directamente ves este controlador, podrías pensar que... "joder, cómo te complicas la vida sólo para ver 4 pixeles. Pon un registro de 4 bits y listo".... Sí, es cierto. Pero esa solución ya sabemos que NO escala.

Señal de video

El segundo problema lo solucionamos realizando comunicación serie. En vez de llevar todas las señales en paralelo, hay que enviarlas en serie por el mismo cable, un bit a continuación del otro. Según se reciben los bits en la pantalla, se van refrescando en el led correspondiente

Partimos del último ejemplo del apartado anterior y nos llevamos la memoria de vídeo fuera.

Como ahora hay que transmitir el contenido de la memoria de vídeo en serie, es decir, bit a bit, usamos un registro de desplazamiento a la izquierda de 4 bits, que se desplaza a la misma velocidad que el raster: un bit por cada ciclo de reloj del sistema. Ahora nuestro sistema está formado por dos partes: En la derecha está la pantalla, que recibe como entrada la señal de vídeo (bit a bit). En la izquierda tenemos el controlador, que tiene almacenado el contenido de lo que queremos visualizar, en su memoria de vídeo, y lo envía en serie a la pantalla

El controlador tiene que "serializar" los datos. Y tiene que estar constantemente enviando los 4 bits del frame. Por eso hacemos que el registro está en bucle espacial: lo que se transmite se vuelve a llevar al registro para que el comienzo del siguiente frame se envíe el mísmo patrón. En este caso el patrón que enviamos es '1111': queremos encender todos los leds.

Inicialmente se están todos los leds apagados, y al apretar el pulsador se captura el nuevo valor, y se envía en serie. Todos los leds se encienden

(2024-09-6-Disp-1x4-11-controlador-serie)

Ahora bien... este diseño funciona (aunque al cargar otros valores se puede desincronizar, como veremos más adelante).... Sin embargo conceptualmente la memoria de vídeo no es algo "móvil". Son registros fijos, que se pueden escribir en cualquier momento. En nuestro caso queremos un registro de 4 bits, donde el MSB se corresponda con el pixel 1, el D2 con el pixel 2, el D1 con el pixel 3 y el D0 con el pixel 3

Así que lo vamos a separar. Por un lado ponemos el registro de memoria de video, y por otro un circuito "serializador", que van enviando los bits uno a uno. Este circuito serializador lo construimos examente igual que el raster que ya tenemos. Ahora tenemos dos raster, uno para selecionar los leds a activar, y otro para escanear los bits a visualizar

(2024-09-6-Disp-1x4-12-controlador-serie)

Este circuito funciona perfectamente. Podemos cargar en la memoria de vídeo lo que queramos en cualquier momento, y se refrescará en los LEDs. PERO siempre y cuando los dos raster estén sincronizados.

En este otro ejemplo NO están sincronizados, y por eso se ve el dato "Desplazado"

(2024-09-6-Disp-1x4-13-controlador-serie)

En este cuaderno técnico tanto el controlador como la pantalla están dentro de la misma FPGA, y no hay que tirar ningún cable serie hacia fuera. Por ello, no hace falta tener 2 rasters... sino que usamos uno para ambas partes del circuito:

(2024-09-6-Disp-1x4-16-controlador-serie)

Usando el controlador

Para comprobar el funcionamiento hacemos una generación de secuencia manual

(2024-09-6-Disp-1x4-15-controlador-serie)

Matriz 2x2

El display que hemos visto de 1x4 LEDs tiene un total de 4 leds, y están colocados en una linea horizontal. Podríamos construir una placa en la que los dos primeros se pongan en la parte superior, y los dos siguientes en la parte inferior, formando una pantalla cuadrada de 2x2. La manera de enviar información sería exactamente igual que el display 1x4, usando exactamente el mismo controlados. La única salvedad es que ahora los bits no van en linea

Así por ejemplo, para crear esta secuencia de 2 estados:

*
 *

y

 *
*

Habría que meter en el registro los valores: 'b1001 en el primer registro y 'b'0110 en el segundo. Pero la transmisión y funcioamiento del controlador es igual: Hay 4 bits que transmitir

Sin embargo, si tenemos matrices con más leds, por ejemplo una de 4x4, que tiene 16 leds en total, necesitaríamos un raster de 16 biestables, para seleccionar individualmente cada led: Recordemos que hay que tener sólo 1 led encendido cada vez. Ahora, en vez de en línea se ponen en forma matricial, pero el funcionamiento es igual

PERO, si en el circuito agrupamos los recursos de otra manera, nos ahorramos biestables. En vez de un raster de 16 biestables, usamos dos: uno para las filas (coordenada y), de 4 biestables, y otro para las columnas (coordenada x), también de 4 biestables. Según la matriz es cada vez más grande, el ahorro es mayor

En el caso de una matriz de leds de 2x2 no hay ahorro. Sin embargo vamos a utilizar esta técnica de dividir en filas y columnas para que sea escalable. Todo lo aprendido con la matriz de 2x2 nos servirá para la de 4x4, 8x8, etc...

Lo primero es colocar los leds en forma de matriz (explicar el hardware de esto)

Una vez que lo tenemos hacemos la primera prueba. Vamos a encender el primer led: el de la esquina superior izquierda (El LED 0,0)

(2024-09-6-Matrix-2x2-Test1-un-led.ice)

En el siguiente ejemplo colocamos un contador unario módulo 2 para las columnas. Cada vez que este contador llega a su valor máximo y se aprieta de nuevo el pulsador, queremos que se incremente un segundo contador módulo 2 para las filas. De esta forma, apretando SW2 recorremos manualmente la matriz, encendiedo el led correspondiente

(2024-09-6-Matrix-2x2-Test03-raster-automatico-all.ice)

Ahora lo hacemos automático, a la velocidad máxima. Todos los leds se encienden (los 4)

En este otro ejemplo inyectamos la señal serie, utilizando puertas AND con las columnas y las filas. Hacemos que se enciendan todos los leds

(2024-09-6-Matrix-2x2-Test04-patron-all.ice)

Ahora llega el momento de meter un patrón, desde la memoria de vídeo. Por simplicidad utilizamos un registro de desplazamiento de 4 bits

(2024-09-6-Matrix-2x2-Test05-patron-all.ice)

También se podría dividor en dos registro, uno para la fila 0 y otro para la fila 1

(2024-09-6-Matrix-2x2-Test06-patron.ice)

Lo siguiente es dividirlo en un registro para la memoria de vídeo y un raster para serializar. Esta memoria de video de momento la implementamos de forma linea, como un registro de 4 bits. Se serializa y se envía a los LEDs

(2024-09-6-Matrix-2x2-Test07-patron.ice)

Ahora la memoria de video la descomponemos en sus 4 biestables, accesibles de manera independiente

La serialización es compleja.... Tengo que encontrar una manera más sencilla e intuitiva...

(2024-09-6-Matrix-2x2-Test08-patron.ice)

He encontrado una un poco más sencilla usando solo multiplexores. También es deserializador

(2024-09-6-Matrix-2x2-Test09-patron.ice)

En este ejemplo se muestra una secuencia en la matriz, de dos estados

(2024-09-6-Matrix-2x2-Test10-patron.ice)

Y en este se mete un cursor que se mueve arriba y abajo con cx y cy

(2024-09-6-Matrix-2x2-Test11-cursorx.ice)

El siguiente paso es escribir en la memoria de video un valor referenciado por la posición del cursor... Básicamente tengo que implementar una memoria de lectura/escritura en unario!

Lunes, 9-Septiembre-2024

Clone this wiki locally