I looked around for a TV test-pattern an found this very simple and clean one:
http://hklab.net/wiki/TV_Video_Signal_Generator_with_Arduino
Its done on an ardunio board, but supprisingly not compiled within the IDE, so I changed the code
to run in Arduino 0009. I also changed it to support the same circuit and pins that Al uses in arduino pong.
So video out is still generated on digital pin 8+9.
Now, I can see 3 nice vertical bars, which tells me that the ghost pictures I get from the arduino
pong code is probably not a hardware issue of my circuit or beamer...
Although the ghost pictures I see in pong are all exactly vertically shifted... maybe I just don't see them in
the 3 vertical bars pattern?
Anyways, I think this code is a good test! And maybe an even better starting point for proper
video generation. It also looks like the _delay_us() function is more accurate than delayMicroseconds...
When I've time and muse to pull that clunky scope from my shelf, I'll compare the signal patterns of this 3 bar test and arduino pong. :-)
/*
Vertical Bars Pattern PAL TV Signal Generator with Arduino
Use this code as you want
2007 Javier Valcarce Garcia, <javier.valcarce@gmail.com>
---
copied from http://hklab.net/wiki/TV_Video_Signal_Generator_with_Arduino
This pattern should work on PAL and NTSC TV sets, as mentioned on the webpage.
It's slightly changed to compile inside the standard Arduino IDE (Version 0009)
Note that the left and right bar are usually not exact the same size, as
there are slight offsets in most TVs.
See reference: http://www.retroleum.co.uk/PALTVtimingandvoltages.html
2007.09.11 Oliver Keller <oli.keller@gmail.com>
*/
// yes, ther is an avrlibc inside arduino...
#include <util/delay.h>
/////////////////////////////////////////////////////////////////////////////////////////////////
// Pins where the 2-bit DAC is connected, this is the composite video-out ;)
// PINB0 is DigitalPin 8, PINB1 is DigitalPin 9
#define PINB0 0 // LSB, 1 kOhm resistor
#define PINB1 1 // MSB, 330 Ohm resistor
// PINB1 PINB0 OUTPUT
// 0 0 0.0V - Sync level
// 0 1 0.3V - Black level
// 1 0 0.6V - Gray level
// 1 1 1.0V - White level
#define LEVEL_SYNC PORTB &= ~(1 << PINB1); PORTB &= ~(1 << PINB0);
#define LEVEL_BLACK PORTB &= ~(1 << PINB1); PORTB |= 1 << PINB0;
#define LEVEL_GRAY PORTB |= 1 << PINB1; PORTB &= ~(1 << PINB0);
#define LEVEL_WHITE PORTB |= 1 << PINB1; PORTB |= 1 << PINB0;
/////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////
inline void vsync_pulse()
{
LEVEL_SYNC;
_delay_us(30);
LEVEL_BLACK;
_delay_us(2);
}
/////////////////////////////////////////////////////////////////////////////////////////////////
inline void equal_pulse()
{
LEVEL_SYNC;
_delay_us(2);
LEVEL_BLACK;
_delay_us(30);
}
/////////////////////////////////////////////////////////////////////////////////////////////////
inline void hsync_pulse()
{
LEVEL_SYNC;
_delay_us(5); //4.7us
LEVEL_BLACK;
_delay_us(7); //7.3us
}
unsigned int line = 0;
/////////////////////////////////////////////////////////////////////////////////////////////////
void setup()
{
/* NOTE THAT THE SIGNAL GENERATED BY THIS PROGRAM HAS A NOT VERY ACCURATE TIMING SO
IT IS POSSIBLE THAT THE IMAGE BLINKS ON YOUR TV SCREEN OR DOESN'T SHOW AT ALL,
THIS PROGRAM WRITTEN IN C (INSTEAD OF ASSEMBLER) IS ONLY A PROOF OF CONCEPT */
DDRB = 0xFF; // PORTB, all pins are outputs
cli();
}
void loop()
{
if (line == 626)
{
line = 1;
}
else
{
line++;
}
switch(line)
{
case 1:
case 2:
case 314:
case 315:
vsync_pulse();
vsync_pulse();
break;
case 3:
vsync_pulse();
equal_pulse();
break;
case 4:
case 5:
case 311:
case 312:
case 316:
case 317:
case 623:
case 624:
case 625:
equal_pulse();
equal_pulse();
break;
case 313:
equal_pulse();
vsync_pulse();
break;
default:
// Image scanline (not a sync line)
hsync_pulse(); // Horizontal Sync, lenght = 12us
LEVEL_GRAY;
_delay_us(8);
LEVEL_BLACK;
_delay_us(14);
LEVEL_WHITE;
_delay_us(8);
LEVEL_BLACK;
_delay_us(14);
LEVEL_GRAY;
_delay_us(8);
//52us in total
}
}
Note the code works on ATmega168 as well as on ATmega8 arduino boards. Its even smaller than the arduino bootloader (1k)
