Teensy 3 VGA colour with code

Is this of any practical use? Probably not. But it does offer up some interesting potential for low-fi low-res and potential art applications. However, if you are looking for something to control your large lcd vga screen with, it’s probably not for you.

VGA_output_Teensy31

Lukas Hartman (www.youtube.com/watch?v=9rqThgI5cB8) has done some great working in getting the timings sorted out to achieve a reasonably solid VGA signal with the Teensy 3. The Horizontal and vertical sync are controlled using the IntervalTimer() function available for the Teensy. Each sync pulse is allocated a pin which is drawn Low or High to generate the pulse of the required length.

Nick Gammon (http://www.gammon.com.au/forum/?id=11608) has a very good description of VGA timing issues and pulse length requirements linked to the work he has done on getting VGA working with Arduino Uno.

Because colour generation for the VGA monitor is derived from voltage values (i.e. an analogue process), and because the Teensy does not have the capability of outputting three analogue signals, one each for B, R and G, we have to get our colour mix from a set of static voltage values. Each of these colours, in this implementation, is derived from its own pin. The colour value can, however, be manipulated to an alternative fixed value by the use of resistors of different values. This is because of the use of the voltage divider concept.

So, using six output pins on the Teensy 3.1 we can derive two colour values for each of Red, Green and Blue, one dull and one bright. Six base colours can be used to give a theoretical palette of 64 colours.

VGA_Teensy3_1

The pins that are to be used to control the colour voltage output are going to be on the same port of the microcontroller. Why? Well, it means that we can set values for the pins in a single processor cycle. This means that we can get the colour settings out as fast as possible, and leaves time for the processor to get other things done.

Port manipulation is described very well across the web, with specifics for Teensy in this tutorial here: https://forum.pjrc.com/threads/17532-Tutorial-on-digital-I-O-ATMega-PIN-PORT-DDR-D-B-registers-vs-ARM-GPIO_PDIR-_PDOR

We assign the colour pins of the VGA monitor to six pins of the Teensy PortB, and with this we are able to switch on or off for each of the six colour values for each of our pixels. For example
If on the below portB pins we have our colour connections as: x|x|g|g|b|b|r|r
And we set the port to:
PORTB = B00000001
Only the pin for the first “r” would be set to high, so producing one of our red pixels. These colour pins can then be mixed as we want them but either setting the pin to high or low for each clock / processor cycle.
In the code, we can put these port configurations into an array and choose from it, or can explicitly set as above, or use hex values to describe the binary. Such as 0x01 being B00000001, 0x10 being B00010000, or blend colour output with 0x14 being B00010100 (which gives some blue and green mixed together).

If we do some loop coding, we can feed a buffer that holds a value for each of our screen pixels with a colour value fast enough to get a refresh rate that works. At the moment I can have 200*200 pixels buffer size. The values in this buffer can be updated by a number of methods. A simple maths for loop can update the buffer values in between each screen refresh so that we can get some geometric patterns flowing. We can use byte colour values (8bits) and shift them into the right six bit places, or we can use some more complex bitwise operations to move colour values around to get them into our RGB values.

Teensy 3 displaying 8bit BMP over VGA, converted to 6bit colours
Teensy 3 displaying 8bit BMP over VGA, converted to 6bit colours

Or, we can update the buffer from an sd card file, such as this 8bit BMP file. 8bit colour = one pixel per byte, but… an 8bit BMP is a little different in concept, as it uses an index to a colour table/palette. The colours are a off, so some of the code needs tweeking, but you get the idea. This needs some more work.