Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of skinGames_forktest by
hardwareIO/lockin.cpp
- Committer:
- mbedalvaro
- Date:
- 2013-10-16
- Revision:
- 41:74e24a0e6e50
File content as of revision 41:74e24a0e6e50:
#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]; }