Introduction

 

Generating color video on the Atmel AVR microcontrollers is basically impossible without additional hardware.  This is because NTSC color video requires the creation of a ~3.58MHz signal, which would be fairly hard to do on a microcontroller running at 16MHz.  The fastest speed that PWM can run is equal to the i/o clock speed divided 256, so to get a 3.58MHz signal the chip would have to be running at over 900 MHz, which is impossible for these chips, of course.  It may be possible to hardcode in the signal by altering values on a port, but this would still require about 4 times the signal frequency (assuming 4 samples per signal cycle), which would allow little time for doing anything else.  Values would not even be able to be taken from flash, as that would require about 2 cycles per value, which would then require the clock speed of the microcontroller to be about 12 times the signal frequency, or 42 MHz.

 

Since I wanted to be able to do something else with the microcontroller besides just display video (i.e. make a game), hardware for encoding the NTSC color was used.  In addition, since creating a good sync signal that the encoding chip could use was more difficult than creating the black and white sync signal, a sync generator chip was also used.

Video Generation Basics

 

Knowing how to create a good black and white signal was very helpful in creating color video, at least when there were problems in the generation.  I used the Video Generation page at the 476 website extensively in addition to the Video Tutorials page, by Glen A. Williamson.  The last website is especially useful in learning about how the sync signal is created, which was definitely important when using the sync generator, as the data sheet for the generator did not explain what the signal looked like.

 

Creating Color

Hardware

The above is a diagram of the circuit used to display video.  Only parts necessary to video production are included; input devices are not included, but can be easily added to any of the open ports on the microcontroller.  Pictured above, you can see the sync signal coming from the ELM304, going to pin 16 on the AD724 and also going to two of the external interrupts on the mega32.  The mega32 uses the last 4 bits of port C to send the color signal to the AD724.  Bits 4 and 5 are used for green, so the two bits must pass through a DAC to convert the two bits to one analog voltage.  The composite output that gets sent to the TV comes out from pin 10 of the AD724.  If the TV has S-Video, pins 9 and 11 can be used to create an S-Video signal.

 

Software

I created two versions of the display software.  The first version is written entirely in assembly and is to be used for 8 bit color, with 4 bits assigned to green, 3 to red and 1 to blue.  A simple paint program was written for this version, where you can move a cursor around the TV screen and change the color of the pixel the cursor is currently located on.  All code was written at the end of a frame, and could be finished within the time of one line, or 63.5 us.

Assembly Code

 

The second version of the code is written in C, with the display portion in assembly.  Once a frame has been written, portions of the code have been reserved for writing C code.  Code should be broken up so that it runs during separate “lines”, meaning that when line 251 has been reached, run task1, when line 252 has been reached, run task2, etc.  This was due to the display code being taken from assembly, so register saving was turned off.  Register saving could be turned on, at the expense of about 75 cycles.  A rewrite of the program would also have to occur, since the majority of the time is spent in the ISR and an interrupt cannot occur while another interrupt is taking place.  In any case, the second version of the code functions in the same as the first version of the code, except the resolution has been doubled, at the expense of color depth.

 

Functions included in the C version:

 

void writePixel(char x, char y, char color);

Writes a color to the specified location.  Colors are 4 bit numbers, green occupying bits 0 and 1, red on bit 2, and blue on bit 3.

int getByteLoc(char x, char y);

Converts (x,y) coordinates to a location in the screen array

char readPixel(char x, char y);

Reads back the color of a pixel.  The color is stored in the first 4 bits of the byte, no matter where the color is taken from (upper or lower nibble)

void invertPixel(char x, char y);

Inverts the color of the pixel at the selected location

void textureWrite(char x, char y, char textureIndex);

Writes an 8x8 texture, based on the texture index, to the selected location.  This will overwrite whatever is currently there. Only works for odd values of x.

void writeChar(char x, char y, char letter, char color);

Writes a 5x7 character to the selected location.  Only works on odd values of x.  The black areas of the character (blank areas) will not write black to the screen, but save what is written there.  Meaning, if you have a blue background, and write a green R to the screen, the blank areas in the R will be blue, instead of black

void paintTime(void);

Main paint program

char pollButtons(void);

Polls the switches located on PORTA

void cursorInvert(void);

Inverts the cursor every 15 frames

 

C code

 

Both versions of the display code work in the following manner

o       The microcontroller interrupts on the sync pulses and waits for the equalization and vertical sync pulses to occur.  At this point, the sync interrupt is turned off and the display interrupt is turned on.