Alvaro Cassinelli
/
skinGames_II
save loops
Diff: hardwareIO/lockin.cpp
- Revision:
- 0:df6fdd9b99f0
diff -r 000000000000 -r df6fdd9b99f0 hardwareIO/lockin.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hardwareIO/lockin.cpp Tue Dec 02 04:39:15 2014 +0000 @@ -0,0 +1,196 @@ +#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 p23, 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 BURST MODE: + 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 { + // unset the lockin pin: + adc.burst(0); + adc.setup(LOCKIN_ADC_PIN, 0); + adc.interrupt_state(LOCKIN_ADC_PIN, 0); + } +} + +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]; +}