Made by: Mason del Rosario, Evan Dorsky, Rahil Dedhia, Jamie Gorson, Jack Fan
For our final project, we decided to program an FPGA to play simple music. We attempted to implement two different kinds of modes: a free-play mode where the user was able to play a combination of seven different notes in a major scale and a song mode where a predetermined song would play. In order to produce different notes, we divided the FPGA's clock by different values which yielded the various notes we wanted. We opted to use seven separate GPIO pins on the FPGA to produce notes, and we were able to play all the notes using a single speaker by building a simple analog signal adder.
Throughout the semester, we have been working in Verilog, and wanted to see how this could be applied by programming an FPGA. We all like music and thought it would be cool to use user input to an FPGA to play chords and songs. In addition, we knew that we could generate signals for notes by dividing the clock of the FPGA, and this gave us an opportunity to have a relatively nicely scoped project. We were able to get code that played a single note fairly quickly, and were able to focus more efforts to learning about an FPGA.
There is a great deal that can be done with playing music, and with this project we could build our way up so we can have something working on every iteration. That way, we could continue adding new functionality to our project without worrying about not having something cool to show.
From “http://www.fpga4fun.com/MusicBox.html,” we first learned how to construct a module in verilog that divides the clock frequency (on our FPGA(Field-Programmalbe Gate Arrays) in our case) to any frequency we desire, thus allowing the FPGA to play any notes. Using Xilinx ISE Design Suite, we could synthesize our code and configure our FPGA. Then, we built a circuit that took in all the signals and played music with a speaker.
An FPGA is a programmable circuit consisting of a large number of “logic cells.” An individual logic cell contains a small lookup table, and may also contain an adder or another fundamental arithmetic circuit. “Programming” an FPGA involves setting the values of the lookup tables so that the FPGA produces the desired outputs for corresponding inputs. This means that few calculations are actually done on the FPGA – rather the FPGA maps every input to the correct output. This lets FPGAs run at blazing speeds, far outpacing conventional processors depending on the task. As FPGAs have become more efficient and logic-dense, their applications have grown to a wide range of fields.
One mode in which our FPGA can operate is a free play mode. In this mode, we utilize seven of the eight switches on our FPGA as user input. We use piano.ucf to map these switches as an input to the piano.v file, which then utilizes them to determine the signals that are sent to seven GPIO pins on the FPGA. This is by dividing the clock of the FPGA in order to create seven different signals with the frequencies necessary to play the notes we wanted. Using the FPGA, we can have a 25MHz, 50Mhz, or 100Mhz clock, so despite only having seven pins to play different notes, we can have three full octaves of music by switching the clock.
The other mode in which want our FPGA to operate is to play a predetermined song. We wrote verilog code to do this, and while this code synthesizes correctly, we are unable to make it work on the FPGA for presently unknown reasons. The code that does this is in LUT\_song.v, which uses a look up table to read from a mem file that contains instructions for individual notes in the form of seven bit binary strings to denote the seven notes that are mapped to our GPIO pins on the FPGA. Currently, the look up table reads from the master.mem file in the appendix, and uses a frequency divider to play each note of We Wish You a Merry Christmas for about a second long.
In order to have all of our GPIO pins play their notes through the same speaker, we needed to construct a circuit that added the signals together. To accomplish this, we created a simple analog signal-adding circuit. This circuit uses an inverting amplifier to amplify the summed signal.
The seven GPIO pins which generate the notes' frequencies are each attached to a 1kΩ resistor. These seven resistors are all attached to the noninverting input of the op amp. Note that the op amp pictured is not the one which we opted to use; while we used a TL081, it is fine to use most any op amp. The inverting amplifier has a resistor, Rf, which determines the gain.
We also connect each GPIO pin to an LED, such that the LED's light up according to the note that we are playing. The notes we are playing are at a frequency high enough that the LED blinks too quickly to be visible to the human eye. As a result, it appears that the LED is always on for any note that is being played.
1. Download Xilinx ISE design tools at http://www.xilinx.com/support/download/index.html/content/xilinx/en/downloadNav/design-tools.html.
2. Clone github repo: https://github.com/mdelrosa/cafinalproject
3. Create a new project in Xilinx (follow instructions from http://tinyurl.com/ca-fpga-13; these next steps outline the process described in the tutorial)
4. Add piano.v as a source
5. Right click on piano.v, click on add source, and add piano.ucf
6. Click on the Green arrow that says “Implement Top Module”; this should synthesize your top level module and implement the design constraints set by the ucf file
7. Double click on “Configure Target Device”
8. Make sure your FPGA is attached to your computer and click on the Boundary Scan button
9. Click on initialize chain; select the .bit file that was generated during synthesis on the first menu that pops up, then click bypass on the second menu
10. Program the chip on the left by right clicking on it and hitting program.
11. If you have not already, build the circuit found in the Analog Circuit subsection. Ensure that the appropriate GPIO pins are attached since the UCF file denotes these specific pins from the FPGA.
12. Use the switches to play different notes/combinations of notes.
Our main difficulty was in implementing the music code (i.e., the module that played a simple song). We managed to synthesize the master.v module and its dependent modules in the Xilinx ISE, but whenever we attempted to configure the target device, we got an un-logged error which prevented us from compiling the code onto the FPGA. The problem is likely to lie in the intricacies of FPGA programming best practices, and we didn't have time to debug it.
While we did make a piano for our project, we belive that the future of our project would be to make the piano play songs on its own. We had coded a verilog script that used a look up table to instruct which note to play and LEDs to light. The XILINX was able to synthesis the code, but fails when trying to use the target device. This project could be improved by having the piano be able to play some predetermined songs.
In our workplan, we set a goal to create an audio/visual synthesizer using an FPGA, which we completed by setting up our FPGA that can play notes and light up LED's depending on In terms of meeting our goals for the demo, we were able to both play music and light up corresponding LED's.
With regard to our workplan, we were able to set out to do everything we wanted to do, partly due to the fact that we were relatively vague in what we actually wanted to do with regard to music. The only step that really took significantly longer than we expected to was synthesizing our verilog code on our FPGA. A large reason for this was that it took us almost a week from when we started to even get all the correct Xilinx packages downloaded and properly installed. Other than that, our timing was about what we expected. Our final step was a rather arbitrary “making our music and lights cooler”, which we have been iteratively doing over the course of the last week, and we now have a final product that we are more than satisfied with.
All of our code is in our github repository: https://github.com/mdelrosa/cafinalproject. The ucf files are all responsible for mapping between the FPGA and our verilog code. The relevant code with regard to the user input piano is in piano.ucf and piano.v, and the code with regard to playing music with a look up table is in master.ucf, LUT_song.v, and memory.mem. The code responsible for switching between the modes and interacting with the FPGA is in master.v.