Cornell University
Electrical Engineering 476
Video Generation
with Atmel Mega32 and Codevision

Introduction

A television (TV) monitor is a good example of a device which needs hard-realtime control. The TV is controlled by periodic synchronization (sync) pulses. If a sync pulse is late, the TV picture quality suffers. So a late calculation is worth nothing. The Atmel AVR mcus are fast enough to generate black and white (but not color) sync and image content, as long as you obsessively pay attention to the time required for every operation.

Small TV monitors also seem to be one of the cheapest graphics devices you can buy, include audio amplifiers and speakers, and are designed to be almost bullet-proof. A perfect lab device.

Video Generation

There are several very good references for understanding how TVs are controlled by a pulse sequence. I particularly liked the Stanford EE281 Handout #7 entitled "TV paint". Also very useful were Software generated video, by Rickard Gunée, Video Tutorials by Glen A. Williamson, and various excellent projects by Alberto Riccibitti. Mark Oreglia, Professor, Department of Physics at The University of Chicago and The Enrico Fermi Institute was kind enough to allow me to post a full interlaced, NTSC sync driver.

The goal is to generate non-interlaced, black and white video, with enough image content to be interesting as a graphics device. The software described here implements an NTSC-rate, non-interlaced, video signal. For ease of teaching, I wanted as much of the code as possible to be in C, with litttle or no assembler. The steps in developing the code are given on the history page. The current version of the code is entirely in CodeVision C and assembler. It generates a 128 (horizontal) by 100 (vertical) bit map at standard video rate. There are utilities for drawing lines, points, and text, and for reading back the screen color. The raster generation code needs to run fast to get good pixel density. Once the TV gets to line 231, there is some extra time to do computations, interact with users, or update state. All drawing must be done during TV scan lines 230-260 and 1-30 to avoid visual artifacts. Drawing is done by writing bits (pixels) into the main screen array, while the array is not being displayed. The drawing utilities describeld below write screen memory for you.

Since most TVs have a sound input, it would be nice to be able to generate some sound from the program. The MEGA32 version of the code uses the timer0 square wave generator to make tones. Since no ISR is required to generate the tone, the music coexists well with the tight timing requirements of the video. An example is show in the code below.

Video DAC

Two bits of a port are used to generate three video levels:

The circuit shown below connects the Mega32 to the TV.

Program Organization

The programs linked below have four main parts:

  1. The timer1 compare-matchA ISR generates the horizontal and vertical sync. One lines 30-230, a single line of the the raster is drawn by dumping 16 bytes to the video DAC as fast a possible. You should not need to modify the ISR unless you want to add a short amount of code that need to execute 15,750 times/sec.
  2. Two big tables containing the bitmaps for the large and small characters. Feel free to design our own characters.
  3. Functions which implement a few primitive graphics operations which are nice to have
  4. The main function of the program. The timers are initialized and constant lines and strings are drawn. Then the program drops into a while loop which spends most of each frame asleep in order to cause ISR to execute with cycle-accurate timing (to aviod video jitter). When the screen is not being actually refreshed by the cpu (of course the sync pulses are still generated), there is about 4 mSec between frames to update the screen content Using the following API.
void video_pt((char x, char y, char c)

Draw a point into video memory. Specify the horizontal position 0<=x<=127, 0<=y<=99 (increasing downward) and the color with black=0, white=1, and xor=2. You can draw about 500 points in one frame time (in compiler version 1.24.6).

char video_set((char x, char y) Read back a point from video memory. A white point will read back as a nonzero value (actually the bit within the video memory byte which is being checked).
void video_line(char x1, char y1, char x2, char y2, char c) Draw a line into video memory. The line extends from (x1,y1) to (x2,y2) with a color as above. Uses a Breshenham algorithm for speed. You can draw about 500 points worth of lines in one frame time (in compiler version 1.24.6).
void video_putchar(char x, char y, char c) Draw a 5x7 character at (x,y) with ascii character code c. The coordinates represent the upper-left corner of the character. You can draw about 16 5x7 characters in one frame time.
void video_smallchar(char x, char y, char c) Draw a 3x5 character at (x,y) with character number c. The x coordinate must be divisible by 4. The coordinates represent the upper-left corner of the character. You can draw about 100 3x5 characters in one frame time.
void video_puts(char x, char y, char *str) Draw a 5x7 string starting at (x,y). The coordinates represent the upper-left corner of the first character. You can draw about 16 5x7 characters in one frame time.
void video_putsmalls(char x, char y, char *str) Draw a 3x5 string starting at (x,y). The x coordinate must be divisible by 4. The coordinates represent the upper-left corner of the first character. You can draw about 100 3x5 characters in one frame time.

Examples

For the most part, you should not have to mess with any of the code before the main routine in the examples below. If you need to perfrom some fast function 15,750 times/sec (perhaps sample the A/D converter to make a digital scope), you could put code at the end of the timer1 ISR. For all examples, be sure to set the CodeVision compiler controls (in the Project:Configure... menu) to:

  1. Bouncing ball with sound 2008
    This code bounces a ball around the screen while playing a musical scale. Collisions with the two thick lines are detected with the video_set function. Video.
  2. Animation with fixed point arithmetic. 2008
    This code simulates gravity and atmospheric drag. Bouncing is enforced by detecting the boundaries of the screen and negating the appropriate velocity component. The calculations are carried out in 8:8 bit fixed point with the binary point at the byte boundary. Video.
  3. 3D perspective projection of a tetrahedron. 2008
    This code assumes that the computer graphic camera is on the negative z-axis, pointing toward the origin, with the x-axis to the right. The projection is perspective. The calculations are carried out in 8:8 bit fixed point. To save time in the code, the video raster was compressed as much as possible so that it only fills about 1/2 the TV screen. Video.
  4. 3D orthographic projection of a tetrahedron. 2008
    This code assumes that the computer graphic camera is on the negative z-axis, pointing toward the origin, with the x-axis to the right. The projection is orthographic to eliminate the slow perspective divide operation in the previous code. To save RAM space, the sine and cosine tables have been moved to eeprom. The calculations are carried out in 8:8 bit fixed point. To save time in the code, the video raster was compressed as much as possible so that it only fills about 1/2 the TV screen. Video.

 


Copyright Cornell University March 2008