Alvaro Cassinelli
/
skinGames_II
save loops
hardwareIO/lockin.cpp
- Committer:
- mbedalvaro
- Date:
- 2014-12-02
- Revision:
- 0:df6fdd9b99f0
File content as of revision 0:df6fdd9b99f0:
#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]; }