Here is a weird thing that grew from a chance conversation: when finished, it will be a clock which displays the time on four separate PAL monochrome monitors; one digit per monitor. The idea is that a single ATMega8 chip can do everything necessary to generate 4 streams of video and still have enough time left over to handle the housekeeping that a clock requires. The only other requirements are a 16MHz crystal - as accurate as possible, because it will be the timebase - and a fistful of resistors to mix the sync and video pulses together.
I don't generate real PAL format video - the ITU would have a fit if they cared about it... To avoid vertical flicker, I don't build a half-line offset into successive fields as the specification requires; instead, I use two fields of 312 lines per frame, for a total of 624 lines. I also do away with equalising pulses, and use a three-line long vertical sync pulse without inverted line syncs.
The tricky thing here is the timing. A 16MHz Mega8 performs the majority of
its operations within a single clock cycle of 62.5nS. However, that's more
than enough jitter to give wibbly vertical lines if the sync pulse or the
start of the active line is displaced by only one clock period.
Unfortunately, the time taken to respond to an internal interrupt on the Atmel range can only be guaranteed if the chip is in sleep mode. It turns out that I need accurate timing, as mentioned above, for both the line sync and the active line start. It's probably possible to use a single interrupt every 64uS, and make sure all the timing intervals through the various test conditions are the same, but life's too short. Instead, I generate an interrupt every 16uS - four times a line. Here's how it works...
Firstly, there's a counter that keeps track of which interrupt has happened. They're numbered 0-3.
Assume that we've just had interrupt #3, and we're asleep. We have to be, because the first thing that happens is the interrupt routine decides - very quickly - which interrupt is next. In this case, it's #0.
Interrupt #0 forces the sync output low because we always need a sync, and it does three things depending where it is on the screen. If it's a field sync, it just returns - we can use that time for other stuff. Otherwise, it delays 4.7uS - one line sync - and then sets the sync output high, Now it decides if video will be displayed on this line and if it will be it goes to sleep; otherwise, again, we can use the time and it returns.
Interrupt #1, in due time, comes along. If we're not on an active line, it returns immediately; if we are, it does an awful lot of reading from memory and setting of output bits. This setting takes 32uS exactly, but the routine runs a wee bit longer...
Which is bad news for interrupt #2. It happened at t+32uS, somewhere in the middle of the display, It doesn't do anything, save increment the interrupt counter and return, and in a non-active line there's no problem. However, the Mega8 merely flags that an interrupt has happened, unless they are enabled by the interrupt routine itself - which by default doesn't happen and in this case would cause a big glitch in the middle of the display.
Snag is, interrupt #3 came along before we finished interrupt #1, so poor old #2 got lost.
Being hard hearted, though, it's easy to deal with this; interrupt #1 - if it's on an active line - increments the interrupt counter and simply pretends that interrupt #2 has happened. How mean is that?
Anyway, when interrupt #1 returns, interrupt #3 has already happened and is champing at the bit... so now it executes. It looks after housekeeping; updating line counts, updating the clock ticks; and then, being very tired, it goes to sleep...
Which is where we came in.
The code here is incomplete, and it's never been tested on real silicon. It simulates beautifully on Atmel's development system 4.07, but it's missing some vital routines; I refer you to ShowTime, which is intended to update the display when a minute changes, and look after setting routines. One day I'll get around to writing it...
Oh, for the record, the chip displays a rather coarse pixel grid of 32 cells across by 48 cells deep. This gives a pixel size of 1uS by 4 lines deep, so the characters will probably look a little stumpy... but it was originally intended to be shown on those 3/4" viewfinder displays, and I can always tweak the height :)