Digital Sound Synthesizer for lab 4

Dependencies:   LSM9DS1_Library_cal PinDetect mbed-rtos mbed

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?

UserRevisionLine numberNew 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 }