640x480x24bit display for DE2-115 board
cgracey
Posts: 14,151
Here's a program that runs on the DE2-115 board and uses the SDRAM driver to buffer a 24-bit display. Because the FPGA only goes 60MHz, it needs all the SDRAM bandwidth to feed the display, so a cog writes the buffer, then leaves it alone for display. The last section of code is the one that plots the pixels into the SDRAM. It uses QARCTAN to determine what color the pixel should be, based on its location:
I'd put a picture of it up, but my camera's batteries are dead.
' ' SDRAM Driver and 640x480 24bbp VGA Demo ' DAT org reps #4,#1 setptra sdram_par 'write initial command list wrlong h00000000,ptra++ 'skip_done then sdram_address (x2) wrlong h00000008,ptra++ 'terminate with end_of_list setcog #8 coginit sdram_adr,sdram_par 'launch SDRAM driver into cog1 coginit graph_adr,graph_par 'launch graph driver into cog2 jmp #vga sdram_adr long driver<<2 + $E80 sdram_par long $E80 graph_adr long driver<<2 + $E80 + $D0 graph_par long $E80 h00000000 long $00000000 h00000008 long $00000008 '******************************* '* VGA 640 x 480 x 8:8:8 RGB * '******************************* ' P4 = VSYNC ' P3 = RED ' P2 = GREEN ' P1 = BLUE ' P0 = HSYNC CON s = 44 'scales DAC output (s = 0..128) DAT vga setptra sdram_par 'set ptra setctra #%00111 'set ctra for PLL*8 setfrqa frqa_ 'set frqa setvid #%0101 'set vid for vga output, negative hsync setvidy vidy_ 'set yiq coefficients setvidi vidi_ setvidq vidq_ cfgdacs #%11_11_11_11 'set dacs to video mode setquad #0 'address QUADs at 0..3 ' ' ' Field loop ' field mov pixel_ptr,#0 'reset SDRAM pixel pointer call #read128 'issue SDRAM read command to prime buffer mov x,#33 'top blanks call #blank mov x,lines_vis 'set visible lines line call #sync 'do horizontal sync mov y,#5 'display 640 pixels :pix4 call #read128 'issue SDRAM read command to begin loading other buffer reps #128/4,#8 'read 32 quads and push them into stack RAM waitvid mode,#0 'issue VID command rdquad ptrb++ 'read a quad and push it nop nop nop pusha 0 pusha 1 pusha 2 pusha 3 notb mode,#31 'toggle stack RAM offset in VID command djnz y,#:pix4 'loop until 5 sets of 128 pixels (640 total) djnz x,#line 'another line? mov x,#10 'bottom blanks call #blank clrp #0 'do vertical sync mov x,#2 call #blank setp #0 jmp #field 'field loop blank call #sync 'blank lines waitvid v640,sync_color0 djnz x,#blank blank_ret ret sync 'horizontal sync sync_ret retd waitvid v16,sync_color0 waitvid v96,sync_color1 waitvid v48,sync_color0 ' ' ' Issue SDRAM read command for 128 pixels (1024 bytes) ' read128 rdlong t,ptra[0] 'wait for last SDRAM command done tjnz t,#read128 setptrb sdram_cmd 'get current data ptr into ptrb xor sdram_cmd,h200 'update command data ptr read128_ret retd 'delayed return wrlong pixel_ptr,ptra[1] 'issue SDRAM address add pixel_ptr,h200 'update pixel pointer wrlong sdram_cmd,ptra[0] 'issue SDRAM read command pixel_ptr long 0 sdram_cmd long $1006 '128 pixels, toggle between $1006 and $1206 h200 long $200 ' ' ' Initialized data ' frqa_ long $0D6D_3A06 '25.175MHz vidy_ long $00_01_00_00 * s 'red gain vidi_ long $00_00_01_00 * s 'green gain vidq_ long $00_00_00_01 * s 'blue gain ' color base mode clocks/pixel clocks/waitvid mode long $00 << 24 + $F << 20 + 1 << 13 + 128 lines_vis long 480 sync_color0 long $0_000000 sync_color1 long $1_000000 v16 long 16 v96 long 96 v48 long 48 v640 long 640 t long 0 x long 0 y long 0 driver 'SDRAM driver follows '******************************** '* * '* Propeller II SDRAM Driver * '* for 16M x 16 devices * '* (FPGA version) * '* * '* Version 0.1 * '* 9 April 2013 * '* by Chip Gracey * '* * '******************************** { SDRAM connections: P85 = cke (held high) Port C P84 = cs P83 = ras P82 = cas P81 = we P80 = udqm (not used) P79 = ldqm (not used) P78..P77 = ba[1..0] P76..P64 = a[12..0] P63..P48 = dq[15..0] Port B Note: All pin directions have a 2-clock delay All pin outputs going to SDRAM have a 3-clock delay, since they are registered at the pin All pin inputs coming from SDRAM have a 2-clock delay, since they are registered at the pin Commands (pairs of longs): name quads bytes hub_address (+0, set 2nd) sdram_address (+1, set 1st) ------------------------------------------------------------------------------------------------------------------------ rw_1024 64 1024 %xxxx_xxxx_xxxx_xxxA_AAAA_AAAA_AAAA_W111 %xxxx_xxxA_AAAA_AAAA_AAAA_AA00_0000_0000 rw_512 32 512 %xxxx_xxxx_xxxx_xxxA_AAAA_AAAA_AAAA_W110 %xxxx_xxxA_AAAA_AAAA_AAAA_AAA0_0000_0000 rw_256 16 256 %xxxx_xxxx_xxxx_xxxA_AAAA_AAAA_AAAA_W101 %xxxx_xxxA_AAAA_AAAA_AAAA_AAAA_0000_0000 rw_128 8 128 %xxxx_xxxx_xxxx_xxxA_AAAA_AAAA_AAAA_W100 %xxxx_xxxA_AAAA_AAAA_AAAA_AAAA_A000_0000 rw_64 4 64 %xxxx_xxxx_xxxx_xxxA_AAAA_AAAA_AAAA_W011 %xxxx_xxxA_AAAA_AAAA_AAAA_AAAA_AA00_0000 rw_32 2 32 %xxxx_xxxx_xxxx_xxxA_AAAA_AAAA_AAAA_W010 %xxxx_xxxA_AAAA_AAAA_AAAA_AAAA_AAA0_0000 rw_16 1 16 %xxxx_xxxx_xxxx_xxxA_AAAA_AAAA_AAAA_W001 %xxxx_xxxA_AAAA_AAAA_AAAA_AAAA_AAAA_0000 skip_done 0 0 %0000_0000_0000_0000_0000_0000_0000_0000 %xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx end_of_list 0 0 %0000_0000_0000_0000_0000_0000_0000_1000 %xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx The driver scans a list for commands. Commands take two longs and are structured as hub_address + sdram_address. To have the driver perform a read or write operation on the SDRAM, first set the sdram_address (2nd long) and then the hub_address (1st long). The driver will set each hub_address long to skip_done (0) when its associated operation has completed. Before starting the driver, build the command list structure with pairs of 0's, then terminate it with an 8. When launching the driver into a cog, point the parameter (S) to the start of the command list. Command list (longs): hub_address (skip_done/rw_xxxx) sdram_address hub_address (skip_done/rw_xxxx) sdram_address hub_address (skip_done/rw_xxxx) sdram_address ... end_of_list } DAT org ' ' ' Initialize SDRAM clocks hub ' ---------------- sdram_driver getptra list '1 - save command list address reps #6000,#1 '1 - repeat instruction for 100us @60MHz mov pinc,h003FFFFF '1 - cke and cs high mov dirc,h003FFFFF wz '6000 - set SDRAM signals to outputs (100us), Z = 0 ' ' ' Scan list for commands ' :finish if_z wrlong cmd,ptra[-2] '1 0 if command finished, set it to skip_done (cmd = 0) mov pinc,h00240400 '1 1 issue 'precharge all' command setb pinc,#20 wz '1 2 deselect, Z = 0 :reset if_z setptra list '1 3 if end_of_list, reset list pointer; satisy Trp mov pinc,h00200037 '1 4 issue 'set mode' command setb pinc,#20 '1 5 deselect, satisfy Tmrd mov pinc,h00226000 '1 6 issue 'auto refresh' command setb pinc,#20 '1 7 deselect, satisfy Trfc in 8 more clocks :next rdlong cmd,ptra++[2] wz '3 0..2 check command, point to next setptrb cmd '1 3 in case command, set hub address if_z jmp #:next '1/4 4/4..7 if skip_done, next command decod3 cmd wc '1 5 decode size bits, C = write and cmd,#%11111110 wz '1 6 isolate bits 7..1, Z = 1 if end_of_list if_z jmp #:reset '1/4 7/7..2 if end_of_list, reset list pointer ' ' ' Execute read/write command clocks hub XFR write SDRAM XFR read SDRAM ' ------------------------------------------------------ rdlong adr,ptra[-1] '3 0..2 - - get SDRAM address shl adr,#7 '1 3 - - make 'active' command with bank and row address or adr,#%1_0011_00 '1 4 - - (ba[1..0], a[12..0]) = adr[24..10] rol adr,#15 '1 5 - - mov pinc,adr '1 6 - - issue 'active' command setb pinc,#20 '1 7 - - deselect, satisfy Trcd in 1 more clock if_c rdquad ptrb++ '1 0 - - if write, read initial QUADs from hub setbc :quad,#0 '1 1 - - set wrquad/rdquad according to read/write if_c setxfr #%010_011 '1 2 <QUADs_to_16_pins> - if write, configure XFR at hub cycle 2 shr adr,#22+1 '1 3 - - make blank command with bank and column address and pinc,h00306000 '1 4 - - (ba[1..0], a[12..0]) = (adr[24..23], %0000, adr[9..1]) or pinc,adr '1 5 - - if_c mov dirb,hFFFF0000 '1 6 - - if write, enable data outputs if_nc setxfr #%100_011 '1 7 <16_pins_to_QUADs> if read, configure XFR at hub cycle 7 if_nc xor pinc,h001A0000 '1 0 - - if read, issue 'read' command if_nc setb pinc,#20 '1 1 - - if read, deselect if_c xor pinc,h00180000 '1 2 - - if write, issue 'write' command (aligns with XFR on next clock) if_c setb pinc,#20 '1 3 output QUAD0 w0 - if write, deselect; read: SDRAM sees 'read' command shr cmd,#1 '1 4 output QUAD0 w1 - get loop count if_nc nop #7 '1 5 output QUAD1 w0 - if read, pad time '(nop) '1 6 (skip to next hub 6) - read: SDRAM starts outputting data stream '(nop) '1 7 - '(nop) '1 0 input w0 read: SDRAM data stream begins arriving in XFR '(nop) '1 1 input w1 -> QUAD0 '(nop) '1 2 input w0 '(nop) '1 3 input w1 -> QUAD1 '(nop) '1 4 input w0 :quad '(rdquad/wrquad) '1 5 output QUAD1 w0 input w1 -> QUAD2 '(rdquad/wrquad) '1 6 output QUAD1 w1 input w0 '(rdquad/wrquad) '1 7 output QUAD2 w0 input w1 -> QUAD3 rdquad ptrb++ '1 0 output QUAD2 w1 input w0 write: read next QUADS; read: write current QUADS djnz cmd,#:quad '1 1 output QUAD3 w0 input w1 -> QUAD0 loop for each set of QUADs '(djnz looping) '1 2 output QUAD3 w1 input w0 '(djnz looping) '1 3 output QUAD0 w0 (new) input w1 -> QUAD1 write: RDQUAD data valid '(djnz looping) '1 4 output QUAD0 w1 input w0 mov pinc,h002C0000 '1 2 output QUAD3 w1 - issue 'burst terminate' command (aligns with XFR on next clock) mov dirb,#0 wz '1 3 - - cancel data outputs (aligns with 'burst terminate'), Z=1 jmp #:finish '4 4..7 - - finish up, scan for next command ' ' Constants ' h00180000 long $00180000 'write' command toggle h001A0000 long $001A0000 'read' command toggle h00200037 long $00200037 'set mode' command (full-page r/w bursts, cas latency = 3) h00226000 long $00226000 'read' command mask h00240400 long $00240400 'precharge all' command h002C0000 long $002C0000 'burst terminate' command h00306000 long $00306000 'blank command mask h003FFFFF long $003FFFFF 'control pins mask hFFFF0000 long $FFFF0000 'data pins mask ' ' ' Variables ' list res 1 'command list pointer cmd res 1 'command adr res 1 'address ' ' '************************ '* * '* Graphics * '* * '************************ ' ' The following program uses SDRAM driver command slot 1 to write the video display (640x480 longs) ' org 'graphics driver graph setpix pix_ 'set 1x1 1-bit texture setpixr pixrgb 'reset pix rgb scaling registers setpixg pixrgb setpixb pixrgb pusha color0 'install texture colors into stack ram at $00 and $01 pusha color1 setquad #0 'init QUADs pointer to #0 fixinda #3,#0 ' ' ' Draw screen left-to-right/top-to-bottom ' :pixel mov xx,xpos 'compute complex arctan of coordinates sub xx,#640/2 mov yy,ypos sub yy,#480/2 qarctan xx,yy getqx xx getqz zz max xx,#511 'make luma from length shl xx,#23 testb xx,#31 wc setbc texture,#0 'set black/white qsincos xx,hsincos 'convert length to sinusoid getqx yy add yy,#$80 shl yy,#8 'set alpha blend setpixa yy shl yy,#16 'swirl colors add zz,yy call #chroma 'make chroma from angle mov pix,z add zz,h55555555 call #chroma shl z,#8 or pix,z add zz,h55555555 call #chroma shl z,#16 or pix,z nop #2 'blend chroma with black or white nop #2 getpix pix call #plot 'plot pixel if_nc jmp #:pixel 'if more pixels, loop jmp #$ ' ' ' Get chroma from 32-bit angle ' chroma qsincos zz,hsincos getqx z add z,#$80 chroma_ret ret hsincos long 77 '127 * 0.607 h55555555 long $55555555 '1/3 circle ' ' ' Plot next pixel, C=1 if end of screen ' plot mov inda++,pix 'store pixel in QUADs incmod qptr,#3 wc 'QUADs full? if_nc jmp #plot_ret 'if not, return :wait rdlong z,ptra[2] 'QUADs full, wait for last command to finish tjnz z,#:wait wrquad pcmd 'write QUADs wrlong pptr,ptra[3] 'write SDRAM address wrlong pcmd,ptra[2] 'write SDRAM command add pptr,#$10 'update SDRAM address plot_ret retd incmod xpos,xlim wc 'increment position if_c incmod ypos,ylim wc if_c mov pptr,#0 'if end-of-screen, reset pixel pointer ' ' ' Variables ' pcmd long $1409 pix long 0 z long 0 xx long 0 yy long 0 zz long 0 pptr long 0 qptr long 0 xlim long 640-1 ylim long 480-1 xpos long 0 ypos long 0 pixrgb long $0000_FF00 color0 long $FF_00_00_00 'solid black color1 long $FF_FF_FF_FF 'solid white ' 1 x 1 map, 1-bit pixels, no mirroring pix_ long %000_000_00_0_00 << 21 + $00 << 9 + texture texture long 0 '1x1 1-bit texture
I'd put a picture of it up, but my camera's batteries are dead.
Comments
Maybe someone can take a screen shot.
I guess you're saying that at 180 MHz clock there'd be time during refresh or something to update SRAM?
No chance of changing SRAM during active display time right? Or, is there?
Could the DE0 show color bars or something in this mode?
Woops! Never mind that .BIN file. I meant to load the .SPIN file there. I'll just delete the .BIN and you can copy and paste that source code into PNUT to run it.
There's no time at 60MHz to update the display, but at 180MHz, you could write it twice over for every display period.
The VGA demo I made a while ago does color bars, but has no need for all-points-addressable graphics, so it runs on the DE0.
Thanks for posting that pic.
Tonight I'll reduce the resolution to 320x240 so that I can potentially write the bitmap 3x over per display period. Then, I'll have the graphics cog animate the colors and patterns.
I was surprised I was able to get such rich analog-looking effects using a few CORDIC functions. Potatohead, Pedward, Sapieha, all you with DE2-115's, have you run this program and played around with the code that draws the image? Having transcendental functions in hardware makes wild things possible.
You could always send me one, I'm at my limit of what I can develop in one COG, since I've been hitting a lot of cycle limits on what I've been tinkering with. I'll post my color TTY text driver in a moment and give some details on what I learned.
I have started and look --- But not played with it.
My Basic eat up all my time.
SDRAM_Graphics6.spin
It renders 26 frames into SDRAM which takes ~20 seconds before you get a stable image. It uses almost all of the 32MB SDRAM.
I don't remember where I put it and I'm not in the office right now, so I'm unable to repost it. I'll post it to a sticky thread later today.
I have:
69f9b0e3a64744c08723feef212d7349 ./PNut.exe
69f9b0e3a64744c08723feef212d7349 ./tty/PNut.exe
69f9b0e3a64744c08723feef212d7349 ./baggers/DE0/PNut.exe
69f9b0e3a64744c08723feef212d7349 ./baggers/JB_Sprites_DE0/PNut.exe
That's the MD5 sum of the file.
I think You look on that instruction.
PNut I have compile that.
PNut_20121221.zip
As soon as I know which is the latest, I will update the sticky with a link to it.
However it doesn't support NOPX, which is supposed to be the same instruction.
http://youtu.be/vS8jVrSbs7k
Sorry for the bad quality, my camera refuses to autofocus on the LCD screen
I finally had time to re-flash my de2...
Your demo is amazing!
I think I'll have some time tomorrow to start on some high resolution SDRAM drivers