jueves, 28 de mayo de 2015

Arduino - Generación de señales de VGA con hardware estádar

  Buenas!
  Navegando en viejos almacenes de demoscene, dí con un proyecto que me llamó poderosamente la atención: Craft de Linus Åkesson; Una obra de arte en miniatura basada en un ATmega88 que genera señales de VGA, los efectos y hasta sonido!
  El hallazgo coincidió con el recién adquirido clon chino de Arduino Mega 2560 y con mis ganas de generar contenido para el blog así que... ¿Porqué no hacer una librería para generar señales de VGA con hardware estándar?

Manos a la obra
  Empezaré con una introducción teórica, para luego discutir la implementación, el hardware y por último el software asociado (librería).


Introducción Teórica

  Se hace referencia a continuación a los tubos de rayos catódicos (monitor de vidrio), cuando los mismos están prácticamente en desuso, reemplazados por pantallas LCD / LED. De todas formas, a nivel eléctrico el estándar se ha mantenido y lo que hacen los monitores modernos es "emular" el comportamiento de un crt para mantener la compatibilidad.

Funcionamiento de un monitor VGA
  A groso modo un monitor o tubo de rayos catódicos (crt) es un tubo al vacío de vidrio con una película de fósforo en la parte frontal (pantalla) sobre la que se hace incidir un haz de rayos catódicos.


  El haz (o los múltiples haces), que "recorre" (barre) constantemente la pantalla de izquierda a derecha y de arriba a abajo (normalmente) al incidir sobre la película de fósforo genera un punto iluminado (pixel) que conforma la imagen mostrada en la pantalla.


  El movimiento de barrido del haz se realiza por medio de los llamados deflectores.
  El control de deflexión y cañón es manejado, en el caso de un monitor VGA por 5 señales eléctricas (5 pines + tierra del DB15 del monitor):
  Sincronización Horizontal (H-SYNC): Señal digital (pulso 0 - 5V)  asociada al deflector vertical del crt (o a su equivalente en un led / lcd) que marca el inicio de una línea, determina la resolución horizontal y asegura que el monitor muestre los pixeles de la misma entre los margenes izquierdo y derecho del área visible de la pantalla.
  Sincronización Vertical (V-SYNC): Señal digital (pulso 0 - 5V) asociada al deflector vertical del crt (o a su equivalente en un led / lcd) que marca el inicio de un "frame", determina la resolución vertical y asegura que las líneas horizontales estén entre el margen superior y inferior del área visible de la pantalla.
  R, G, B: Señales analógicas en el rango 0V (oscuro) a 0.7V (máxima intensidad) asociadas al cañón de electrones del crt (o a su equivalente en un led / lcd) que controlan la intensidad de cada componente de color que combinados conforman el color pixel a pixel, linea a linea de la pantalla.


  El estándar es muy estricto en cuanto a los tiempos de las formas de onda. Cualquier variación genera deformaciones, parpadeos, problemas de alineación, etc.
  Cada modo de los muy variados tiene tu respectivo diagramas de tiempo; Para mas información consultar VGA Timings.
  A continuación diagramas / tablas de formas de onda y tiempos del modo VGA 640 x 480 x 60hz.

Diagrama de tiempos simplificado para el modo VGA 640x480 60hz



Tabla de tiempos


Representación gráfica alternativa


Análisis de Implementación

  ¿Porqué 640x480? Primero es el más estándar de los modos (introducido por IBM para las PS/2 por el año 1987). Segundo es el de menor resolución y por ende el mas "alcanzable". 320x200 y 320 x240 son variantes del 640x480 y 640x400 (cuatro pixeles por pixel) y no hay beneficios para la implementación.
  El primer escollo de la implementación tienen que ver con la frecuencia de reloj del los pixeles: 25.175mhz.
  ¿Que es este valor? La frecuencia (velocidad) a la que deben variar las señales analógicas de los 3 componentes de color (R, G y B) para conseguir la resolución horizontal de 640 pixeles.
  Demás está decir que esa frecuencia de reloj es inalcanzable con hardware estándar (Arduino basado en microcontrolador de familia ATmega).
  Para nuestro caso en particular, utilizando DAC's de escaleras de resistencias (se explicará posteriormente), la frecuencia máxima alcanzable será de 16mhz / 3 (ciclos de instrucción por pixel) ~5,3mhz. La máxima resolución alcanzable con esta configuración será de ~135pixeles en ancho por 480 líneas de alto (sin límites).
  Se plantea una alternativa para el modo monocromático utilizando el puerto serial de controlador para generar las señales. En este caso la frecuencia máxima alcanzable será de 16mhz / 2 (máxima frecuencia del usart) = 8mhz. La máxima resolución alcanzable con esta configuración será de ~203pixeles en ancho por 480 líneas de alto.
  Con reloj de 20mhz (en algunos casos viene / se puede reemplazar) mejorará levemente el rendimiento y se podrá subir ligeramente la resolución.
  La utilización con reloj de 8mhz queda directamente descartada.

Implementación

Circuito
  Se plantean dos circuitos diferentes para la generación de color en los modos color y monocromático.

VGA Color
  Como mencionaba anteriormente, para los niveles de RGB es necesario generar señales analógicas en el rango [0V - 0.7V].
  Como primera medida, la familia de microcontroladores AVR ATmega de Atmel carecen de DAC's; pero aún si los tuvieran, se requiere de una frecuencia según especificación de 25.175 mhz (en criollo, el DAC tiene que ser capaz de "cambiar de valor" 25 millones de veces por segundo), lo que directamente escapa a controladores de gama baja / media, independientemente de la marca.
  Utilizaré entonces los clásicos y conocidos DAC's conformados por resistencias en escalera (http://es.wikipedia.org/wiki/Red_R-2R).


  Este tipo de topología es probablemente la forma mas simple y económica de construir un DAC para generar una señal analógica (Vout) a partir de los datos digitales del puerto digital al que las resistencias estén conectadas (a(0) .. a(n-1)),
  Para nuestro caso usaremos 2 redes de 3 bits para los componentes rojo / verde y una de 2 bits para los componentes azules.
  Pueden generarse entonces 8 niveles de rojo / verde y 4 de azul siendo la máxima cantidad de colores representables 8 * 8 * 4 = 256 (RGB 3-3-2).
  En el esquema se utilizan las E/S digitales [22 - 29] (corresponden al PORTA del microcontrolador) para los DAC en escalera de los componentes de color y PWM [12, 13] para las señales de sincronismo. El puerto utilizado puede modificarse desde el include de configuración de la librería (ArduinoVGAConfig.h).


  R4, R9 y R16: Están contempladas para el caso de que algún monitor no tenga los 75ohms según especificación, en cuyo caso, se necesitarían para "compensar" ya que el cálculo del DAC ladder es para esa impedancia de carga.

VGA Monocromático

  El circuito para el modo monocromático (blanco y negro) es bastante mas sencillo. A diferencia del circuito para generación de VGA color se necesitan solo dos niveles de color (dos estados), blanco y negro. El negro se obtiene a partir de la aplicación de 0V en cada uno de los canales de color.
El blanco a partir de la aplicación de 0.7V (intensidad máxima) en cada uno de los canales.
  Requiere de muy pocos componentes y puede ser construido en protoboard o directamente dentro de las "tapitas" del conector DB15.


  Cuenta con solo 5 resistencias de las cuales son 3 las estrictamente necesarias (R1, R2 y R3).
R1, R2 y R3 están calculadas para generar una caída de tensión de ~0.7V en la resistencia interna del monitor (75ohms).
  R4 y R5 son limitadoras de corriente con la finalidad de proteger el puerto del controlador del Arduino ante cualquier eventualidad.
  En el esquema se utiliza la E/S digital 18 (TX del USART1 del microcontrolador) para los componentes de color, PWM [12, 13] para las señales de sincronismo y tierra (se puede usar cualquiera). Los puertos utilizados puede modificarse desde el include de configuración de la librería (ArduinoVGAConfig.h).


Software
  A nivel software se deben generar por una lado las señales de sincronismo, las de video y proveer al usuario de una interfaz (clase pública) con rutinas que permitan modificar el contenido de la pantalla.

Señales de sincronismo

  Las señales de sincronismo deben ser generadas con la mayor exactitud / precisión posible.
  Utilizaré para ello uno de los Timers de 16bits de la familia de microcontroladores ATmega.
  El timer es un periférico de hardware accesible desde el código vía registros capaz de ejecutar rutinas cada intervalos específicos (interrupción), medir tiempos y generar formas de onda.

  A partir del Timer se generará:
    Interrupción cada 31,8uS (horizontal)
    Pulso de sincronismo horizontal de 3.8uS generado por módulo Ouput Compare del Timer
    Señal de video
    Pulso de sincronismo vertical generado desde la interrupción

Memoria de video
  Espacio de memoria RAM asignado como buffer intermedio entre la interfaz de usuario (clase pública) y la librería de generación de señales de bajo nivel.
  Las funciones gráficas de la librería de control vuelcan contenido sobre la memoria de video.
  La sección de bajo nivel de la librería, a la tasa de refresco correspondiente con el modo (60hz), vuelca el contenido en la pantalla crt (genera las formas de onda acorde al contenido).


  Para el modo VGA color se utilizará un byte por pixel.
  Para una resolución de 640 x 480 pixeles se requerirían 640*480 = 307200bytes (El Arduino mega2560 cuenta con 8192 bytes de ram); Demás está decir que una de las limitantes del modo color con hardware estándar será entonces la memoria RAM disponible.
  En los ejemplos utilizaré una resolución de 64 x 64 = 4096bytes. Estos parámetros podrán modificarse en el include de configuración de la librería (ArduinoVGAConfig.h).
  Para el modo VGA monocromático se utilizará un bit por pixel (8 pixeles por byte).
  Utilizaré una resolución de 160 x 120 pixeles = 2400bytes. Estos parámetros se podrán modificar también desde el #include de configuración de la librería para permitir su utilización a costas de reducir la resolución en Arduinos de baja gama.

Generación de señales de color
  Propongo dos conjuntos de rutinas para la generación de señales para los dos modos, ambas dentro de la misma librería y configurables por condicionales de compilación (ArduinoVGAConfig.h).

VGA Color

  Para la generación de señales a color utilizaré a nivel software uno de los puertos estándar disponibles en el microcontrolador del Arduino.
  En la figura se observa uno de los DAC escalera (componente rojo) conectado a 3 pines de un puerto del microcontrolador.
  Los 3 bits en estado bajo corresponderán a una tensión a la salida de la red de 0V (menor intensidad de rojo = negro).
  Alternando el estado de los pines del controlador se pueden obtener diferentes niveles de tensión (escalera) hasta alcanzar el máximo de 0.7V (mayor intensidad de rojo).
  El mismo esquema se repite para los 3 componentes de color (rojo, verde, azul).
  La resistencia de carga de 75ohms corresponde a la impedancia interna del monitor en las líneas de color (R, G, B).


  Los componentes de color para el relleno de una línea horizontal se obtienen a partir de alternar tantos bytes por el puerto como pixeles haya de resolución; En nuestro caso, unos 128bytes.
  La salida de datos por el puerto por cuestiones de tiempo debe necesariamente de escribirse en ensamblador:

//carga en registro el contenido del puntero [Y] (apunta a la memoria de video)
//incrementa Y en 1 (siguiente pixel)
LD R0,Y+  //2 ciclos de reloj
//pone en el puerto A el contenido del registro
OUT PORTA, R0  // 1 ciclo de reloj
LD R0,Y+
OUT PORTA, R0
...
LD R0,Y+
OUT PORTA, R0


VGA Monocromático

  Como mencionaba en párrafos anteriores, utilizaré un puerto de comunicaciones USART para generar las formas de onda.
  El puerto USART de los controladores ATmega cuentan con las siguientes características interesantes para nuestra aplicación:
  (1) Soportan el modo SPI con lo que se eliminan los elementos de sincronismo (start bit, stop bit) de la línea de datos.
  (2) Tienen doble buffer de transmisión, que permite "ir cargando" el contenido del segundo byte a transmitir cuando todavía se está transmitiendo el primero (el puerto SPI no puede usarse para esta aplicación por este motivo).
  (3) Máximo baudrate soportado: FOSC / 2. Supera ampliamente en frecuencia a la operación sobre puerto estándar.

  En la figura se observa el pin de la transmisión del USART conectado a los 3 pines de los componentes de color del monitor VGA.
  Las resistencias de 75ohms corresponden a las impedancias internas de cada una de las entradas de color del monitor.
  El divisor resistivo formado por cada resistencia de 470ohms y la impedancia interna de 75ohms esta calculado para una caída de tensión de ~0.7V cuando el pin TX del controlador esté en estado alto (1) y de 0V cuando el pin esté en estado bajo (0).


  Los componentes de color para el relleno de una línea horizontal se obtienen a partir de enviar tantos bytes por el puerto serial como pixeles / 8 haya de resolución; En nuestro caso, para 160 bytes corresponden 20 bytes enviados por el USART del controlador.
  A 8 pixeles por byte, el color de cada pixel será negro si el bit correspondiente es 0 y blanco (0.7v para Rojo, Verde y Azul) si el bit es 1.

  La salida de datos por el puerto por cuestiones de tiempo debe necesariamente de escribirse en ensamblador:

//carga en registro el contenido del puntero [Y] (apunta a la memoria de video)
//incrementa Y en 1 (siguiente pixel)
LD R0, Y+
//transmite por USART el contenido del registro
STS UDR1, R0
//carga contenido del siguiente pixel
LD R0, Y+
//demora hasta que esté libre el doble buffer para el siguietne byte a transmitir
NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP
//transmite por USART el contenido del registro
STS UDR1, R0
...
LD R0, Y+
NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP
STS UDR1, R0


Librería

  La librería está compuesta por una clase pública para el usuario (ArduinoVGA.cpp) y una librería de bajo nivel (ArduinoVGAEngine.cpp) con las rutinas de generación de señal.
  La misma es de código abierto (licencia a definir) y puede ser descargada desde la web de SourceForge desde aquí.

Importante
  (1) Por cuestiones de rendimiento es necesario desactivar el Timer0, utilizado para las rutinas de demora: millis(), micros(), etc. Se provee de una rutina de generación de demoras como reemplazo (VGA.Delay()).
    No es posible utilizar estas rutinas como así tampoco otros periféricos con la generación de interrupciones activa.
    Es una limitación importante de la librería y uno de los costos por no utilizar hardware externo.
  (2) El ~92% del tiempo el microcontrolador estará dedicado a la generación de señales de VGA. Solo en el ~8% restante (denominado "tiempo de blanqueo") el controlador estará "relativamente liberado" para ejecutar el código de usuario (1,5mS de 16,7ms) así que habrá que "ingeniárselas".
 
Clase pública
class ArduinoVGA {
  public:
    Init(void);
    void PutPixel(unsigned short x, unsigned short y, unsigned char color);
    void PutPixel(unsigned short x, unsigned short y, unsigned char r, unsigned char g, unsigned char b);
    unsigned char RGB2Color(unsigned char r, unsigned char g, unsigned char b);
    void ClrScr(unsigned char color);
    void ClrScr(unsigned char r, unsigned char g, unsigned char b);
    void ClrScr(void);
    void Delay(unsigned short ms);
    void Line(short x0, short y0, short x1, short y1, unsigned char color);
    void Rectangle(short x0, short y0, short x1, short y1, unsigned char color);
    void FillRectangle(short x0, short y0, short x1, short y1, unsigned char color);
    void Triangle(short x0, short y0, short x1, short y1, short x2, short y2, unsigned char color);
    void Polygon(short x[], short y[], unsigned char vertexCount, unsigned char color);
    void Circle(short x0, short y0, short radius, unsigned char color);
    void FontLoad(const unsigned char *font);
    void FontColor(unsigned char color, unsigned char backgroundColor);
    void GotoXY(unsigned char x, unsigned char y);
    void Write(char *s);
    void Write(unsigned char x, unsigned char y, char *s);
};

Descripción de los métodos

Init();
Inicializa la librería.

PutPixel(x, y, color);
Pone un pixel en las coordenadas en pixeles [x, y] de color RGB empaquetado [0..255].

PutPixel(x, y, r, g, b);
Pone un pixel en las coordenadas en pixeles [x, y] de componentes de color r [0..7], g [0..7] y b [0..3].

RGB2Color(r, g, b);
Convierete color de tres componentes [r], [g], [b] a empaquetado de 8 bits [0..255].
El formato del empaquetado (byte) será de bit mas significativo a menos significativo [BBGGGRRR].

ClrScr(color);
Borra la pantalla pintando con color RGB empaquetado [0..255].

ClrScr(r, g, b);
Borra la pantalla pintando con color de componentes r [0..7], g [0..7] y b [0..3].

ClrScr();
Borra la pantalla (negro).

Delay(ms);
Genera demora en ms.
Como mencionábamos anteriormente, varias de las rutinas estándar de Arduino son desactivadas durante la inicialización de esta librería por cuestiones de rendimiento.

Line(x0, y0, x1, y1, color);
Dibuja línea desde coordenadas en pixeles  [x0, y0] a coordenadas [x1, y1] de color RGB empaquetado [0..255].

Rectangle(x0, y0, x1, y1, color);
Dibuja un rectángulo con coordenadas de vértice superior izquierdo [x0, y0], [x1, y1] de vértice inferior derecho y de color RGB empaquetado [0..255].

FillRectangle(x0, y0, x1, y1, color);
Dibuja un rectángulo relleno con coordenadas de vértice superior izquierdo [x0, y0], [x1, y1] de vértice inferior derecho y de color RGB empaquetado [0..255].

Triangle(x0, y0, x1, y1, x2, y2, color);
Dibuja un triángulo con vértices de coordenadas [x0, y0], [x1, y1] y [x2, y2] de color RGB empaquetado [0..255].

Polygon(x[], y[], vertexCount, color);
Dibuja un polígono de [vertexCount] vértices de coordenadas {[x[0], y[0]] .. [x[vertexCount - 1], y[vertexCount - 1]]} de color RGB empaquetado [0..255].

Circle(x0, y0, radius, color);
Dibuja circunsferencia con centro en coordenadas en pixeles [x0, y0], radio en pixeles [radius] y color RGB empaquetado [0..255].

FontLoad(*font);
Selecciona fuente [font] almacenada en memoria flash.
Se utilizan las fuentes del proyecto arduino-tvout ya incluidas dentro de la librería.

FontColor(color, backgroundColor);
Configura color de fuente y color de fondo. Ambos parámetros color RGB empaquetado [0..255].

GotoXY(x, y);
Posiciona puntero de escritura en coordenadas en pixeles [x, y]

Write(char *s);
Escribe cadena de caracteres en posición de puntero de escritura.
Modifica la posición del puntero (permite escribir múltiples cadenas una a continuación de la otra).

Write(x, y, *s);
Escribe una cadena [s] en las coordenadas en pixeles [x, y].
Modifica la posición del puntero (permite escribir múltiples cadenas una a continuación de la otra).

Instalación / Utilización
  La instalación es la "clásica" del IDE Arduino:
    Menú Programa -> Include Library -> Add .ZIP Library
  Para más información consultar la documentación oficial: Installing Additional Arduino Libraries

  Una vez instalada la librería en el IDE, en un Sketch nuevo o existente se debe proceder con la inclusión de la librería: Programa -> Include Library -> Arduino VGA.
  Los métodos de la clase publica están disponibles vía la instancia global VGA. (VGA.PutPixel, VGA.ClrScr, VGA.Line, VGA.Circle, etc).

Sketch de ejemplo
#include <ArduinoVGA.h>
#include <ArduinoVGAConfig.h>
#include <ArduinoVGAEngine.h>
#include <font6x8.h>

// codificado dentro del método setup()
// la librería desactiva varias funcionalidades de Arduino por cuestiones
//de rendimiento.
void setup() {
  // inicialización de la librería
  VGA.Init();
  // carga fuente a utilizar por las rutinas de escritura
  VGA.FontLoad(font6x8);
  // bucle infinito
  while (1){
    // dibuja circulo de radio, posición y aleatoria de la pantalla
    VGA.Circle(random(RX), random(RY), random(10) + 1, random(2));
    // selecciona color de fuente aleatorio y color de fondo negro
    VGA.FontColor(random(2), 0);
    // escribe cadena "Hola mundo!" en posición aleatoria de la pantalla
    VGA.Write(random(RX), random(RY), "Hola mundo!");
  }  
}

// la rutina no se llama nunca en este ejemplo
// jamás se retorna de la rutina setup()
void loop() {
}

Otros ejemplos de uso

  A continuación un demo para cada uno de los modos.
  Ambos forman parte de la librería y pueden ser abiertos como Sketch's de ejemplo de la librería (Archivo -> Ejemplos -> ArduinoVGA).

  VGA Color
    Para el modo color algunos fractales y un par de efectos de demoscene en resolución 64 x 64 (no puedo mas por cuestiones de RAM).


  Efectos según orden de aparición:
    Fuego (básico por cuestiones de RAM)
    Fractales
      Sierpisky
      Mandelbrot
    Prueba de fuentes
    Shadebos

  VGA Monocromático
  Para el modo monocromático programé una librería de gráficos de tortuga para nada pulida para hacer algunos fractales recursivos.
  La resolución elegida en este caso es de 160 x 120.


  Efectos según orden de aparición:
    Fractales
      Arbol
      Dragón
      Sierpisky
      Koch
    Prueba de fuentes
    Bolas sobre curvas de Lissajous
    Figuras geométricas

Conclusiones

  • El resultado es bastante bueno considerando las importantes limitaciones producto de la memoria RAM y la frecuencia de reloj.
  • En modo monocromático cuenta con resolución aceptable y es relativamente utilizable para aplicaciones varias.
  • En modo color es bastante limitado (resolución), es con fines de experimentación y no se le puede pedir mucho mas.
  • Tiene unos cuantos detalles que estimo iré puliendo con el tiempo.

  En lo próximo
    Con la misma idea voy a diseñar un shield con un microcontrolador mas potente (tentativamente algún de la familia ATxmega), memoria RAM onboard y algún que otro chiche, comandado vía SPI por un Arduino y su correspondiente librería de control.
    Agregaré alguna que otra función a la librería de interfaz (ArduinoVGA).
    Crearé repositorio con el contenido aquí presentado (Sourceforge probablemente).
    Trabajaré la librería de bajo nivel (generación de señales) con el fin de exprimir al máximo el hardware y poder mejorar levemente la resolución en los diferentes modos.
    Corregiré pequeños detalles de la implementación.
    Documentaré el código fuente.

  Doy por terminado este artículo, espero el contenido haya sido de utilidad.
  Cualquier duda no duden en consultar, nos vemos en la siguiente entrada.
  Saludos, Luis.-

17 comentarios:

  1. Me encantó el documento sería posible transcribirlo para un Arduino Due?? Como vez ?

    ResponderBorrar
    Respuestas
    1. Buenas! Primer comentario! Te ganaste un... "Gracias por comentar" :)
      Totalmente factible, aparte de que el micro tiene prestaciones para aprovechar (96k de RAM, 80mhz de clock, , DMA, etc) lo que permitiría mejorar notablemente las pretaciones (+resolución, buffer de video, etc).
      No veo impedimentos salvo por los niveles de tensión de algunas de las señales del VGA: 5V y el Due usa 3V3 (nada que no se pueda solucionar de todas formas).
      Me pongo en campaña de conseguir un Due, en cuanto lo tenga veo de adaptar.
      Saludos.-

      Borrar
  2. Si solo necesito 1 o 2 FPS, ¿Podría funcionar con una resolución mayor y un cristal de 16Mhz? ¿O es estrictamente necesario mandar los datos a tal velocidad?. El punto seria utilizar Un attiny85 para mostrar un dato cada uno o dos segundos, pero utilizando el cristal interno configurado a 16MHz.
    Saludos

    ResponderBorrar
  3. Buenas Andres, muchas gracias por comentar.
    Respecto a tus consultas:
    (1) El máximo de resolución teórico sería de los ~135 a los ~203 pixeles en ancho por 480 pixeles en alto (con clock a 16mhz); No se si esa resolución es suficiente para lo que estás necesitando.
    Tengo dudas respecto al funcionamiento por la estabilidad del oscilador interno (RC). Habría que hacer algunos ensayos pero lo mas probable es que haya jitter (temblequeo) o se pierdan temporalmente las señales de sincronismo (y por ende le video).
    (2) Si, es estrictamente necesario generar las señales de video y sincronismo del modo de video selecionado (ej. 640 x 480 pixeles x 60hz) independientemente de que se use o no toda la resolución / tasa de refresco.
    En la web hay varios ejemplos de generación de video con tiny85 pero todos (por lo menos los que vi) son con clock externo.
    Dale un vistazo a este por ejemplo: http://www.avrfreaks.net/forum/quark-85-demo-kube-184-x-240-vga-8-colors-and-sound-tiny85
    Genera señales RGB (pocos colores) en resoluciones de 210x240 y sonido. Usa un clock de 32mhz, algunas resistencias y unos diodos (está el esquemático, código fuente y algunos videos en donde muestra el funcionamiento).
    (3) A todas estas limitaciones se le suman la poca memoria RAM y FLASH del microcontrolador (512bytes + 8k) que complican un poco mas las rutinas.
    Si me das unos días (ahora estoy con mucho laburo) hago algunos experimentos y te comento.
    Saludos.-

    ResponderBorrar
  4. Hola, gracias por compartir esta inforamcion:
    te consulto si en ves de graficar quisiera ver señales como tipo osciloscopio pero con eje x/y ?
    seria posible de esta manera.
    soy nuevo en todo esto por eso la consulta
    Saludos

    ResponderBorrar
    Respuestas
    1. Buenas Dardo. Gracias por comentar / consultar.
      Dos problemas que veo para esta aplicación:
      (1) Baja resolución (160 x 120 en monocromático). Por ahí se podría hacer algún tuneo (cambiar el cristal del Arduino), subir un poco el clock y así la resolución.
      (2) Muchísimo tiempo de procesador utilizado para la generación de video: No hay tiempo para tomar muestras (samplear) con el conversor analógico a digital (se hace una cosa u otra).
      Talvez utilizando dos arduinos conectados: Uno para sampleo y el otro para la generación de video.
      Con un Arduino mas grande (Due, Zero, M0) cambia completamente la ecuación: Lo veo mas factible, incluso para hacer algún tipo de procesamiento de la muestras (FFT, filtros, etc).
      Saludos.-

      Borrar
  5. Hola no se si estés familiarizado con los micros lpc, mi idea seria usar un lpc4337 de doble núcleo asimétrico m4 m0 con. 512k de flash por núcleo RAM compartida de mas de 100k y 204mhz de velocidad, sera suficiente para una resolución de 320x200x60hz a 16 colores? Y se podrán modificar tus rutinas

    ResponderBorrar
    Respuestas
    1. Buenas! Perdón por la tardanza :$
      No conozco la familia pero si los Cortex (m4, m3, m0).
      La características de ambos son mas que suficientes para generar video con esa resolución / cantidad de colores.
      Te recomiendo dar un vistazo al artículo Arduino - Generación de señales de VGA con Arduino DUE (https://goo.gl/HtH2wc) en el que uso un Arduino DUE (Cortex-M3).
      Se genera video utilizando DMA y es lógicamente bastante mas eficiente.
      Saludos.-

      Borrar
  6. Hola tengo el Arduino mega 2560 y despues de hacer todo lo que pone en esta web me da un error y es el siguiente:ArduinoVGA.h: No such file or directory si alguien me puede ayudar se lo agradecería.Muchas gracias.

    ResponderBorrar
    Respuestas
    1. Buenas Juan. No estoy teniendo problemas con importar la librería, abrir alguno de los ejemplos y compilar.
      El "síntoma" es como si la librería no estuviera incluida dentro de la lista de librerías.
      El proceso es:
      (1) Descargar "ArduinoVGA.R1(28052015024637).zip" de sourceforge (https://goo.gl/75a9ZL).
      (2) Utilizar el gestor de librerías para agregar la librería al IDE de Arduino: "Programa -> Incluir librería -> Añadir librería .ZIP".
      (3) Verificar que la librería esté instalada (normalmente en C:\Users\?\Documents\Arduino\libraries\ArduinoVGA).
      (4) Seleccionar la placa Arduino / Genuino Mega desde "Herramientas".
      (5) Abrir alguno de los ejemplos de la librería.
      (6) Compilar.

      Borrar
    2. Me olvidé los "saludos"! Gracias por comentar.-

      Borrar
  7. Muy interesante este post y muy buena documentación.
    Te hago una consulta, es posible tomar la señal de video de un tv y procesarla desde arduino? Por ejemplo conectar la salida del deco (hdmi) y conectarla a mi arduino para luego poder leer las señales RGB y tratarlas.

    ResponderBorrar
    Respuestas
    1. Buenas Orlando, gracias por comentar / consultar.
      No, no es posible: El HDMI es una interfaz digital de alta definición con tiempos de reloj muy por encima de lo que puede manejar un arduino.
      Tampoco la información podría almacenarse (para post-procesado) / procesarse en tiempo real.
      Saludos.-

      Borrar
  8. buen día, excelente post. Llegue hasta acá por lo siguiente: donde trabajo hay varios monitores que se querian desechar como basura informatica y se me ocurrio usarlos para hacer un proyecto muchisimos mas basico que el que hiciste vos. La idea era hacer un display de 7 segmentos pero usando monitores en vez de leds. Me puse a investigar como hacer para prender el monitor en un solo color y me tope con los siguientes problemas: no se nada de electrónica :) y no logro que quede prendido en un color, solo puedo hacer que parpadee rápido. Preguntas: como seria el circuito para este proyecto? Por que no puedo hacer que el monitor se quede en un color fijo? que riesgos corre mi placa arduino UNO? desde ya muchas gracias y excelente tu trabajo

    ResponderBorrar
  9. como estás, buenos días.
    gracias por los comentarios y perdón por la tardanza (no vi las notificaciones).
    si, se podría, el tema son los costos (3 x DAC0808, uno para cada componente salvo que solo se quiera escala de grises [256]) el incremento en la complejidad del circuito contra los beneficios (lo único que veo es "mas exactitud en la representación de colores").
    saludos.-

    ResponderBorrar
  10. Buenas Carlos!
    Gracias por los comentarios y perdón por la tardanza.
    Buena idea! Comentame la cantidad de monitores que pretendés usar o si el plan es múltiples dígitos en un solo monitor.
    En el caso de que se pretenda utilizar varios monitores (con diferentes dígitos en cada uno) controlados desde un solo arduino (lo que interpreto):
    (1) Hacen faltas algunas modificaciones a la librería (las puedo hacer si me das algo de tiempo). La resolución de salida va a ser baja (pixeles cuadrados grandes). Entiendo de todas formas que para mostrar digitos va a andar bien.
    (2) No habría riesgos para el arduino salvo haya problemas en alguna fuente de alimentación de algún monitor (aclarame si son de tubo o lcd / led).
    (3) Indicame el color que te interesa de los dígitos y te preparo un diagrama: Si es blanco o alguno de los primarios (RGB) el cicuito es mas sencillo (tiene menos componentes).
    Otra alternativa es que me pases un diagrama del circuito y el scketch de arduino que estás utilizando y te doy mi punto de vista / sugerencias.
    Saludos.-

    ResponderBorrar
  11. Hola el proyecto de los monitores se piso sacar a delante gracias por el post está interesante

    ResponderBorrar