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.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 DigitalOut ledSwitchOne(LED_SWITCH_ONE); 00020 InterruptIn switchTwo(SWITCH_TWO); 00021 AnalogIn ainPot(POT_ANALOG_INPUT); // I cannot use this directly because the adc is being used by the locking. We have to re-setup it (see updatePotValue()) 00022 00023 // Testing leds (for debugging): 00024 DigitalOut myLed1(LED1); // note: LED1/2/3/4 are defined in mbed.h, and correspond to mbed pins 32, 34, 35 and 37 00025 DigitalOut myLed2(LED2); 00026 DigitalOut myLed3(LED3); 00027 DigitalOut myLed4(LED4); 00028 00029 void HardwareIO::init(void) 00030 { 00031 setLaserLockinPower(1); // this may be always ON (the IR laser). But we may want to switch it off sometimes... 00032 Laser_Red = 0; // note: this is not the lockin-laser! (in the future, the lock in laser will be infrared...) 00033 Laser_Green = 0; 00034 Laser_Blue = 0; 00035 00036 // Test leds: 00037 myLed1=0; 00038 myLed2=0; 00039 myLed3=0; 00040 myLed4=0; 00041 00042 //Serial Communication setup: 00043 pc.baud(SERIAL_SPEED); 00044 00045 // Setup for lock-in amplifier and pwm references: 00046 setLaserLockinPower(1);// actually this is the Red laser in the hardware 00047 lockin.init(); 00048 00049 // Setup for DAC control to move the mirrors: 00050 // Set spi for 8 bit data, high steady state clock, 00051 // second edge capture, with a 10MHz clock rate: 00052 csDAC = 1; 00053 spiDAC.format(16,0); 00054 spiDAC.frequency(16000000); 00055 00056 // default initial mirror position: 00057 writeOutX(CENTER_AD_MIRROR_X); 00058 writeOutY(CENTER_AD_MIRROR_Y); 00059 00060 // Load LUT table: 00061 setLUT(); 00062 00063 // Set interrupts on RAISING edge for button-switch functions: 00064 // 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. 00065 // By default, the InterruptIn is setup with an internal pull-down resistor, but for security and clarity I will do it explicitly here: 00066 switchOne.mode(PullUp); // pull down seems not very good 00067 switchTwo.mode(PullUp); 00068 switchOne.fall(this, &HardwareIO::switchOneInterrupt); // attach the address of the flip function to the falling edge 00069 switchTwo.fall(this, &HardwareIO::switchTwoInterrupt); // attach the address of the flip function to the falling edge 00070 switchOneState=true; 00071 switchTwoState=false; 00072 switchOneChange=false; 00073 switchTwoChange=false; 00074 00075 setSwitchOneState(true); //equal to switchOneState=true, plus set led value. False means fixed threshold, true AUTO THRESHOLD (will be the default mode) 00076 00077 // Read and update pot value: 00078 // updatePotValue(); // the value will be ajusted in the range 0-255 00079 } 00080 00081 void HardwareIO::setSwitchOneState(bool newstate) 00082 { 00083 switchOneState=newstate; 00084 ledSwitchOne=(switchOneState? 1 :0); 00085 } 00086 00087 // these ISR could do more (like debouncing). 00088 // For the time being, I will debounce electrically with a small capacitor. 00089 void HardwareIO::switchOneInterrupt() 00090 { 00091 switchOneState=!switchOneState; 00092 ledSwitchOne=(switchOneState? 1 :0); // this switch has a built-in led 00093 switchOneChange=true; 00094 } 00095 void HardwareIO::switchTwoInterrupt() 00096 { 00097 switchTwoState=!switchTwoState; 00098 switchTwoChange=true; 00099 } 00100 00101 bool HardwareIO::switchOneCheck(bool& state) 00102 { 00103 if (switchOneChange) { 00104 switchOneChange=false; 00105 state=switchOneState; 00106 return(true); 00107 } else 00108 return(false); 00109 } 00110 00111 bool HardwareIO::switchTwoCheck(bool& state) 00112 { 00113 if (switchTwoChange) { 00114 switchTwoChange=false; 00115 state=switchTwoState; 00116 return(true); 00117 } else return(false); 00118 } 00119 00120 unsigned char HardwareIO::updatePotValue() // this will update the pot value, and return it too. 00121 { 00122 //The value will be ajusted in the range 0-255 00123 //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. 00124 potValue=(unsigned char )(ainPot*255); 00125 00126 /* USING the adc library: 00127 // unset fast adc for lockin, and set normal adc for conversion from analog input pin: 00128 lockin.setADC_forLockin(0); 00129 adc.setup(POT_ANALOG_INPUT,1); 00130 00131 wait(1); 00132 00133 //Measure pin POT_ANALOG_INPUT 00134 adc.select(POT_ANALOG_INPUT); 00135 //Start ADC conversion 00136 adc.start(); 00137 //Wait for it to complete 00138 while(!adc.done(POT_ANALOG_INPUT)); 00139 potValue=adc.read(POT_ANALOG_INPUT); 00140 00141 //Unset pin POT_ANALOG_INPUT 00142 adc.setup(POT_ANALOG_INPUT,0); 00143 00144 lockin.setADC_forLockin(1); 00145 // wait(1); 00146 */ 00147 00148 // Attention! reading using the AnalogIn library seems to break my burst reading mode. So, we need to re-set it: 00149 lockin.setADC_forLockin(1); 00150 00151 return(potValue); 00152 } 00153 00154 //write on the first DAC, output A (mirror X) 00155 void HardwareIO::writeOutX(unsigned short value) 00156 { 00157 if(value > MAX_AD_MIRRORS) value = MAX_AD_MIRRORS; 00158 if(value < MIN_AD_MIRRORS) value = MIN_AD_MIRRORS; 00159 00160 value |= 0x7000; 00161 value &= 0x7FFF; 00162 00163 csDAC = 0; 00164 spiDAC.write(value); 00165 csDAC = 1; 00166 } 00167 00168 //write on the first DAC, output B (mirror Y) 00169 void HardwareIO::writeOutY(unsigned short value) 00170 { 00171 if(value > MAX_AD_MIRRORS) value = MAX_AD_MIRRORS; 00172 if(value < MIN_AD_MIRRORS) value = MIN_AD_MIRRORS; 00173 00174 value |= 0xF000; 00175 value &= 0xFFFF; 00176 00177 csDAC = 0; 00178 spiDAC.write(value); 00179 csDAC = 1; 00180 } 00181 00182 void HardwareIO::setLaserLockinPower(int powerValue) 00183 { 00184 if(powerValue > 0) { 00185 lockin.setLaserPower(true); 00186 } else { 00187 lockin.setLaserPower(false); 00188 } 00189 } 00190 00191 void HardwareIO::setRedPower(int powerValue) 00192 { 00193 if(powerValue > 0) { 00194 Laser_Red = 1; 00195 } else { 00196 Laser_Red = 0; 00197 } 00198 } 00199 void HardwareIO::setGreenPower(int powerValue) 00200 { 00201 if(powerValue > 0) { 00202 Laser_Green = 1; 00203 } else { 00204 Laser_Green = 0; 00205 } 00206 } 00207 void HardwareIO::setBluePower(int powerValue) 00208 { 00209 if(powerValue > 0) { 00210 Laser_Blue = 1; 00211 } else { 00212 Laser_Blue = 0; 00213 } 00214 } 00215 00216 00217 void HardwareIO::setRGBPower(unsigned char color) // NOTE: this do NOT affect the power of the lockin laser... 00218 { 00219 // lockin.setLaserPower((color&0x04)>0? true : false); 00220 Laser_Red=(color&0x04)>>2; 00221 Laser_Green=(color&0x02)>>1; 00222 Laser_Blue =color&0x01; 00223 } 00224 00225 // Attention: we should stop the displaying engine lsd before calling this (if we want, otherwise it will continue showing the 00226 // displayed objects/scene, but it will be weird) - this is done in the WRAPPERS methods. 00227 void HardwareIO::showLimitsMirrors(unsigned short pointsPerLine, unsigned short durationSecs) 00228 { 00229 //unsigned short pointsPerLine=150; 00230 int shiftX = (MAX_AD_MIRRORS - MIN_AD_MIRRORS) / pointsPerLine; 00231 int shiftY = (MAX_AD_MIRRORS - MIN_AD_MIRRORS) / pointsPerLine; 00232 00233 setRGBPower(0x07);// all displaying lasers ON 00234 00235 //for (int repeat=0; repeat<times; repeat++) { 00236 00237 Timer t; 00238 t.start(); 00239 while(t.read_ms()<durationSecs*1000) { 00240 00241 writeOutX(MIN_AD_MIRRORS); 00242 writeOutY(MIN_AD_MIRRORS); 00243 00244 for(int j=0; j<pointsPerLine; j++) { 00245 wait_us(200);//delay between each points 00246 writeOutY(j*shiftY + MIN_AD_MIRRORS); 00247 } 00248 00249 writeOutX(MIN_AD_MIRRORS); 00250 writeOutY(MAX_AD_MIRRORS); 00251 for(int j=0; j<pointsPerLine; j++) { 00252 wait_us(200);//delay between each points 00253 writeOutX(j*shiftX + MIN_AD_MIRRORS); 00254 } 00255 00256 writeOutX(MAX_AD_MIRRORS); 00257 writeOutY(MAX_AD_MIRRORS); 00258 for(int j=0; j<pointsPerLine; j++) { 00259 wait_us(200);//delay between each points 00260 writeOutY(-j*shiftX + MAX_AD_MIRRORS); 00261 } 00262 00263 writeOutX(MAX_AD_MIRRORS); 00264 writeOutY(MIN_AD_MIRRORS); 00265 for(int j=0; j<pointsPerLine; j++) { 00266 wait_us(200);//delay between each points 00267 writeOutX(-j*shiftX + MAX_AD_MIRRORS); 00268 } 00269 00270 } 00271 t.stop(); 00272 Laser_Green=0; 00273 } 00274 00275 void HardwareIO::scan_serial(unsigned short pointsPerLine) 00276 { 00277 //scan the total surface with a custom resolution 00278 //send the lockin value for each point as a byte on the serial port to the PC 00279 //use "scanSLP_save" to see the data on processing 00280 00281 int shiftX = (MAX_AD_MIRRORS - MIN_AD_MIRRORS) / pointsPerLine; 00282 int shiftY = (MAX_AD_MIRRORS - MIN_AD_MIRRORS) / pointsPerLine; 00283 00284 for(int j=0; j<pointsPerLine; j++) { 00285 writeOutX(MIN_AD_MIRRORS); 00286 writeOutY(j*shiftY + MIN_AD_MIRRORS); 00287 00288 wait_us(300);//begining of line delay 00289 for(int i=0; i<pointsPerLine; i++) { 00290 writeOutX(i*shiftX + MIN_AD_MIRRORS); 00291 00292 wait_us(200);//delay between each points 00293 00294 // SEND A VALUE BETWEEN 0 and 255: 00295 pc.putc(int(255.0*lockin.getMedianValue()/4095));//printf("%dL",int(valueLockin*255));//pc.putc(int(lockin*255));// 00296 } 00297 } 00298 } 00299 00300 //load Look-up Table from LUT.TXT file 00301 //or create the file with scanLUT() if not existing. 00302 void HardwareIO::setLUT() 00303 { 00304 00305 FILE *fp = fopen(LUT_FILENAME, "r"); // Open file on the local file system for writing 00306 if(fp) { 00307 //load the file into the lut table; keep the SAME resolution! 00308 fread(lut,sizeof(uint16),LUT_RESOLUTION*LUT_RESOLUTION,fp); 00309 fclose(fp); 00310 } else { 00311 //fclose(fp); 00312 //if the file "LUT.TXT" doesn't exist, create one with scanLUT() 00313 lockin.setLaserPower(true); 00314 scanLUT(); 00315 } 00316 00317 } 00318 00319 //scan the total surface with a fixed 2^x resolution 00320 //create the Look-Up Table used to "flatten" the scan according to the position 00321 // 00322 //To Do: maybe detect high frequency to be sure the area is clean and empty? 00323 void HardwareIO::scanLUT() 00324 { 00325 00326 //reset lut table 00327 for(int j=0; j<LUT_RESOLUTION; j++) { 00328 for(int i=0; i<LUT_RESOLUTION; i++) { 00329 lut[i][j] =0; 00330 } 00331 } 00332 00333 int delayScanning = 300; //in us 00334 00335 //define the distance between each points (from 0 to 4096) and the offset (here 0) 00336 float shiftX = 1.0*(MAX_AD_MIRRORS - MIN_AD_MIRRORS) / (LUT_RESOLUTION-1); 00337 float shiftY = 1.0*(MAX_AD_MIRRORS - MIN_AD_MIRRORS) / (LUT_RESOLUTION-1); 00338 float offsetX = MIN_AD_MIRRORS; 00339 float offsetY = MIN_AD_MIRRORS; 00340 00341 //move the mirrors to the first position 00342 writeOutX(MAX_AD_MIRRORS); 00343 writeOutY(MIN_AD_MIRRORS); 00344 wait_us(500); 00345 00346 float x, y; 00347 00348 //scan the surface NB_SCANS times 00349 //the total value in lut[i][j] shouldn't exceed uint16 !!! 00350 for(int loop=0; loop<NB_SCANS; loop++) { 00351 for(int j=0; j<LUT_RESOLUTION; j++) { 00352 y = shiftY*j + offsetY ; 00353 writeOutY(int(y)); 00354 //scan from right to left 00355 for(int i=LUT_RESOLUTION-1; i>=0; i--) { 00356 x = shiftX*i + offsetX; 00357 writeOutX(int(x)); 00358 wait_us(delayScanning); 00359 lut[i][j] += lockin_read(); 00360 } 00361 //re-scan from left to right 00362 for(int i=0; i<LUT_RESOLUTION; i++) { 00363 x = shiftX*i + offsetX; 00364 writeOutX(int(x)); 00365 wait_us(delayScanning); 00366 lut[i][j] += lockin_read(); 00367 } 00368 } 00369 } 00370 00371 00372 //save tab in file 00373 FILE *fp; 00374 #ifdef LUT_FILENAME 00375 fp = fopen(LUT_FILENAME, "w"); // Open file on the local file system for writing 00376 fwrite(lut,sizeof(uint16),LUT_RESOLUTION*LUT_RESOLUTION,fp); 00377 fclose(fp); //close the file (the mBed will appear connected again) 00378 #endif 00379 00380 #ifdef LUT_H_FILENAME 00381 //save tab in Human readable file (not used by the program, this is just for checking) 00382 // NOTE: we divide the content of the lut table by NB_SCANS, for easy reading (values should be between 0-4095) 00383 fp = fopen(LUT_H_FILENAME, "w"); // Open file on the local file system for writing 00384 fprintf(fp, "scan resolution: %d x %d\r\n",LUT_RESOLUTION, LUT_RESOLUTION); 00385 for(int j=0; j<LUT_RESOLUTION; j++) { 00386 for(int i=0; i<LUT_RESOLUTION; i++) { 00387 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) ); 00388 } 00389 } 00390 fclose(fp); //close the file (the mBed will appear connected again) 00391 #endif 00392 00393 } 00394 00395 00396 //Return the lockin value "corrected with the Look-UpTable" - this means a RATIO between two reflectivities (and normally, this is <1). 00397 float HardwareIO::lockInCorrectedValue(unsigned short x, unsigned short y) 00398 { 00399 //*******Correction using DIRECT approximation 00400 #ifdef LUT_DIRECT 00401 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) 00402 #endif 00403 00404 //*******Correction using BILINEAR approximation 00405 #ifdef LUT_BILINEAR 00406 unsigned short X = x >> LUT_BITS_SHIFT; //mirror "x" is 12bits, LUT "X" needs 4bits when lut is 17x17 00407 unsigned short Y = y >> LUT_BITS_SHIFT; //mirror "y" is 12bits, LUT "Y" needs 4bits when lut is 17x17 00408 float dx = 1.0*(x & LUT_BITS_MASK)/(LUT_BITS_MASK+1); //weight to apply on X (mask with 255 and norm) 00409 float dy = 1.0*(y & LUT_BITS_MASK)/(LUT_BITS_MASK+1); //weight to apply on Y (mask with 255 and norm) 00410 00411 //Wheighted mean approximation of the Look-Up Table at the position (x,y): 00412 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] ); 00413 00414 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) 00415 #endif 00416 00417 //*******Correction using LINEAR approximation 00418 #ifdef LUT_LINEAR 00419 unsigned short X = x >> LUT_BITS_SHIFT; //mirror "x" is 12bits, LUT "X" needs 4bits when lut is 17x17 00420 unsigned short Y = y >> LUT_BITS_SHIFT; //mirror "y" is 12bits, LUT "Y" needs 4bits when lut is 17x17 00421 float dx = 1.0*(x & LUT_BITS_MASK)/(LUT_BITS_MASK+1); //weight to apply on X (mask with 255 and norm) 00422 float dy = 1.0*(y & LUT_BITS_MASK)/(LUT_BITS_MASK+1); //weight to apply on Y (mask with 255 and norm) 00423 float linearLUT, dzx, dzy; 00424 00425 if(dx>dy) { //if the position is on the "top-right" triangle 00426 dzx = (lut[X+1][Y] - lut[X][Y]) * dx; 00427 dzy = (lut[X+1][Y+1] - lut[X+1][Y]) * dy; 00428 } else { //if the position is on the "bottom-left" triangle 00429 dzy = (lut[X][Y+1] - lut[X][Y]) * dy; 00430 dzx = (lut[X+1][Y+1] - lut[X][Y+1]) * dx; 00431 } 00432 00433 //linear approximation of the Look-Up Table at the position (x,y): 00434 linearLUT = lut[X][Y] + dzx + dzy; 00435 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) 00436 00437 #endif 00438 00439 //*******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) 00440 #ifdef NO_LUT 00441 return 1.0* lockin_read()/4096; 00442 #endif 00443 00444 } 00445
Generated on Tue Jul 12 2022 19:19:38 by
1.7.2
