Starting and stopping video: synchronizing the start to external events.
Phil Pilgrim (PhiPi)
Posts: 23,514
Here's a video gotcha I learned the hard way. I was wanting to start a video output sequence a certain amount of time after an external stimulus. It was also necessary for the video scale (vscl) to vary from event to event (think double-wide characters) but for the start time to remain invariant. In most apps, once the video hardware is started, it just keeps running, and you don't have to worry too much about any startup glitches or which of vcfg or vscl gets loaded first. The system quickly reaches a steady state, and you can just start feeding it pixels.
But I wanted to be able to turn the video on and off at precise times, so what happens at startup was of paramount importance. It seemed reasonable to assume that I could load vscl first with the scale factor I wanted, then load vcfg with the proper configuration data and that the video would start up with the scale factor I had selected. Then, once the video output was done, I could just set vcfg to zero and wait for the next event. I couldn't have been more wrong! The startup delays varied, and I couldn't figure out why.
What I learned and the take-home lesson from this thread is as follows: The video hardware does not load its internal scaling register from vscl when vcfg is initialized. The only time this register is loaded is during the execution of a waitvid. When you turn on the video by setting vcfg, it starts up using the scaling values extant internally, not the value in vscl. What this means is that you have to "prime the pump" with the next vscl value before the last waitvid. The last waitvid can, however, be a dummy. In other words, you can set vcfg to zero immediately following it, thus truncating the video output from it almost instantly.
Here's a program I wrote to illustrate what I'm talking about:
It generates two video frames, one after each marker pulse: a narrow one, followed by a wide one. When the "extra vscl load" is commented out, this is what the output looks like:
········
Notice that the start time is one full video frame long, equal in length to the frame before the video was turned off.
Now, with the extra load included, here's the improved output:
········
Here, the start time is always one full narrow video frame, since this is the scaling written with the extra load. For an even faster startup, one could load vscl at the end of every line of video with an even smaller clocks-per-frame value.
-Phil
_
But I wanted to be able to turn the video on and off at precise times, so what happens at startup was of paramount importance. It seemed reasonable to assume that I could load vscl first with the scale factor I wanted, then load vcfg with the proper configuration data and that the video would start up with the scale factor I had selected. Then, once the video output was done, I could just set vcfg to zero and wait for the next event. I couldn't have been more wrong! The startup delays varied, and I couldn't figure out why.
What I learned and the take-home lesson from this thread is as follows: The video hardware does not load its internal scaling register from vscl when vcfg is initialized. The only time this register is loaded is during the execution of a waitvid. When you turn on the video by setting vcfg, it starts up using the scaling values extant internally, not the value in vscl. What this means is that you have to "prime the pump" with the next vscl value before the last waitvid. The last waitvid can, however, be a dummy. In other words, you can set vcfg to zero immediately following it, thus truncating the video output from it almost instantly.
Here's a program I wrote to illustrate what I'm talking about:
[b]CON[/b] [b]_clkmode[/b] = [b]xtal1[/b] + [b]pll8x[/b] [b]_xinfreq[/b] = 10_000_000 CLKSPERPIXEL = 1 [b]PUB[/b] Start [b]cognew[/b](@synctest,0) [b]DAT[/b] [b]org[/b] 0 synctest [b]mov[/b] [b]ctra[/b],[b]ctra[/b]0 'Set up ctra for video PLL. [b]mov[/b] [b]frqa[/b],[b]frqa[/b]0 [b]mov[/b] [b]vscl[/b],[b]vscl[/b]0 'Set up video scaling. [b]mov[/b] [b]vcfg[/b],#0 'Disable video output for now. [b]mov[/b] [b]dira[/b],#1 :testlp [b]or[/b] [b]outa[/b],#1 'Wide marker. [b]nop[/b] [b]nop[/b] [b]andn[/b] [b]outa[/b],#1 [b]mov[/b] [b]vscl[/b],[b]vscl[/b]0 'Setup fast video scale. [b]mov[/b] [b]vcfg[/b],[b]vcfg[/b]0 'Enable video output. [b]waitvid[/b] colors,pixels 'Output video high. [b]waitvid[/b] colors,#0 'Output video low. [b]mov[/b] [b]vcfg[/b],#0 'Disable video output before low finishes. [b]or[/b] [b]outa[/b],#1 'Narrow marker. [b]andn[/b] [b]outa[/b],#1 [b]mov[/b] [b]vscl[/b],[b]vscl[/b]1 'Setup slow video scale. [b]mov[/b] [b]vcfg[/b],[b]vcfg[/b]0 'Enable video output. [b]waitvid[/b] colors,pixels 'Output video high. [b]mov[/b] [b]vscl[/b],[b]vscl[/b]0 '<------------EXTRA VSCL LOAD-------------< [b]waitvid[/b] colors,#0 'Output video low. [b]mov[/b] [b]vcfg[/b],#0 'Turn off video output. [b]jmp[/b] #:testlp 'Loop-d-loop. [b]ctra[/b]0 [b]long[/b] %00001 << 26 | (%011 + >| CLKSPERPIXEL) << 23 [b]frqa[/b]0 [b]long[/b] $16e8_b9fd [b]vscl[/b]0 [b]long[/b] CLKSPERPIXEL << 12 | 16 * CLKSPERPIXEL [b]vscl[/b]1 [b]long[/b] CLKSPERPIXEL << 13 | 32 * CLKSPERPIXEL [b]vcfg[/b]0 [b]long[/b] %01 << 29 | 1 << 28 | %000 << 9 | %0001 colors [b]long[/b] $0101_0100 pixels [b]long[/b] $ffff_ffff
It generates two video frames, one after each marker pulse: a narrow one, followed by a wide one. When the "extra vscl load" is commented out, this is what the output looks like:
········
Notice that the start time is one full video frame long, equal in length to the frame before the video was turned off.
Now, with the extra load included, here's the improved output:
········
Here, the start time is always one full narrow video frame, since this is the scaling written with the extra load. For an even faster startup, one could load vscl at the end of every line of video with an even smaller clocks-per-frame value.
-Phil
_
Comments
This is something that got in my way a coupla times. Thought it was me actually! Didn't have a scope either [noparse]:)[/noparse]
Thanks for posting this.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Propeller Wiki: Share the coolness!
Chat in real time with other Propellerheads on IRC #propeller @ freenode.net
Safety Tip: Life is as good as YOU think it is!
If the internal frame count is not known, like on start-up, waitcnt at least 212 PLL ticks to ensure reaching a 0 count before setting vscl, or of course just waitvid. Waiting on cnt is better when synchronizing multiple cogs. I believe VGA.spin uses the 2-3ms PLL locking time to also accomplish this.
Post Edited (Andrew E Mileski) : 2/13/2009 12:44:56 AM GMT
VSCL is really two entities - a COG accessible register, and a pair of PLLA driven counters. And the pixel data is also two entities - a latch loaded by WAITVID and a shifter. When the frame counter rolls over it triggers a load of the VSCL counters from the VSCL register, a load of the pixel data shifter from the latch, and releases the COG if it's halted on WAITVID.
I suspect (but haven't proven) the VSCL counter is free running and not dependent on VCFG. i.e. if you set VCFG[noparse][[/noparse]30..29] = %00 VSCL & the pixel shifter will continue to operate. Even if VCFG could be used to halt the VSCL counters, when you re-enabled it you have no way of controlling the phase of PLLA w.r.t. the CPU clock (or the phase of the frame counter for that matter).
(Update) I've now proven VCFG[noparse][[/noparse]30..29] = %00 does stop the VSCL counters.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Composite NTSC sprite driver: http://forums.parallax.com/showthread.php?p=800114
Post Edited (ericball) : 4/29/2009 6:29:20 PM GMT
-Phil