VGA
Folders and files
Name | Name | Last commit date | ||
---|---|---|---|---|
parent directory.. | ||||
Due VGA Library by stimmer V0.987654321 - 23/11/2013 1) Quick start ============== Place the VGA folder in your libraries directory Start or restart the Arduino IDE For VGA mono: ------------- Upload File->Examples->VGA->HelloWorld Connect pin 42 to VGA VSync (pin 14 on VGA D-connector) Connect pin 43 to VGA HSync (pin 13 on VGA D-connector) Connect GND to VGA GND (pins 5,6,7,8,10 on VGA D-connector) Connect SPI MOSI pin (bottom middle pin on 6-pin SPI connector) through a 100 ohm resistor to VGA Red, Green and Blue pins (pins 1,2 and 3 on D-connector) Turn on monitor :-) If the monitor has trouble, try some small resistors between 42 and VSync, and 43 and HSync (10 to 100 ohm) For VGA colour: --------------- Upload File->Examples->VGA->HelloWorldColour Connect Due to monitor as follows: Due pin 34 -> 820R resistor -> VGA pin 3 (blue) Due pin 35 -> 390R resistor -> VGA pin 3 (blue) Due pin 36 -> 2k2 resistor -> VGA pin 2 (green) Due pin 37 -> 1k resistor -> VGA pin 2 (green) Due pin 38 -> 470R resistor -> VGA pin 2 (green) Due pin 39 -> 2k2 resistor -> VGA pin 1 (red) Due pin 40 -> 1k resistor -> VGA pin 1 (red) Due pin 41 -> 470R resistor -> VGA pin 1(red) Due pin 42 -> VGA pin 14 (VSync) Due pin 43 -> VGA pin 13 (HSync) Due pin GND -> VGA pins 5,6,7,8,10 For NTSC/PAL: ------------- Upload File->Examples->VGA->DrawingTestNTSC (or DrawingTestPAL) Connect Due to TV as follows: Due pin 36 -> 3k3 resistor -> Video In Due pin 37 -> 1k6 resistor -> Video In Due pin 38 -> 820R resistor -> Video In Due pin 39 -> 390R resistor -> Video In Due pin 40 -> 200R resistor -> Video In Due pin 41 -> 100R resistor -> Video In Due pin GND -> Video GND On some TVs this will not work. You may need a 100uF capacitor between the resistors and Video In. 2) Basic usage ============== The library is very simple to use - see the examples #include <VGA.h> at the top of your sketch, VGA.begin(640,480); in setup for mono or VGA.begin(320,240,VGA_COLOUR); for colour. Then call various drawing functions, eg: drawPixel(x, y, col); sets a single pixel to colour col drawLine(x0, y0, x1, y1, col); draws a line from (x0,y0) to (x1,y1) fillCircle(x, y, r, col); circle, center (x,y) radius r For text, use VGA.print(...) and VGA.println(...) just like Serial.print(...) and Serial.println(...) 3) Colours ========== In mono mode, 1 is white, 0 is black, and -1 inverts the pixel. In colour mode (and PAL and NTSC modes), colours are interpreted in binary as RRRGGGBB. So for example: 0b11111111 = 255 = white 0b11110000 = 240 = orange 0b11100000 = 224 = red 0b10010010 = 146 = grey 0b00011100 = 28 = green 0b10000011 = 227 = purple 0b00000011 = 3 = blue 0b00000000 = 0 = black In the draw* and fill* functions, negative colour values XOR with the current colour of the pixel, ie newcol=oldcol^(-col) 4) API ====== int VGA.begin(int x, int y, int m=VGA_MONO); Initializes the display, resolution (x,y). m is VGA_MONO or VGA_COLOUR Returns: 0 on success, negative on failure Not all resolutions work on all monitors. Highest recommended resolutions are 800x600 in mono and 320x240 in colour. int VGA.beginNTSC(); Initializes the display in NTSC mode, 320x200 pixels. Returns: 0 on success, negative on failure int VGA.beginPAL(); Initializes the display in PAL mode, 320x240 pixels. Returns: 0 on success, negative on failure void VGA.end(); Stops the display, and frees memory. void VGA.clear(int col=0); Clears the screen to colour col, or black if col is not specified. void VGA.drawPixel(int x, int y, int col); Draws pixel at (x,y) in colour col void VGA.drawLine(int x0, int y0, int x1, int y1, int col); Draws line from (x0,y0) to (x1,y1) in colour col void VGA.drawTri(int x0,int y0,int x1,int y1,int x2,int y2,int col); void VGA.fillTri(int x0,int y0,int x1,int y1,int x2,int y2,int col); Draws or fills triangle (x0,y0),(x1,y1),(x2,y2) in colour col void VGA.drawRect(int x0, int y0, int x1, int y1, int col); void VGA.fillRect(int x0, int y0, int x1, int y1, int col); Draws or fills rectangle with corners (x0,y0),(x1,y1) in colour col void VGA.drawCircle(int x, int y, int r, int col); void VGA.fillCircle(int x, int y, int r, int col); Draws or fills circle center (x,y) radius r in colour col void VGA.drawEllipse(int x0, int y0, int x1, int y1, int col); void VGA.fillEllipse(int x0, int y0, int x1, int y1, int col); Draws or fills ellipse bounded by rectangle (x0,y0),(x1,y1) in colour col void VGA.drawText(char *text, int x, int y, int fgcol, int bgcol= -256, int dir=0); Draws text at any pixel position. (x,y) is the top-left corner of the text before rotation. fgcol is the colour of the text. bgcol is the colour of the text background or -256 for a transparent background. dir is the direction of the text. 0 is normal, 1 is up, 2 is upside-down and 3 is down. -1 draws the text going downwards but with the individual characters oriented normally. void VGA.scroll(int x, int y, int w, int h, int dx, int dy,int col=0); Scrolls an area of the screen, top left corner (x,y), width w, height h by (dx,dy) pixels. If dx>0 scrolling is right, dx<0 is left. dy>0 is down, dy<0 is up. void VGA.moveCursor(int column, int line); Moves the print position to (column, line) void VGA.setPrintWindow(int left, int top, int width, int height); Restricts the printing window to an area of width x height characters, at a position left characters in and top characters down. void VGA.unsetPrintWindow(){tww=tw;twh=th;twx=twy=0;} Restores the print window to be the whole screen. void VGA.clearPrintWindow(); Clears the print window to the current text paper colour. void VGA.scrollPrintWindow(); Scrolls the print window up one line and moves the print position to the bottom. void VGA.setInk(int i){ink=i;} Sets the text colour to i. void VGA.setPaper(int p){paper=p;} Sets the text background colour to p virtual size_t VGA.write(const uint8_t *buffer, size_t size); virtual size_t VGA.write(uint8_t c); These functions are similar to Serial.write, except output gets printed to the screen. These functions enable print and println to work correctly. void VGA.waitBeam() void VGA.waitSync() These functions wait for the beam position to be off-screen. waitBeam will return immediately if the beam is already off-screen, waitSync will always wait for the next frame. These can be used to reduce flicker. void VGA.setMonitorFreqRange(int hmin, int hmax, int vmin, int vmax) This function can be tried if your monitor has trouble syncing to some modes. All frequencies are in Hz, eg setMonitorFreqRange(27000, 82000, 58, 65); Call this before VGA.begin(...) void VGA.setSyncPolarity(bool h, bool v) Swaps the polarity of the sync signals. Most monitors don't need this. Call this before VGA.begin(...) void VGA.putPPixelFast(int x, int y, int c) int VGA.getPPixelFast(int x, int y) void VGA.putCPixelFast(int x, int y, int c) int VGA.getCPixelFast(int x, int y) Fast inline pixel put/get routines. The P functions are for mono modes and the C functions are for colour modes. 5) Low Level ============ In mono modes, the screen is arranged as an array of 16-bit words. Each line has enough words for the pixels (eg 40 words in 640x480 mode) plus 2 spare words which are used for blanking and must always be 0. uint16_t *VGA.pb; // Pixel buffer memory address int VGA.pw; // Count of words from one line to the next (aka stride or pitch) int VGA.pbsize; // Total size of pixel buffer (note these sizes are 16-bit words) The SAM3X also supports a bit-banding alias region in memory, where each bit is mapped to a 32-bit address. uint32_t *VGA.pbb; // Pixel buffer bit-banding alias address (read datasheet p75) int VGA.pbw; // Pixel buffer bit-banding stride (in 32-bit words) To help understand usage of these, look at the following functions: void putPPixelFast(int x, int y, int c){pbb[y*VGA.pbw+(x^15)]=c;} int getPPixelFast(int x, int y){return pbb[y*VGA.pbw+(x^15)];} In colour modes there are no spare words needed so the colour buffer is just an array of uint8_t[width*height]. uint8_t *VGA.cb; // Colour buffer memory address int VGA.cw; // Colour buffer stride, in bytes int VGA.cbsize; // Size of colour buffer in bytes 6) How it works =============== Don't ask ;-) Basically it uses nested interrupts. Each line the PWM hardware generates the horizontal sync signal then interrupts the processor. Unfortunately it interrupts at a very slightly different time each line, which would cause a shimmering effect. So the PWM interrupt puts the processor to sleep, waiting to be interrupted again by a timer interrupt at higher priority. Since the processor wasn't doing anything, this interrupt is precisely synchronized to the timer and the display is rock solid :-) The mono modes use DMA and SPI hardware (42MHz for 800x600!) and are therefore quite fast. The SPI DMA uses another interrupt to signal the end of a line. Unfortunately at the end of transmission the SPI output goes HIGH, which would cause a white line. That's why there are spare blanking words at the end of the line - when the interrupt fires the DMA is out of data but the blanking words are still being output, so the interrupt routine quickly sets the pin back to PIO mode, putting it low, and avoiding the white line. The colour mode uses DMA to the SMC - static memory controller - to output 8 bits of data at a time to pins 34-41. No end-of-line interrupt is needed here because the output goes high impedance when data is not being written. The pixel width is controlled by changing the memory timing registers in the SMC. The NTSC and PAL modes use a pair of DMA buffers. One is outputting the signal for the line whilst the interrupt routine is filling the other buffer for the next line. The colour burst and chroma phase tables have been precalculated (which is why these modes use so much flash). Have fun!