Close

PAL Video timings & cycle counting

A project log for Tjipp8 - A Chip-8 game console

A low part count PIC16F1705 game console for the ancient (1970's) Chip-8 bytecode interpreters originally run at the Cosmac 1802.

matsengmatseng 01/18/2017 at 06:200 Comments

The PIC is using an internal 32MHz clock (actually generated by an internal 8MHz clock multiplied by 4 by an internal PLL) giving a base 8MHz / 125ns instruction rate.

In non-interlaced mode the PAL tv standard have 312 lines at a length of 64us each. This adds up to a frame rate of 19.968ms or 50.08Hz.

So each line is 64us long and at a 125ns (0.125us) instruction rate I can (or actually rather "have to") use 512 instructions for each line. That is not entirely true, since some instructions (most notable goto's, calls's and conditional skip/branches) takes two instruction times.

I'm outputting a composite video signal with both of the two sync signals (vertical and horizontal) and the video/pixel data is mixed together into one signal.

The horizontal/line sync is normally a 4us long low pulse that is sent at the very beginning of each of the 312 lines. But at the beginning of each frame there is a several hundred microseconds long vertical sync pulse as well. During this time we still need to regularly send the horizontal/line sync pulses but the output is already held low by the vertical sync, so during that period they have to be sent as short high "interruptions" instead.

Apparently there are some trickery to coax the tv into behaving nicely in non-interlaced mode. The TV is most happy with the interlaced mode where the odd lines are sent in the first frame and the even lines is send in the next, but this is a pain in the neck to do from a lowly microcontroller as it requires the last line to be split into two halves and some other complications that I rather live without. But by sending some extra short and extra super long sync pulses during the frame sync (beginning of each full frame) the TV seems happy enough.

My code is currently timed by keeping track of the number of instructions and their execution time (1/2 cycles), I'm not using interrupts to control the timing, this is the next step now when I got the basic functionality tested and working. I've made a number of subroutines (aka "functions" for you belonging to the high-level language crowd) that takes care of a specific type of line. Each function takes exactly 507 cycles to allow for some extra code like the loops to be added between the calls. If I don't need to do anything between two calls I simply add a 5 cycle delay there to waste up the time to a perfect 512.

A few handling the special vertical syncs. One doing the regular video lines, but not outputting any data to just get some margins at the top and bottom of the screen. And one that is actually outputting video data by shifting out 8 bytes one by one on a gpio pin resulting in 64 pixels in X-resolution.

The same 8 bytes of data is used on 7 consecutive lines to build up a a roughly square pixel. Then the next set of 8 bytes are used for the following 7 lines.

This image shows the basic timing that I'm using:

I got the most of the VGA info from http://martin.hinner.info/vga/pal.html

FrameLoop:
    call    SyncLongLongLine
    call    SyncLongLongLine
    call    SyncLongShortLine
    call    SyncShortShortLine
    call    SyncShortShortLine

(Loop40Times)
    call    VideoLine
(Loop224Times)
    call    PixelsLine
(Loop40Times)
    call    VideoLine

    call    SyncShortShortLine
    call    SyncShortShortLine
    call    SyncShortShortLine

    goto    FrameLoop

Discussions