How to generate video signals in software using PIC
During the Christmas holidays 1997-1998, I started on a small project, trying to generate a video signal with a PIC16C84. I had seen some video clock generating video signals in software, and thought it was a quite interesting idea, and wanted to take it a step further. I didn’t know much about video signals back then, I basically just had seen how a single scan-line works. But during the spring I learned more and succeeded in making the game Pong with a PIC16C84. I thought this was quite cool, so I made it available on the Internet, and during the summer I also made the game Tetris. I had a lot of feedback about the games from people telling me how cool it was, and from people who actually built the games. Based on this feedback I guess that probably 200-300 people have built my games, which is much more than I expected. A lot of people ask me stuff about video signals and how these games can generate a video signal in real-time in software, so that’s why I’m writing this small piece of text about how to generate video signals in real-time. Hopefully this text will help you to understand video signals and how my games work.
Note: I’ve written a much better document also describing how to generate color, it is based on my SX28 game system, SX28 is a “PIC-compatible microcontroller on steroids” (or actually they’ve just made a true RISC processor with CPI=1 and clocked it very fast)
In this text I assume that you have some basic knowledge about TV’s and good knowledge in electronics and PIC programming, but even if you know a lot of electronics and PIC micro-controllers, you would probably have to read it a couple of times before you understand it completely. (If you don’t understand this text, then don’t ask me about it because if you don’t understand it when I explain it in such detail as in this text, then it is impossible for me to make you understand in a short email)
To understand anything about generating video signals in real-time, one must know how video-signals work in detail, so before we look at any code we’ll have to talk about video signals.
How a standard TV-set works.
A standard TV-set is built with a vacuum tube, which has a phosphor screen that an electron canon shoots at. When the electrons from the cannon hits the screen, light is emitted from the phosphor as long as the canon shoots electrons at it, and it also has a short afterglow. The electron beam from the electron-cannon can be bent using magnets so it shoots at different parts of the screen. If this is controlled so it draws horizontal lines all over the screen repeatedly, while the intensity of the beam is controlled, an image can be drawn on the screen. The screen is redrawn 25 times per second on a PAL system, but to reduce flickering the image is interlaced, showing first all odd lines then all even lines, so the image is partially updated 50 times per second. Thanks to the “persistance of vision effect” of the human brain the image seems to be constant instead of flickering at 50Hz. To get color each dot on the screen is divided into three colors: red, green and blue, however here we’ll only discuss black and white television, because that is only what is possible to generate real-time in software using a PIC.
Different TV standards
There are three major TV-standards: NTSC, SECAM and PAL. The NTSC (Short for “National Television System Committe”, but back in the early days of TV there was problems with getting the same color over the whole picture so a more evil interpretation of the letters is that it stands for “Never The Same Color” ) is the American TV-standard, it has only 525 scan-lines, but it has a update frequency of 30Hz. SECAM (Short for “SÉquentiel Couleur Avec Mémoire” (French for “Sequential Color With Memory”), but as the French usually want to get their own solution to problems, a more evil interpretation is that it stands for “System Essentially Contrary to the American Method”) is the French TV-standard, it has improved color stability and higher intensity resolution but with less color resolution, I don’t know much about that standard. The European standard is PAL (Phase Alternating Lines, or as a PAL enthusiast would interpret the letters: “Perfect At Last”), it has 625 lines per frame, 25 frames per second. It is based on NTSC, but the color-coding has been improved by using a phase shift on every other line to remove the color errors that occurred with NTSC. In this document I will focus on the PAL.
The information in the video signal
The image seen on the screen has different intensities. As the electron beam sweeps over the screen, the intensity that should be at the position of the beam, is sent as a voltage level in the video signal.. There is no information in this intensity information about where the electron beam is on the screen. To solve this, a synchronization pulse is sent in the beginning of each line to tell the TV that the current line is finished and move down the electron beam to the next line. (Like the <Enter> key on the keyboard, when writing a text with a computer) The TV must also know when a new image is coming, this is done by making a special synchronization pattern. (Like the “new document” function when writing a text with a computer) An image that is updated 25 times per second would be quite flickering, so therefor all even lines are drawn first and then all odd, this method shows 50 half images per second, making the picture have less flickering. The information whether the image contains even or odd lines are sent in the vertical synchronization pattern, as different patterns for odd and even images. The video signal has a voltage range 0 to 1V, where 0.3V represents black, and 1.0V is white (gray intensities have voltages between these values). Levels close to zero represent synchronization pulses
The image is divided into scan-lines, it is the most important part of the image since it contains the image data. The scan-lines are all 64us long. First a 4us long sync pulse is sent, by setting the signal level to 0V, to tell the TV that a new line is coming. The old TV’s was kind of slow, so they needed 8us after the sync-pulse to get the electron beam in position. During this time the signal is kept at black level. The 8us delay is followed by the image data for 52us, drawn on the screen from the left to the right with the intensities obtained from the video signal. Black is represented by 0.3V and as the voltage increases the intensity increases, with the maximum intensity at 1.0v (white). See the image right to see the scan-line.
Putting the scan-lines together to an image
An image is built from 625scanlines, but a TV doesn’t show 625 lines. Some of the lines are used for synchronization pulses, and some lines are invisible (I don’t know exactly how many) because old TVs needed some time to move the electron beam from the bottom of the screen. (Those invisible lines are nowadays used for other purposes, Text-TV for example).
The vertical synchronization pulses.
To tell the TV that a new image is coming, a special pattern of synchronization pulses is sent. Since the picture is built from two half pictures, the pattern is different for the odd and even images. The vertical synchronization pulses looks like this
This picture shows the different vertical synchronization pulses for the two half images. The levels are 0v and 0.3v. Numbers below signals shows scan-line number. (Click to enlarge)
How to do it in software
Creating video signals in software Ok, this is the part about how to create the video signal in software, it will not be possible to understand if you don’t understand the video signal stuff described above.
When you know how a video signal should look like, it is quite easy to generate it in software, if you have unlimited processing power. The problem is that it requires a lot of power from the processor, but if you don’t have a powerful processor it can be done anyway, by thinking before writing the code.
In my code examples in this part I will use the two following macros:
DNOP – dual nop, a macro to wait for two clock cycles, instead of two nops
DELAY – a delay macro that delays 3 times the number of clocks in the W-register.
To be able to generate a video signal, some hardware is needed to be able to generate signal levels between 0 and 1V. To get a picture you’ll need at least 3 levels. The TV needs sync and black level to be able to lock on the video signal. If you want more than a black image you’ll need some gray or white level. Some kind of digital to analog converter is needed, with at least 2bits to get enough levels. The input impedance of the composite input on a standard TV is 75 Ohms, and by using two resistors a 2-bit DA can be created (as in the images below) thanks to voltage division.
By connecting both D0 and D1 to ground, the voltage at the input of the TV will be 0v (sync level) because nothing is connected to VDD.
Connecting D1 to ground and D0 to 5v, will put the 450ohm resistor in parallel with the 75ohm input impedance of the TV, and with the 900ohm resistor connected in series, and thanks to voltage division this generates 0.33v at the input of the TV, and that is quite black. (true black level is 0.3v)
Connecting D1 to ground and D0 to 5v, will put the 900ohm resistor in parallel with the 75ohm input impedance of the TV, and with the 450ohm resistor connected in series, and thanks to voltage division this generates 0.67v at the input of the TV, and that is gray.
Connecting both D1 and D0 to 5v, will put the 450ohm resistor in parallel with the 900 ohm resistor, with the 75ohm input impedance of the TV connected in series, and thanks to voltage division this generates 1.0 at the input of the TV, and that is white level.
With this circuit, four levels can be created. The image above shows the equivalent circuits for the four different levels and how the voltages are created. Resistor values are not critical, you could use the more standard values 470 and 1k instead of 450 and 900, it will still work anyway. (Little bit different intensities, but not much)Ok, so now we can create sync, black, gray and white levels. That is enough to make simple graphics like in my Pong and Tetris games. It is possible to create more levels by using better DA converters with more levels, but if you want more bits in the DA you should use a real DA instead of the resistor-based that I use in my games. (You’ll also need a faster processor)
Software vs. hardware generated video signals.
On a standard video system like the graphics card in a PC, information about what to draw on the screen is taken from a memory. This is done automatically in hardware. Synchronization pulses are also created automatically in hardware, all the software need to do is to write to the memory to tell the hardware what the image on the screen should look like. Not only does this require a lot of hardware, it also requires a lot of memory, on a PC graphics card there is usually several megabytes of graphics memory. In a PIC16F84 there is 68byte memory, and that memory should also be used for other purposes like application variables and such. It is not possible to store the whole image in memory like on graphics cards, the image has to be generated as the video signal sweeps across the screen. Generating video signals in software on such a simple processor is kind of hard, only very simple images can be created. The advantage is that it is quite cheap, and it is quite cool too. =)One scan-line, making a vertical bar.
The first test I made when I started experimenting with software generated video was to make a white vertical bar on the screen. By creating one scan-line with color information gray-black-white-black-gray, and repeated the scan-line forever, an image could be seen on a TV. The signal contained the horizontal sync-pulse, followed by a delay and then the color information, so the TV could lock to the signal horizontally. (Not vertically because, there was no vertically sync-pulses). I think it looked something like this:
For more detail: How to generate video signals in software using PIC