NTSC Spiral Demo - Now with HDMI and VGA output

2»

Comments

  • cgraceycgracey Posts: 12,610
    edited 2019-12-11 - 15:39:11
    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.

  • cgraceycgracey Posts: 12,610
    edited 2019-12-11 - 16:05:01
    It's set up to run at 60Hz. You have to modify it to get it to go 75Hz.
  • JRetSapDoogJRetSapDoog Posts: 836
    edited 2019-12-11 - 19:54:39
    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.
  • JRetSapDoogJRetSapDoog Posts: 836
    edited 2019-12-11 - 20:56:55
    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.
  • cgraceycgracey Posts: 12,610
    edited 2019-12-11 - 20:59:34
    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.
  • jmgjmg Posts: 14,278
    ... 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)
  • JRetSapDoogJRetSapDoog Posts: 836
    edited 2019-12-11 - 21:43:50
    cgracey wrote: »
    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.
  • JRetSapDoogJRetSapDoog Posts: 836
    edited 2019-12-11 - 21:52:47
    jmg wrote: »
    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.
    jmg wrote: »
    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)
    Edit2: I'll stop doing that (touching the crystal area on my one-week old board). I guess that's why we do this:
    waitx   ##20_000_000 / 100                      'allow crystal+PLL 10ms to stabilize
    
  • roglohrogloh Posts: 1,990
    edited 2019-12-12 - 08:26:23
    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.
  • The 10 ms figure is conservative, 8 ms is still plenty. But yeah, I've still been changing all my sources to 25 MHz anyway.

  • JRetSapDoogJRetSapDoog Posts: 836
    edited 2019-12-12 - 20:21:19
    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:
            hubset #0         ' set 20MHz+ mode
            waitx   ##25_000_000/100    ' ~10ms
            rep #1, #0
            drvnot #57
    

    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.
  • Yeah when we've tested this I think we've seen a range 23 to 26 MHz

    Congrats JRetSapDoog, you're in the >25.175 MHz club, should be able to do VGA on RCFAST

  • There is a club?

    Well, now that I am home, I gotta measure this on my chip.

    Cool.

Sign In or Register to comment.