Pantallas de vídeo. Fundamentos. Display de 1x4 LEDs - Obijuan/Cuadernos-tecnicos-FPGAs-libres GitHub Wiki
Descripción
Estudio de los fundamentos de los sistemas de vídeo, utilizando como ejemplo un display mínimo de 1x4 LEDs. Se diseñan 3 versiones del controlador, añadiéndose progresivamente nuevos elementos para explicar todos los conceptos relacionados. Finalmente se construyen tres aplicaciones más avanzadas: dos consolas binarias y un circuito de dibujo
- Icestudio: Todos los ejemplos se han probado con Icestudio-0.12. Usa esta versión o superior
- Ejemplos: Todos los ejemplos de este cuaderno técnico están accesibles en su repositorio en github
Contenido
- Introducción
- Display de 1x4 LEDs. Versión 1
- Ilusiones ópticas
- Display 1x4: Versión 2
- Display 1x4: Versión 3
- Componente Refresh 1x4
- Controlador paralelo
- Controlador de 4x1 bits
- Generación directa de la señal de vídeo
- Ejemplo 16: Señal de vídeo constante: Encender todos los LEDs
- Ejemplo 17: Señal de vídeo constante: Todos los LEDs parpadean
- Ejemplo 18: Señal de vídeo constante: Un LED encendido
- Ejemplo 19: Señal de vídeo constante: Dos LEDs encendidos
- Ejemplo 20: LEDs alternantes
- Ejemplo 21: LEDs alternantes (Manualmente)
- Dibujando un Cursor
- Combinación de señales de vídeo
- Aplicaciones
- Conclusiones
- Autor
- Licencia
- Atribuciones
- Enlaces
Introducción
Las pantallas son dispositivos que usamos para mostrar información. Antiguamente eran mecánicas, como las que había en los aeropuertos y estaciones de trenes (Y posiblemente todavía las siga habiendo en algunos sitios)
(Designed by macrovector / Freepik [1])
En la actualidad se usan Pantallas electrónicas. Ejemplos típicos de estas pantallas son: Televisiones, pantalla de móviles, monitores, paneles de LEDs. Se caracterizan porque son discretas. Las imágenes que muestran están formadas por diminutos puntos llamados píxeles
Las pantallas en color tienen los 3 píxeles básicos de color agrupados: rojo, verde y azul (RGB). Al brillar cada uno con su propia intesidad, se generan todos los colores. Por el contrario las pantallas monocromo tienen todos sus píxeles de un único color
Cuantos más píxeles haya, mejor resolución tendrá la pantalla y las imágenes se mostrarán más definidas. Encontramos pantallas con resoluciones desde unos pocos píxeles hasta millones de ellos. Aquí se recopilan algunas, para hacernos una idea
- Ultra Alta definición (UHD)
Nombre | Resolución | Número de píxeles (aprox) |
---|---|---|
8K | 8192 x 4320 | 35 Millones |
4K | 4096 × 3112 | 12 Millones |
Las pantallas de Ultra Alta definición tienen decenas de millones de píxeles. Son las que se utilizan en las televisiones grandes. Ya hay muchos canales que retransmiten en 4K
- Alta definición (HD)
Nombre | Resolución | Número de píxeles (aprox) |
---|---|---|
Full HD | 1920 × 1080 | 2 Millones |
HD | 1280 x 720 | 1 Millón |
Las pantallas de HD tienen del orden de Millones de píxeles. La resolución Full HD son las que típicamente se usan para los monitores de los ordenadores. Por ejemplo, es la resolución que tengo en la pantalla del portátil con el que escribo este cuaderno técnico
- Década de los 80: Monitores PC
Nombre | Resolución | Número de píxeles (aprox) |
---|---|---|
XGA | 1024 x 768 | 800 mil |
SVGA | 800 x 600 | 500 mil |
VGA | 640 x 480 | 300 mil |
CGA | 320 x 200 | 64 mil |
Previamente a la alta definición, las pantallas tenían resoluciones estándares del orden del centenar de millón de pixeles. La VGA (640x480) era una de las más extendidas. A principios de los 80, con la llegada del IBM PC, la resolución era de 320 x 200. Había monitores en color (CGA) y otros en monocromo, que típicamente eran de color verde
- Ordenadores y consolas retro
Nombre | Resolución | Número de píxeles (aprox) |
---|---|---|
ZX Spectrum | 256 x 192 | 50 mil |
Atari 2600 | 160 x 190 | 30 mil |
Muchos ordenadores de 8 bits de finales de los 70 y principios de los 80 tienen en torno a la Decena de millares de píxeles. Como son resoluciones bajas, se pueden ver perfectamente los píxeles
- Pantallas pequeñas
Nombre | Resolución | Número de píxeles (aprox.) |
---|---|---|
Pantalla OLED SSH1106 | 128 x 64 | 8000 |
Pantalla LCD 16x2 caracteres | 80 x 14 | 1000 |
En el siguiente escalón están las pantallas pequeñas, que tienen millares de pixeles. Las pantallas OLED son muy pequeñas en tamaño, y típicamente tienen una resolución de 128 x 64. Las pantallas LCD de caracteres son más antiguas. Tienen espacio para dos filas de 16 caracteres. Cada carácter es de 5x7 píxeles
- Paneles de LEDs
Nombre | Resolución | Número de píxeles |
---|---|---|
Panel de 32 x 32 LEDs | 32 x 32 | 1024 |
Pantalla en Cruz para Farmacias | 32 x 32 | 1024 |
Panel cercanias Renfe | 96 x 8 | 768 |
Luz semáforo (circular) | círculo | 171 |
Pantalla ascensor | 12 x 8 | 96 |
Arduino UNO R4 | 12 x 8 | 96 |
Matriz de 8 x 8 | 8 x 8 | 64 |
Placa IceFun | 8 x 4 | 32 |
Placa Microbit | 5 x 5 | 25 |
Display 7 segmentos | ---- | 8 |
Los paneles LED son las pantallas con resoluciones más bajas. Cada LED es un pixel. El panel estándar es uno de 32x32 y tiene 1024 LEDs. Se pueden construir pantallas mucho más grandes mediante su unión. Por ejemplo, en la figura vemos una cruz de una farmacia que está compuesta por 5 paneles de 32x32
Los letreros luminosos de muchas estaciones también usan paneles LEDs. Por ejemplo en las estaciones de Renfe Cercanías de Madrid hay muchos paneles de información con capacidad para mostrar mensajes de 16 caracteres. Cada carácter se forma mediante una matriz de 6x8 LEDs, lo que en total nos da un total de 768 LEDs
Las luces de los semáforos actualmente también están formadas por LEDs. En este caso la forma es circular, y cada luz tiene una media de 170 LEDs. Ya vamos por el orden de las centenas
En Algunos ascensores hay pantallas que tienen espacio para 2 caracteres de 6x8. El primero se usa para indicar si el ascensor sube o baja, y el segundo para indicar el piso (del 0 al 9). En total tienen 96 LEDs
Algunas placas incorporan una matriz de LEDs, para aprender a hacer efectos luminosos. La placa Arduino UNO R4 tiene una matriz de 12x8 LEDs (96 LEDs en total)
Una muy común es la matriz de 8x8 LEDs, que tiene 64 LEDs en total. Se puede combinar con otras para hacer pantallas más grandes. Ya vamos por pantallas que tienen decenas de LEDs
La placa IceFUN, que lleva una FPGA Libre, incorpora una matriz de 8 x 4 LEDs (32 LEDs) para controlarlos mediante un circuito digital. La placa Microbit BBC tiene una matriz de 5x5 LEDs
La pantalla con más baja resolución es el Display de 7 segmentos, que está formado por 8 LEDS (los 7 segmentos y el punto). En este caso los LEDs de los segmentos en realidad están alargados. Pero son un único LED, y se controlan igual que si fuesen LEDs normales
Aunque las pantallas son muy variadas en resolución, yendo desde Decenas de millones de píxeles (UHD) hasta unos pocos LEDs, los principios de funcionamiento son comunes a todas. Y son estos principios fundamentales los que vamos a estudiar en este cuaderno técnico
Por ello utilizaremos una pantalla de LEDs miuy básica, con una resolución de 1x4 píxeles, y con todos los LEDs del mismo color (pantalla monocromo)
Display de 1x4 LEDs. Versión 1
Comenzamos por el caso más sencillo. Una pantalla formada por una única línea de 4 LEDs. Este caso nos servirá para detectar los problemas, y endenter los porqués de la arquitectura de los controladores de las pantallas de mayores resoluciones
Este ejemplo de cutre pantalla de 4 píxeles (LEDs) nos servirá también para aprender la terminología y los conceptos de los sistemas de visualización de vídeo
Para implementar los 4 píxeles de nuestro cutre-display utilizamos 4 LEDs. Ya sabemos cómo conectarlos a la placa Alhambra-II, como vimos en el Cuaderno técnico 16: Conexión de LEDs en la Alhambra II. Placa AP‐LED8‐THT. En los ejemplos vamos a utilizar la placa AP-LED8-THT. Usamos los 4 LEDs de mayor peso e ignoramos el resto
Ejemplo 1: Puesta en marcha. Patrón constante
Vamos primero a mostrar el patrón 1101
en los LEDs, es decir, queremos que se enciendan los dos de la izquierda (D7 y D6), y el de la derecha (D4). Esto es muy fácil. Basta con hacer un circuito conectando directamente los bits 0
ó 1
al LED que corresponda. Este sería el esquema:
Con esto comprobamos si las conexiones funcionan. Este sería el circuito en Icestudio:
Lo cargamos y vemos el resultado:
Comprobamos que nuestro cutre-display de 4 píxeles funciona. ¡Ya tenemos el display 1x4 listo!
Memoria de Vídeo
Las pantallas se usan para mostrar información. Esta información está dentro del circuito, almacenada en algún lugar. Y en un momento determinado se muestra en la pantalla
En el ejemplo 1 estamos mostrando un patrón constante, que NO podemos cambiar. No es realmente un circuito útil. Necesitamos añadir un elemento de memoria que se cargue con la información a mostrar en el display. Y al que se le pueda escribir nueva información que modifique la anterior
En el display 1x4 esto lo hacemos añadiendo un Biestable D a cada LED. Tendremos por tanto 4 Biestables D. Cada uno de ellos contine la información que se está visualizando en el display. Y en cualquier otro momento se carga con el siguiente valor a mostrar. Estos Biestables son la memoria de Vídeo: Contienen la información que se está mostrando en el display en un instante dado
La señal write
es la que se usa para mostrar nueva información. Al activarla se escribe en la memoria de Video. Y como la salida de la memoria de vídeo está conectada directamente a los LEDs, se muestra la nueva información escrita. En el esquema se están usando números constantes, pero en realidad esta información podría venir de cualquier otra parte del circuito
Ejemplo 2: Escritura en memoria de Vídeo
En este ejemplo mostramos otra vez el patrón 1101
en los LEDs, pero a través de la memoria de vídeo del display 1x4. Para mostrar información en el display hay que escribirla en su memoria de vídeo asociada
Inicialmente la memoria de vídeo está limpia (todos los biestables a 0
) por eso todos los LEDs están apagados. Al apretar el pulsador SW1
se activa la señal de Write
y se escribe el patrón 1101
en la memoria de vídeo (biestables). Los LEDs del display muestran la nueva información
Este es el circuito en Icestudio:
(Ejemplos/Ej02-Disp1x4-patron-video.ice)
Como en este ejemplo la información que escribimos en la memoria de vídeo es siempre la misma, si volvemos a pulsaro SW1
no ocurrirá nada. Si apretamos reset, le memoria de vídeo vuelve a su estado inicial con todo ceros y se apagan los LEDs
En este vídeo de Youtube lo vemos en funcionamiento:
Con esto ya tenemos implementando un mini-controlador para nuestro cutre-display de 4 píxeles. Fácil, ¿No?
Analizando el controlador del display 1x4
El controlador que hemos diseñado tiene dos propiedades con gran repercusión:
- La conexión entre la memoria de vídeo y la pantalla es en PARALELO. Se utiliza un cable para cada LED
El sistema está formado por dos partes. Una es el controlador de vídeo, que de momento sólo incluye la memoria de vídeo. Y la otra es la pantalla física. Para unir ambas partes necesitamos tirar 4 cables. En nuestro ejemplo estos 4 cables son los que van de la Alhambra-II hacia la placa AP-LED8. Están implementados en los conectores D7-D4
Si esta pantalla 1x4 la queremos llevar a más distancia, habría que unir ambas partes con los 4 cables de datos más 1 de GND
Típicamente tenemos por un lado la pantalla, que incluye los elementos físicos que hacen de pixeles (LEDs en nuestro caso) y la electrónica. En el display 1x4 la pantalla la componen sólo LEDs. Por otro lado tenemos el dispositivo que queremos que muestre información. Ambos elementos se conectan por un cable
- El consumo es proporcional al número de LEDs. A más LEDs, mayor consumo
El consumo de la pantalla NO es constante, sino que varía en función de cuántos LEDs están encendidos. Si no encendemos ningún LED, nuestra pantalla 1x4 no consume. Si sólo encendemos 1 LED, el consumo será el que nos diga el fabricante que tiene ese LED. Consideraremos que ese consumo es de 1 uc: una unidad de consumo. Lo llamamos así porque para este análisis NO importa el valor exacto.
Ahora encedemos 2 LEDs. Como todos los leds son iguales (del mismo fabricante), su consumo individual es el mismo (1 uc). Y como están conectados en paralelo, su consumo es la suma de ambos, es decir, 2 uc
Si encendemos 3 LEDs, el consumo es de 3 uc. El caso peor, el de mayor consumo, es cuando TODOS los LEDs están encendidos. En este caso es de 4 uc
Problemas de escalado del controlador
El controlador para la pantalla 1x4 funciona. Es muy básico, pero con esta arquitectura podríamos sacar por esa pantalla cualquier cosa: información fija o animaciones
Sin embargo, si lo queremos usar para controlar pantallas con mayor resolución, aparecen Problemas de escalado. Vamos a analizar los dos problemas principales: el consumo y el cable de conexión. Debido a estos problemas, hay que elegir otra arquitectura para los controladores de vídeo
Problema de consumo
En los controladores paralelos hemos visto que el consumo aumenta proporcionalmente al número de LEDs
Supongamos que lo queremos usar para visualizar información en una pantalla con resolución de 32 x 32 LEDs. En total tiene 1024 LEDs. Su consumo, en el caso peor cuando TODOS los LEDs están encendidos, es de 1024 uc. Aproximadamente ¡¡¡1000 veces más de consumo que la pantalla 1x4!!!!. Como los LEDs consumen muy poco, aunque se multiplique por mil todavía el consumo podría ser aceptable...
Si ahora usamos una pantalla HD, con resolución de 1280 x 720 LEDs, tenemos casi ¡un millón de LEDs!. ¡¡El consumo se multiplica por 1 millón!!. No es viable este controlador. No escala. Hay que buscar otra arquitectura que escale mejor
¿Cómo lo solucionamos?
Problema del cable de conexión
PERO tenemos otro problema. Uno más trivial: El cable de conexión entre el controlador y la pantalla. Si queremos usar la pantalla de 32x32 LEDs, ¡Tendríamos que tirar 1000 cables!. El cable de conexión tendría en su interior 1000 cables, uno para cada LED. Sería un cable gordo que tendría una sección de aproximadamente 3cm. Es gordo, pero todavía es abordable
Sin embargo si nos vamos ahora a HD, el cable gordo tiene en su interior ¡¡casi 1 millón de cables!!. Tendría un diámetro de aproxamente ¡¡¡1 metro!!!. Esto es Inviable
¿Cómo lo solucionamos?
Ilusiones ópticas
Nuestro sistema visual es muy complejo. Lo que percibimos no sólo depende de los ojos, sino también del cerebro y de cómo lo interpreta. Debido a eso, NO percibimos la realidad exactamente como es. Construimos una realidad diferente, distorsionada
Una de estas ilusiones es la de Percibir objetos que NO están presentes. Su equivalente en el mundo de la fotografía se llama Light painting. Si el tiempo de exposición es muy alto y movemos una fuente de luz, no se observa un punto de luz sino una línea continua de luz. En esta foto se muestra un ejemplo, en el que se está pintando con una bengala
(Fuente: Robert Knapp, Wikipedia)
Esa misma ilusión nos ocurre a los humanos, sin necesidad de usar una cámara de fotos. Para reproducirla basta con que tengas un puntero láser y lo apuntes contra una pared clara y lisa. Si mueves el puntero lentamente, lo que vemos es un punto de luz, en movimiento. Pero si ahora lo empiezas a mover rápidamente en círculos, percibirás la circunferencia completa, como si de verdad existiese ese "halo".
En realidad sólo hay un único punto de luz, moviéndose rápidamente. Nuestro sistema visual NOS ESTA ENGAÑANDO
¿Cuánto de rápido hay que mover el puntero para que aparezca esta ilusión óptica? Esto es algo que se puede cuantizar. Y lo haremos experimentalmente en los siguientes apartados
Esta ilusión óptica es la que usaremos para solucionar los dos problemas que tenemos 😎
Simulando el puntero láser
Vamos a simular el puntero láser, para provocar la aparición de la ilusión óptica, y poder estudiarla
Al apretar el botón del puntero láser, se envía el rayo incidente que impacta en un punto de la pared. La Luz se refleja en la pared en las diferentes direcciones. Es esta luz reflejada la que nos permite ver el punto en la pared
Si no hubiese reflejo, no veríamos el punto. Este punto de reflejo de la luz es el que vamos a modelar con un LED. Al fin y al cabo ambos son Emisores de luz. Uno debido a los reflejos. El otro por emisión directa
Si con este punto reflejado se produce la ilusión óptica al moverlo rápidamente, es razonable pensar que ocurrirá lo mismo con el LED. Vamos a probarlo
Si movemos el puntero láser lentamente, veremos el punto completo. El movimiento que hacemos con la mano es continuo, por lo que el punto se mueve también de forma continua. Pero vamos a suponer que se mueve de forma discreta, saltando de una posición fija a la siguiente. En total tenemos 4 posiciones, numeradas de la 0 a la 3
Ahora sustituimos los puntos de luz reflejada del puntero láser por los LEDs, y simulamos el movimiento del punto, encendiendo y apagando los LEDs, como vemos en esta animación
¡Tenemos un LED en movimiento! Ahora tenemos que implementarlo en un circuito
Ejemplo 3: Un LED en movimiento
Ya sabemos cómo hacer un circuito como ese. De hecho ya lo hemos hecho en el Cuaderno técnico 18: Fundamentos. Sistema Unario, al implementar contadores cíclicos one-hot
Para lograr ese movimiento sólo hay que conectar 4 Biestables D en serie, y realizar un bucle espacial entre el último y el primero. Utilizamos un Corazón para actualizar los LEDs a una frecuencia baja. Por ejemplo 1Hz
Usamos codificación one-hot, por lo que sólo habrá un LED encendido en cada momento. Este es el circuito en Icestudio:
En este vídeo de Youtube lo vemos en funcionamiento:
Ya tenemos nuestro puntero láser simulado, a baja velocidad: es un punto rojo que se mueve. Lo siguiente que haremos será caracterizar este movimiento usando parámetros del circuito, para entender bien lo que está sucediendo
Parámetros del movimiento
Tenemos una pantalla formada por una única línea de N
LEDs (N
=4 en el ejemplo 3). Estos LEDs son nuestros píxeles. Tenemos que uno de los píxeles (LEDs) se mueve hacia la derecha, a velocidad constante. Observando el movimiento (ejemplo anterior) vemos que en cada momento SOLO hay 1 LED encendido cada vez
Definimos los siguientes parámetros y señales asociados a este pixel en movimiento:
-
Reloj del pixel (Pixel clock): Es la señal periódica que se usa para actualizar la visualización de los píxeles. En el ejemplo 3 la hemos denominado
Next
. Con cada tic del pixel clock el pixel avanza una posición a la derecha -
Tiempo de pixel,
Tp
: Es el periodo del pixel clock. Nos indica el tiempo que está encendido el pixel (LED) -
Frecuencia de pixel,
fp
: Es la inversa del tiempo de pixel.fp = 1 / Tp
. Nos indica la cantidad posiciones que avanza el LED en 1 segundo. Lo medimos en Hz, aunque su significado son posiciones por segundo. Así, si el pixel clock tiene una frecuencia de 1 Hz, significa que el LED avanza 1 posición cada segundo. Si su frecuencia es de 2Hz, entonces avanza el doble de rápido: a 2 posiciones por segundo. A mayor frecuencia, mayor velocidad
En esta figura se muestra el pixel clock, el parámetro Tp
y el estado de los 4 LEDs según se propaga el movimiento
El LED vuelve al comienzo al llegar al extremo derecho, debido al bucle espacial. Hay una repetición. El LED da vueltas y vueltas. Definimos los siguientes parámetros y señales asociados a esta repetición:
-
Reloj de pantalla (Screen clock): Es la señal periódica que indica con un tic cuándo el LED ha vuelto a la posición inicial (el comienzo de la pantalla). La posición 0
-
Tiempo de pantalla,
Ts
: El tiempo que tarda el pixel en recorrer la pantalla completa (y volver al origen) -
Frecuencia de pantalla,
fs
: Número de veces que el pixel recorre la pantalla completa en un segundo. Lo medimos en Hz, aunque su significado son pantallas por segundo.
Si por ejemplo fs
es de 10Hz, significa que el LED recorre 10 pantallas en un segundo, y Ts
es 1/10 = 100ms. Es decir, que el LED tarda 100ms en recorrer una pantalla completa
En esta figura se muestra el screen clock junto al resto de señales para compararlas, cuando el LED da 2 vueltas (pantalla 0 y pantalla 1)
Como vemos en la figura, el tiempo de pantalla está relacionado con el tiempo de pixel. Las ecuaciones son:
- $T_s=N.T_p$
Como en la pantalla hay N LEDs y cada LED está encendido un tiempo $T_p$, tardará en total $N.T_p$
- $f_s=\frac{f_p}{N}$
La frecuencia de pantalla es siempre N veces menor que la de pixel
Experimentos: Reproduciendo la ilusión óptica en los LEDs
Partimos del ejemplo 3, en el que se mueve el LED con una frecuencia de pixel de 1Hz. Como se mueve muy despacio, no hay ilusión óptica. Estos son los valores de todos los parámetros:
$f_p$ | $T_p$ | $T_s$ | $f_s$ | Resultado |
---|---|---|---|---|
1Hz | 1s | 4s | 0.25Hz | Sin ilusión óptica |
2Hz | 0.5s | 2s | 0.5Hz | Sin ilusión óptica |
4Hz | 250ms | 1s | 1Hz | Sin ilusión óptica |
5Hz | 200ms | 800ms | 1.25Hz | Sin ilusión óptica |
10Hz | 100ms | 400ms | 2.5Hz | Sin ilusión óptica |
20Hz | 50ms | 200ms | 5Hz | Sin ilusión óptica |
40Hz | 25ms | 100ms | 10Hz | Sin ilusión óptica |
80Hz | 12.5ms | 50ms | 20Hz | Parpadeo de todos los LEDs a la vez |
100Hz | 10ms | 40ms | 25Hz | Parpadeo de todos los LEDs a la vez |
160Hz | 6.25ms | 25ms | 40Hz | ¡Línea fija! Todos los LEDs encendidos |
200Hz | 5ms | 20ms | 50Hz | ¡Línea fija! Todos los LEDs encendidos |
El parámetro importante es la frecuencia de pantalla ($f_s$). Observamos que para la medición de 40Hz, ya se ven todos los LEDs encendidos. No hay parpadeo. Según las condiciones de luminosidad sería posible todavía notar un ligerísimo tintineo
A partir de una frecuencia de pantalla de 50Hz Ya no se nota absolutamente nada. Esta es la frecuencia usada típicamente en las televisiones y monitores retros. Es nuestra frecuencia de corte. En todo sistema de vídeo, tenemos que utilizar una frecuencia de pantalla mayor o igual a 50Hz
[!NOTE]
Esta frecuencia de corte de 50Hz es para Los humanos. Si usamos una cámara para ver la pantalla, sí aparecerá tintineo o parpadeos aleatorios. Cuanto mayor sea la frecuencia de pantalla, más estática estará la imagen de la pantalla al verla a través de cámaras
Ejemplo 4: Máxima frecuencia de pantalla
En este ejemplo se recorren todos los LEDs a la máxima velocidad. Se utilizan biestables D del sistema, que se actualizan a la frecuencia de 12Mhz (El pixel clock es de 12Mhz)
Estos son los valores de los parámetros:
$f_p$ | $T_p$ | $T_s$ | $f_s$ |
---|---|---|---|
12MHz | 83.3ns | 333ns | 3Mhz |
La frecuencia de pantalla es de 3Mhz, por tanto la ilusión óptica se produce (incluso a través de la cámara del móvil), y se ven todos los LEDs encendidos
Este es el circuito en Icestudio:
Este es el resultado:
Los 4 LEDs están encendidos... pero en realidad... ¡Sólo hay uno moviéndose muy rápido!
La frecuencia de pantalla es de 3Mhz. ¡Es una velocidad altísima!. ¡Recorre 3 Millones de pantallas por segundo!
Intensidad del LED en movimiento
Vamos a fijarnos en el tiempo de LED y en el Tiempo de pantalla, de un único LED, para el display de 1x4 LEDs. Como referencia tomaremos el primer LED (LED 0). La pinta que tiene la señal es como se muestra en esta figura:
La señal es un PWM, como vimos en el Cuaderno Técnico 1: Unidad de PWM de frecuencia aproximada. El LED está encendido un Tiempo Ton, y apagado durante Toff. Por tanto, el ciclo de trabajo lo calculamos así:
$$D = \frac{T_{on}}{T_{off}} $$
Por otro lado, el tiempo de encendido $T_{on}$ es igual al tiempo de pixel $T_p$, y el tiempo de pantalla $T_s$ es $4.T_p$. Lo que nos da:
$$D = \frac{T_{on}}{T_{off}} = \frac{T_p}{T_s} = \frac{T_p}{4.T_p} = \frac{1}{4} = 25% $$
Es decir, el ciclo de trabajo es del 25%
En general, si tenemos una pantalla de N LEDs, el tiempo de pantalla será $T_s = N.T_p $, y por tanto, el ciclo de trabajo es $\frac{1}{N}$
El ciclo de trabajo nos indica la cantidad de energía transmitida al LED, y nos da una idea del brillo del LED. Lo que vemos es que al aumentar el número de LEDs, la intesidad será menor
Display 1x4: Version 2
Aplicando los conocimientos que tenemos sobre las ilusiones ópticas ya podemos solucionar los dos problemas que teníamos: Consumo y cableado. Y hacer así escalables los controladores
Reduciendo el consumo: Imagen rasterizada y refresco
Gracias a la ilusión óptica, podemos mostrar información en la pantalla ENCENDIENDO SOLO 1 LED cada vez. Con esto logramos un consumo muy bajo. Técnicamente el consumo es sólo el de un LED (el LED activo)
Ahora tenemos un nuevo elemento: el ráster (Rasterizador) que nos señala el pixel activo. Es el pixel que debe tomar el valor correspondiente de la memoria de vídeo
Para comprender bien sus fundamentos, este ráster lo implementamos usando el sistema unario. Cada pixel de la salida de vídeo lo habilitamos con una puerta AND, activada por los bits del ráster. De esta forma el LED correspondiente se pone a 1
si tiene un 1
en su memoria de vídeo y es el LED activo (está señalado por el ráster)
Esta es la arquitectura del nuevo controlador
La memoria de vídeo contiene el valor 1101
que es el que se quiere visualizar en los LEDs. Si se activa la señal write
se carga un nuevo valor. El ráster está en continuo movimiento, a la velocidad de 12Mhz (pixel clock). Inicialmente (lo mostrado en la figura) el ráster está seleccionando el primer pixel. Como el valor del primer píxel es 1
, y es el pixel activo, mediante la AND correspondiente se activa. Por ello vemos cómo el primer LED está encendido (y el resto apagados)
En esta animación se muestra el funcionamiento, a baja velocidad
El raster recorre todos los LEDs, uno a uno. Gracias a la AND se muestra en el pixel correspondiente el valor que tiene en la memoria de vídeo. Cuando se muestra a alta velocidad, debido a la ilusión óptica, en la pantalla vemos el valor 1101
Este es el circuito en Icestudio
(Ej05-Disp1x4-v2-patron-video.ice)
En este vídeo de Youtube lo vemos en funcionamiento:
El comportamiento es igual al del controlador original, PERO se ha solucionado el problema del consumo. Para ello hemos tenido que añadir el ráster, que indica el LED activo en cada momento. La imagen se dibuja píxel a píxel. Por eso se denomina imagen rasterizada. El ráster se encarga de recorrer los bits de la memoria de vídeo y de refrescar el estado de los LEDs. Por ello hablamos de la tasa de refresco de la pantalla, o de la frecuencia de la pantalla, medido en frames por segundo. En este ejemplo cada frame son 4 LEDs. La tasa de refresco es de 3 Millones de frames por segundo (3.000.000 fps)
Cableado: Vídeo serializado
Lo siguiente es solucionar el problema número 2: El cableado. En el controlador que tenemos hasta ahora lleva la información desde la memoria de vídeo hasta los LEDs (pantalla) en paralelo. Para pocos píxeles está bien, pero NO si tenemos muchos
Dado que ahora sólo hay un píxel activo cada vez, ya NO es necesario llevar esta información en paralelo. La podemos llevar en serie, usando un único cable
Esta es la nueva arquitectura
La memoria envía en serie los 4 valores para los LEDs. El ráster de la pantalla selecciona cíclicamente los LEDs, para determinar el LED activo, y es ese LED activo el que recibe el bit serie
Este es el circuito en Icestudio:
(Ej06-Disp1x4-v2-patron-video.ice)
La memoria serie está implementada mediante un registro de desplazamiento a la derecha. Cada ciclo de reloj se envía un bit. El patrón de bits serie que se envía es 1101
. Como es un registro de desplazamiento a la derecha, el primer bit que se envía es el de más a la derecha, por lo que hay que inicializarlo con el valor 1011
Este es el resultado. Observamos el valor 1101
en los LEDs
En este nuevo controlador ya está solucionado el problema del cableado. Ahora sólo hay un único cable entre la memoria de vídeo y la pantalla. La información que se envía por este cable serie se denomina señal de vídeo
Señal de vídeo
La señal de vídeo es una señal serie que lleva la información desde la memoria de vídeo a la pantalla. Contiene el valor de cada uno de los píxeles para cada frame. En nuestro caso del display de 1x4 LEDs, la señal lleva la información de los píxeles 0,1,2 y 3, para el frame0, luego para el frame1, el 2, etc...
Para el caso del controlador del ejemplo 6, en el que se visualiza el patrón 1101
en los LEDs, la señal de vídeo tiene esta pinta:
Ejemplo 7: Visualizando la señal de vídeo en el LEDOSCOPIO
La señal de vídeo la podemos visualizar fácilmente con el LEDOSCOPIO. Aprovechamos además para simplificar el circuito, utilizando registros de desplazamiento
La pantalla la simplificamos utilizando una puerta AND de habilitación. En vez de usar 4 puertas AND independientes, usamos una de 4 bits con entrada de habilitación. Hace la misma función que el circuito anterior (son equivalentes): deja pasar el bit serie al LED activo, indicado por el ráster
El ráster es un registro de desplazamiento a la derecha, a la velocidad del reloj del sistema, conectado en anillo. Su salida en paralelo indica, en unario (one-hot), cuál es el LED activo
Finalmente la memoria seria se implementa con un registro de desplazamiento a la izquierda, a la velocidad del reloj del sistema
(Ej07-Disp1x4-v2-LEDoscopio.ice)
El circuito es equivalente al ejemplo 6, pero mucho más compacto.
La señal de video
la metemos en el LEDOSCOPIO para visualizarla en los LEDs. Este es el resultado:
Ejemplo 8: Visualizando la señal de vídeo en el analizador IceRok
La señal de vídeo del display 1x4 tiene frames muy pequeños: de sólo 4 bits (1 bit por pixel). Con el LEDOscopio es suficiente para verlo. Sin embargo, para señales de vídeo con frames mayores, necesitamos otra manera de visualización: El analizador lógico
Para saber cuándo termina un frame, y por tanto, saber que en el ciclo siguiente empieza un frame, utilizamos el bit de más a la derecha del ráster. Lo denominamos frame
, precisamente porque nos indica el fin del frame
Capturamos ahora dos señales: la de video
y frame
. Esto es el resultado:
Comprobamos que aparece la señal vídeo esperada. Cada frame tiene el valor 1101
. Y todos los frames son iguales (porque el patrón que se muestra en los LEDs es fijo)
Memoria de vídeo serie
En el controlador actual para el display 1x4, hemos implementado la memoria de vídeo mediante un registro de desplazamiento, para que el dato se serialice y se envíe bit a bit hacia la pantalla
Pero hay un problema. El valor almacenado en esta memoria NO es un valor fijo, sino que está constantemente desplazándose. ¿Qué biestable se corresponde con el pixel 0? Inicialmente el de la izquierda, pero en el instante siguiente contiene el pixel 1, y luego el 2... Y si ahora queremos meter otro valor en el pixel 0... ¿En qué biestable lo cargamos?
Lo que nos interesa es tener una memoria de vídeo fija, que se sepa en todo momento qué biestable está asignado a qué pixel, para poderlo modificar cuando queramos. La solución es utilizar un registro para almacenar el valor, y un circuito para serializar este valor, enviándolo bit a bit hacia la pantalla
Ejemplo 9: Memoria de vídeo serie con ráster
Este es el nuevo circuito en Icestudio
(Ej09-Disp1x4-v2-memoria-video.ice)
Ahora la memoria se divide en 3 elementos independientes:
-
Un registro (Implementado mediante 4 Biestables D) que almacena el valor que se quiere visualizar. Este es el registro que hay que sobreescribir para dibujar otro patrón en los LEDs del display. En el ejemplo inicialmente el valor es 0, y al apretar el pulsador SW1 se carga con el nuevo patrón:
1101
-
Un serializador. Es el elemento que toma el valor del registro y lo envía bit a bit por la señal de vídeo serie. Como estamos trabajando en el sistema unario, para centrarnos en los fundamentos, este serializador está formado por 4 multiplexores 2-1 en cascada
-
Ráster de memoria: Es un contador unario (one-hot) que nos indica qué pixel de la memoria de vídeo es el pixel actual que hay que enviar por la señal de vídeo. Primero está seleccionado el pixel 0, luego el 1, luego el 2, etc...
En este vídeo de Youtube lo vemos en funcionamiento:
Inicialmente el display está apagado. Al apretar el pulsador SW1 se carga el valor 1101
en la memoria de vídeo y se visualiza en la pantalla
Observamos que ahora tenemos 2 Rásters: uno para la memoria de vídeo y otro para la pantalla. Su misión es la misma: señalar el elemento activo (usando el sistema unario-one-hot). En el caso del ráster de memoria se selecciona el valor del pixel actual. Se empiza por el pixel0, luego el 1, etc... La misión del ráster de pantalla es la de seleccionar el LED activo. Es el LED al que se le aplica el valor señalado por el ráster de memoria
Ejemplo 10: Memoria de vídeo serie con ráster (Implementación 2)
Este es el mismo ejemplo 9: la memoria de vídeo con ráster, pero implementando usando registros de desplazamiento y un multiplexor 2-1 unario. El raster de memoria es exactamente igual que el de pantalla: un registro de desplazamiento del sistema a la derecha
(Ej10-Disp1x4-v2-memoria-video.ice)
Ambos circuitos, de los ejemplos 9 y 10, son equivalentes, y ocupan los mismos recursos. Pero este último es más compacto
Ya, por fin, tenemos un controlador final. Incluye todos los conceptos que necesitamos para escalarlo a pantallas más grandes: Memoria de vídeo, señal de vídeo, refresco, frame, ráster...
El problema de la sincronización
En la arquitectura de nuestro controlador tenemos ahora 2 rásters: Uno para seleccionar el valor del pixel de la memoria de vídeo, y el otro para indicar el pixel activo en la pantalla. Para que se puedan visualizar correctamente patrones en la pantalla, ambos rásters tienen que estar sincronizados
Rásters sincronizados
Cuando los dos rásters están sincronizados, todo funciona correctamente. En esta animación se han representado los dos rásters mediante dos flechas. El ráster de la izquierda es el de la memoria de vídeo. Recorre cada uno de los bits almacenados. El ráster de la derecha es la flecha que recorre los LEDs de la pantalla
Como ambos rásters están sincronizados, el patrón de la memoria de vídeo 1101
se visualiza correctamente en los LEDs de la pantalla: 🔴🔴⚫🔴
Rásters NO sincronizados
Sin embargo, si los rásters no están sincronizados, la imagen mostrada en los LEDs NO será la misma que la que se encuentra en la memoria de vídeo. ¡El patrón saldrá desplazado!
En esta animación vemos lo que ocurre. El ráster 2 está adelantado con respecto al ráster 1. Debido a ello, cuando el ráster 1 está "señalando" el dato del pixel 0, el ráster 2 está "apuntando" al pixel 1, por lo que se enciende el LED incorrecto
El resultado de esta desincronización es que el patrón de la memoria de vídeo 1101
se visualiza en la pantalla como 🔴🔴🔴⚫
Ejemplo 11: Efecto de los rásters NO sincronizados
Este es el mismo ejemplo que el 10, pero los rásters están desincronizados para apreciar el efecto en los LEDs
Este es el resultado. Comprobamos que efectivamente el valor que se visualiza es 🔴🔴🔴⚫ en vez de 🔴🔴⚫🔴
Manteniendo la sincronización
¿Cómo mantener la sincronización entre la memoria de vídeo y la pantalla? Necesitamos enviar una señal adicional de sincronización, que llamaremos vsync
(Syncronización vertical). Esta señal en realidad ya la hemos usado antes: es la que indica cuándo finaliza el frame, y por tanto, que en el siguiente ciclo comienza un frame nuevo
Entre la memoria y la pantalla hay 2 hilos, uno con la señal de vídeo (video
) y otra con la señal de sincronización (vsync
)
La señal de sincronización es fácil de generar: la tomamos del bit más a la derecha del ráster 1. Cuando la pantalla la recibe, reinicia el ráster 2 para que apunte al pixel 0. A partir de ahí ya los dos rásteres permanecerán sincronizados
En esta animación se muestra el proceso de sincronización. Inicialmente el ráster 1 y el ráster 2 están desincronizados (por 2 píxeles). Cuando el ráster 1 llega al pixel 3, se activa la señal de sincronización, y el ráster 2 retorna al pixel 0, por lo que quedan sincronizados
En la segunda vuelta del ráster 1 ambos rásteres ya están sincronizados, apuntando a los mismos píxeles. Y lo mismo en la tercera vuelta. Ahí es donde se para la animación, y se vuelve a comenzar
El resultado es que los rásteres se sincronizan, aunque hay un frame al comienzo que saldrá distinto
Ejemplo 12: Implementación de la sincronización
En este ejemplo se muestra la implementación de la sincronización. Inicialente los dos ráster están desincronizados. El ráster 2 se actualiza con el valor correcto cuando se recibe la señal vsync
. Está implementando mediante un registro de desplazamiento a la derecha del sistema, con entrada de load
. La señal de vsync
está conectada directamente a load
Al ejecutarse, efectivamente, se ve el valor correcto en los LEDs: 🔴🔴⚫🔴
Display 1x4: Versión 3
Ya tenemos todos los conocimientos para construir el controlador de vídeo final, para una pantalla de 1x4 LEDs. Construiremos 4 controladores diferentes, todos basados en las ideas discutidas previametne
En todos ellos usaremos un único ráster, para seleccionar el LED activo de la pantalla, y determinar el valor del pixel activo. De esta forma no tenemos problemas de sincronización. Esto lo podemos hacer porque tanto la pantalla como la memoria de vídeo están en la misma FPGA (y no hay que tirar cables)
Componente refresh 1x4
Hay un elemento común a todos los controladores. Es el circuito de refresco de pantalla. Se encarga de recibir la señal de vídeo, demultiplexarla y mostrarla en los LEDs. Recordamos que la imagen que se muestra NO es fija, sino que sólo hay un LED encendido cada vez. Vemos una imagen fija por la ilusión óptica
Esta es la pinta que tiene nuestro circuito de refresco para la pantalla:
Como entrada recibe la señal de vídeo, compuesta por los frames de 4 bits. Como salida tiene los LEDs de la pantalla, en los que realiza el refresco. Además saca el valor actual del ráster de pantalla y la señal vsync
, para usarlo en el resto de controladores.
Este controlador está disponible en la colección IceLEDs
Implementación
Esta es la implementación del controlador:
El módulo incluye el ráster y la puerta AND de habilitación para activar el LED actual
Ejemplo 13: Lamp-test
En este ejemplo se encienden todos los LEDs, para comprobar que el circuito de refresco funciona correctamente.
En paralelo se coloca una pantalla de 4 LEDs sin refresco. Se activa/desactiva con el pulsador SW1
. De esta forma se puede comprobar que efectivamente el brillo de la pantalla de refresco es menor que la pantalla sin refresco
(Ej13-Disp1x4-v3-lamp-test.ice)
En este vídeo de Youtube lo vemos en funcionamiento:
Controlador paralelo
Este controlador ofrece una interfaz paralela de acceso a la pantalla, pudiendo escribir un valor de 4 bits directamente. Es el controlador más básico y sencillo. Al activarse su señal de escritura write
se almacena el valor y se muestra en la pantalla
El valor escrito se almacena en una memoria de vídeo 1x4 (Un registro de 4 bits) y se envía a los LEDs por refresco, usando un pixel clock de 12Mhz, lo que da un framerate de 3Mhz
Veremos dos implementaciones de este controlador: una con escritura directa y la otra sincronizada con vsync
Implementación 1
Esta es la implementación directa. Se usa un registro de 4 bits como memoria de vídeo
La escritura en la memoria de vídeo es asíncrona: se puede realizar en cualquier momento. El ráster puede estar en cualquier posición. Como esta pantalla es muy pequeña no se nota ningún efecto. Sin embargo, al realizar la escritura el ráster puede estar en mitad del frame, por lo que ese frame tendría un trozo del frame anterior y otro del nuevo
En Displays con muchos LEDs es algo que hay que tener en cuenta para que la imagen, o las animaciones mostradas, se vean perfectamente
Implementación 2
En esta segunda implementación la escritura asíncrona se realiza en un registro buffer intermedio. Cuándo se activa la señal vsync
el buffer se escribe en la memoria de vídeo. De esta forma siempre se muestra el frame completo, con independencia de cuándo se hace la escritura en el controlador
Esta implementación depende del controlador de la implementación 1
Ejemplo 14: Secuencia de dos valores en los LEDs
En este ejemplo se prueba el controlador paralelo con escritura sincronizada (implementación 2). Se genera una secuencia de 2 valores, que cambia cada segundo. El primer valor escribe en el ciclo 0, al arrancar el circuito
(Ej14-Disp1x4-v3-sequence.ice)
En este vídeo de Youtube lo vemos en funcionamiento:
Controlador de 4x1 bits
En este controlador se acceden a los pixels de la pantalla individualmente. Cada pixel está mapeado en una dirección (0 - 3). La interfaz con este controlador es la misma que la de una memoria de 4x1 bits
Para trabajar en lo fundamental, usaremos una memoria con direcciones en unario (one-hot). En ella, la dirección del primer pixel es 0001
, y los siguientes píxeles están en 0010
, 0100
y 1000
Los controladores de acceso a pixel son los que nos permiten hacer "dibujos". Aunque en un display 1x4 apenas se puede hacer nada
Implementación
Para la implementación se utiliza una memoria 4x1 dual, con direcciones unarias. El ráster se utiliza para direccionar esta memoria y refrescar la pantalla
Ejemplo 15: Animación
En este ejemplo de uso del controlador se genera una secuencia de movimiento en los LEDs, pero escribiéndose los bits de manera independiente. Se utiliza un contador unario para poner a 1
todos los píxeles, secuencialmente. Al terminar se cambia el valor a 0
y se vuelve a recorrer la memoria apagando todos los LEDs. Finalmente se vuelve al comienzo
La secuencia que se genera en los LEDs es: 🔴⚫⚫⚫, 🔴🔴⚫⚫, 🔴🔴🔴⚫, 🔴🔴🔴🔴, ⚫🔴🔴🔴, ⚫⚫🔴🔴, ⚫⚫⚫🔴 y ⚫⚫⚫⚫
(Ej15-Disp1x4-v3-animacion.ice)
En este vídeo de Youtube lo vemos en funcionamiento:
Generación directa de la señal de vídeo
Los controladores anteriores generan la señal de vídeo a partir de la memoria de vídeo, recorriéndola con el ráster. Sin embargo, en otros controladores podemos generar la señal de vídeo directamente, utilizando circuitos combinacionales
Veremos ejemplos de cómo hacerlo, para el display 1x4
Ejemplo 16: Señal de vídeo constante: Encender todos los LEDs
Este ejemplo ya lo conocemos, pero lo ponemos como ejemplo de generación directa de la señal de vídeo. Si esta señal la dejamos al valor 1
constante, entonces se encienden todos los LEDs
(Ej16-Disp1x4-v3-direct-video.ice)
La señal de vídeo que se genera es constante, con el valor 1
:
El resultado ya lo conocemos: TODOS los LEDs se encienden
Ejemplo 17: Señal de vídeo constante: Todos los LEDs parpadean
Si la señal de vídeo es constante a 1
, todos los LEDs se encienden. Ya lo hemos visto. Si la señal fuese contante a 0
, todos los LEDs estarían apagados. En este ejemplo generamos una señal de vídeo que está medio segundo a 1
y medio segundo a 0
. Como es una variación lenta, frente al refresco que es de 3M frames/segundo, el resultado es que hay muchos frames en los que todos los LEDs están encendidos, y muchos frames en los que están todos apagados, generándose un efecto de parpadeo lento
(Ej17-Disp1x4-v3-direct-video.ice)
Por supuesto que habrá frames transitorios en los habrá unos leds encendidos y otros apagados, pero no será apreciable por el ojo humano
Esta es la señal de vídeo:
No se muestran los frames transitorios
En este vídeo de Youtube lo vemos en funcionamiento:
Ejemplo 18: Señal de vídeo constante: Un LED encendido
En este ejemplo se enciende el pixel 3, generando directamente la señal de vídeo a partir del ráster de pantalla. La forma de hacerlo es muy sencilla, basta con conectar directamente el bit 0 del ráster a la señal de vídeo
(Ej18-Disp1x4-v3-direct-video.ice)
Esta es la señal de vídeo resultante. Sólo se activa el pixel 3, el resto de píxeles se transmiten a 0
. La señal de vídeo de todos los frames es la misma:
En esta imagen se muestra el resultado. Sólo se enciende el LED derecho del display
Ejemplo 19: Señal de vídeo constante: Dos LEDs encendidos
Si queremos mantener encendidos dos o más LEDs, sólo hay que combinar las salidas correspondientes del ráster de pantalla con una o varias puertas OR para obtener la señal de vídeo. En este ejemplo se encienden los LEDs 2 y 3, manteniéndose a 0
los otros dos LEDs. La señal de vídeo la generamos aplicando la puerta OR entre las salidas 0 y 1 del ráster de pantalla (que se corresponden con los píxeles 3 y 2 respectivamente)
(Ej19-Disp1x4-v3-direct-video.ice)
Esta es la señal de vídeo que se obtiene. Todos los frames son iguales. Los píxeles 0 y 1 están siempre a 0
y los píxeles 2 y 3 están siempre a 1
En esta image vemos el resultado: los LEDs correspondientes a los píxeles 2 y 3 están encendidos
Ejemplo 20: LEDs alternantes
Las señales de vídeo generadas directamente también podemos construirlas de manera que los frames cambien en función del estado de un bit. En este ejemplo generamos una secuencia de dos LEDs Alternantes. Se crean unos frames en los que la salida de los LEDs es 🔴🔴⚫⚫ y otros frames donde es la contraria: ⚫⚫🔴🔴
El patrón ⚫⚫🔴🔴 es el que hemos creado en el ejemplo anterior: basta con hacer la operación OR entre los bits 0 y 1 del ráster de pantalla. Si aplicamos una puerta NOT a este resultado, obtenemos el complementario: 🔴🔴⚫⚫. Para alternar entre estas dos secuencias, utilizamos una puerta NOT "variable": Si hay puerta NOT obtenemos una secuencia, y si NO hay puerta NOT la otra. Esto se implementa con una puerta XOR. Por un lado se introduce el resultado de la OR, y por el otro si queremos negar (1
) o NO (0
) el patrón
Este bit define qué patrón se muestra. Utilizaremos un corazón de 1 Hz para cambiarlo, de manera que durante medio segundo sale el primer patrón y durante el otro medio segundo el otro patrón
(Ej20-Disp1x4-v3-direct-video.ice)
Esta es la señal de vídeo que se genera. En régimen permanente hay dos frames, cada uno para mostrar un patrón en los LEDs: 1100
y 0011
. Por supuesto aparecerá un frame transitorio entre cada dos estables donde este patrón puede cambiar, pero sólo será un frame, y no lo aprecia el ojo humano
En este vídeo de Youtube lo vemos en funcionamiento:
Ejemplo 21: LEDs alternantes (Manualmente)
Este ejemplo es el mismo que antes: Se muestran dos patrones en los LEDs, pero ahora el cambio se produce al apretar el pulsador SW1
. El circuito es el mismo, pero ahora la entrada a la puerta XOR proviene del pulsador en vez del corazón
(Ej21-Disp1x4-v3-direct-video.ice)
La señal de vídeo es exactamente la misma que en el ejemplo anterior
En este vídeo de Youtube lo vemos en funcionamiento:
Dibujando un Cursor
El cursor es el elemento visual que indica al usuario la posición activa de la pantalla: Es el lugar donde se va a dibujar el siguiente pixel o carácter indicado por el usuario. En nuestro display 1x4, tenemos 4 posiciones, por tanto el cursor se refiere al LED activo
Este cursor lo creamos directamente, generando la señal de vídeo. En este apartado supondremos que en la pantalla sólo está el cursor. Pero esta señal de vídeo se puede combinar con otra que venga de la memoria de vídeo (como veremos en el siguiente apartado)
Vamos a centrarnos en crear la señal de vídeo directamente en hardware, sin usar memoria de vídeo, para mostrar el cursor
Posición del cursor
En nuestra pantalla de 1x4 LEDs tenemos un total de 4 posiciones, desde la 0 hasta la 3. El cursor es la posición que se considera activa, y queda definida por su valor. Este valor se almacena en un un registro unario de 4 bits. Las posiciones del cursor pueden ser, en unario, 1000
, 0100
, 0010
y 0001
. A partir de este valor se genera una señal de vídeo que hace que se encienda el LED correspondiente a la posición del cursor
Para generar esta señal de vídeo con la posición del cursor usamos un multiplexor 4-1 unario, como vemos en los siguientes ejemplos
Ejemplo 22: Cursor fijo con movimiento hacia adelante
En este ejemplo se genera una señal de vídeo directa con un 1
fijo en la posición actual del cursor. Al apretar el pulsador SW1
se avanza el cursor a la siguiente posición
En este vídeo de Youtube lo vemos en funcionamiento:
Ejemplo 23: Cursor parpadeante con movimiento adelante/atrás
En este ejemplo se genera una señal de vídeo con un cursor parpadeante que se mueve hacia adelante y atrás con las teclas SW2
y SW1
respectivamente. El parpadeo se genera mediante la puerta AND entre la señal de vídeo del cursor y un corazón de 2 Hz
(Ej23-Disp1x4-v3-cursor-parpadeante.ice)
En este vídeo de Youtube lo vemos en funcionamiento:
Combinación de señales de vídeo
Podemos crear señales de vídeo independientes mediante diferentes circuitos, y luego combinarlas para crear la señal de vídeo final que se muestra en los LEDs. Por ejemplo, estas señales pueden venir de una memoria de vídeo, de un circuito que genere la señal de vídeo directamente o bien del circuito del Cursor
Combinación con puerta OR
La combinación de las señales de vídeo puede ser aditiva, sumándose ambas señales mediante una puerta OR
En esta figura se muestra la suma de dos señales de ejemplo. Una que enciende los LEDs 2 y 3: ⚫⚫🔴🔴 y otra que enciende el LED 0: 🔴⚫⚫⚫. El resultado es que se encienden 3 LEDs en total: 🔴⚫🔴🔴
Ejemplo 24: Combinando dos señales con una puerta OR
En este ejemplo se combinan las señales de la figura anterior, y se muestra la señal combinada en los LEDs: 🔴⚫🔴🔴
(Ej24-Disp1x4-v3-combinacion-or.ice)
Este es el resultado:
Combinación con puerta XOR
Otra forma de combinar las señales es mediante una PUERTA XOR. En este caso se cambia el estado de los bits de una señal según las posiciones activas de la otra señal.
En esta figura se muestra la operación XOR entre las señales 🔴🔴⚫⚫ y 🔴⚫⚫🔴. El resultado es ⚫🔴⚫🔴. La señal 🔴⚫⚫🔴 indica que se debe cambiar de estado el bit izquierdo y el derecho, dejando en su estado inicial los dos centrales
Ejemplo 25: Combinando dos señales con una puerta XOR
En este ejemplo se combinan las señales de la figura anterior, y se muestra la señal combinada en los LEDs: 🔴⚫🔴⚫
(Ej25-Disp1x4-v3-combinacion-xor.ice)
Este es el resultado:
Aplicaciones
Vamos a desarrollar algunos ejemplos más elaborados del uso del display 1x4
Ejemplo 26: Consola binaria sin edición
En este ejemplo se presenta una consola binaria. Está formada por 3 botones: Uno para introducir el 1
binario, otro para el 0
y la tecla de ENTER
. La consola nos permite introducir números en binario de 4 bits. Al apretar la tecla ENTER se captura este valor en un registro y se muestra en 4 LEDs
El display 1x4 se utiliza en la introducción de los datos. Hay un LED parpadeante que indica la posición actual: el cursor. Según se introducen los bits se encienden o apagan los leds correspondientes. Si ya se han introducido 4 bits, el sistema no admite más y el cursor desaparece. Al apretar enter se pone el valor a cero y se lleva el cursor a la izquierda para pedir el siguiente número
Como es una consola muy básica, no se permite mover el cursor hacia atrás para borrar un bit
Este es el escenario. Se ha colocado un mini-teclado, con las teclas 0
, 1
y Enter
conectadas. La tecla DEL
NO se usa en este ejemplo
Este es el circuito
(Ej26-Disp1x4-v3-App-Terminal-binario.ice)
El controlador lo forma un biestable que determina el modo de funcionamiento: modo edición (1) y dato introducido (0). Cuando el cursor está en la última posición y se introduce un número, se termina el modo edición. Cuando NO se está en modo edición, la señal del cursor parpadeante NO se envía al display, y tampoco se pueden introducir más dígitos
Se generan dos señales de vídeo, una con el cursor y otra con el número que se introduce, que se combinan mediante una puerta XOR para apreciar el parpadeo del cursor. Los dígitos se introducen en una memoria con salida en paralelo. Al apretar la tecla ENTER se captura este valor en un registro para mostrarlo en otros 4 LEDs, y hacer un reset para volver al estado inicial
En este vídeo de Youtube lo vemos en funcionamiento:
Ejemplo 27: Consola binaria con edición
Esta es una ampliación de la consola: se añade la tecla DEL
para eliminar el último bit introducido, y poder así editar. En vez de un biestable RS para almacenar el estado del circuito se utiliza un autómata, con sus transiciones
El cursor se implementa con un registro de desplazamiento izquierda/derecha, ya que ahora se pude mover en ambas direcciones. Avanza hacia la derecha cuando se introducen dígito 0
ó 1
. Avanza hacia la izquierda cuando se aprieta la tecla DEL
(y NO estamos en la posición inicial)
(Ej27-Disp1x4-v3-App-Terminal-binario-del.ice)
La información introducida se guarda en una memoria con salida paralelo, que es la que se serializa y se muestra en el display. En paralelo estos dígitos se introducen en otro registro para mostrarlos en los LEDs al apretar ENTER. Se usa otro registro para mostrarlos alineados a la derecha. Así, por ejemplo, si se pulsa 1
y 0
, en los LEDs del display vemos 🔴⚫ y el cursor parpadeando. Si se aprieta ENTER en los LEDs inferiores se muestra este número alineado a la derecha: ⚫⚫🔴⚫
En este vídeo de Youtube lo vemos en funcionamiento:
Ejemplo 28: Aplicación HWPAINT 1x4
La aplicación HWPaint es un circuito para pintar por hardware. Mediante dos pulsadores el cursor se mueve hacia la derecha o la izquierda. Con otra tecla se cambia el estado del LED donde está el cursor, para pintar el pixel o borrarlo. Con otra tecla salimos o entramos en el modo edición. Fuera del modo edición podemos ver nuestros píxeles pintados, sin el cursor
Este es el escenario:
Este es el circuito:
En este vídeo de Youtube lo vemos en funcionamiento:
Conclusiones
Cuando trabajamos con pantallas de vídeo de pocos píxeles (LEDs), basta con usar un registro de N bits como memoria de vídeo y enviar la información en paralelo. El consumo es bajo y se usan pocos cables
Sin embargo, para pantallas de mayor resoluciòn esta solución NO escala y tenemos que usar otra arquitectura. La información de vídeo se envía en serie de forma que en la pantalla se activa un LED cada vez. El sistema se complica pero el consumo es muy bajo y el conexionado se simplifica (un único cable de que transporta la señal de vídeo)
Como sólo hay un LED activo cada vez, la pantalla se debe refrescar al menos a la frecuencia de 50Hz, para ver la información estable y sin parpadeos
Hemos entendido los fundamentos usando un display de 1x4 LEDs: Una única línea de 4 LEDs. Esto nos ha permitido estudiar los conceptos más importantes:
- Frecuencia de refresco
- Pixel clock
- Ráster
- Memoria de vídeo
- Señal de vídeo
- Frame
- Cursro
- Vsync
- ...
Insisto en que todo esto NO es necesario para displays con pocos LEDs como el que hemos usado de 1x4, pero sí es absolutamente necesario para trabajar con pantallas de más resolución
En próximos Cuadernos técnicos seguiremos trabajando con pocos LEDs pero distribuidos en 2D, de forma matricial
Autor
- Juan González-Gómez (Obijuan)
Licencia
Atribuciones
- [1]: Display mecánico. Designed by macrovector / Freepik
- Imagen IBM PC Monocromo. CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=51833
- Imagen IBM PC-XT: Museo de informática UCM: https://www.fdi.ucm.es/migs/catalogo/ibm_pc_xt/
- Imagen Monitor LCD: De florisla from Mechelen, Belgium - LG L194WT-SF LCD monitor, CC BY-SA 2.0, https://commons.wikimedia.org/w/index.php?curid=3829386
- Imagen semáforo: De Syafiqshahalam at en.wikipedia - Own Work, Dominio público, https://commons.wikimedia.org/w/index.php?curid=16068082
- Light Paiting: De Robert Knapp Photographer www.modernartphotograph.com - Trabajo propio, CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=11862559
Enlaces
- Wikipedia: Resolución de pantalla: https://es.wikipedia.org/wiki/Resoluci%C3%B3n_de_pantalla