Nathan Weiss / Mbed 2 deprecated 4180_lab4

Dependencies:   LSM9DS1_Library_cal PinDetect mbed-rtos mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 #include "mbed.h"
00002 #include "rtos.h"
00003 #include "mpr121.h"
00004 #include "PinDetect.h"
00005 #include "LSM9DS1.h"
00006 
00007 // Sound waveform synthesizer
00008 // The program precomputes 128 data points on one wave cycle 
00009 // for triangular, sawtooth, and sine waves. These are stored 
00010 // and outout to the PWM to vary the PWM duty cycle. A very high 
00011 // PWM frequency is used and the frequency of the output soundwave 
00012 // is changed by changing the sampling rate. The program uses the 
00013 // IMU to shift frequencies, the keypad to choose center frequencies, 
00014 // the RGB LED to visually display pitch, and a pushbutton to switch between wave modes.
00015 
00016 #define PI 3.141592653589793238462
00017 
00018 InterruptIn irq(p11);
00019 I2C i2c1(p9,p10);
00020 Mpr121 touchpad(&i2c1, Mpr121::ADD_VSS); 
00021 PwmOut PWM(p26);
00022 Serial pc(USBTX,USBRX);
00023 LSM9DS1 IMU(p28, p27, 0xD6, 0x3C);
00024 Mutex stdio_mutex; 
00025 
00026 PwmOut RGBLED_r(p21);
00027 PwmOut RGBLED_g(p22);
00028 PwmOut RGBLED_b(p23);
00029 
00030 PinDetect pb1(p17);
00031 DigitalOut led1(LED1);
00032 DigitalOut led2(LED2);
00033 DigitalOut led3(LED3);
00034 DigitalOut led4(LED4);
00035 
00036 //Global variables used by interrupt routines and threads
00037 volatile int i=0;
00038 volatile int j=0;
00039 float sineInit[128];
00040 float sawInit[128];
00041 float triInit[128];
00042 volatile float baseFreq = 440;
00043 float maxDeltaFreq = 200;
00044 float maxDeltaXAxis = 15;
00045 volatile float freq = 900;
00046 volatile float deltaFreq = 0;
00047 volatile float deltaXAxis = 0;
00048 volatile float deltaXAxisOld = 0;          
00049 float frequencyScales[12] = {261.626, 293.665, 329.628, 349.228, 391.995, 440.0,
00050                              493.883, 523.251, 587.33, 659.255, 783.991, 880};
00051 
00052 enum Waveforms {sine=0,sawTooth,triangle};
00053 Waveforms wave = sine;
00054 
00055 //Samples IMU every .5 seconds and adjusts frequencies accordingly
00056 void sample_IMU(void const *args)
00057 {
00058     while(1) {
00059         if(IMU.accelAvailable()) {
00060             stdio_mutex.lock();
00061             deltaXAxisOld = deltaXAxis;
00062             deltaXAxis = (0.0024*IMU.readAccel(X_AXIS)); //Measures difference of IMU from base value of 0
00063             stdio_mutex.unlock();
00064         }
00065         Thread::wait(500);
00066     }
00067 }
00068 
00069 //Plays the current waveform at the current frequency
00070 void playSineWave() {
00071     while(j<150) {  //Controls how many cycles. Plays about 3 full cycles
00072         switch(wave) {
00073             case sine:
00074                 PWM = (sineInit[i]);
00075             break;
00076             case sawTooth:
00077                 PWM = sawInit[i];
00078             break;
00079             case triangle:
00080                 PWM = triInit[i];
00081             break;
00082             default:
00083                 led2 = 0;
00084                 led3 = 0;
00085                 led4 = 0;
00086             break;
00087         }
00088         //(1.0 + sin((float(i)*freq*6.28318530717959/(128.0))))/2.0);
00089         // increment pointer and wrap around back to 0 at 128
00090         if(i>60) {
00091             j++;
00092         }
00093         i = (i+1) & 0x07F;
00094         wait_us(1000000.0/((freq+deltaFreq)*128));
00095     }
00096     
00097     //At the end of 3 cycles, reset counters
00098     i=0;
00099     j=0;
00100     
00101     int value=touchpad.read(0x00);
00102     value +=touchpad.read(0x01)<<8;
00103     if (value == 0) {
00104         //Reset values if keypad is not being touched
00105         PWM = 0;
00106         deltaFreq = 0;
00107         deltaXAxis = 0;
00108         RGBLED_r = 0;
00109         RGBLED_g = 0;
00110         RGBLED_b = 0;
00111     } else {
00112         //If the keypad has a nonzero value, update the frequency and play more cycles
00113         stdio_mutex.lock();
00114         float diff = (abs(deltaXAxis - deltaXAxisOld) > 2) ? deltaXAxis : deltaXAxisOld; //Makes the delta frequency resistant to noise in the IMU
00115         stdio_mutex.unlock();
00116         
00117         //Calculates delta frequency from center frequency based off of IMU accelerometer
00118         if(abs(diff) > maxDeltaXAxis)
00119             deltaFreq = maxDeltaFreq;
00120         else {
00121             deltaFreq = diff/maxDeltaXAxis*maxDeltaFreq;
00122         }
00123         
00124         RGBLED_r = abs(freq-deltaFreq-220)/880;
00125         RGBLED_g = abs(freq-220)/880;
00126         RGBLED_b = abs(freq+deltaFreq-220)/880;;
00127         playSineWave();
00128     }
00129 }
00130 
00131 //Called when the touchpad is tapped
00132 void fallInterrupt() {
00133     int key_code=0;
00134     int n=0;
00135     int value=touchpad.read(0x00);
00136     value +=touchpad.read(0x01)<<8;
00137     for (n=0; n<12; n++) {
00138         if (((value>>n)&0x01)==1) {
00139             key_code=n+1;
00140         }
00141     }
00142     //sets frequency based on the tapped value
00143     freq = frequencyScales[key_code-1];
00144     if (value != 0) {
00145         playSineWave();
00146     }
00147 }
00148 
00149 //Switches the current waveform and leds
00150 void pb1_released_callback(void){
00151     if (wave == triangle) {
00152         led2 = 1;
00153         led3 = 0;
00154         led4 = 0;
00155         wave = sine;
00156     } else if (wave == sine) {
00157         led2 = 0;
00158         led3 = 1;
00159         led4 = 0;
00160         wave = sawTooth;
00161     } else {
00162         led2 = 0;
00163         led3 = 0;
00164         led4 = 1;
00165         wave = triangle;
00166     }
00167 }
00168 
00169 int main()
00170 {
00171     pc.printf("Program starting.");
00172     PWM.period(1.0/200000.0);
00173     led2 = 1;
00174     led3 = 0;
00175     led4 = 0;
00176     
00177     // Precompute 128 sample points on one wave cycle for three wave forms
00178     // used for continuous wave output later
00179     for(int k=0; k<128; k++) {
00180         sineInit[k] = 1.0*((1.0 + sin((float(k)/128.0*2*PI)))/2.0);
00181         sawInit[k] = (1.0 + ((-2.0*1.0/PI)*atan(cos(float(k)*PI/128.0)/sin(float(k)*PI/128.0))))/2.0;
00182         triInit[k] = (1.0 + ((2.0*1.0/PI)*asin(sin(2.0*PI*float(k)/128.0))))/2.0;
00183         // scale the waves from 0.0 to 1.0 - as needed for AnalogOut arg 
00184     }
00185     
00186     //Configure the IMU
00187     IMU.begin();
00188     if (!IMU.begin()) {
00189         pc.printf("Failed to communicate with LSM9DS1.\n");
00190     }
00191     IMU.calibrate(1);
00192     
00193     //Configure the Push button
00194     pb1.mode(PullUp);
00195     wait(0.01);
00196     pb1.attach_deasserted(&pb1_released_callback);
00197     pb1.setSampleFrequency();
00198     
00199     //Set up the I2C Touch keypad interrupt
00200     irq.fall(&fallInterrupt);
00201     irq.mode(PullUp);
00202     
00203     //And the IMU Sample thread
00204     Thread t1(sample_IMU);
00205     
00206     while(1) {}
00207 }