by Casey Alvarado, Mika Ichiki-Welches, Cynthia Chen, Nitya Dhanushkodi and Zoher Ghadyalli
Using a Field Programmable Gate Array (FPGA), we built a digital piano that plays the frequencies of the C major scale, given by:
From there, we decided to experiment with frequencies by using a linear feedback shift register (LFSR), which was used in old videogames to make sounds. Really just experimenting with what the LFSR sounds like, we ended up corresponding the frequency of each note to the clock of the LFSR (maybe gating the clock, okay okay yeah its bad). As a result, we produced an octave that is fed into an LFSR. The result is interesting to listen to and sound somewhat similar to the sound effects in old arcade games.
The last thing we attempted to do from there was play a song we hard-coded using our piano notes. A button press on the FPGA plays a fixed tune.
We built a piano on an FPGA by outputting frequencies corresponding to the musical notes of a piano. For example, the note A is at 440 Hz. We created an up counter that divided the frequency of a 25 MHz clock by how many times a wave has to wait to oscillate at the desired musical note frequency. We divided the clock by how many times it takes to get the correct frequency of 440 Hz, and assigned each note's frequency to the GPIO pins (input/output pins of the FPGA). We then just jumped these pins to a breadboard and connected this frequency output to a speaker.
We enabled each note frequency using the switches on the FPGA as enables in the top level module that the FPGA synthesizes. You can enable as many switches at once and play notes or chords.
In order to divide the clock by how many times it takes to achieve our desired frequency we establish a counter that increments on each positive edge of the clock. Initially, following example code we found online, we set up a 16-bit counter.
In terms of dividing the frequency, the lower the frequency desired, the higher the count had to be. We were looking at the most significant bit of our count, which oscillated at the desired frequency. However, for lower frequencies, the count had to be higher and higher. In doing so, we actually had to use 17 bits, instead of 16 for our count. In the same way, moving to higher frequencies decreased the count and then we needed to change which bit we were assigning as our frequency output, because the lower counts may not have exceeded the value of the 15th bit.
In addition, we realized that one of the GPIO pins on the FPGA was not outputting the expected amount of volts. All of our frequencies coming out of the FPGA oscillated from 0V to approximately 3.3V. However, out of one GPIO pin, we were only measuring a maximum voltage of 400 mV, which was not enough to drive the speaker. We know that this is a problem with the FPGA and not our code because when we connect the A note to a different pin, it works. It appears that something is happening with that pin and it is not providing the correct amount of correct.
After successfully completing the piano portion of this lab, we decided to experiment a bit with an LFSR, which is a linear-feedback shift register whose input bit is a linear function of its previous state.
“The most commonly used linear function of single bits is exclusive-or (XOR). An LFSR feeds two of the bits currently in the shift register through the XOR gate. The result is the bit that is shifted into the register. In this way, the input to the shift register is dependent on the current state of the shift register.
The initial value of the LFSR is called the seed, and because the operation of the register is deterministic, the stream of values produced by the register is completely determined by its current (or previous) state. Likewise, because the register has a finite number of possible states, it must eventually enter a repeating cycle. However, an LFSR with a well-chosen feedback function can produce a sequence of bits which appears random.” (Wikipedia) For our purposes, this would produce multiple frequencies.
We tried to create a mode in our project that played a song. Our code implemented this such that we would have “song” be a matrix that was 8 bits wide (for each note of the octave) and 9 bits deep (one for every beat in the song). For every beat, we hard coded the note or chord that we wanted to play. For example the C chord (CEG) was 10101000. Each note or chord would loop in order through genvar. Unfortunately, although this module seemed to have worked in ModelSim, it wouldn’t synthesize in Xilinx. Our suspicion is that this was a problem with the timing of our loop. We didn’t include any delays in our loop, because we didn’t know how the syntax of delays worked when placing them into our module.
Because hearing our hardware sing is pretty cool! We all love music and we wanted to channel that through our CompArch project. We also wanted to learn more about how the FPGA worked with a audio and explore how the frequency domain worked together with hardware to produce sound. We were also curious about how a piano with digital musical note frequencies sounded, in comparison to the piano musical notes we were accustomed to hearing. We were even thinking about changing the digital signal to an an analog one to be able to compare the differences or even building a triangle wave in addition to the square wave to hear the differences. It was all about sound experimentation and how we could use what we learned this semester to make cool sounds!
The first thing we needed to do was slow down the clock. We ran the clock through an Up Counter so that the flip flops would wait for the clock appropriately to get the correct signal at, for example, 440 Hz. We had an up counter for each note, but it was pointed out to us that we could have just one up counter and get the signal at any point of the up counter at the frequencies we wanted. The note modules (musicA, musicB, etc) each take in a clock, counter and enable and output to the speaker. We then created a LUT to We uploaded this to the FPGA after making a top level module that declared all the switches as the enables for the notes as mentioned above. To upload to the FPGA, you need to open the project FPGAPiano in Xilinx and set top.v as the top level module. Then continue to synthesize, generalize, and configure as described in the FPGA tutorial. Now the switches will act as a piano!
Using the LFSR, we initially attempted to listen to the output bits, a random collection of 0s and 1s. Since the output of the LFSR is approximately, random, we were expecting to hear just static. However, our problem is that we did not slow down our clock, so our speaker, outputting frequencies in the MHz, played a soft incredibly high-pitched noise.
We then decided to slow down our clock to the frequencies of each note, as in our piano, and then feed that into the LFSR. When we did that, we were able to hear repetitive chip-tune like sounds, very much making the expected static noises in a discernible pattern.
In order to make our chip-tunes a higher pitch, the base clock frequency can be changed. We used a 25 MHz clock on the FPGA so that our upcounters did not need to count to larger numbers, but for our chip-tunes, simply manipulating the frequency of the clock on the FPGA produces drastically different sounds. In order to make a chip-tune that sounds more like the effects used in an old school arcade game, try switching the clock to 50 or 100 MHz.
You can synthesize either the piano mode or the LFSR chip tunes mode on the FPGA. Clone our repository at https://github.com/yunhsincynthiachen/CompArchFPGAPianoFinal and program the FPGA in Xilinx opening the project LFSR or FPGAPiano.
Here are instructions to run the code in ModelSim and Xilinx:
In ModelSim: For the FPGA Piano, run “do_piano.do” in ModelSim, in order to run the test bench that shows the FPGA piano can play multiple notes at the same time, and can switch notes. For the FPGA LFSR Piano, run “do_LFSR.do” in ModelSim, in order to run the test bench that shows the LFSR can run different pseudo-random patterns. In order to test out a song that we were trying to program in the FPGA, we have a file called “doTrueLove.do” that when run, implements the entire song and shows the waves and sequence of all of the notes in the song.
In Xilinx: For the FPGA Piano, in the file “FPGA Piano”, open and implement the top module of the project FPGA Piano. For the LFSR, in the file “LFSR”, open and implement the top module of the project LFSR. In order to run or look at our attempt at programming a button to switch between the states of piano and the LFSR, run the project “LFSR_all” in the folder “LFSR_and_Piano”.