Laser Sensing Display for UI interfaces in the real world

Dependencies:   mbed

Fork of skinGames_forktest by Alvaro Cassinelli

hardwareIO/lockin.cpp

Committer:
mbedalvaro
Date:
2014-04-17
Revision:
47:199042980678
Parent:
41:74e24a0e6e50

File content as of revision 47:199042980678:

#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();
    
     // SET ADC IN BURST MODE:
    lockin.setADC_forLockin(1);
}

void Lockin::setADC_forLockin(int mode) {
    if (mode>0) {
    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);
    } else {
    //adc.startmode(0,0);
    adc.burst(0);
    adc.setup(LOCKIN_ADC_PIN, 0);
    //adc.select(LOCKIN_ADC_PIN);
    adc.interrupt_state(LOCKIN_ADC_PIN, 0);
    //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];
}