Hidden Links

 

Music Man

 

Roeurn Tourn and Anthony Ma


The purpose of this experiment was to create a musical instrument using the nexys-2 board and the 3-axis accelerometer sensor.

System Requirements

The system required the use of the 3-axis accelerometer with the nexys-2 board to play music. Eight externals buttons were used to select musical notes in the key of C. Once the note was selected, a square wave was generated with the frequency corresponding to the selected note and outputted to the DAC and from there to a speaker. The accelerometer was used to actively alter the pitch of the note selected. Tilting the accelerometer forwards and backwards (positive and negative movement in the y- axis) changed the octave of the particular note. Forwards movement moves the note to a lower octave and backwards movement moves the note to a higher octave. The music man defaults to middle C (approximately 440Hz) and is limited to a range of 2 octaves lower from there and 2 octaves higher from there. Once the user moves the note into the new octave stage, he/she can return to the level state (0 acceleration in the x and y axis) and the music man will retain the new octave setting until the next octave change. From any particular octave the user also has the ability to "bend" the note. Tilting the accelerometer left or right (positive and negative movement in the x-axis) changes the pitch of the selected noted discretely by changing its frequency lower or higher around the selected frequency. The user can return to the selected note by returning to the level state. Unlike in the octave changing functionality, memory of the previous state is not retained in the note bending functionality. Finally the music man has the ability to output waveforms representing chords (3 notes played together). These chord waveforms also have the ability to change octaves and bend pitch just like their corresponding individual notes.

System Specification & Architecture

In total, this project makes use of the 3-axis accelerometer, nexys board, an ADC, a DAC, LCD screen, external buttons circuit, and a speaker. The sensor is constantly polled for its acceleration values in the x and y axis. Both of these values are calibrated so that they fall within a range of 100 to -100.    The calibrated acceleration values are outputted to the LCD screen along with the present octave range of the music man, more on this later. External buttons select the frequency of the square wave thats outputted using the DAC. Changes in acceleration of the x and y axis trigger bending of the pitch and changing of the octave respectively. Finally the music man supports playing up to 3 notes simultaneously called chords. Playing more than one note simultaneously results in a modulated waveform representing the same waveform from when two or more notes clash with one another.


This project used 1,931 out of 9,312 slice flip flops for 20% logic utilization. The code size is 7.8 kBytes.
Hardware 3-axis Accelerometer The Sparkfun accelerometer uses the ADXL335 accelerometer chip. Inside the chip there are micromachined structures, attached to a polysilicon spring, suspend over a silicon wafer. The chip measures acceleration by the deflection of the structure, via the capacitance change between the structure and the wafer. This system produces a maximum output of 3g, and can survive a shock at about 10,000g. The Sparkfun board, includes the recommended filtering and decoupling capacitors, and breadboard size through-hole solder points.

The device operates on 1.8V-3.6V. The Nexys-2 board provides 3.0V. The chip outputs analog voltage values that update at 1600Hz for the X and Y axis, and 550 Hz for the Z axis. The analog voltage range for 0g is around 1.5V.


Although the rate of change Vout of each axis is a straight-line function, their min and max values are different for each axis. Also because output sensitivity (scaling factor) varies proportional to the supply voltage, and all datasheet values were generated for Vs at 3.6V this project operates at 3.0V. All these factors make a calibration function essential.

DAC

In order for the Nexys-2 board to send the generated square wave to the speaker, the DAC was used to generate the analog signal. This project used the Digilent PmodDA1 DAC. The DAC communicates via an SPI interface. The dac_send() function works by
following these steps: [1]

1. Set mode, inhibit Master, disable SPI

2. Write initial data: Send lower byte to DTR

3. Disable SSR: Disconnect DAC

4. Set mode, inhibit Master, enable SPI

5. Enable SSR: Activate DAC

6. Set mode, Uninhibit Master (UNFREEZE)

7. Poll DTR_Empty (bit 29 in IPISR)

8. Byte transfer done! Inhibit Master (UNFREEZE)

9. Reset IPISR bit 29

10. Write new data: Send higher byte to DTR

11. UNFREEZE 12. Poll DTR_Empty (bit 29 in IPISR)

13. Byte trasfer done! FREEZE 14. Reset IPISR bit 29

15. Disable SSR: Deactivate DAC 16. Set mode, inhibit Master, disable SPI

ADC

For the Nexys board to read the analog values from the 3-axis accelerometer an ADC is required. This project uses the Digilent PmodAD1 ADC. The ADC communicates via an SPI interface. It is noteworthy that this SPI is slightly different from what is taught in class. Each Digilent board mounts two ADCs that share a single chip select line, and clock input. This means that the SPI clock of the X SPI is also clocking the Y ADC. Reading the Y ADC requires some adjustment of the SPI function. The adc_get() function works by following these steps: [2]

1. Set mode, inhibit master, disable SPI

2. Write DUMMY data: Send lower byte to DTR

3. Disable SSR: Disconnect ADC

4. Set mode, inhibit Master, enable SPI Start the data transfer

5. Enable SSR: Activate ADC

6. Set mode, Uninhibit Master (UNFREEZE)

7. Poll TxEmpty waits for transmit to finish

8. Inhibity Master (FREEZE)

9. Write new DUMMY data: Send lower byte to DTR

10. UNFREEZE

11. Poll TxEmpty waits for transmit to finish

12. FREEZE 13. Disable SSR: Deactivate ADC

14. Set mode, inhibit Master, disable SPI

SPI

To accomplish this project a PmodAD1 boards is required to read 2 analog voltage readings. There must also be 2 SPI hardware IPs installed on microblaze to read both axes. The Z axis is not used in this project. The analog signal from the from the accelerometer connects to the X ADC, and the Y ADC. Both ADCs exist on the same Pmod board. The X SPI Slave Select (referred to as Chip Select on the Pmod) and the X SPI Clock are both patched into the Y ADC. See diagram below.

 

To do a reading, both X ADC and Y ADC are read at the same time. Each line of the standard X SPI function are repeated with the Y SPI for the Y ADC. Despite the fact that there are no external uses of the Y SPI clock, or Y SPI Slave Select, these inputs must be included in the Y SPI IP for the system to function. The SPI function then also must be adjusted to receive 2 dereferenced pointers.

 

Software Main

The main function (see the diagram below) runs the LCD setup routines created in the first lab, it also enables interrupts before running a read sensor loop. This loop polls the sensor for raw data, using the DAC and SPI set up described above and stores the sensor read data inside 2 global variables. This data is then calibrated in two subroutines called xcal(int x) and ycal(int y).




Calibration testing was done by placing each accelerometer in positive g and negative g situations; this produced our min and max values or our calibration sensor inputs. This data was used to create a best fit plot to generate our transfer function. The xcal and ycal functions are described below.



Displaying the data requires a few conversions the global variables are of integer data type, to be displayed they must be converted into a char array and then can canted with other text to be readable. To accomplish, the iota function is used that was brought in from the internet. text concatenation is accomplished by a specialize function that outputs to the first line.

ISR

The ISR loop runs at every transition point in the wave form, ether at transition higher, or lower. when a transition happens and the ISR is called. It first checks the switches/external buttons, to update the requested frequencies. The sensor is then updated, and before the recal_waveturn() is called. The system can runs up to three square waves at the same time. These waves are described virtually and increment by a separate function, called recal_waveturn(). More on each of these functions are described in the text below. See the following chart for the general ISR breakdown.

The external buttons, are wired into the switch GPIO IO, and are described by the diagram below. They are 8 active high momentary buttons that have 200k ohm pull down resistor attached. The system was constructed using parts purchased from RadioShack. Note that the check switch function will refer to these external buttons.



The check swt function does two main things, it sets the frequency, and other major global variables, and it also initialized the virtual wave functions. Each time the function executes the switch setting are set into last_swt, and the last y setting are set into last_y. If these values change then more code is executed.

When a change in the recorded y value is detected the bend logic executes. This logic so small it is left inside check_swt. Multiple implementations of the bend function were tried, but the best sounding version ended up being a simple addition of the y data to our lowest frequency, Freq_1.

When a change in any of the switches is detected the system goes into a a logical routine described below. The resulting logic is quite simple, the system will read one switch at a time, from lowest note to highest note. when an “on” switch is detected, that frequency value is placed inside Freq_1, if that slot is filled, then that frequency value is placed in Freq_2 unless that slot is filled, then Freq_3 is filled with that frequency value. This will continue until all Frequency slots are filled, or when all switches are read.
The function terminates by setting the last_swt value to the current_swt value, and initializing wave1, wave2 and wave3.

Traking a wave

The system tracks 3 virtual waves, that are defined by by a few global variables.

•    Freq_1; the frequency value of the first wave.

•    rising1: tracks if the wave is currently in high mode or low mode.

•    t_reset_1: is the time length of one half period.

•    t_running_1: is the time length from “now” to when the wave toggles next, ether (high / low.)

•    wave1: is the amplitude of the virtual wave, ranges from 0 to 1365 (1/3 DAC high)

•    duty_cycle1: identifies if the wave is on or off


The function waving1() must be called the moment a wave is to be toggled from high to low, or low to high. Knowing when to call waving1(), waving2(), or waving3(), is the function of recal_waveturn().

 

recal_waveturn


The function title is short for “recalibrate the next wave to turn”. (see the flow chart below) Despite that fact that the system is tracking three waveforms, the only interrupt that matters is the next one. And the time it takes to get there. This can be calculated and it’s value is set as next_interrupt. When this function runs, the time stored in next_interrupt equals the the time that just previously elapsed. The function first updates t_running_1, t_running_2, and t_running_3, by decrementing them the value of next_interrupt.

 

The system then checks each t_running_# to see if any of the timers reached zero, if it did, then the waving# function is called, and the timer is reset to t_reset_#. After these waving# functions are called, the amplitude value stored in wave1, wave2, and wave3 are updated and can be outputted through the dac_send function. Because each waveform is already a value between 0 and 1/3 dac max, no further calibration of the numbers are required. (note: the # sign designates that this process is reaped for waves 1 2 and 3)
The next_interrupt time is given a default value, and is then checked against each t_running_# is to find the smaller number. This corresponds to the next interrupt to occur.
This value is then placed into the load register of TIMER0 and the interrupt is reset.

Testing Procedure

Testing of this project was largely trial-and-error based. The accelerometer was used to make changes to the frequency and modulation of the square wave output. In order to detect these discrete changes, an oscilloscope was used to verify that the correct frequency waveform was being produced. First the switches on the nexys-2 board were used to each individually output a note in the musical key of C. Once it was verified that each switch produced the correct frequency, the custom made button circuit was brought in to replace the switches because playing music with buttons was easier than playing with switches. The external buttons were verified to be working when pressing them produced the same waveforms that the switches previous had. The 3-axis accelerometer was verified to work properly from the previous sensor project and that same functionality, minus acceleration measurements in the z-axis, was brought directly into this project. Monitoring of the accelerometer's functionality was done by updating the LCD with the acceleration values in the x and y axes. The accelerometer octave changing functionality as well as it's note bending functionality were each brought in individually and verified to work by monitor the change in the waveform frequency on the oscilloscope. Finally the oscilloscope was used to monitor the modulated waveform that was produced from the chord functionality.

 

Encountered Problems

Combining waves at two different wave length produces secondary effects that required a more complex algorithm than originally expected. Combining two different waves or more, produces a new fundamental frequency, a new first order harmonic, something musicians refer to as the "beat frequency". See the image below.



Because the two waves are at two different length, their phase difference changes over time too. This creates a natural loudening and fainting of the notes as the two frequency move in and out of phase. The wave length of the beat frequency (wb), can be calculated from the wave length of the longer wave w2 and the wave length of the shorter wave w1.


To solve this problems the waves cannot be combined in a single time window of the fundamental frequency of any of the original waves. One solution involved calculating the new first order harmonic and combining waves inside of this time domain, but that became too complicated. The more elegant solution was to allow the beat frequency to occur naturally out of the natural synthesis from waves combined in the system. That approached is outlined above in recal_wave.


Another problem that was encountered while working on this project was the issue of converting integers to characters. In order to write the accelerations to the LCD, the integers from the adc_get() first had to be converted into arrays of characters in order to be accepted by the LCD_write() function. The C standard library has a function called itoa() that coverts integers to chars but the library was too large to import onto the board. In order to get around this problem, the itoa() function and the function that it uses, reverse(), were found on Wikipedia and the code was brought into the file rather than imported from the standard library. [3]

Conclusion

In this experiment the nexys-2 board and the 3-axis accelerometer sensor were used to create a unique musical instrument. The music man most resembles a piano as a musical instrument. The music man has to ability to play individual notes, chords of up to 3 notes, and covers the full octave range of a keyboard. However, the music is unique from a keyboard in that it has the ability to bend the pitch of notes and it reaches new octaves through the tilting of the accelerometer. The features that really set the music man aside from most other musical instruments are its abilities to bend notes and play chords. There are only a small number of musical instruments that have both these abilities, such as the guitar. Because notes can be bent to discretely change their pitch, the music man can also change keys from C to any of the other 11 keys. This experiment is closely related to the function generator project where waveforms were first generated using the DAC, and the sensor project where the accelerometer was first successfully interfaced with the nexys-2 board. In this project a fully operational musical instrument was created.

 

Work Cited

[1], [2] spiTxRx.c, https://blackboard.calpoly.edu/webapps/portal/frameset.jsp?useCas=1&tab=courses&url=/bin/common/course.pl?cours e_id=_53758_
[3] itoa function, http://en.wikipedia.org/wiki/Itoa