Here's the spiral demo in 1280 x 1024 VGA 60Hz. You can change it to 75Hz by changing two constants.
I made this the other day, but just got it working right. It uses 6 or 7 cogs to render the image into two small buffers that the VGA driver flips between for glitch-free video.
'***************************
'* VGA Spiral 1280x1024 *
'***************************
CON vga_base = 8 'must be a multiple of 8
cogs = 6 '2..7, set to 7 for 75Hz
loads = 1024 / (cogs * 2) + 1
lines = loads * cogs * 2
blanks = 38 - (lines-1024)
intensity = 90 '0..128
fclk = 320_000_000.0
fpix = 108_000_000.0 '60Hz, set to 135_000_000 for 75Hz
fset = (fpix / fclk * 2.0) * float($4000_0000)
DAT org
hubset ##%1_000000_0000001111_1111_10_00 'config PLL, 20MHz/1*16*1 = 320MHz
waitx ##20_000_000 / 100 'allow crystal+PLL 10ms to stabilize
hubset ##%1_000000_0000001111_1111_10_11 'switch to PLL
coginit #7,.vga 'launch vga cog
.launch coginit .cogn,.bmap 'launch bitmap cogs
djnf .cogn,#.launch
.bmap long @pgm_bmap
.vga long @pgm_vga
.cogn long cogs - 1
'**********************************
'* VGA 1280 x 1024 x 8bpp rgbi8 *
'**********************************
DAT org
pgm_vga setxfrq ##round(fset) 'set transfer frequency to fpix
setcy ##intensity << 24 'r set colorspace for rgb
setci ##intensity << 16 'g
setcq ##intensity << 08 'b
setcmod #%01_0_000_0 'enable colorspace conversion
wrpin dacmode_hsy,#0<<6 + vga_base + 0 'enable dac mode in pin 0 for hsync
wrpin dacmode_rgb,#2<<6 + vga_base + 1 'enable dac modes in pins 1..3 for rgb
drvl #3<<6 + vga_base 'enable dac outputs
rdfast ##1280*cogs*2/64,##bitmap 'set rdfast to wrap on bitmap
' Field loop
field callpa #blanks,#blank 'top blanks
mov i,##lines 'set visible lines
line call #hsync 'do horizontal sync
xcont m_rf,#0 'do visible line
incmod nth,#cogs-1 wc 'every nth line?
if_c incmod sync,##lines/cogs-1 '..inc and update sync counter
if_c wrlong sync,#0 '..last sync value written is 0
djnz i,#line 'another line?
callpa #1,#blank 'bottom blanks
drvnot #vga_base+4 'vsync on
callpa #3,#blank 'vsync blanks
drvnot #vga_base+4 'vsync off
jmp #field 'loop
' Subroutines
blank call #hsync 'blank lines
xcont m_vi,#0
_ret_ djnz pa,#blank
hsync xcont m_bs,#0 'horizontal sync
xzero m_sn,#1
_ret_ xcont m_bv,#0
' Data
dacmode_hsy long %0000_0000_000_1011000000111_01_00000_0 '123-ohm 3.3V, cog 7 dac channels
dacmode_rgb long %0000_0000_000_1011100000111_01_00000_0 '75-ohm 2.0V, cog 7 dac channels
m_bs long $7F010000 + 48 'before sync
m_sn long $7F010000 + 112 'sync
m_bv long $7F010000 + 248 'before visible
m_vi long $7F010000 + 1280 'visible
m_rf long $BF030000 + 1280 'visible rfbyte rgbi8
nth long 0
sync long 0
i res 1
'****************************************
'* Make spirals in 1280 x 1024 bitmap *
'****************************************
org
pgm_bmap cogid .cog 'set start/end lines according to cogid
' Make lut table for rgbi8 translation
.lut mov .px,.z 'make lookup table for fast translation
test .px,#$20 wc 'convert 6 LSBs to 5-bit up/down ramp
if_c xor .px,#$3F
and .px,#$1F
mov .py,.z
shr .py,#1 'apply 3 MSBs to RGB bits
and .py,#$E0
or .px,.py
wrlut .px,.z
incmod .z,#$1FF wc
if_nc jmp #.lut
' Render loop
.line rdlong .x,#0 wz 'wait for next sync
cmp .x,.sync wz
if_z jmp #.line
mov .sync,.x wz 'update sync
if_z neg .y,##1024/2 'if sync=0, set initial y
if_z add .y,.cog
if_z sub .z,#1 '..and rotate spiral
if_nz add .y,#cogs 'else, inc y
mov .x,.cog 'set line address
testb .sync,#0 wc
if_nc add .x,#cogs
mul .x,##1280
add .x,##bitmap
wrfast #0,.x
neg .x,##1280/2 'set initial x
.pixels qvector .x,.y '0 in 'do overlapped QVECTOR ops for 16 pixels
add .x,#1 '1 in
qvector .x,.y
add .x,#1 '2 in
qvector .x,.y
add .x,#1 '3 in
qvector .x,.y
add .x,#1 '4 in
qvector .x,.y
add .x,#1 '5 in
qvector .x,.y
add .x,#1 '6 in
qvector .x,.y
add .x,#1 '7 in
qvector .x,.y
getqx .px+0 '0 out
getqy .py+0
add .x,#1 '8 in
qvector .x,.y
getqx .px+1 '1 out
getqy .py+1
add .x,#1 '9 in
qvector .x,.y
getqx .px+2 '2 out
getqy .py+2
add .x,#1 '10 in
qvector .x,.y
getqx .px+3 '3 out
getqy .py+3
add .x,#1 '11 in
qvector .x,.y
getqx .px+4 '4 out
getqy .py+4
add .x,#1 '12 in
qvector .x,.y
getqx .px+5 '5 out
getqy .py+5
add .x,#1 '13 in
qvector .x,.y
getqx .px+6 '6 out
getqy .py+6
add .x,#1 '14 in
qvector .x,.y
getqx .px+7 '7 out
getqy .py+7
add .x,#1 '15 in
qvector .x,.y
getqx .px+8 '8 out
getqy .py+8
shr .py+0,#32-9 'get 9 MSBs of theta (stuff code between GETQx ops)
add .py+0,.px+0 'add rho to twist it
getqx .px+9 '9 out
getqy .py+9
shr .py+1,#32-9
add .py+1,.px+1
getqx .px+10 '10 out
getqy .py+10
shr .py+2,#32-9
add .py+2,.px+2
getqx .px+11 '11 out
getqy .py+11
shr .py+3,#32-9
add .py+3,.px+3
getqx .px+12 '12 out
getqy .py+12
shr .py+4,#32-9
add .py+4,.px+4
getqx .px+13 '13 out
getqy .py+13
shr .py+5,#32-9
add .py+5,.px+5
getqx .px+14 '14 out
getqy .py+14
shr .py+6,#32-9
add .py+6,.px+6
getqx .px+15 '15 out
getqy .py+15
add .py+0,.z 'add z to slowly spin it
rdlut .py+0,.py+0 'lookup rgbi8 color
wfbyte .py+0 'write rgbi8 pixel to bitmap
add .py+1,.z
rdlut .py+1,.py+1
wfbyte .py+1
add .py+2,.z
rdlut .py+2,.py+2
wfbyte .py+2
add .py+3,.z
rdlut .py+3,.py+3
wfbyte .py+3
add .py+4,.z
rdlut .py+4,.py+4
wfbyte .py+4
add .py+5,.z
rdlut .py+5,.py+5
wfbyte .py+5
add .py+6,.z
rdlut .py+6,.py+6
wfbyte .py+6
shr .py+7,#32-9
add .py+7,.px+7
add .py+7,.z
rdlut .py+7,.py+7
wfbyte .py+7
shr .py+8,#32-9
add .py+8,.px+8
add .py+8,.z
rdlut .py+8,.py+8
wfbyte .py+8
shr .py+9,#32-9
add .py+9,.px+9
add .py+9,.z
rdlut .py+9,.py+9
wfbyte .py+9
shr .py+10,#32-9
add .py+10,.px+10
add .py+10,.z
rdlut .py+10,.py+10
wfbyte .py+10
shr .py+11,#32-9
add .py+11,.px+11
add .py+11,.z
rdlut .py+11,.py+11
wfbyte .py+11
shr .py+12,#32-9
add .py+12,.px+12
add .py+12,.z
rdlut .py+12,.py+12
wfbyte .py+12
shr .py+13,#32-9
add .py+13,.px+13
add .py+13,.z
rdlut .py+13,.py+13
wfbyte .py+13
shr .py+14,#32-9
add .py+14,.px+14
add .py+14,.z
rdlut .py+14,.py+14
wfbyte .py+14
shr .py+15,#32-9
add .py+15,.px+15
add .py+15,.z
rdlut .py+15,.py+15
wfbyte .py+15
incmod .x,##1280/2-1 wc 'check if x at limit
if_nc jmp #.pixels
jmp #.line
' Data
.z long 0
.sync long 0
.x res 1
.y res 1
.px res 16
.py res 16
.cog res 1
' Bitmap
orgh
alignl
bitmap 'bitmap is 1280 bytes x cogs * 2
I'll have to dig up the CRT to view that fully. All my LCDs are 60 Hz max ... although, I've never tried forcing the plasma TV to some odd mode on the VGA input. I suspect it'll just complain and not show a picture.
Cool, that's working here. The arms are narrower (more tightly packed/denser) than before, but there are still 8 of them. So, you can see them expand farther/further across the screen.
Actually, I'm running this on a small 7" screen with a native resolution of 800x480 that's set to stretch VGA to WVGA. to fill the screen, which it does fine. But the chip on the driver board has no problem handling the 1280 x 1024 resolution and down sampling it (I guess) to something that the screen can display. And it runs buttery smooth.
If I counted right (and I think that I did), 57 spiral arms per minute cross the top of the screen at 60 Hz (nearly one arm/second). And 71 spiral arms per minute cross the screen at 75 Hz. Arms per minute seems to be a good way to express the rate that the eye sees/experiences this animation. So, the number of arms/minute (not second) is almost the same as the number of frames per second.
As for the P2 chip, it's only warm. You're going to have to do better, Chip, if I'm going to roast any marshmallows over the chip. Are you sure you don't have a 16 core, 1 MB variant of the chip hiding in your skunkworks? Yeah, maybe your FPGA board.
It's off topic, but I noticed something of an electrical nature while running this animation that would also apply to other programs running on the P2 Eval board (Rev B version):
Seated in a chair with my bare feet off the floor, if I touch the unpopulated pair of pads for the two-pin header beside the crystal on the top side of the board, nothing happens. But if I put a bare foot to the tile floor, then the VGA screen goes black (or says "no signal" if I touch them for more than a second or so). But once I lift up my foot (to better isolate myself from earth ground), the animation reappears. What's more, the animation continued to run (spiral outwards) even when the screen was black based on where the arms were once video was reestablished. So, such touching is not stopping the clock (and I don't think that it's using the internal 20+ MHz RC oscillator when this happens). Note, the P2 is not rebooting (I've got the spiral animation in RAM, not in the flash chip). And again, the spiral arms make progress (spiral outwards) even when the screen is black (either that, or the animation jumps ahead, though I doubt it).
Based on my experience with my P1 boards, I expected that touching the crystal pins (or near them) would lock up the chip, requiring a reset or power cycle. But that doesn't seem to be happening with the P2. The P2 seems more resilient or less sensitive to such touching. Yeah, I'd better not touch things too much, though.
By the way, if do the same touch test with the two pads for the header on the back side of the board with my feet off the floor, the screen often goes black without my touching a foot to the floor. I guess it's easier to make good contact on the back side.
I think you are stopping the crystal from oscillating when you touch it. And then it starts back up when you let go of it. The PLL follows the crystal without any deadly glitches occurring, apparently.
... What's more, the animation continued to run (spiral outwards) even when the screen was black based on where the arms were once video was reestablished....
What you see is the effect of the Xtal stopping, which then Free-runs the PLL, so the P2 continues to run, but at wrong-sync numbers, & so the display blanks.
Doing that is not recommended, as P2 has known issues with enabling the clock before PLL is correctly locked. (as do most MCUs with PLLs)
I think you are stopping the crystal from oscillating when you touch it. And then it starts back up when you let go of it. The PLL follows the crystal without any deadly glitches occurring, apparently.
That's what I originally suspected. But that wouldn't seem to explain why the spiral arms continue to make progress even when the screen is black. Is there something in your code that would cause the animation to be able to jump ahead based on real time once I stop touching things? That seems unlikely to me, and especially unlikely if the crystal is not oscillating (unless an internal oscillator is being used). I assume that your animation code depends only on the hub ram state, not actual time (such that each frame depends on the last rendered frame in hub ram). If that's true and indeed the animation makes progress while the screen is black (which I'm pretty sure it does), then a clock signal of some kind seemingly is getting through, whether external or internal, (unless see below).
Edit: Just double-checked, and the spiral arms definitely make progress while the screen is black. Hmm, maybe I'm only affecting my VGA screen and not the P2 at all. That is, perhaps I'm not stopping or affecting the crystal at all.
What you see is the effect of the Xtal stopping, which then Free-runs the PLL, so the P2 continues to run, but at wrong-sync numbers, & so the display blanks.
Oh, I see! Thanks, jmg. So the PLL is still running. Yes, that makes sense. Edit: Yeah, that explains everything.
Bear in mind that waitx ##20000000 / 100 gives you that 10ms delay only for a 20MHz RC oscillator.
My two P2-EVAL boards run up around 25MHz, so if you want to wait 10ms you might want to use waitx 25000000/100, assuming 25MHz is the high range of the RC oscillator. Not sure what the upper value is meant to be.
Thanks for the helpful feedback, rogloh & evanh. I'll probably start using 25000000/100, at least in my own code. I ran the following code and put a scope probe on P57:
The scope read 6.54 MHz. There's no jump penalty for rep (if I understand correctly). It takes two passes of the drvnot instruction to make a full cycle. So that's two instructions. And each instruction takes two system clock cycles. So, that 2x2=4 cycles, and if I multiply 4x6.54 MHz, I get 26.16 MHz for the built-in fast RC oscillator. That's pretty close to 25 MHz and not super far away from 20 MHz. Hope I figured that right.
Comments
I made this the other day, but just got it working right. It uses 6 or 7 cogs to render the image into two small buffers that the VGA driver flips between for glitch-free video.
Actually, I'm running this on a small 7" screen with a native resolution of 800x480 that's set to stretch VGA to WVGA. to fill the screen, which it does fine. But the chip on the driver board has no problem handling the 1280 x 1024 resolution and down sampling it (I guess) to something that the screen can display. And it runs buttery smooth.
If I counted right (and I think that I did), 57 spiral arms per minute cross the top of the screen at 60 Hz (nearly one arm/second). And 71 spiral arms per minute cross the screen at 75 Hz. Arms per minute seems to be a good way to express the rate that the eye sees/experiences this animation. So, the number of arms/minute (not second) is almost the same as the number of frames per second.
As for the P2 chip, it's only warm. You're going to have to do better, Chip, if I'm going to roast any marshmallows over the chip. Are you sure you don't have a 16 core, 1 MB variant of the chip hiding in your skunkworks? Yeah, maybe your FPGA board.
Seated in a chair with my bare feet off the floor, if I touch the unpopulated pair of pads for the two-pin header beside the crystal on the top side of the board, nothing happens. But if I put a bare foot to the tile floor, then the VGA screen goes black (or says "no signal" if I touch them for more than a second or so). But once I lift up my foot (to better isolate myself from earth ground), the animation reappears. What's more, the animation continued to run (spiral outwards) even when the screen was black based on where the arms were once video was reestablished. So, such touching is not stopping the clock (and I don't think that it's using the internal 20+ MHz RC oscillator when this happens). Note, the P2 is not rebooting (I've got the spiral animation in RAM, not in the flash chip). And again, the spiral arms make progress (spiral outwards) even when the screen is black (either that, or the animation jumps ahead, though I doubt it).
Based on my experience with my P1 boards, I expected that touching the crystal pins (or near them) would lock up the chip, requiring a reset or power cycle. But that doesn't seem to be happening with the P2. The P2 seems more resilient or less sensitive to such touching. Yeah, I'd better not touch things too much, though.
By the way, if do the same touch test with the two pads for the header on the back side of the board with my feet off the floor, the screen often goes black without my touching a foot to the floor. I guess it's easier to make good contact on the back side.
What you see is the effect of the Xtal stopping, which then Free-runs the PLL, so the P2 continues to run, but at wrong-sync numbers, & so the display blanks.
Doing that is not recommended, as P2 has known issues with enabling the clock before PLL is correctly locked. (as do most MCUs with PLLs)
Edit: Just double-checked, and the spiral arms definitely make progress while the screen is black. Hmm, maybe I'm only affecting my VGA screen and not the P2 at all. That is, perhaps I'm not stopping or affecting the crystal at all.
My two P2-EVAL boards run up around 25MHz, so if you want to wait 10ms you might want to use waitx 25000000/100, assuming 25MHz is the high range of the RC oscillator. Not sure what the upper value is meant to be.
The scope read 6.54 MHz. There's no jump penalty for rep (if I understand correctly). It takes two passes of the drvnot instruction to make a full cycle. So that's two instructions. And each instruction takes two system clock cycles. So, that 2x2=4 cycles, and if I multiply 4x6.54 MHz, I get 26.16 MHz for the built-in fast RC oscillator. That's pretty close to 25 MHz and not super far away from 20 MHz. Hope I figured that right.
Congrats JRetSapDoog, you're in the >25.175 MHz club, should be able to do VGA on RCFAST
Well, now that I am home, I gotta measure this on my chip.
Cool.