This repo contains a collection of FPGA projects targeting Papilio Pro boards, which are based on the Spartan 6 LX9 FPGA. The code was written in VHDL using Xilinx ISE Design Suite 14.7 (WebPACK Edition).
These projects are mostly based on Introducing the Spartan 3E FPGA and VHDL from SparkFun. Projects are listed in chronological order, based on when I completed them.
The project under flashy_lights uses the LEDs on the LogicStart MegaWing to display a sequence of patterns that are read from block RAM (configured as a single port ROM). It uses a simple counter to loop over addresses in the ROM. At each address a pattern of eight bits determines which LEDs are switched on.
The ROM can found in flashy.coe.
The project under segment_counter uses the seven-segment display on the LogicStart MegaWing to display a hexadecimal counter. The segment_counter module uses a 36-bit counter, which is incremented on the rising edge of the clock signal. Bits 35-20 are shown on the seven segment display, with bits 35-28 also mapped onto the LEDs.
Although a video might be more helpful, here is a photo of Segment Counter:
Note that the order of the LEDs is backwards from this perspective.
This project is an extension of Segment Counter. segment_counter_input changes the behaviour of the counter so that it only changes when the joystick is being pushed left or right. When it is pushed to the left, the counter decrements, and when pushed to the right, the counter increments. The counter can be reset by pressing the joystick button for a moment.
The LEDs have also been changed to indicate which input has been registered.
The project under simple_vga uses the VGA port on the LogicStart MegaWing to output a checkboard signal. Probably the most interesting part of this project is that it uses a Clock Divider IP Core to convert the board's 32MHz clock signal to 25.125MHz, which is required to generate a 640x480 VGA signal.
Here is a photo of Simple VGA in action:
Building on Simple VGA, the vga_crosshair project displays two intersecting lines. The crosshair, or point of intersection, can be moved using the joystick. Movement is performed on the rising edge of the VSYNC signal, to avoid tearing.
90% of the way towards a playable first-person shooter, right?
The project under audio_wave uses the 3.5mm audio jack on the LogicStart MegaWing to output audio, using a sine wave stored in Block RAM. The sine wave data is stored in sine.coe, and contains 1024 8-bit values. The main module relies on a module called dac8, which implements a Delta-Sigma DAC as per Xilinx App Note 154.
A small C program has also been included, for generating sine wave data. This can be found in sine.c.
The tone that is played is approximately 488hz. The clock is ~32mhz, and we use the highest 10 bits of a 16 bit counter to choose which sample to read from memory. So 32,000,000 / 2^6 = 500,000 samples per second. We have 1024 samples, and frequency is the number of times we can play all of those samples per second. In this case it is 500,000 / 1024 = 488.28125.
It sounds like this.
volume_control builds on Audio Wave by adding a volume control, with 16 levels of volume. It does this using a multiplier IP block which multiplies a 4-bit volume signal with the sample that is currently being played. The lowest 4 bits of the product are discarded, and the highest 8 bits are played.
The volume can be controlled using the joystick on the MegaWing, and is displayed as a hexadecimal value on the seven segment display.
volume_control_16 is a simple iteration on Volume Control that uses a 16-bit DAC instead of an 8-bit DAC. The code for generating a COE file has been updated accordingly, in sine16.c.
I finally got my hands on an Arcade MegaWing. This improves on the standard MegaWing by adding support for 4096-colour VGA, as well as various inputs. gamepad_test builds upon the VGA Crosshair example, adding support for a Sega Mega Drive gamepad. It also makes the necessary adjustments to work with the updated VGA output.
Here it is in action:
Input/output pins were be updated to match the new wing, and wiring for a ground pin was added for the controller.
bitmap_display builds on Simple VGA by allowing a small bitmap/sprite to be drawn from Block RAM. The image to be drawn is in dither.coe, and a program for generating the COE file can be found in dither.c.
It's difficult to tell from the photo that this is a pure bitmap image (i.e. ones and zeros), so the darker triangles are actually dithered:
This turned out to be more sensitive to timing than I expected. The bitmap is read from Block RAM one row at a time, and it was necessary to update the read address earlier enough to ensure that the output would be available in time to be drawn. Failing to do this caused pixel alignment issues.
The next challenge is full colour support...
The full_colour project takes advantage of the 12-bit (4096 colour) output of the Arcade MegaWing. Like the Bitmap Display project, it draws a small sprite from Block RAM. However, there are two changes to how the sprite is drawn. The first is that the data is stored per-pixel, rather than per-row. The second is that each pixel contains 12 bits of colour data (4 bits per channel). The image to be drawn is in gradient.coe, and a program for generating the COE file can be found in gradient.c.
To make things more interesting, the image is drawn twice, resulting in two separate sprites that bounce around the screen:
This was achieved by converting the single port ROM into a dual port ROM, allowing two memory locations to be read on each clock cycle.
The rs232_receiver project is based on Hamster's response in this post on the Gadget Factory Forum. It allows the LEDs on the LogicStart MegaWing to be controlled via the USB serial interface, using the RS-232 protocol. A simple oversampling approach is used to handle incoming data.
On my Linux machine, I was able to connect to the device /dev/ttyUSB1
with both minicom
and screen
, using a baud rate of 9600. Any keyboard input is sent to the FPGA, and used to control LEDs.
Using minicom
, you will need to configure the serial port like so:
+-----------------------------------------------------------------------+
| A - Serial Device : /dev/ttyUSB1 |
| B - Lockfile Location : /var/lock |
| C - Callin Program : |
| D - Callout Program : |
| E - Bps/Par/Bits : 9600 8N1 |
| F - Hardware Flow Control : No |
| G - Software Flow Control : No |
| |
| Change which setting? |
+-----------------------------------------------------------------------+
For screen
, you can use:
screen /dev/ttyUSB1 9600
You may need to run these via sudo
.
On Windows, you can use a terminal emulator such as putty.
The rs232_echo project builds on the RS-232 Receiver by echoing each byte received back to the transmitter. This is implemented using a TX component that maintains a buffer containing the next byte to be sent (if any), and the current state of the transmission. The next byte to be sent is set whenever a complete byte is received by the RX component.
LED feedback has been removed, since it is no longer required ;)
- Free-Range VHDL from Free Range Factory
- Introducing the Spartan 3E FPGA and VHDL from SparkFun
- ISE In-Depth Tutorial from Xilinx
This code should be considered to be in the public domain.