8
\$\begingroup\$

I have an Altera DE2 board and trying to draw sprites. I am having some trouble implementing a screen buffer.

I have a display entity that at a 25 MHZ rate outputs pixels for vga display.

I was hoping to implement a buffer in SDRAM. The original idea was to load pixels the next pixel at a rate of 25 MHZ from the SDRAM. This works, but I can't write pixels to the SDRAM at this rate nor can clear the screen fast enough for each new frame. It takes me 2 clocks to write data and my board operates at 50 MHZ so I have just enough time to do a complete read.

I would assume I'm doing something terribly, terribly wrong. How is such a drawing canvas normally implemented in VHDL?

I closest thing I could find is to use a 2-3-3 (R-G-B) color scheme to retrieve each pixel and write to the canvas ram during the "porch" (blanking) VGA time. This means that at each of the 25mhz clocks I can only update 15% of the screen and I somehow need my circuit the be aware of which 15% it is updating?

I can't figure out how to use double buffering because I can't figure out how to write data to the memory while reading. Is there a way to avoid bit-banging the protocol? How does this guy do it?

enter image description here

\$\endgroup\$
  • \$\begingroup\$ double buffering? \$\endgroup\$ – davidcary Nov 13 '11 at 2:46
  • \$\begingroup\$ @davidcary, with some detail on how to approach doing double buffering you have answered the question. I realize that takes time and I cannot throw stones as one that often gives a quick quip as a comment to help the user with their problem until someone can write a high quality answer. \$\endgroup\$ – Kortuk Nov 13 '11 at 4:45
  • 2
    \$\begingroup\$ When you say "Is there a way to avoid bit-banging the protocol?", I assume that means you haven't written the SDRAM controller yourself. I recommend doing so, it's a good exercise, and you'll understand more about how SDRAM works and how to exploit its timings. \$\endgroup\$ – mng Nov 14 '11 at 0:31
3
\$\begingroup\$

A couple of approaches which may be useful for some styles of display is to divide the display panel into tiles, and

  1. restrict each tile to using a small set of colors, allowing the use of fewer than 8 bits per pixel, or
  2. use a byte or two from each tile to select a location from which to read bitmap data.
The first approach could reduce the rate at which data had to be read from display memory. For example, if one used tiles that were 16x16 and could each have four colors chosen from a set of 256, then without using any extra RAM in the FPGA one could reduce the number of memory reads per 16 pixels to eight (four color values, plus four bytes for the bitmap). If one added 160 bytes' worth of buffering/RAM(*) to the FPGA, one could reduce the number of memory reads per 16 pixels to four, using an extra 160 reads every 16 scan lines to read the next set of tile colors. If one wanted 16 colors per tile, the second approach would require an extra 640 bytes of RAM unless one placed some restrictions on the number of different palettes that could exist on a line.

The second approach would probably increase rather than reduce the total memory bandwidth required to produce a display, but would reduce the amount of memory that would have to be updated to change the display--one could change a byte or two to update an 8x8 or 16x16 area of the screen. Depending upon what you're trying to display, it may be helpful when using this style of approach to use one memory device to hold the tile shapes, and another to hold the tile selection. One might, for example, use a fast 32Kx8 RAM to hold a couple 80x60 tile maps with two bytes per tile. If the FPGA didn't have any buffering, it would have to read one byte every four pixels; even with a 40ns static RAM, that would leave plenty of time for the CPU to update the display (an entire screen would only be 9600 bytes). The memory bandwidth for reading out the tile shapes would be no better than it is now, but that part of memory wouldn't have to be updated.

Incidentally, if one didn't want to add a 32Kx8 RAM but could add add 320 bytes of buffering/RAM(**) to the FPGA, one could use a tile-map approach but have the CPU or DMA feed 160 bytes to the display every 8 scan lines. That would burden the controller somewhat even when nothing on the display was changing, but could simplify the circuitry.

(*) The buffer could be implemented as RAM, or as a sequence of 32 40-bit-long shift registers plus a little control logic.

(**) The buffer could be implemented as two 160-byte RAMs, or as two groups of sixteen 80-bit shift registers.

\$\endgroup\$
5
\$\begingroup\$

Sprites are not normally done with a frame buffer (as I understand the word). Instead you compare the x and y coordinate with the xmin,ymin and xmax,ymax of the sprite. If the current scan position falls inside the sprite, output the relevant colour from the sprite memory.

If you are trying to display a frame buffer, take heart. This was my first major FPGA project. SDRAM shouldn't be a problem at 100MHz (I first did this about a decade ago, and silicon is waaay faster now), so multiply up your 50MHz clock. Writing your own controller will be educational :)

That gives you plenty of bandwidth to play with, you can then double buffer, no problem. 60Hz VGA needs an average of 18Mpixels/sec. If you have a 16-bit wide device, you have 200MBytes/sec of peak bandwidth. Even if you only manage to be 50% efficient (which should be doable) that's 100Mpixels/sec @ 16 bits per pixel or 50Mpixels/sec @ 32bits per pixel.

For example, it may be that your RAM needs 60ns to setup a read, but can burst 8 words in 80 ns after that - that's 8 bytes in ~140ns. IF you can get your RAM to do longer bursts, that would help amortise the cost of setting up the read.

Based on your comment that it's a byte-side RAM, that's a bit over 50MBytes/sec, only 16Mpixels/sec @ 24 bits per pixel :( You just don't have enough bandwidth to do a truecolour display, even at VGA. You could do 8 bits per pixel pretty readily, but that's only 2 or 3 bits per colour - which may be OK for your application, I don't know. Or you could do a 256-colour lookup table like in the old days - after reading from the frame buffer you then use the value to lookup in an internal RAM clock to get the 24-bits (or 18 bits, which would fit nicely in a BRAM) of colour to output to the monitor.

The double buffering still works:

Display a frame from address 0 (just read all the pixels out in turn, pausing the reads during the blanking intervals).

Write your next frame into another location. For this double buffering, your DRAM controller will have to prioritise between the competing demands of the read and write channels. Hint, prioritise the reads as they are time-critical :)

\$\endgroup\$
  • \$\begingroup\$ Is it generally better to prioritize reads, or is it better to read data into a FIFO, give writes priority when a certain amount of data is in the FIFO, and give reads priority when the FIFO level gets too low? I've found that at least when driving LCD's which have a clock signal, it's useful to allow read timing to be fairly 'loose' provided all the data gets shifted out on time. \$\endgroup\$ – supercat Nov 14 '11 at 17:04
  • \$\begingroup\$ Thanks for your post, I might take a look at buffering. But I think it takes me 2 clocks (1/50 MHZ) to read data and I also have an 8-bit wide device. \$\endgroup\$ – Mikhail Nov 14 '11 at 19:46
  • \$\begingroup\$ @supercat: yes, that's a more advanced solution which might be necessary if bandwidth is being pushed. \$\endgroup\$ – Martin Thompson Nov 15 '11 at 20:01
  • 1
    \$\begingroup\$ @Misha: It takes a while to setup a data read, but you can burst read large amounts at once. \$\endgroup\$ – Martin Thompson Nov 15 '11 at 20:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.