Laser Sensing Display for UI interfaces in the real world

Dependencies:   mbed

Fork of skinGames_forktest by Alvaro Cassinelli

Revision:
31:5f039cbddee8
Child:
34:1244fa3f2559
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hardwareIO/lockin.cpp	Sun Sep 23 10:11:43 2012 +0000
@@ -0,0 +1,185 @@
+#include "lockin.h"
+
+Lockin lockin=Lockin();//pre-instanciation of object lockin with inter-file scope (declared extern in .h file)
+
+
+// NOTE: the ADC interrupt catching function is not a method of the Lockin class, hence the use of the pre-instantiated object "lockin":
+void catchInterupt(uint32_t value){ 
+    lockin.buffer_pos=(lockin.buffer_pos+1)%BUFFER_SIZE;
+    lockin.buffer[lockin.buffer_pos] = (value>>4)&0xFFF; // this is 12 bit precision ADC (0 to 4095), can be stored in an "unsigned short" (two bytes)
+}
+
+// PWM generation is configure as double edge 
+// MR0 (Match Register 0) control the frequency
+// 'pwm2' uses MR1 and MR2 (rising and falling edges)
+// 'pwm4' uses MR3 and MR4 (rising and falling edges)
+// 'pwm1' and 'pwm3' cannot be used since they share the same Match Register
+// for the moment, all PWM pin are set as output:
+PwmOut  pwm1(p26);
+PwmOut  pwm2(LOCKIN_LASER_PIN); //USED: this is pin p25, the LOCKIN_LASER_PIN
+PwmOut  pwm3(p24);
+PwmOut  pwm4(LOCKIN_REF_PIN); //USED: this is pin p22, the LOCKIN_REF_PIN
+PwmOut  pwm5(p22); 
+PwmOut  pwm6(p21);
+
+//Lockin::Lockin(){}
+
+void Lockin::init(){
+
+    //configure PWM for the laser and the Lockin
+    refFreq = 147;
+    offsetRef = 40;
+    halfRefFreq = refFreq / 2;
+    
+    refFrequency = 653; //init the lock-in frequency at 653 kHz
+    phaseShiftLaser = 0.546; //offset of 54% for the laser signal
+    phaseShiftLockin = 0; //no offset for the lock-in reference
+    initPWM();
+
+    //configure ADC:
+    clearBuffer();
+    
+    adc.startmode(0,0);
+    adc.burst(1);
+    adc.setup(LOCKIN_ADC_PIN, 1);
+    adc.select(LOCKIN_ADC_PIN);
+    adc.interrupt_state(LOCKIN_ADC_PIN, 1);
+    adc.append(LOCKIN_ADC_PIN, catchInterupt);
+}
+
+
+void Lockin::initPWM(){
+    
+    float halfPeriod = 0.5 * MBEDFREQUENCY / refFrequency; // half shared periof
+    _currentMR[0] = int(1.0 * MBEDFREQUENCY / refFrequency); //save the current value of MR0 (shared periof) //147
+    _currentMR[1] = int(phaseShiftLaser * halfPeriod); //save the current value of MR1 //40
+    _currentMR[2] = int(_currentMR[1] + halfPeriod); //save the current value of MR2  //40+73
+    _currentMR[3] = int(phaseShiftLockin * halfPeriod); //save the current value of MR1 //0
+    _currentMR[4] = int(_currentMR[3] + halfPeriod); //save the current value of MR2 //73
+
+    
+    // set PWM:
+    LPC_PWM1->TCR = (1 << 1);               // Reset counter, disable PWM
+    LPC_SC->PCLKSEL0 &= ~(0x3 << 12);
+    LPC_SC->PCLKSEL0 |= (1 << 12);          // Set peripheral clock divider to /1, i.e. system clock
+
+    LPC_PWM1->PCR |= 0x0014;                // Double edge PWM for PWM2,4
+
+    LPC_PWM1->MR0 = _currentMR[0];                      // Match Register 0 is shared period counter for all PWM1
+
+    LPC_PWM1->MR1 = _currentMR[1];                      // Match Register 1 is laser rising edge counter
+    LPC_PWM1->MR2 = _currentMR[2];                      // Match Register 2 is laser falling edge counter
+    LPC_PWM1->MR3 = _currentMR[3];                      // Match Register 3 is lock-in rising edge counter
+    LPC_PWM1->MR4 = _currentMR[4];                      // Match Register 4 is lock-in falling edge counter
+
+    LPC_PWM1->LER |= 1;                     // Start updating at next period start
+    LPC_PWM1->TCR = (1 << 0) || (1 << 3);   // Enable counter and PWM
+}
+
+//change the frequency of the PWM after initPWM()
+void Lockin::setPWMFrequency(float freq){
+    refFrequency = freq;
+    _currentMR[0] = int(MBEDFREQUENCY / refFrequency); //save the current value of MR0
+    LPC_PWM1->MR0 = _currentMR[0]; //update PWM shared period register
+    LPC_PWM1->LER |= 1; //update PWM
+}
+
+//change the phase shift of the sensing laser after initPWM()
+void Lockin::setLaserPhaseShift(float phaseShift){
+    phaseShiftLaser = phaseShift;
+    float halfPeriod = 0.5 * MBEDFREQUENCY / refFrequency;
+    _currentMR[1] = int(phaseShiftLaser * halfPeriod); //save the current value of MR1
+    _currentMR[2] = _currentMR[1] + halfPeriod; //save the current value of MR2
+    
+    LPC_PWM1->MR1 = _currentMR[1]; //update Laser rising edge match register
+    LPC_PWM1->MR2 = _currentMR[2]; //update Laser faling edge match register
+}
+
+//change the phase shift of the lock-in after initPWM()
+void Lockin::setLockinPhaseShift(float phaseShift){    
+    phaseShiftLockin = phaseShift;
+    float halfPeriod = 0.5 * MBEDFREQUENCY / refFrequency;
+    _currentMR[3] = int(phaseShiftLockin * halfPeriod); //save the current value of MR1
+    _currentMR[4] = _currentMR[3] + halfPeriod; //save the current value of MR2
+    
+    LPC_PWM1->MR3 = _currentMR[3]; //update lock-in rising edge match register
+    LPC_PWM1->MR4 = _currentMR[4]; //update lock-in faling edge match register
+}
+
+
+void Lockin::setLaserPower(bool power){
+    if(power){
+        LPC_PWM1->MR1 = _currentMR[1];
+        LPC_PWM1->MR2 = _currentMR[2];
+        LPC_PWM1->LER |= 1; // update PWM at the next period
+    }
+    else{
+        LPC_PWM1->MR1 = 0; //set rising edge at 0
+        LPC_PWM1->MR2 = 0; //set falling edge at 0
+        LPC_PWM1->LER |= 1; // update PWM at the next period
+    }
+}
+
+void Lockin::clearBuffer(){
+    for(int i=0; i<BUFFER_SIZE; i++){
+        buffer[i] = 0;
+    }
+    buffer_pos = BUFFER_SIZE;
+}
+
+/*
+void Lockin::catchInterupt(uint32_t value){ 
+    buffer_pos++;
+    buffer_pos%=BUFFER_SIZE;
+    buffer[buffer_pos] = value;
+}
+*/
+
+//****** aquisition method *****//
+unsigned short Lockin::getLastValue(){
+    return buffer[buffer_pos];
+}
+
+unsigned short Lockin::getSmoothValue(){
+    unsigned short smoothValue = buffer[0];
+    for(int i=1; i<BUFFER_SIZE; i++){
+        smoothValue += buffer[i];
+    }
+    smoothValue = (unsigned short)(smoothValue/BUFFER_SIZE); // note: we could have more precision (sub-12 bit), but it's not required and would imply using a float as output
+    
+    return smoothValue;
+}
+
+unsigned short Lockin::getMedianValue(){
+    //this method applies a median filter to the buffer
+    //It reduces the salt-and-pepper noise
+    //It seems that this noise is very strong on certain mBed board, but not all...
+
+   // unsigned short orderedBuffer[BUFFER_SIZE_MEDIAN];
+    
+    //sort half of the buffer:
+    
+    //copy buffer
+    for(int i=0; i<BUFFER_SIZE_MEDIAN; i++){
+        orderedBuffer[i] = buffer[(buffer_pos+BUFFER_SIZE-i+DELAY_BUFFER_MEDIAN)%BUFFER_SIZE];
+    }
+    
+    //order buffer
+    for(int i=0; i<BUFFER_SIZE_MEDIAN-1; i++){
+        int minPos = i;
+        
+        //get min
+        for(int j=i+1; j<BUFFER_SIZE_MEDIAN; j++){
+            if(orderedBuffer[j] < orderedBuffer[minPos]) minPos = j;
+        }
+        
+        //swap min to the right position
+        if(minPos != i){
+            int tmpMin = orderedBuffer[minPos];
+            orderedBuffer[minPos] = orderedBuffer[i];
+            orderedBuffer[i] = tmpMin;
+        }
+    }
+    
+    return orderedBuffer[BUFFER_SIZE_MEDIAN/2];
+}