Hey all. So I received a couple messages on Twitter asking for more details on my previous post about how to actually set up the UP VGA peripherals in Qsys. I like taking things step-by-step (and I’m really busy with school right now @_@), so rather than posting the whole project in one go, I’m going to break it down. If you want more info now, check the Video IP Cores Guide for Qsys; it will give you the basic setups for a character display, pixel display, and a combination of the two (aka video out). In this post however, I’m just going to go over the finer points of the character display system setup and provide a basic system for download. The next post will add in pixel buffer functionality.
To follow along, you’ll (as always) need Quartus II and Nios II SBT for Eclipse. You’ll also need the University Program IP cores for your version of Quartus. I am using v12.1 in this article, but I’ve done it with previous versions and it’s worked just fine.
Start a new project in Quartus and open up Qsys. Add the basic Nios system – the CPU, system timer, jtag/uart, etc. To this add the Clock Signals for DE Boards. This is basically a PLL that’s autoconfigured for use as a system clock, and optionally an SDRAM clock, VGA clock, and an audio clock. For this system you’ll need a VGA clock. If you wish to use the SDRAM instead of on-chip RAM, you’ll need to also enable the SDRAM clock (and export it too, so you can connect it to the SDRAM clock pin!)
To this, add the character buffer with DMA. This core will allow you to specify a location on the screen (note: this is not the same as a pixel location – the character buffer will allow 80×60 character locations). Leave the video out device as DE2 VGA DAC, but do not yet enable transparency (this will be necessary later, when the pixel buffer & alpha blender are added).
Next, add a Dual Clock FIFO, which will bridge the clock domains (50 MHz system clock, 25 MHz VGA controller). In preparation for adding the pixel output components, set the color bits to 10, and the color planes to 3. Finally, add a VGA controller.
Generating this system will allow you to write text to the screen – either single characters, or entire strings, using these functions (taken directly from altera_avalon_video_character_buffer_with_dma.h):
/////////////////////////////////////////////////////////////////////////////// // direct operation functions /** * @brief Opens the character buffer device specified by <em> name </em> * * @param name -- the character buffer component name in SOPC Builder. * * @return The corresponding device structure, or NULL if the device is not found **/ alt_up_char_buffer_dev* alt_up_char_buffer_open_dev(const char* name); /** * @brief Draw a character at the location specified by <em>(x, y)</em> on the * VGA monitor with white color and transparent background * * @param ch -- the character to draw * @param x -- the \em x coordinate * @param y -- the \em y coordinate * * @return 0 for success, -1 for error (such as out of bounds) **/ int alt_up_char_buffer_draw(alt_up_char_buffer_dev *char_buffer, unsigned char ch, unsigned int x, unsigned int y); /** * @brief Draw a NULL-terminated text string at the location specified by <em>(x, y)</em> * * @param ch -- the character to draw * @param x -- the \em x coordinate * @param y -- the \em y coordinate * * @return 0 for success, -1 for error (such as out of bounds) **/ int alt_up_char_buffer_string(alt_up_char_buffer_dev *char_buffer, const char *ptr, unsigned int x, unsigned int y); /** * @brief Clears the character buffer's memory * * @return 0 for success **/ int alt_up_char_buffer_clear(alt_up_char_buffer_dev *char_buffer);
Simply open the device, and assuming success, you’ll be able to use the draw and draw_string functions to output text to the screen! Next time, we’ll add in some pixel buffer functionality so you can actually use that info in that double buffering post.
Tips & Tricks
One thing to keep in mind is that clearing the buffer can take a long time, especially if you’re updating more than just text (i.e. pixel buffer, other update logic). If it’s taking too long to clear between writes, consider only invalidating those regions that require it. That is – keep some static character buffers of the same length as the text you’re writing (say, a 32 character buffer) filled with spaces. When you need to invalidate some region, just write the empty string there instead of clearing the whole buffer. Chances are, you’ve got text on the screen (like a label) that never changes. At the cost of a little complexity and a little memory, you don’t have to.
Note #1: It is a partial project. That means some small parts have been left to you. The Qsys system is there, but you must instantiate the processor & assign pins, etc.
Note #2: I’ve chosen to use the SDRAM as my main memory, but you can opt for the on-chip memory. Just remember you’ll need to reduce device drivers & disable C++ support in the BSP.
If you have a problem with the project or find a glaring error, leave a comment and I’ll try to help :)