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