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 scoreLight_Advanced by
hardwareIO.cpp
00001 #include "hardwareIO.h" 00002 00003 HardwareIO IO; // preintantiation of cross-file global object IO 00004 00005 // -------------------------------------- (0) SETUP ALL IO (call this in the setup() function in main program) 00006 00007 Serial pc(USBTX, USBRX); // tx, rx 00008 LocalFileSystem local("local"); // Create the local filesystem under the name "local" 00009 00010 SPI spiDAC(MOSI_PIN, MISO_PIN, SCK_PIN); // mosi, miso, sclk 00011 DigitalOut csDAC(CS_DAC_MIRRORS); 00012 00013 DigitalOut Laser_Red(LASER_RED_PIN); // NOTE: this is NOT the lock in sensing laser (actually, not used yet) 00014 DigitalOut Laser_Green(LASER_GREEN_PIN); 00015 DigitalOut Laser_Blue(LASER_BLUE_PIN); 00016 00017 // Some manual controls over the hardware function: 00018 InterruptIn switchOne(SWITCH_ONE); 00019 InterruptIn switchTwo(SWITCH_TWO); 00020 AnalogIn ainPot(POT_ANALOG_INPUT); 00021 //DigitalIn RotaryEncoderPinA(ROTARY_ENCODER_PINA); // not needed: this is done in the CRotaryEncoder library (as input or interrupt) 00022 //DigitalIn RotaryEncoderPinB(ROTARY_ENCODER_PINB); 00023 00024 DigitalIn twoStateSwitch(TWO_STATE_SWITCH); 00025 00026 void HardwareIO::init(void) { 00027 00028 // Set laser powers down: 00029 setRedPower(0);// TTL red laser (not used - actually not present) 00030 setGreenPower(0); 00031 setBluePower(0); 00032 00033 //Serial Communication setup: 00034 pc.baud(115200);// 00035 //pc.printf("Serial Connection established \r\n"); 00036 // pc.baud(921600);//115200);// 00037 00038 // Setup for lock-in amplifier and pwm references: 00039 setLaserLockinPower(1);// actually this is the Red laser in the hardware 00040 lockin.init(); 00041 00042 // Setup for DAC control to move the mirrors: 00043 // Set spi for 8 bit data, high steady state clock, 00044 // second edge capture, with a 10MHz clock rate: 00045 csDAC = 1; 00046 spiDAC.format(16,0); 00047 spiDAC.frequency(16000000); 00048 00049 // default initial mirror position: 00050 writeOutX(CENTER_AD_MIRROR_X); 00051 writeOutY(CENTER_AD_MIRROR_Y); 00052 00053 // Rotary encoder 1 (to set the FIXED THRESHOLD VALUE): 00054 rotaryEncoder1.SetMinMax(0,255); 00055 rotaryEncoder1.Set(0); // initial value 00056 00057 // Rotary encoder 2 (to set the additional correction angle): 00058 rotaryEncoder2.SetMinMax(-10,10); 00059 rotaryEncoder2.Set(0); // initial value 00060 00061 // Load LUT table: 00062 setLUT(); 00063 00064 // Set interrupts on RAISING edge for button-switch functions: 00065 // Note: The pin input will be logic '0' for any voltage on the pin below 0.8v, and '1' for any voltage above 2.0v. 00066 // By default, the InterruptIn is setup with an internal pull-down resistor, but for security and clarity I will do it explicitly here: 00067 switchOne.mode(PullUp); // pull down seems not very good 00068 switchTwo.mode(PullUp); 00069 switchOne.fall(this, &HardwareIO::switchOneInterrupt); // attach the address of the flip function to the falling edge 00070 switchTwo.fall(this, &HardwareIO::switchTwoInterrupt); // attach the address of the flip function to the falling edge 00071 switchOneState=true; 00072 switchTwoState=false; 00073 switchOneChange=false; 00074 switchTwoChange=false; 00075 00076 // ATTENTION: initial state of the switch should correspond to the inital state of the threshold mode in the constructor of the laser trajectory objects (not nice): 00077 setSwitchOneState(true); //equal to switchOneState=true, plus set led value. False means fixed threshold, true AUTO THRESHOLD (will be the default mode) 00078 // NOTE: actually this interrupt switches are not used anymore to change threhold... 00079 00080 // Initial state of the two state switch (and don't forget to set the internal pullup resistors!): 00081 twoStateSwitch.mode(PullUp);// Use internal pullup for pushbutton 00082 twoStateSwitchState=twoStateSwitch.read(); // attention: twoStateSwitch is actually a method (this is equal to twoStateSwitch.read()); 00083 twoStateSwitchChange=true; // this will force reading the initial threshold mode the first time the program runs 00084 00085 // Read and update pot value: 00086 // updatePotValue(); // the value will be ajusted in the range 0-255 00087 } 00088 00089 void HardwareIO::setSwitchOneState(bool newstate) { 00090 switchOneState=newstate; 00091 //ledSwitchOne=(switchOneState? 1 :0); 00092 } 00093 00094 // these ISR could do more (like debouncing). 00095 // For the time being, I will debounce electrically with a small capacitor. 00096 void HardwareIO::switchOneInterrupt() { 00097 switchOneState=!switchOneState; 00098 switchOneChange=true; 00099 } 00100 00101 void HardwareIO::switchTwoInterrupt() { 00102 switchTwoState=!switchTwoState; 00103 switchTwoChange=true; 00104 } 00105 00106 bool HardwareIO::switchOneCheck(bool& new_state) { 00107 new_state=switchOneState; 00108 if (switchOneChange) { 00109 switchOneChange=false; 00110 return(true); 00111 } else 00112 return(false); 00113 } 00114 00115 bool HardwareIO::switchTwoCheck(bool& new_state) { 00116 new_state=switchTwoState; 00117 if (switchTwoChange) { 00118 switchTwoChange=false; 00119 return(true); 00120 } else return(false); 00121 } 00122 00123 // NOT interrupt-based switch: 00124 bool HardwareIO::twoStateSwitchCheck(bool& new_state) { 00125 new_state=twoStateSwitch; // note: twoStateSwitch is a method! 00126 if (twoStateSwitchState==new_state) { 00127 // this means that the switch did not change state: 00128 return(false); 00129 } else { 00130 twoStateSwitchState=new_state; 00131 return(true); 00132 } 00133 } 00134 00135 00136 // THIS IS NOT WORKING!!!!!! 00137 unsigned char HardwareIO::updatePotValue() { // this will update the pot value, and return it too. 00138 //The value will be ajusted in the range 0-255 00139 //The 0.0v to 3.3v range of the AnalogIn is represented in software as a normalised floating point number from 0.0 to 1.0. 00140 00141 // potValue=(unsigned char )(ainPot*255); 00142 // Attention: go back to burst mode: 00143 // lockin.setADC_forLockin(1); 00144 // wait(1); 00145 00146 //USING the adc library: 00147 // unset fast adc for lockin, and set normal adc for conversion from analog input pin: 00148 lockin.setADC_forLockin(0); 00149 // wait(1); 00150 00151 //Measure pin POT_ANALOG_INPUT 00152 adc.select(POT_ANALOG_INPUT); 00153 //Start ADC conversion 00154 adc.start(); 00155 //Wait for it to complete 00156 while(!adc.done(POT_ANALOG_INPUT)); 00157 potValue=adc.read(POT_ANALOG_INPUT); 00158 00159 //Unset pin POT_ANALOG_INPUT 00160 adc.setup(POT_ANALOG_INPUT,0); 00161 00162 lockin.setADC_forLockin(1); 00163 wait(0.5); 00164 00165 return(potValue); 00166 } 00167 00168 //write on the first DAC, output A (mirror X) 00169 void HardwareIO::writeOutX(unsigned short value){ 00170 if(value > MAX_AD_MIRRORS) value = MAX_AD_MIRRORS; 00171 if(value < MIN_AD_MIRRORS) value = MIN_AD_MIRRORS; 00172 00173 value |= 0x7000; 00174 value &= 0x7FFF; 00175 00176 csDAC = 0; // this means the chip is enabled (negated logic), so CLK and SDI (data) can be transfered 00177 spiDAC.write(value); 00178 csDAC = 1; // rising the pin actually writes the data in the corresponding DAC register... 00179 } 00180 00181 //write on the first DAC, output B (mirror Y) 00182 void HardwareIO::writeOutY(unsigned short value){ 00183 if(value > MAX_AD_MIRRORS) value = MAX_AD_MIRRORS; 00184 if(value < MIN_AD_MIRRORS) value = MIN_AD_MIRRORS; 00185 00186 value |= 0xF000; 00187 value &= 0xFFFF; 00188 00189 csDAC = 0; 00190 spiDAC.write(value); 00191 csDAC = 1; 00192 } 00193 00194 void HardwareIO::setLaserLockinPower(int powerValue){ 00195 if(powerValue > 0){ 00196 lockin.setLaserPower(true); 00197 } 00198 else{ 00199 lockin.setLaserPower(false); 00200 } 00201 } 00202 // THE TTL controlled lasers: 00203 // Note: the red one is not used here 00204 void HardwareIO::setRedPower(int powerValue){ 00205 if(powerValue > 0){ 00206 Laser_Red = 1; 00207 } 00208 else{ 00209 Laser_Red = 0; 00210 } 00211 } 00212 void HardwareIO::setGreenPower(int powerValue){ 00213 if(powerValue > 0){ 00214 Laser_Green = 1; 00215 } 00216 else{ 00217 Laser_Green = 0; 00218 } 00219 } 00220 void HardwareIO::setBluePower(int powerValue){ 00221 if(powerValue > 0){ 00222 Laser_Blue = 1; 00223 } 00224 else{ 00225 Laser_Blue = 0; 00226 } 00227 } 00228 00229 void HardwareIO::setRGBPower(unsigned char color) { 00230 lockin.setLaserPower((color&0x04)>0? true : false); // NOTE: here the "red" is the lockin laser, not the TTL one (not used yet) 00231 Laser_Green=(color&0x02)>>1; 00232 Laser_Blue =color&0x01; 00233 } 00234 00235 void HardwareIO::showLimitsMirrors(int seconds) { 00236 unsigned short pointsPerLine=150; 00237 int shiftX = (MAX_AD_MIRRORS - MIN_AD_MIRRORS) / pointsPerLine; 00238 int shiftY = (MAX_AD_MIRRORS - MIN_AD_MIRRORS) / pointsPerLine; 00239 00240 Laser_Green=1; 00241 00242 //for (int repeat=0; repeat<times; repeat++) { 00243 00244 Timer t; 00245 t.start(); 00246 while(t.read_ms()<seconds*1000) { 00247 00248 writeOutX(MIN_AD_MIRRORS);writeOutY(MIN_AD_MIRRORS); 00249 00250 for(int j=0; j<pointsPerLine; j++){ 00251 wait_us(200);//delay between each points 00252 writeOutY(j*shiftY + MIN_AD_MIRRORS); 00253 } 00254 00255 writeOutX(MIN_AD_MIRRORS);writeOutY(MAX_AD_MIRRORS); 00256 for(int j=0; j<pointsPerLine; j++) { 00257 wait_us(200);//delay between each points 00258 writeOutX(j*shiftX + MIN_AD_MIRRORS); 00259 } 00260 00261 writeOutX(MAX_AD_MIRRORS);writeOutY(MAX_AD_MIRRORS); 00262 for(int j=0; j<pointsPerLine; j++) { 00263 wait_us(200);//delay between each points 00264 writeOutY(-j*shiftX + MAX_AD_MIRRORS); 00265 } 00266 00267 writeOutX(MAX_AD_MIRRORS);writeOutY(MIN_AD_MIRRORS); 00268 for(int j=0; j<pointsPerLine; j++) { 00269 wait_us(200);//delay between each points 00270 writeOutX(-j*shiftX + MAX_AD_MIRRORS); 00271 } 00272 00273 } 00274 t.stop(); 00275 Laser_Green=0; 00276 } 00277 00278 void HardwareIO::scan_serial(unsigned short pointsPerLine){ 00279 //scan the total surface with a custom resolution 00280 //send the lockin value for each point as a byte on the serial port to the PC 00281 //use "scanSLP_save" to see the data on processing 00282 // First, set the red laser on, and other off: 00283 setRGBPower(0x4); 00284 wait_us(1000); // just to give time to the lockin to set 00285 00286 int shiftX = (MAX_AD_MIRRORS - MIN_AD_MIRRORS) / pointsPerLine; 00287 int shiftY = (MAX_AD_MIRRORS - MIN_AD_MIRRORS) / pointsPerLine; 00288 00289 for(int j=0; j<pointsPerLine; j++){ 00290 writeOutX(MIN_AD_MIRRORS); 00291 writeOutY(j*shiftY + MIN_AD_MIRRORS); 00292 00293 wait_us(300);//begining of line delay 00294 for(int i=0; i<pointsPerLine; i++){ 00295 writeOutX(i*shiftX + MIN_AD_MIRRORS); 00296 00297 wait_us(200);//delay between each points 00298 00299 // SEND A VALUE BETWEEN 0 and 255: 00300 pc.putc(int(255.0*lockin.getMedianValue()/4095));//printf("%dL",int(valueLockin*255));//pc.putc(int(lockin*255));// 00301 } 00302 } 00303 } 00304 00305 //load Look-up Table from LUT.TXT file 00306 //or create the file with scanLUT() if not existing. 00307 void HardwareIO::setLUT(){ 00308 00309 FILE *fp = fopen(LUT_FILENAME, "r"); // Open file on the local file system for writing 00310 if(fp){ 00311 //load the file into the lut table; keep the SAME resolution! 00312 fread(lut,sizeof(uint16),LUT_RESOLUTION*LUT_RESOLUTION,fp); 00313 fclose(fp); 00314 } 00315 else{ 00316 //fclose(fp); 00317 //if the file "LUT.TXT" doesn't exist, create one with scanLUT() 00318 lockin.setLaserPower(true); 00319 scanLUT(); 00320 } 00321 00322 } 00323 00324 //scan the total surface with a fixed 2^x resolution 00325 //create the Look-Up Table used to "flatten" the scan according to the position 00326 // 00327 //To Do: maybe detect high frequency to be sure the area is clean and empty? 00328 void HardwareIO::scanLUT(){ 00329 00330 //reset lut table 00331 for(int j=0; j<LUT_RESOLUTION; j++){ 00332 for(int i=0; i<LUT_RESOLUTION; i++){ 00333 lut[i][j] =0; 00334 } 00335 } 00336 00337 int delayScanning = 300; //in us 00338 00339 //define the distance between each points (from 0 to 4096) and the offset (here 0) 00340 float shiftX = 1.0*(MAX_AD_MIRRORS - MIN_AD_MIRRORS) / (LUT_RESOLUTION-1); 00341 float shiftY = 1.0*(MAX_AD_MIRRORS - MIN_AD_MIRRORS) / (LUT_RESOLUTION-1); 00342 float offsetX = MIN_AD_MIRRORS; 00343 float offsetY = MIN_AD_MIRRORS; 00344 00345 //move the mirrors to the first position 00346 writeOutX(MAX_AD_MIRRORS);writeOutY(MIN_AD_MIRRORS); 00347 wait_us(500); 00348 00349 float x, y; 00350 00351 //scan the surface NB_SCANS times 00352 //the total value in lut[i][j] shouldn't exceed uint16 !!! 00353 for(int loop=0; loop<NB_SCANS; loop++){ 00354 for(int j=0; j<LUT_RESOLUTION; j++){ 00355 y = shiftY*j + offsetY ; 00356 writeOutY(int(y)); 00357 //scan from right to left 00358 for(int i=LUT_RESOLUTION-1; i>=0; i--){ 00359 x = shiftX*i + offsetX; 00360 writeOutX(int(x)); 00361 wait_us(delayScanning); 00362 lut[i][j] += lockin_read(); 00363 } 00364 //re-scan from left to right 00365 for(int i=0; i<LUT_RESOLUTION; i++){ 00366 x = shiftX*i + offsetX; 00367 writeOutX(int(x)); 00368 wait_us(delayScanning); 00369 lut[i][j] += lockin_read(); 00370 } 00371 } 00372 } 00373 00374 00375 //save tab in file 00376 FILE *fp; 00377 #ifdef LUT_FILENAME 00378 fp = fopen(LUT_FILENAME, "w"); // Open file on the local file system for writing 00379 fwrite(lut,sizeof(uint16),LUT_RESOLUTION*LUT_RESOLUTION,fp); 00380 fclose(fp); //close the file (the mBed will appear connected again) 00381 #endif 00382 00383 #ifdef LUT_H_FILENAME 00384 //save tab in Human readable file (not used by the program, this is just for checking) 00385 // NOTE: we divide the content of the lut table by NB_SCANS, for easy reading (values should be between 0-4095) 00386 fp = fopen(LUT_H_FILENAME, "w"); // Open file on the local file system for writing 00387 fprintf(fp, "scan resolution: %d x %d\r\n",LUT_RESOLUTION, LUT_RESOLUTION); 00388 for(int j=0; j<LUT_RESOLUTION; j++){ 00389 for(int i=0; i<LUT_RESOLUTION; i++){ 00390 fprintf(fp, "X=%d,\tY=%d,\tI=%d\t \r\n", int(shiftX*i + offsetX), int(shiftY*j + offsetY), int(1.0*lut[i][j]/NB_SCANS) ); 00391 } 00392 } 00393 fclose(fp); //close the file (the mBed will appear connected again) 00394 #endif 00395 00396 } 00397 00398 00399 //Return the lockin value "corrected with the Look-UpTable" - this means a RATIO between two reflectivities (and normally, this is <1). 00400 float HardwareIO::lockInCorrectedValue(unsigned short x, unsigned short y){ 00401 //*******Correction using DIRECT approximation 00402 #ifdef LUT_DIRECT 00403 return 2.0* NB_SCANS * lockin_read() / (lut[x >> LUT_BITS_SHIFT][y >> LUT_BITS_SHIFT]); // 2 * NB_SCANS is the number of recorded sample added to one position of the LUT (scan is performed twice: left-right and right-left) 00404 #endif 00405 00406 //*******Correction using BILINEAR approximation 00407 #ifdef LUT_BILINEAR 00408 unsigned short X = x >> LUT_BITS_SHIFT; //mirror "x" is 12bits, LUT "X" needs 4bits when lut is 17x17 00409 unsigned short Y = y >> LUT_BITS_SHIFT; //mirror "y" is 12bits, LUT "Y" needs 4bits when lut is 17x17 00410 float dx = 1.0*(x & LUT_BITS_MASK)/(LUT_BITS_MASK+1); //weight to apply on X (mask with 255 and norm) 00411 float dy = 1.0*(y & LUT_BITS_MASK)/(LUT_BITS_MASK+1); //weight to apply on Y (mask with 255 and norm) 00412 00413 //Wheighted mean approximation of the Look-Up Table at the position (x,y): 00414 float wmLUT = (1-dy)*( (1-dx)*lut[X][Y] + dx*lut[X+1][Y] ) + dy*( (1-dx)*lut[X][Y+1] + dx*lut[X+1][Y+1] ); 00415 00416 return 2.0* NB_SCANS * lockin_read() / wmLUT;// 2 * NB_SCANS is the number of recorded sample added to one position of the LUT (scan is performed twice: left-right and right-left) 00417 #endif 00418 00419 //*******Correction using LINEAR approximation 00420 #ifdef LUT_LINEAR 00421 unsigned short X = x >> LUT_BITS_SHIFT; //mirror "x" is 12bits, LUT "X" needs 4bits when lut is 17x17 00422 unsigned short Y = y >> LUT_BITS_SHIFT; //mirror "y" is 12bits, LUT "Y" needs 4bits when lut is 17x17 00423 float dx = 1.0*(x & LUT_BITS_MASK)/(LUT_BITS_MASK+1); //weight to apply on X (mask with 255 and norm) 00424 float dy = 1.0*(y & LUT_BITS_MASK)/(LUT_BITS_MASK+1); //weight to apply on Y (mask with 255 and norm) 00425 float linearLUT, dzx, dzy; 00426 00427 if(dx>dy){ //if the position is on the "top-right" triangle 00428 dzx = (lut[X+1][Y] - lut[X][Y]) * dx; 00429 dzy = (lut[X+1][Y+1] - lut[X+1][Y]) * dy; 00430 } 00431 else{ //if the position is on the "bottom-left" triangle 00432 dzy = (lut[X][Y+1] - lut[X][Y]) * dy; 00433 dzx = (lut[X+1][Y+1] - lut[X][Y+1]) * dx; 00434 } 00435 00436 //linear approximation of the Look-Up Table at the position (x,y): 00437 linearLUT = lut[X][Y] + dzx + dzy; 00438 return 2.0* NB_SCANS * lockin_read() / linearLUT; // 2 * NB_SCANS is the number of recorded sample added to one position of the LUT (scan is performed twice: left-right and right-left) 00439 00440 #endif 00441 00442 //*******No corrections, just return the value divided by 4096 (this means we are assuming that the surface is everywhere perfectly reflective - we supposedly get the max value always) 00443 #ifdef NO_LUT 00444 return 1.0* lockin_read()/4096; 00445 #endif 00446 00447 }
Generated on Tue Jul 12 2022 18:50:27 by
1.7.2
