Digital Sound Synthesizer for lab 4
Dependencies: LSM9DS1_Library_cal PinDetect mbed-rtos mbed
main.cpp@0:0d977b83a68d, 2016-03-15 (annotated)
- Committer:
- nsloth
- Date:
- Tue Mar 15 21:27:30 2016 +0000
- Revision:
- 0:0d977b83a68d
Final Submission for ECE4180 Lab 4
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
nsloth | 0:0d977b83a68d | 1 | #include "mbed.h" |
nsloth | 0:0d977b83a68d | 2 | #include "rtos.h" |
nsloth | 0:0d977b83a68d | 3 | #include "mpr121.h" |
nsloth | 0:0d977b83a68d | 4 | #include "PinDetect.h" |
nsloth | 0:0d977b83a68d | 5 | #include "LSM9DS1.h" |
nsloth | 0:0d977b83a68d | 6 | |
nsloth | 0:0d977b83a68d | 7 | // Sound waveform synthesizer |
nsloth | 0:0d977b83a68d | 8 | // The program precomputes 128 data points on one wave cycle |
nsloth | 0:0d977b83a68d | 9 | // for triangular, sawtooth, and sine waves. These are stored |
nsloth | 0:0d977b83a68d | 10 | // and outout to the PWM to vary the PWM duty cycle. A very high |
nsloth | 0:0d977b83a68d | 11 | // PWM frequency is used and the frequency of the output soundwave |
nsloth | 0:0d977b83a68d | 12 | // is changed by changing the sampling rate. The program uses the |
nsloth | 0:0d977b83a68d | 13 | // IMU to shift frequencies, the keypad to choose center frequencies, |
nsloth | 0:0d977b83a68d | 14 | // the RGB LED to visually display pitch, and a pushbutton to switch between wave modes. |
nsloth | 0:0d977b83a68d | 15 | |
nsloth | 0:0d977b83a68d | 16 | #define PI 3.141592653589793238462 |
nsloth | 0:0d977b83a68d | 17 | |
nsloth | 0:0d977b83a68d | 18 | InterruptIn irq(p11); |
nsloth | 0:0d977b83a68d | 19 | I2C i2c1(p9,p10); |
nsloth | 0:0d977b83a68d | 20 | Mpr121 touchpad(&i2c1, Mpr121::ADD_VSS); |
nsloth | 0:0d977b83a68d | 21 | PwmOut PWM(p26); |
nsloth | 0:0d977b83a68d | 22 | Serial pc(USBTX,USBRX); |
nsloth | 0:0d977b83a68d | 23 | LSM9DS1 IMU(p28, p27, 0xD6, 0x3C); |
nsloth | 0:0d977b83a68d | 24 | Mutex stdio_mutex; |
nsloth | 0:0d977b83a68d | 25 | |
nsloth | 0:0d977b83a68d | 26 | PwmOut RGBLED_r(p21); |
nsloth | 0:0d977b83a68d | 27 | PwmOut RGBLED_g(p22); |
nsloth | 0:0d977b83a68d | 28 | PwmOut RGBLED_b(p23); |
nsloth | 0:0d977b83a68d | 29 | |
nsloth | 0:0d977b83a68d | 30 | PinDetect pb1(p17); |
nsloth | 0:0d977b83a68d | 31 | DigitalOut led1(LED1); |
nsloth | 0:0d977b83a68d | 32 | DigitalOut led2(LED2); |
nsloth | 0:0d977b83a68d | 33 | DigitalOut led3(LED3); |
nsloth | 0:0d977b83a68d | 34 | DigitalOut led4(LED4); |
nsloth | 0:0d977b83a68d | 35 | |
nsloth | 0:0d977b83a68d | 36 | //Global variables used by interrupt routines and threads |
nsloth | 0:0d977b83a68d | 37 | volatile int i=0; |
nsloth | 0:0d977b83a68d | 38 | volatile int j=0; |
nsloth | 0:0d977b83a68d | 39 | float sineInit[128]; |
nsloth | 0:0d977b83a68d | 40 | float sawInit[128]; |
nsloth | 0:0d977b83a68d | 41 | float triInit[128]; |
nsloth | 0:0d977b83a68d | 42 | volatile float baseFreq = 440; |
nsloth | 0:0d977b83a68d | 43 | float maxDeltaFreq = 200; |
nsloth | 0:0d977b83a68d | 44 | float maxDeltaXAxis = 15; |
nsloth | 0:0d977b83a68d | 45 | volatile float freq = 900; |
nsloth | 0:0d977b83a68d | 46 | volatile float deltaFreq = 0; |
nsloth | 0:0d977b83a68d | 47 | volatile float deltaXAxis = 0; |
nsloth | 0:0d977b83a68d | 48 | volatile float deltaXAxisOld = 0; |
nsloth | 0:0d977b83a68d | 49 | float frequencyScales[12] = {261.626, 293.665, 329.628, 349.228, 391.995, 440.0, |
nsloth | 0:0d977b83a68d | 50 | 493.883, 523.251, 587.33, 659.255, 783.991, 880}; |
nsloth | 0:0d977b83a68d | 51 | |
nsloth | 0:0d977b83a68d | 52 | enum Waveforms {sine=0,sawTooth,triangle}; |
nsloth | 0:0d977b83a68d | 53 | Waveforms wave = sine; |
nsloth | 0:0d977b83a68d | 54 | |
nsloth | 0:0d977b83a68d | 55 | //Samples IMU every .5 seconds and adjusts frequencies accordingly |
nsloth | 0:0d977b83a68d | 56 | void sample_IMU(void const *args) |
nsloth | 0:0d977b83a68d | 57 | { |
nsloth | 0:0d977b83a68d | 58 | while(1) { |
nsloth | 0:0d977b83a68d | 59 | if(IMU.accelAvailable()) { |
nsloth | 0:0d977b83a68d | 60 | stdio_mutex.lock(); |
nsloth | 0:0d977b83a68d | 61 | deltaXAxisOld = deltaXAxis; |
nsloth | 0:0d977b83a68d | 62 | deltaXAxis = (0.0024*IMU.readAccel(X_AXIS)); //Measures difference of IMU from base value of 0 |
nsloth | 0:0d977b83a68d | 63 | stdio_mutex.unlock(); |
nsloth | 0:0d977b83a68d | 64 | } |
nsloth | 0:0d977b83a68d | 65 | Thread::wait(500); |
nsloth | 0:0d977b83a68d | 66 | } |
nsloth | 0:0d977b83a68d | 67 | } |
nsloth | 0:0d977b83a68d | 68 | |
nsloth | 0:0d977b83a68d | 69 | //Plays the current waveform at the current frequency |
nsloth | 0:0d977b83a68d | 70 | void playSineWave() { |
nsloth | 0:0d977b83a68d | 71 | while(j<150) { //Controls how many cycles. Plays about 3 full cycles |
nsloth | 0:0d977b83a68d | 72 | switch(wave) { |
nsloth | 0:0d977b83a68d | 73 | case sine: |
nsloth | 0:0d977b83a68d | 74 | PWM = (sineInit[i]); |
nsloth | 0:0d977b83a68d | 75 | break; |
nsloth | 0:0d977b83a68d | 76 | case sawTooth: |
nsloth | 0:0d977b83a68d | 77 | PWM = sawInit[i]; |
nsloth | 0:0d977b83a68d | 78 | break; |
nsloth | 0:0d977b83a68d | 79 | case triangle: |
nsloth | 0:0d977b83a68d | 80 | PWM = triInit[i]; |
nsloth | 0:0d977b83a68d | 81 | break; |
nsloth | 0:0d977b83a68d | 82 | default: |
nsloth | 0:0d977b83a68d | 83 | led2 = 0; |
nsloth | 0:0d977b83a68d | 84 | led3 = 0; |
nsloth | 0:0d977b83a68d | 85 | led4 = 0; |
nsloth | 0:0d977b83a68d | 86 | break; |
nsloth | 0:0d977b83a68d | 87 | } |
nsloth | 0:0d977b83a68d | 88 | //(1.0 + sin((float(i)*freq*6.28318530717959/(128.0))))/2.0); |
nsloth | 0:0d977b83a68d | 89 | // increment pointer and wrap around back to 0 at 128 |
nsloth | 0:0d977b83a68d | 90 | if(i>60) { |
nsloth | 0:0d977b83a68d | 91 | j++; |
nsloth | 0:0d977b83a68d | 92 | } |
nsloth | 0:0d977b83a68d | 93 | i = (i+1) & 0x07F; |
nsloth | 0:0d977b83a68d | 94 | wait_us(1000000.0/((freq+deltaFreq)*128)); |
nsloth | 0:0d977b83a68d | 95 | } |
nsloth | 0:0d977b83a68d | 96 | |
nsloth | 0:0d977b83a68d | 97 | //At the end of 3 cycles, reset counters |
nsloth | 0:0d977b83a68d | 98 | i=0; |
nsloth | 0:0d977b83a68d | 99 | j=0; |
nsloth | 0:0d977b83a68d | 100 | |
nsloth | 0:0d977b83a68d | 101 | int value=touchpad.read(0x00); |
nsloth | 0:0d977b83a68d | 102 | value +=touchpad.read(0x01)<<8; |
nsloth | 0:0d977b83a68d | 103 | if (value == 0) { |
nsloth | 0:0d977b83a68d | 104 | //Reset values if keypad is not being touched |
nsloth | 0:0d977b83a68d | 105 | PWM = 0; |
nsloth | 0:0d977b83a68d | 106 | deltaFreq = 0; |
nsloth | 0:0d977b83a68d | 107 | deltaXAxis = 0; |
nsloth | 0:0d977b83a68d | 108 | RGBLED_r = 0; |
nsloth | 0:0d977b83a68d | 109 | RGBLED_g = 0; |
nsloth | 0:0d977b83a68d | 110 | RGBLED_b = 0; |
nsloth | 0:0d977b83a68d | 111 | } else { |
nsloth | 0:0d977b83a68d | 112 | //If the keypad has a nonzero value, update the frequency and play more cycles |
nsloth | 0:0d977b83a68d | 113 | stdio_mutex.lock(); |
nsloth | 0:0d977b83a68d | 114 | float diff = (abs(deltaXAxis - deltaXAxisOld) > 2) ? deltaXAxis : deltaXAxisOld; //Makes the delta frequency resistant to noise in the IMU |
nsloth | 0:0d977b83a68d | 115 | stdio_mutex.unlock(); |
nsloth | 0:0d977b83a68d | 116 | |
nsloth | 0:0d977b83a68d | 117 | //Calculates delta frequency from center frequency based off of IMU accelerometer |
nsloth | 0:0d977b83a68d | 118 | if(abs(diff) > maxDeltaXAxis) |
nsloth | 0:0d977b83a68d | 119 | deltaFreq = maxDeltaFreq; |
nsloth | 0:0d977b83a68d | 120 | else { |
nsloth | 0:0d977b83a68d | 121 | deltaFreq = diff/maxDeltaXAxis*maxDeltaFreq; |
nsloth | 0:0d977b83a68d | 122 | } |
nsloth | 0:0d977b83a68d | 123 | |
nsloth | 0:0d977b83a68d | 124 | RGBLED_r = abs(freq-deltaFreq-220)/880; |
nsloth | 0:0d977b83a68d | 125 | RGBLED_g = abs(freq-220)/880; |
nsloth | 0:0d977b83a68d | 126 | RGBLED_b = abs(freq+deltaFreq-220)/880;; |
nsloth | 0:0d977b83a68d | 127 | playSineWave(); |
nsloth | 0:0d977b83a68d | 128 | } |
nsloth | 0:0d977b83a68d | 129 | } |
nsloth | 0:0d977b83a68d | 130 | |
nsloth | 0:0d977b83a68d | 131 | //Called when the touchpad is tapped |
nsloth | 0:0d977b83a68d | 132 | void fallInterrupt() { |
nsloth | 0:0d977b83a68d | 133 | int key_code=0; |
nsloth | 0:0d977b83a68d | 134 | int n=0; |
nsloth | 0:0d977b83a68d | 135 | int value=touchpad.read(0x00); |
nsloth | 0:0d977b83a68d | 136 | value +=touchpad.read(0x01)<<8; |
nsloth | 0:0d977b83a68d | 137 | for (n=0; n<12; n++) { |
nsloth | 0:0d977b83a68d | 138 | if (((value>>n)&0x01)==1) { |
nsloth | 0:0d977b83a68d | 139 | key_code=n+1; |
nsloth | 0:0d977b83a68d | 140 | } |
nsloth | 0:0d977b83a68d | 141 | } |
nsloth | 0:0d977b83a68d | 142 | //sets frequency based on the tapped value |
nsloth | 0:0d977b83a68d | 143 | freq = frequencyScales[key_code-1]; |
nsloth | 0:0d977b83a68d | 144 | if (value != 0) { |
nsloth | 0:0d977b83a68d | 145 | playSineWave(); |
nsloth | 0:0d977b83a68d | 146 | } |
nsloth | 0:0d977b83a68d | 147 | } |
nsloth | 0:0d977b83a68d | 148 | |
nsloth | 0:0d977b83a68d | 149 | //Switches the current waveform and leds |
nsloth | 0:0d977b83a68d | 150 | void pb1_released_callback(void){ |
nsloth | 0:0d977b83a68d | 151 | if (wave == triangle) { |
nsloth | 0:0d977b83a68d | 152 | led2 = 1; |
nsloth | 0:0d977b83a68d | 153 | led3 = 0; |
nsloth | 0:0d977b83a68d | 154 | led4 = 0; |
nsloth | 0:0d977b83a68d | 155 | wave = sine; |
nsloth | 0:0d977b83a68d | 156 | } else if (wave == sine) { |
nsloth | 0:0d977b83a68d | 157 | led2 = 0; |
nsloth | 0:0d977b83a68d | 158 | led3 = 1; |
nsloth | 0:0d977b83a68d | 159 | led4 = 0; |
nsloth | 0:0d977b83a68d | 160 | wave = sawTooth; |
nsloth | 0:0d977b83a68d | 161 | } else { |
nsloth | 0:0d977b83a68d | 162 | led2 = 0; |
nsloth | 0:0d977b83a68d | 163 | led3 = 0; |
nsloth | 0:0d977b83a68d | 164 | led4 = 1; |
nsloth | 0:0d977b83a68d | 165 | wave = triangle; |
nsloth | 0:0d977b83a68d | 166 | } |
nsloth | 0:0d977b83a68d | 167 | } |
nsloth | 0:0d977b83a68d | 168 | |
nsloth | 0:0d977b83a68d | 169 | int main() |
nsloth | 0:0d977b83a68d | 170 | { |
nsloth | 0:0d977b83a68d | 171 | pc.printf("Program starting."); |
nsloth | 0:0d977b83a68d | 172 | PWM.period(1.0/200000.0); |
nsloth | 0:0d977b83a68d | 173 | led2 = 1; |
nsloth | 0:0d977b83a68d | 174 | led3 = 0; |
nsloth | 0:0d977b83a68d | 175 | led4 = 0; |
nsloth | 0:0d977b83a68d | 176 | |
nsloth | 0:0d977b83a68d | 177 | // Precompute 128 sample points on one wave cycle for three wave forms |
nsloth | 0:0d977b83a68d | 178 | // used for continuous wave output later |
nsloth | 0:0d977b83a68d | 179 | for(int k=0; k<128; k++) { |
nsloth | 0:0d977b83a68d | 180 | sineInit[k] = 1.0*((1.0 + sin((float(k)/128.0*2*PI)))/2.0); |
nsloth | 0:0d977b83a68d | 181 | sawInit[k] = (1.0 + ((-2.0*1.0/PI)*atan(cos(float(k)*PI/128.0)/sin(float(k)*PI/128.0))))/2.0; |
nsloth | 0:0d977b83a68d | 182 | triInit[k] = (1.0 + ((2.0*1.0/PI)*asin(sin(2.0*PI*float(k)/128.0))))/2.0; |
nsloth | 0:0d977b83a68d | 183 | // scale the waves from 0.0 to 1.0 - as needed for AnalogOut arg |
nsloth | 0:0d977b83a68d | 184 | } |
nsloth | 0:0d977b83a68d | 185 | |
nsloth | 0:0d977b83a68d | 186 | //Configure the IMU |
nsloth | 0:0d977b83a68d | 187 | IMU.begin(); |
nsloth | 0:0d977b83a68d | 188 | if (!IMU.begin()) { |
nsloth | 0:0d977b83a68d | 189 | pc.printf("Failed to communicate with LSM9DS1.\n"); |
nsloth | 0:0d977b83a68d | 190 | } |
nsloth | 0:0d977b83a68d | 191 | IMU.calibrate(1); |
nsloth | 0:0d977b83a68d | 192 | |
nsloth | 0:0d977b83a68d | 193 | //Configure the Push button |
nsloth | 0:0d977b83a68d | 194 | pb1.mode(PullUp); |
nsloth | 0:0d977b83a68d | 195 | wait(0.01); |
nsloth | 0:0d977b83a68d | 196 | pb1.attach_deasserted(&pb1_released_callback); |
nsloth | 0:0d977b83a68d | 197 | pb1.setSampleFrequency(); |
nsloth | 0:0d977b83a68d | 198 | |
nsloth | 0:0d977b83a68d | 199 | //Set up the I2C Touch keypad interrupt |
nsloth | 0:0d977b83a68d | 200 | irq.fall(&fallInterrupt); |
nsloth | 0:0d977b83a68d | 201 | irq.mode(PullUp); |
nsloth | 0:0d977b83a68d | 202 | |
nsloth | 0:0d977b83a68d | 203 | //And the IMU Sample thread |
nsloth | 0:0d977b83a68d | 204 | Thread t1(sample_IMU); |
nsloth | 0:0d977b83a68d | 205 | |
nsloth | 0:0d977b83a68d | 206 | while(1) {} |
nsloth | 0:0d977b83a68d | 207 | } |