Alvaro Cassinelli
/
skinGames_II
save loops
hardwareIO/lockin.cpp@1:3be7b7d050f4, 2014-12-02 (annotated)
- Committer:
- mbedalvaro
- Date:
- Tue Dec 02 08:29:59 2014 +0000
- Revision:
- 1:3be7b7d050f4
- Parent:
- 0:df6fdd9b99f0
updated
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
mbedalvaro | 0:df6fdd9b99f0 | 1 | #include "lockin.h" |
mbedalvaro | 0:df6fdd9b99f0 | 2 | |
mbedalvaro | 0:df6fdd9b99f0 | 3 | Lockin lockin=Lockin();//pre-instanciation of object lockin with inter-file scope (declared extern in .h file) |
mbedalvaro | 0:df6fdd9b99f0 | 4 | |
mbedalvaro | 0:df6fdd9b99f0 | 5 | |
mbedalvaro | 0:df6fdd9b99f0 | 6 | // NOTE: the ADC interrupt catching function is not a method of the Lockin class, hence the use of the pre-instantiated object "lockin": |
mbedalvaro | 0:df6fdd9b99f0 | 7 | void catchInterupt(uint32_t value){ |
mbedalvaro | 0:df6fdd9b99f0 | 8 | lockin.buffer_pos=(lockin.buffer_pos+1)%BUFFER_SIZE; |
mbedalvaro | 0:df6fdd9b99f0 | 9 | 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) |
mbedalvaro | 0:df6fdd9b99f0 | 10 | } |
mbedalvaro | 0:df6fdd9b99f0 | 11 | |
mbedalvaro | 0:df6fdd9b99f0 | 12 | // PWM generation is configure as double edge |
mbedalvaro | 0:df6fdd9b99f0 | 13 | // MR0 (Match Register 0) control the frequency |
mbedalvaro | 0:df6fdd9b99f0 | 14 | // 'pwm2' uses MR1 and MR2 (rising and falling edges) |
mbedalvaro | 0:df6fdd9b99f0 | 15 | // 'pwm4' uses MR3 and MR4 (rising and falling edges) |
mbedalvaro | 0:df6fdd9b99f0 | 16 | // 'pwm1' and 'pwm3' cannot be used since they share the same Match Register |
mbedalvaro | 0:df6fdd9b99f0 | 17 | // for the moment, all PWM pin are set as output: |
mbedalvaro | 0:df6fdd9b99f0 | 18 | //PwmOut pwm1(p26); |
mbedalvaro | 0:df6fdd9b99f0 | 19 | PwmOut pwm2(LOCKIN_LASER_PIN); //USED: this is pin p25, the LOCKIN_LASER_PIN |
mbedalvaro | 0:df6fdd9b99f0 | 20 | PwmOut pwm3(p24); |
mbedalvaro | 0:df6fdd9b99f0 | 21 | PwmOut pwm4(LOCKIN_REF_PIN); //USED: this is pin p23, the LOCKIN_REF_PIN |
mbedalvaro | 0:df6fdd9b99f0 | 22 | //PwmOut pwm5(p22); |
mbedalvaro | 0:df6fdd9b99f0 | 23 | //PwmOut pwm6(p21); |
mbedalvaro | 0:df6fdd9b99f0 | 24 | |
mbedalvaro | 0:df6fdd9b99f0 | 25 | //Lockin::Lockin(){} |
mbedalvaro | 0:df6fdd9b99f0 | 26 | |
mbedalvaro | 0:df6fdd9b99f0 | 27 | void Lockin::init(){ |
mbedalvaro | 0:df6fdd9b99f0 | 28 | |
mbedalvaro | 0:df6fdd9b99f0 | 29 | //configure PWM for the laser and the Lockin |
mbedalvaro | 0:df6fdd9b99f0 | 30 | refFreq = 147; |
mbedalvaro | 0:df6fdd9b99f0 | 31 | offsetRef = 40; |
mbedalvaro | 0:df6fdd9b99f0 | 32 | halfRefFreq = refFreq / 2; |
mbedalvaro | 0:df6fdd9b99f0 | 33 | |
mbedalvaro | 0:df6fdd9b99f0 | 34 | refFrequency = 653; //init the lock-in frequency at 653 kHz |
mbedalvaro | 0:df6fdd9b99f0 | 35 | phaseShiftLaser = 0.546; //offset of 54% for the laser signal |
mbedalvaro | 0:df6fdd9b99f0 | 36 | phaseShiftLockin = 0; //no offset for the lock-in reference |
mbedalvaro | 0:df6fdd9b99f0 | 37 | initPWM(); |
mbedalvaro | 0:df6fdd9b99f0 | 38 | |
mbedalvaro | 0:df6fdd9b99f0 | 39 | //configure ADC: |
mbedalvaro | 0:df6fdd9b99f0 | 40 | clearBuffer(); |
mbedalvaro | 0:df6fdd9b99f0 | 41 | |
mbedalvaro | 0:df6fdd9b99f0 | 42 | // SET ADC IN BURST MODE: |
mbedalvaro | 0:df6fdd9b99f0 | 43 | lockin.setADC_forLockin(1); |
mbedalvaro | 0:df6fdd9b99f0 | 44 | } |
mbedalvaro | 0:df6fdd9b99f0 | 45 | |
mbedalvaro | 0:df6fdd9b99f0 | 46 | void Lockin::setADC_forLockin(int mode) { |
mbedalvaro | 0:df6fdd9b99f0 | 47 | if (mode>0) { // ADC BURST MODE: |
mbedalvaro | 0:df6fdd9b99f0 | 48 | adc.startmode(0,0); |
mbedalvaro | 0:df6fdd9b99f0 | 49 | adc.burst(1); |
mbedalvaro | 0:df6fdd9b99f0 | 50 | adc.setup(LOCKIN_ADC_PIN, 1); |
mbedalvaro | 0:df6fdd9b99f0 | 51 | adc.select(LOCKIN_ADC_PIN); |
mbedalvaro | 0:df6fdd9b99f0 | 52 | adc.interrupt_state(LOCKIN_ADC_PIN, 1); |
mbedalvaro | 0:df6fdd9b99f0 | 53 | adc.append(LOCKIN_ADC_PIN, catchInterupt); |
mbedalvaro | 0:df6fdd9b99f0 | 54 | } else { |
mbedalvaro | 0:df6fdd9b99f0 | 55 | // unset the lockin pin: |
mbedalvaro | 0:df6fdd9b99f0 | 56 | adc.burst(0); |
mbedalvaro | 0:df6fdd9b99f0 | 57 | adc.setup(LOCKIN_ADC_PIN, 0); |
mbedalvaro | 0:df6fdd9b99f0 | 58 | adc.interrupt_state(LOCKIN_ADC_PIN, 0); |
mbedalvaro | 0:df6fdd9b99f0 | 59 | } |
mbedalvaro | 0:df6fdd9b99f0 | 60 | } |
mbedalvaro | 0:df6fdd9b99f0 | 61 | |
mbedalvaro | 0:df6fdd9b99f0 | 62 | void Lockin::initPWM(){ |
mbedalvaro | 0:df6fdd9b99f0 | 63 | |
mbedalvaro | 0:df6fdd9b99f0 | 64 | float halfPeriod = 0.5 * MBEDFREQUENCY / refFrequency; // half shared periof |
mbedalvaro | 0:df6fdd9b99f0 | 65 | _currentMR[0] = int(1.0 * MBEDFREQUENCY / refFrequency); //save the current value of MR0 (shared periof) //147 |
mbedalvaro | 0:df6fdd9b99f0 | 66 | _currentMR[1] = int(phaseShiftLaser * halfPeriod); //save the current value of MR1 //40 |
mbedalvaro | 0:df6fdd9b99f0 | 67 | _currentMR[2] = int(_currentMR[1] + halfPeriod); //save the current value of MR2 //40+73 |
mbedalvaro | 0:df6fdd9b99f0 | 68 | _currentMR[3] = int(phaseShiftLockin * halfPeriod); //save the current value of MR1 //0 |
mbedalvaro | 0:df6fdd9b99f0 | 69 | _currentMR[4] = int(_currentMR[3] + halfPeriod); //save the current value of MR2 //73 |
mbedalvaro | 0:df6fdd9b99f0 | 70 | |
mbedalvaro | 0:df6fdd9b99f0 | 71 | |
mbedalvaro | 0:df6fdd9b99f0 | 72 | // set PWM: |
mbedalvaro | 0:df6fdd9b99f0 | 73 | LPC_PWM1->TCR = (1 << 1); // Reset counter, disable PWM |
mbedalvaro | 0:df6fdd9b99f0 | 74 | LPC_SC->PCLKSEL0 &= ~(0x3 << 12); |
mbedalvaro | 0:df6fdd9b99f0 | 75 | LPC_SC->PCLKSEL0 |= (1 << 12); // Set peripheral clock divider to /1, i.e. system clock |
mbedalvaro | 0:df6fdd9b99f0 | 76 | |
mbedalvaro | 0:df6fdd9b99f0 | 77 | LPC_PWM1->PCR |= 0x0014; // Double edge PWM for PWM2,4 |
mbedalvaro | 0:df6fdd9b99f0 | 78 | |
mbedalvaro | 0:df6fdd9b99f0 | 79 | LPC_PWM1->MR0 = _currentMR[0]; // Match Register 0 is shared period counter for all PWM1 |
mbedalvaro | 0:df6fdd9b99f0 | 80 | |
mbedalvaro | 0:df6fdd9b99f0 | 81 | LPC_PWM1->MR1 = _currentMR[1]; // Match Register 1 is laser rising edge counter |
mbedalvaro | 0:df6fdd9b99f0 | 82 | LPC_PWM1->MR2 = _currentMR[2]; // Match Register 2 is laser falling edge counter |
mbedalvaro | 0:df6fdd9b99f0 | 83 | LPC_PWM1->MR3 = _currentMR[3]; // Match Register 3 is lock-in rising edge counter |
mbedalvaro | 0:df6fdd9b99f0 | 84 | LPC_PWM1->MR4 = _currentMR[4]; // Match Register 4 is lock-in falling edge counter |
mbedalvaro | 0:df6fdd9b99f0 | 85 | |
mbedalvaro | 0:df6fdd9b99f0 | 86 | LPC_PWM1->LER |= 1; // Start updating at next period start |
mbedalvaro | 0:df6fdd9b99f0 | 87 | LPC_PWM1->TCR = (1 << 0) || (1 << 3); // Enable counter and PWM |
mbedalvaro | 0:df6fdd9b99f0 | 88 | } |
mbedalvaro | 0:df6fdd9b99f0 | 89 | |
mbedalvaro | 0:df6fdd9b99f0 | 90 | //change the frequency of the PWM after initPWM() |
mbedalvaro | 0:df6fdd9b99f0 | 91 | void Lockin::setPWMFrequency(float freq){ |
mbedalvaro | 0:df6fdd9b99f0 | 92 | refFrequency = freq; |
mbedalvaro | 0:df6fdd9b99f0 | 93 | _currentMR[0] = int(MBEDFREQUENCY / refFrequency); //save the current value of MR0 |
mbedalvaro | 0:df6fdd9b99f0 | 94 | LPC_PWM1->MR0 = _currentMR[0]; //update PWM shared period register |
mbedalvaro | 0:df6fdd9b99f0 | 95 | LPC_PWM1->LER |= 1; //update PWM |
mbedalvaro | 0:df6fdd9b99f0 | 96 | } |
mbedalvaro | 0:df6fdd9b99f0 | 97 | |
mbedalvaro | 0:df6fdd9b99f0 | 98 | //change the phase shift of the sensing laser after initPWM() |
mbedalvaro | 0:df6fdd9b99f0 | 99 | void Lockin::setLaserPhaseShift(float phaseShift){ |
mbedalvaro | 0:df6fdd9b99f0 | 100 | phaseShiftLaser = phaseShift; |
mbedalvaro | 0:df6fdd9b99f0 | 101 | float halfPeriod = 0.5 * MBEDFREQUENCY / refFrequency; |
mbedalvaro | 0:df6fdd9b99f0 | 102 | _currentMR[1] = int(phaseShiftLaser * halfPeriod); //save the current value of MR1 |
mbedalvaro | 0:df6fdd9b99f0 | 103 | _currentMR[2] = _currentMR[1] + halfPeriod; //save the current value of MR2 |
mbedalvaro | 0:df6fdd9b99f0 | 104 | |
mbedalvaro | 0:df6fdd9b99f0 | 105 | LPC_PWM1->MR1 = _currentMR[1]; //update Laser rising edge match register |
mbedalvaro | 0:df6fdd9b99f0 | 106 | LPC_PWM1->MR2 = _currentMR[2]; //update Laser faling edge match register |
mbedalvaro | 0:df6fdd9b99f0 | 107 | } |
mbedalvaro | 0:df6fdd9b99f0 | 108 | |
mbedalvaro | 0:df6fdd9b99f0 | 109 | //change the phase shift of the lock-in after initPWM() |
mbedalvaro | 0:df6fdd9b99f0 | 110 | void Lockin::setLockinPhaseShift(float phaseShift){ |
mbedalvaro | 0:df6fdd9b99f0 | 111 | phaseShiftLockin = phaseShift; |
mbedalvaro | 0:df6fdd9b99f0 | 112 | float halfPeriod = 0.5 * MBEDFREQUENCY / refFrequency; |
mbedalvaro | 0:df6fdd9b99f0 | 113 | _currentMR[3] = int(phaseShiftLockin * halfPeriod); //save the current value of MR1 |
mbedalvaro | 0:df6fdd9b99f0 | 114 | _currentMR[4] = _currentMR[3] + halfPeriod; //save the current value of MR2 |
mbedalvaro | 0:df6fdd9b99f0 | 115 | |
mbedalvaro | 0:df6fdd9b99f0 | 116 | LPC_PWM1->MR3 = _currentMR[3]; //update lock-in rising edge match register |
mbedalvaro | 0:df6fdd9b99f0 | 117 | LPC_PWM1->MR4 = _currentMR[4]; //update lock-in faling edge match register |
mbedalvaro | 0:df6fdd9b99f0 | 118 | } |
mbedalvaro | 0:df6fdd9b99f0 | 119 | |
mbedalvaro | 0:df6fdd9b99f0 | 120 | |
mbedalvaro | 0:df6fdd9b99f0 | 121 | void Lockin::setLaserPower(bool power){ |
mbedalvaro | 0:df6fdd9b99f0 | 122 | if(power){ |
mbedalvaro | 0:df6fdd9b99f0 | 123 | LPC_PWM1->MR1 = _currentMR[1]; |
mbedalvaro | 0:df6fdd9b99f0 | 124 | LPC_PWM1->MR2 = _currentMR[2]; |
mbedalvaro | 0:df6fdd9b99f0 | 125 | LPC_PWM1->LER |= 1; // update PWM at the next period |
mbedalvaro | 0:df6fdd9b99f0 | 126 | } |
mbedalvaro | 0:df6fdd9b99f0 | 127 | else{ |
mbedalvaro | 0:df6fdd9b99f0 | 128 | LPC_PWM1->MR1 = 0; //set rising edge at 0 |
mbedalvaro | 0:df6fdd9b99f0 | 129 | LPC_PWM1->MR2 = 0; //set falling edge at 0 |
mbedalvaro | 0:df6fdd9b99f0 | 130 | LPC_PWM1->LER |= 1; // update PWM at the next period |
mbedalvaro | 0:df6fdd9b99f0 | 131 | } |
mbedalvaro | 0:df6fdd9b99f0 | 132 | } |
mbedalvaro | 0:df6fdd9b99f0 | 133 | |
mbedalvaro | 0:df6fdd9b99f0 | 134 | void Lockin::clearBuffer(){ |
mbedalvaro | 0:df6fdd9b99f0 | 135 | for(int i=0; i<BUFFER_SIZE; i++){ |
mbedalvaro | 0:df6fdd9b99f0 | 136 | buffer[i] = 0; |
mbedalvaro | 0:df6fdd9b99f0 | 137 | } |
mbedalvaro | 0:df6fdd9b99f0 | 138 | buffer_pos = BUFFER_SIZE; |
mbedalvaro | 0:df6fdd9b99f0 | 139 | } |
mbedalvaro | 0:df6fdd9b99f0 | 140 | |
mbedalvaro | 0:df6fdd9b99f0 | 141 | /* |
mbedalvaro | 0:df6fdd9b99f0 | 142 | void Lockin::catchInterupt(uint32_t value){ |
mbedalvaro | 0:df6fdd9b99f0 | 143 | buffer_pos++; |
mbedalvaro | 0:df6fdd9b99f0 | 144 | buffer_pos%=BUFFER_SIZE; |
mbedalvaro | 0:df6fdd9b99f0 | 145 | buffer[buffer_pos] = value; |
mbedalvaro | 0:df6fdd9b99f0 | 146 | } |
mbedalvaro | 0:df6fdd9b99f0 | 147 | */ |
mbedalvaro | 0:df6fdd9b99f0 | 148 | |
mbedalvaro | 0:df6fdd9b99f0 | 149 | //****** aquisition method *****// |
mbedalvaro | 0:df6fdd9b99f0 | 150 | unsigned short Lockin::getLastValue(){ |
mbedalvaro | 0:df6fdd9b99f0 | 151 | return buffer[buffer_pos]; |
mbedalvaro | 0:df6fdd9b99f0 | 152 | } |
mbedalvaro | 0:df6fdd9b99f0 | 153 | |
mbedalvaro | 0:df6fdd9b99f0 | 154 | unsigned short Lockin::getSmoothValue(){ |
mbedalvaro | 0:df6fdd9b99f0 | 155 | unsigned short smoothValue = buffer[0]; |
mbedalvaro | 0:df6fdd9b99f0 | 156 | for(int i=1; i<BUFFER_SIZE; i++){ |
mbedalvaro | 0:df6fdd9b99f0 | 157 | smoothValue += buffer[i]; |
mbedalvaro | 0:df6fdd9b99f0 | 158 | } |
mbedalvaro | 0:df6fdd9b99f0 | 159 | 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 |
mbedalvaro | 0:df6fdd9b99f0 | 160 | |
mbedalvaro | 0:df6fdd9b99f0 | 161 | return smoothValue; |
mbedalvaro | 0:df6fdd9b99f0 | 162 | } |
mbedalvaro | 0:df6fdd9b99f0 | 163 | |
mbedalvaro | 0:df6fdd9b99f0 | 164 | unsigned short Lockin::getMedianValue(){ |
mbedalvaro | 0:df6fdd9b99f0 | 165 | //this method applies a median filter to the buffer |
mbedalvaro | 0:df6fdd9b99f0 | 166 | //It reduces the salt-and-pepper noise |
mbedalvaro | 0:df6fdd9b99f0 | 167 | //It seems that this noise is very strong on certain mBed board, but not all... |
mbedalvaro | 0:df6fdd9b99f0 | 168 | |
mbedalvaro | 0:df6fdd9b99f0 | 169 | // unsigned short orderedBuffer[BUFFER_SIZE_MEDIAN]; |
mbedalvaro | 0:df6fdd9b99f0 | 170 | |
mbedalvaro | 0:df6fdd9b99f0 | 171 | //sort half of the buffer: |
mbedalvaro | 0:df6fdd9b99f0 | 172 | |
mbedalvaro | 0:df6fdd9b99f0 | 173 | //copy buffer |
mbedalvaro | 0:df6fdd9b99f0 | 174 | for(int i=0; i<BUFFER_SIZE_MEDIAN; i++){ |
mbedalvaro | 0:df6fdd9b99f0 | 175 | orderedBuffer[i] = buffer[(buffer_pos+BUFFER_SIZE-i+DELAY_BUFFER_MEDIAN)%BUFFER_SIZE]; |
mbedalvaro | 0:df6fdd9b99f0 | 176 | } |
mbedalvaro | 0:df6fdd9b99f0 | 177 | |
mbedalvaro | 0:df6fdd9b99f0 | 178 | //order buffer |
mbedalvaro | 0:df6fdd9b99f0 | 179 | for(int i=0; i<BUFFER_SIZE_MEDIAN-1; i++){ |
mbedalvaro | 0:df6fdd9b99f0 | 180 | int minPos = i; |
mbedalvaro | 0:df6fdd9b99f0 | 181 | |
mbedalvaro | 0:df6fdd9b99f0 | 182 | //get min |
mbedalvaro | 0:df6fdd9b99f0 | 183 | for(int j=i+1; j<BUFFER_SIZE_MEDIAN; j++){ |
mbedalvaro | 0:df6fdd9b99f0 | 184 | if(orderedBuffer[j] < orderedBuffer[minPos]) minPos = j; |
mbedalvaro | 0:df6fdd9b99f0 | 185 | } |
mbedalvaro | 0:df6fdd9b99f0 | 186 | |
mbedalvaro | 0:df6fdd9b99f0 | 187 | //swap min to the right position |
mbedalvaro | 0:df6fdd9b99f0 | 188 | if(minPos != i){ |
mbedalvaro | 0:df6fdd9b99f0 | 189 | int tmpMin = orderedBuffer[minPos]; |
mbedalvaro | 0:df6fdd9b99f0 | 190 | orderedBuffer[minPos] = orderedBuffer[i]; |
mbedalvaro | 0:df6fdd9b99f0 | 191 | orderedBuffer[i] = tmpMin; |
mbedalvaro | 0:df6fdd9b99f0 | 192 | } |
mbedalvaro | 0:df6fdd9b99f0 | 193 | } |
mbedalvaro | 0:df6fdd9b99f0 | 194 | |
mbedalvaro | 0:df6fdd9b99f0 | 195 | return orderedBuffer[BUFFER_SIZE_MEDIAN/2]; |
mbedalvaro | 0:df6fdd9b99f0 | 196 | } |