Median of 3 filter for multiple time of flight sensors translated from arduino by pololu
Dependents: wheelchaircontrol wheelchaircontrol2 wheelchaircontrol3 wheelchaircontrol4 ... more
VL53L1X.cpp
00001 // Most of the functionality of this library is based on the VL53L1X API 00002 // provided by ST (STSW-IMG007), and some of the explanatory comments are quoted 00003 // or paraphrased from the API source code, API user manual (UM2356), and 00004 // VL53L1X datasheet. 00005 00006 #include "VL53L1X.h" 00007 #include "mbed.h" 00008 00009 // Constructors //////////////////////////////////////////////////////////////// 00010 VL53L1X::VL53L1X(PinName SDA, PinName SCL, PinName shutDown) : 00011 _i2c(SDA,SCL), _shutDown(shutDown) 00012 , io_timeout(0) // no timeout 00013 , did_timeout(false) 00014 , calibrated(false) 00015 , saved_vhv_init(0) 00016 , saved_vhv_timeout(0) 00017 , distance_mode(Unknown){ 00018 //Set I2C fast and bring reset line high 00019 _i2c.frequency(400000); 00020 address = AddressDefault << 1; 00021 turnOff(); 00022 } 00023 00024 /*VL53L1X::VL53L1X() 00025 : address(AddressDefault) 00026 { 00027 }*/ 00028 00029 // Public Methods ////////////////////////////////////////////////////////////// 00030 00031 void VL53L1X::setAddress(uint8_t new_addr) 00032 { 00033 writeReg(I2C_SLAVE__DEVICE_ADDRESS, new_addr & 0x7F); 00034 wait(.02); 00035 address = new_addr << 1; 00036 printf("%x\r\n", readReg(I2C_SLAVE__DEVICE_ADDRESS)); 00037 } 00038 00039 // Initialize sensor using settings taken mostly from VL53L1_DataInit() and 00040 // VL53L1_StaticInit(). 00041 // If io_2v8 (optional) is true or not given, the sensor is configured for 2V8 00042 // mode. 00043 bool VL53L1X::init(bool io_2v8) 00044 { 00045 // check model ID and module type registers (values specified in datasheet) 00046 int tempRegister = readReg16Bit(IDENTIFICATION__MODEL_ID); 00047 printf("temporary %x\r\n", tempRegister); 00048 if (tempRegister != 0xEACC) { 00049 return false; 00050 } 00051 00052 // VL53L1_software_reset() begin 00053 00054 writeReg(SOFT_RESET, 0x00); 00055 wait(.001); 00056 writeReg(SOFT_RESET, 0x01); 00057 00058 // VL53L1_poll_for_boot_completion() begin 00059 00060 startTimeout(); 00061 int firmware = (readReg16Bit(FIRMWARE__SYSTEM_STATUS)); 00062 printf("firmware : %x\r\n", firmware); 00063 while ((readReg(FIRMWARE__SYSTEM_STATUS) & 0x01) == 0) 00064 { 00065 printf("stuck\r\n"); 00066 if (checkTimeoutExpired()) 00067 { 00068 did_timeout = true; 00069 return false; 00070 } 00071 } 00072 // VL53L1_poll_for_boot_completion() end 00073 00074 // VL53L1_software_reset() end 00075 00076 // VL53L1_DataInit() begin 00077 00078 // sensor uses 1V8 mode for I/O by default; switch to 2V8 mode if necessary 00079 if (io_2v8) 00080 { 00081 writeReg(PAD_I2C_HV__EXTSUP_CONFIG, 00082 readReg(PAD_I2C_HV__EXTSUP_CONFIG) | 0x01); 00083 } 00084 00085 // store oscillator info for later use 00086 fast_osc_frequency = readReg16Bit(OSC_MEASURED__FAST_OSC__FREQUENCY); 00087 osc_calibrate_val = readReg16Bit(RESULT__OSC_CALIBRATE_VAL); 00088 00089 // VL53L1_DataInit() end 00090 00091 // VL53L1_StaticInit() begin 00092 00093 // Note that the API does not actually apply the configuration settings below 00094 // when VL53L1_StaticInit() is called: it keeps a copy of the sensor's 00095 // register contents in memory and doesn't actually write them until a 00096 // measurement is started. Writing the configuration here means we don't have 00097 // to keep it all in memory and avoids a lot of redundant writes later. 00098 00099 // the API sets the preset mode to LOWPOWER_AUTONOMOUS here: 00100 // VL53L1_set_preset_mode() begin 00101 00102 // VL53L1_preset_mode_standard_ranging() begin 00103 00104 // values labeled "tuning parm default" are from vl53l1_tuning_parm_defaults.h 00105 // (API uses these in VL53L1_init_tuning_parm_storage_struct()) 00106 00107 // static config 00108 // API resets PAD_I2C_HV__EXTSUP_CONFIG here, but maybe we don't want to do 00109 // that? (seems like it would disable 2V8 mode) 00110 writeReg16Bit(DSS_CONFIG__TARGET_TOTAL_RATE_MCPS, TargetRate); // should already be this value after reset 00111 writeReg(GPIO__TIO_HV_STATUS, 0x02); 00112 writeReg(SIGMA_ESTIMATOR__EFFECTIVE_PULSE_WIDTH_NS, 8); // tuning parm default 00113 writeReg(SIGMA_ESTIMATOR__EFFECTIVE_AMBIENT_WIDTH_NS, 16); // tuning parm default 00114 writeReg(ALGO__CROSSTALK_COMPENSATION_VALID_HEIGHT_MM, 0x01); 00115 writeReg(ALGO__RANGE_IGNORE_VALID_HEIGHT_MM, 0xFF); 00116 writeReg(ALGO__RANGE_MIN_CLIP, 0); // tuning parm default 00117 writeReg(ALGO__CONSISTENCY_CHECK__TOLERANCE, 2); // tuning parm default 00118 00119 // general config 00120 writeReg16Bit(SYSTEM__THRESH_RATE_HIGH, 0x0000); 00121 writeReg16Bit(SYSTEM__THRESH_RATE_LOW, 0x0000); 00122 writeReg(DSS_CONFIG__APERTURE_ATTENUATION, 0x38); 00123 00124 // timing config 00125 // most of these settings will be determined later by distance and timing 00126 // budget configuration 00127 writeReg16Bit(RANGE_CONFIG__SIGMA_THRESH, 360); // tuning parm default 00128 writeReg16Bit(RANGE_CONFIG__MIN_COUNT_RATE_RTN_LIMIT_MCPS, 192); // tuning parm default 00129 00130 // dynamic config 00131 00132 writeReg(SYSTEM__GROUPED_PARAMETER_HOLD_0, 0x01); 00133 writeReg(SYSTEM__GROUPED_PARAMETER_HOLD_1, 0x01); 00134 writeReg(SD_CONFIG__QUANTIFIER, 2); // tuning parm default 00135 00136 // VL53L1_preset_mode_standard_ranging() end 00137 00138 // from VL53L1_preset_mode_timed_ranging_* 00139 // GPH is 0 after reset, but writing GPH0 and GPH1 above seem to set GPH to 1, 00140 // and things don't seem to work if we don't set GPH back to 0 (which the API 00141 // does here). 00142 writeReg(SYSTEM__GROUPED_PARAMETER_HOLD, 0x00); 00143 writeReg(SYSTEM__SEED_CONFIG, 1); // tuning parm default 00144 00145 // from VL53L1_config_low_power_auto_mode 00146 writeReg(SYSTEM__SEQUENCE_CONFIG, 0x8B); // VHV, PHASECAL, DSS1, RANGE 00147 writeReg16Bit(DSS_CONFIG__MANUAL_EFFECTIVE_SPADS_SELECT, 200 << 8); 00148 writeReg(DSS_CONFIG__ROI_MODE_CONTROL, 2); // REQUESTED_EFFFECTIVE_SPADS 00149 00150 // VL53L1_set_preset_mode() end 00151 00152 // default to long range, 50 ms timing budget 00153 // note that this is different than what the API defaults to 00154 setDistanceMode(Short); 00155 setMeasurementTimingBudget(50000); 00156 00157 // VL53L1_StaticInit() end 00158 00159 // the API triggers this change in VL53L1_init_and_start_range() once a 00160 // measurement is started; assumes MM1 and MM2 are disabled 00161 writeReg16Bit(ALGO__PART_TO_PART_RANGE_OFFSET_MM, 00162 readReg16Bit(MM_CONFIG__OUTER_OFFSET_MM) * 4); 00163 t.start(); 00164 return true; 00165 } 00166 00167 // Write an 8-bit register 00168 void VL53L1X::writeReg(uint16_t registerAddr, uint8_t data) 00169 { 00170 char data_write[3]; 00171 data_write[0] = (registerAddr >> 8) & 0xFF; //MSB of register address 00172 data_write[1] = registerAddr & 0xFF; //LSB of register address 00173 data_write[2] = data & 0xFF; 00174 _i2c.write(address, data_write, 3); 00175 } 00176 00177 void VL53L1X::writeReg16Bit(uint16_t registerAddr, uint16_t data) 00178 { 00179 char data_write[4]; 00180 data_write[0] = (registerAddr >> 8) & 0xFF; //MSB of register address 00181 data_write[1] = registerAddr & 0xFF; //LSB of register address 00182 data_write[2] = (data >> 8) & 0xFF; 00183 data_write[3] = data & 0xFF; 00184 _i2c.write(address, data_write, 4); 00185 } 00186 00187 00188 // Write a 32-bit register 00189 /* 00190 void VL53L1X::writeReg32Bit(uint16_t registerAddr, uint32_t data) 00191 { 00192 char data_write[5]; 00193 data_write[0] = (registerAddr >> 8) & 0xFF; //MSB of register address 00194 data_write[1] = registerAddr & 0xFF; //LSB of register address 00195 data_write[2] = (data >> 16) & 0xFF; 00196 data_write[3] = (data >> 8) & 0xFF; 00197 data_write[4] = data & 0xFF; 00198 _i2c.write(address, data_write, 5); 00199 } 00200 */ 00201 void VL53L1X::writeReg32Bit(uint16_t registerAddr, uint32_t data) 00202 { 00203 char data_write[6]; 00204 data_write[0] = (registerAddr >> 8) & 0xFF; //MSB of register address 00205 data_write[1] = registerAddr & 0xFF; //LSB of register address 00206 data_write[2] = (data >> 24) & 0xFF; 00207 data_write[3] = (data >> 16) & 0xFF; 00208 data_write[4] = (data >> 8) & 0xFF;; 00209 data_write[5] = data & 0xFF; 00210 _i2c.write(address, data_write, 6); 00211 } 00212 00213 00214 // Read an 8-bit register 00215 uint8_t VL53L1X::readReg(uint16_t registerAddr) 00216 { 00217 uint8_t data; 00218 char data_write[2]; 00219 char data_read[1]; 00220 data_write[0] = (registerAddr >> 8) & 0xFF; //MSB of register address 00221 data_write[1] = registerAddr & 0xFF; //LSB of register address 00222 _i2c.write(address, data_write, 2,0); 00223 _i2c.read(address,data_read,1,1); 00224 //Read Data from selected register 00225 data=data_read[0]; 00226 return data; 00227 } 00228 00229 uint16_t VL53L1X::readReg16Bit(uint16_t registerAddr) 00230 { 00231 uint8_t data_low; 00232 uint8_t data_high; 00233 uint16_t data; 00234 00235 char data_write[2]; 00236 char data_read[2]; 00237 data_write[0] = (registerAddr >> 8) & 0xFF; //MSB of register address 00238 data_write[1] = registerAddr & 0xFF; //LSB of register address 00239 _i2c.write(address, data_write, 2,0); 00240 _i2c.read(address,data_read,2,1); 00241 data_high = data_read[0]; //Read Data from selected register 00242 data_low = data_read[1]; //Read Data from selected register 00243 data = (data_high << 8)|data_low; 00244 00245 return data; 00246 } 00247 // Read a 32-bit register 00248 uint32_t VL53L1X::readReg32Bit(uint16_t reg) 00249 { 00250 uint32_t value; 00251 /* 00252 _i2c.beginTransmission(address); 00253 _i2c.write((reg >> 8) & 0xFF); // reg high byte 00254 _i2c.write( reg & 0xFF); // reg low byte 00255 last_status = _i2c.endTransmission(); 00256 00257 _i2c.requestFrom(address, (uint8_t)4); 00258 value = (uint32_t)_i2c.read() << 24; // value highest byte 00259 value |= (uint32_t)_i2c.read() << 16; 00260 value |= (uint16_t)_i2c.read() << 8; 00261 value |= _i2c.read(); // value lowest byte 00262 */ 00263 return value; 00264 } 00265 00266 // set distance mode to Short, Medium, or Long 00267 // based on VL53L1_SetDistanceMode() 00268 bool VL53L1X::setDistanceMode(DistanceMode mode) 00269 { 00270 // save existing timing budget 00271 uint32_t budget_us = getMeasurementTimingBudget(); 00272 switch (mode) 00273 { 00274 case Short: 00275 // from VL53L1_preset_mode_standard_ranging_short_range() 00276 00277 // timing config 00278 writeReg(RANGE_CONFIG__VCSEL_PERIOD_A, 0x07); 00279 writeReg(RANGE_CONFIG__VCSEL_PERIOD_B, 0x05); 00280 writeReg(RANGE_CONFIG__VALID_PHASE_HIGH, 0x38); 00281 00282 // dynamic config 00283 writeReg(SD_CONFIG__WOI_SD0, 0x07); 00284 writeReg(SD_CONFIG__WOI_SD1, 0x05); 00285 writeReg(SD_CONFIG__INITIAL_PHASE_SD0, 6); // tuning parm default 00286 writeReg(SD_CONFIG__INITIAL_PHASE_SD1, 6); // tuning parm default 00287 00288 break; 00289 00290 case Medium: 00291 // from VL53L1_preset_mode_standard_ranging() 00292 00293 // timing config 00294 writeReg(RANGE_CONFIG__VCSEL_PERIOD_A, 0x0B); 00295 writeReg(RANGE_CONFIG__VCSEL_PERIOD_B, 0x09); 00296 writeReg(RANGE_CONFIG__VALID_PHASE_HIGH, 0x78); 00297 00298 // dynamic config 00299 writeReg(SD_CONFIG__WOI_SD0, 0x0B); 00300 writeReg(SD_CONFIG__WOI_SD1, 0x09); 00301 writeReg(SD_CONFIG__INITIAL_PHASE_SD0, 10); // tuning parm default 00302 writeReg(SD_CONFIG__INITIAL_PHASE_SD1, 10); // tuning parm default 00303 00304 break; 00305 00306 case Long: // long 00307 // from VL53L1_preset_mode_standard_ranging_long_range() 00308 00309 // timing config 00310 writeReg(RANGE_CONFIG__VCSEL_PERIOD_A, 0x0F); 00311 writeReg(RANGE_CONFIG__VCSEL_PERIOD_B, 0x0D); 00312 writeReg(RANGE_CONFIG__VALID_PHASE_HIGH, 0xB8); 00313 00314 // dynamic config 00315 writeReg(SD_CONFIG__WOI_SD0, 0x0F); 00316 writeReg(SD_CONFIG__WOI_SD1, 0x0D); 00317 writeReg(SD_CONFIG__INITIAL_PHASE_SD0, 14); // tuning parm default 00318 writeReg(SD_CONFIG__INITIAL_PHASE_SD1, 14); // tuning parm default 00319 00320 break; 00321 00322 default: 00323 // unrecognized mode - do nothing 00324 return false; 00325 } 00326 00327 // reapply timing budget 00328 setMeasurementTimingBudget(budget_us); 00329 00330 // save mode so it can be returned by getDistanceMode() 00331 distance_mode = mode; 00332 00333 return true; 00334 } 00335 00336 // Set the measurement timing budget in microseconds, which is the time allowed 00337 // for one measurement. A longer timing budget allows for more accurate 00338 // measurements. 00339 // based on VL53L1_SetMeasurementTimingBudgetMicroSeconds() 00340 bool VL53L1X::setMeasurementTimingBudget(uint32_t budget_us) 00341 { 00342 // assumes PresetMode is LOWPOWER_AUTONOMOUS 00343 00344 if (budget_us <= TimingGuard) { return false; } 00345 00346 uint32_t range_config_timeout_us = budget_us -= TimingGuard; 00347 if (range_config_timeout_us > 1100000) { return false; } // FDA_MAX_TIMING_BUDGET_US * 2 00348 00349 range_config_timeout_us /= 2; 00350 00351 // VL53L1_calc_timeout_register_values() begin 00352 00353 uint32_t macro_period_us; 00354 00355 // "Update Macro Period for Range A VCSEL Period" 00356 macro_period_us = calcMacroPeriod(readReg(RANGE_CONFIG__VCSEL_PERIOD_A)); 00357 00358 // "Update Phase timeout - uses Timing A" 00359 // Timeout of 1000 is tuning parm default (TIMED_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT) 00360 // via VL53L1_get_preset_mode_timing_cfg(). 00361 uint32_t phasecal_timeout_mclks = timeoutMicrosecondsToMclks(1000, macro_period_us); 00362 if (phasecal_timeout_mclks > 0xFF) { phasecal_timeout_mclks = 0xFF; } 00363 writeReg(PHASECAL_CONFIG__TIMEOUT_MACROP, phasecal_timeout_mclks); 00364 00365 // "Update MM Timing A timeout" 00366 // Timeout of 1 is tuning parm default (LOWPOWERAUTO_MM_CONFIG_TIMEOUT_US_DEFAULT) 00367 // via VL53L1_get_preset_mode_timing_cfg(). With the API, the register 00368 // actually ends up with a slightly different value because it gets assigned, 00369 // retrieved, recalculated with a different macro period, and reassigned, 00370 // but it probably doesn't matter because it seems like the MM ("mode 00371 // mitigation"?) sequence steps are disabled in low power auto mode anyway. 00372 writeReg16Bit(MM_CONFIG__TIMEOUT_MACROP_A, encodeTimeout( 00373 timeoutMicrosecondsToMclks(1, macro_period_us))); 00374 00375 // "Update Range Timing A timeout" 00376 writeReg16Bit(RANGE_CONFIG__TIMEOUT_MACROP_A, encodeTimeout( 00377 timeoutMicrosecondsToMclks(range_config_timeout_us, macro_period_us))); 00378 00379 // "Update Macro Period for Range B VCSEL Period" 00380 macro_period_us = calcMacroPeriod(readReg(RANGE_CONFIG__VCSEL_PERIOD_B)); 00381 00382 // "Update MM Timing B timeout" 00383 // (See earlier comment about MM Timing A timeout.) 00384 writeReg16Bit(MM_CONFIG__TIMEOUT_MACROP_B, encodeTimeout( 00385 timeoutMicrosecondsToMclks(1, macro_period_us))); 00386 00387 // "Update Range Timing B timeout" 00388 writeReg16Bit(RANGE_CONFIG__TIMEOUT_MACROP_B, encodeTimeout( 00389 timeoutMicrosecondsToMclks(range_config_timeout_us, macro_period_us))); 00390 // VL53L1_calc_timeout_register_values() end 00391 00392 return true; 00393 } 00394 00395 // Get the measurement timing budget in microseconds 00396 // based on VL53L1_SetMeasurementTimingBudgetMicroSeconds() 00397 uint32_t VL53L1X::getMeasurementTimingBudget() 00398 { 00399 // assumes PresetMode is LOWPOWER_AUTONOMOUS and these sequence steps are 00400 // enabled: VHV, PHASECAL, DSS1, RANGE 00401 00402 // VL53L1_get_timeouts_us() begin 00403 00404 // "Update Macro Period for Range A VCSEL Period" 00405 uint32_t macro_period_us = calcMacroPeriod(readReg(RANGE_CONFIG__VCSEL_PERIOD_A)); 00406 00407 // "Get Range Timing A timeout" 00408 00409 uint32_t range_config_timeout_us = timeoutMclksToMicroseconds(decodeTimeout( 00410 readReg16Bit(RANGE_CONFIG__TIMEOUT_MACROP_A)), macro_period_us); 00411 00412 // VL53L1_get_timeouts_us() end 00413 00414 return 2 * range_config_timeout_us + TimingGuard; 00415 } 00416 00417 // Start continuous ranging measurements, with the given inter-measurement 00418 // period in milliseconds determining how often the sensor takes a measurement. 00419 void VL53L1X::startContinuous(uint32_t period_ms) 00420 { 00421 // from VL53L1_set_inter_measurement_period_ms() 00422 writeReg32Bit(SYSTEM__INTERMEASUREMENT_PERIOD, period_ms * osc_calibrate_val); 00423 writeReg(SYSTEM__INTERRUPT_CLEAR, 0x01); // sys_interrupt_clear_range 00424 writeReg(SYSTEM__MODE_START, 0x40); // mode_range__timed 00425 } 00426 00427 // Stop continuous measurements 00428 // based on VL53L1_stop_range() 00429 void VL53L1X::stopContinuous() 00430 { 00431 writeReg(SYSTEM__MODE_START, 0x80); // mode_range__abort 00432 00433 // VL53L1_low_power_auto_data_stop_range() begin 00434 00435 calibrated = false; 00436 00437 // "restore vhv configs" 00438 if (saved_vhv_init != 0) 00439 { 00440 writeReg(VHV_CONFIG__INIT, saved_vhv_init); 00441 } 00442 if (saved_vhv_timeout != 0) 00443 { 00444 writeReg(VHV_CONFIG__TIMEOUT_MACROP_LOOP_BOUND, saved_vhv_timeout); 00445 } 00446 00447 // "remove phasecal override" 00448 writeReg(PHASECAL_CONFIG__OVERRIDE, 0x00); 00449 00450 // VL53L1_low_power_auto_data_stop_range() end 00451 } 00452 00453 // Returns a range reading in millimeters when continuous mode is active 00454 // (readRangeSingleMillimetersx () also calls this function after starting a 00455 // single-shot range measurement) 00456 uint16_t VL53L1X::read(bool blocking) 00457 { 00458 if (blocking) 00459 { 00460 // startTimeout(); 00461 00462 /* dataReady returns 0. Loop is never entered. */ 00463 /* 00464 while (dataReady()) 00465 { 00466 if (checkTimeoutExpired()) 00467 { 00468 did_timeout = true; 00469 ranging_data.range_status = None; 00470 ranging_data.range_mm = 0; 00471 ranging_data.peak_signal_count_rate_MCPS = 0; 00472 ranging_data.ambient_count_rate_MCPS = 0; 00473 return ranging_data.range_mm; 00474 } 00475 }*/ 00476 } 00477 00478 readResults(); 00479 00480 if (!calibrated) 00481 { 00482 setupManualCalibration(); 00483 calibrated = true; 00484 } 00485 00486 updateDSS(); 00487 00488 getRangingData(); 00489 00490 writeReg(SYSTEM__INTERRUPT_CLEAR, 0x01); // sys_interrupt_clear_range 00491 00492 return ranging_data.range_mm; 00493 } 00494 00495 // convert a RangeStatus to a readable string 00496 // Note that on an AVR, these strings are stored in RAM (dynamic memory), which 00497 // makes working with them easier but uses up 200+ bytes of RAM (many AVR-based 00498 // Arduinos only have about 2000 bytes of RAM). You can avoid this memory usage 00499 // if you do not call this function in your sketch. 00500 const char * VL53L1X::rangeStatusToString(RangeStatus status) 00501 { 00502 switch (status) 00503 { 00504 case RangeValid: 00505 return "range valid"; 00506 00507 case SigmaFail: 00508 return "sigma fail"; 00509 00510 case SignalFail: 00511 return "signal fail"; 00512 00513 case RangeValidMinRangeClipped: 00514 return "range valid, min range clipped"; 00515 00516 case OutOfBoundsFail: 00517 return "out of bounds fail"; 00518 00519 case HardwareFail: 00520 return "hardware fail"; 00521 00522 case RangeValidNoWrapCheckFail: 00523 return "range valid, no wrap check fail"; 00524 00525 case WrapTargetFail: 00526 return "wrap target fail"; 00527 00528 case XtalkSignalFail: 00529 return "xtalk signal fail"; 00530 00531 case SynchronizationInt: 00532 return "synchronization int"; 00533 00534 case MinRangeFail: 00535 return "min range fail"; 00536 00537 case None: 00538 return "no update"; 00539 00540 default: 00541 return "unknown status"; 00542 } 00543 } 00544 00545 // Did a timeout occur in one of the read functions since the last call to 00546 // timeoutOccurred()? 00547 bool VL53L1X::timeoutOccurred() 00548 { 00549 bool tmp = did_timeout; 00550 did_timeout = false; 00551 return tmp; 00552 } 00553 00554 // Private Methods ///////////////////////////////////////////////////////////// 00555 00556 // "Setup ranges after the first one in low power auto mode by turning off 00557 // FW calibration steps and programming static values" 00558 // based on VL53L1_low_power_auto_setup_manual_calibration() 00559 void VL53L1X::setupManualCalibration() 00560 { 00561 // "save original vhv configs" 00562 saved_vhv_init = readReg(VHV_CONFIG__INIT); 00563 saved_vhv_timeout = readReg(VHV_CONFIG__TIMEOUT_MACROP_LOOP_BOUND); 00564 00565 // "disable VHV init" 00566 writeReg(VHV_CONFIG__INIT, saved_vhv_init & 0x7F); 00567 00568 // "set loop bound to tuning param" 00569 writeReg(VHV_CONFIG__TIMEOUT_MACROP_LOOP_BOUND, 00570 (saved_vhv_timeout & 0x03) + (3 << 2)); // tuning parm default (LOWPOWERAUTO_VHV_LOOP_BOUND_DEFAULT) 00571 00572 // "override phasecal" 00573 writeReg(PHASECAL_CONFIG__OVERRIDE, 0x01); 00574 writeReg(CAL_CONFIG__VCSEL_START, readReg(PHASECAL_RESULT__VCSEL_START)); 00575 } 00576 00577 // read measurement results into buffer 00578 void VL53L1X::readResults() 00579 { 00580 char infoToWrite[2]; 00581 char infoToRead[18]; 00582 //_i2c.beginTransmission(address); 00583 //_i2c.write(address); 00584 //_i2c.write((RESULT__RANGE_STATUS >> 8) & 0xFF); // reg high byte 00585 //_i2c.write( RESULT__RANGE_STATUS & 0xFF); // reg low byte 00586 // last_status = _i2c.endTransmission(); 00587 infoToWrite[0] = ((RESULT__RANGE_STATUS >> 8) & 0xFF); 00588 infoToWrite[1] = ( RESULT__RANGE_STATUS & 0xFF); 00589 _i2c.write(address, infoToWrite, 2, 1); 00590 00591 // _i2c.requestFrom(address, (uint8_t)17); 00592 _i2c.read(address, infoToRead, 17, 0); 00593 00594 wait(.005); 00595 results.range_status = infoToRead[0]; 00596 00597 // infoToRead[1]; // report_status: not used 00598 00599 results.stream_count = infoToRead[2]; 00600 00601 results.dss_actual_effective_spads_sd0 = (uint16_t)infoToRead[3] << 8; // high byte 00602 results.dss_actual_effective_spads_sd0 |= infoToRead[4]; // low byte 00603 00604 // infoToRead[5]; // peak_signal_count_rate_mcps_sd0: not used 00605 // infoToRead[6]; 00606 00607 results.ambient_count_rate_mcps_sd0 = (uint16_t)infoToRead[7] << 8; // high byte 00608 results.ambient_count_rate_mcps_sd0 |= infoToRead[8]; // low byte 00609 00610 // infoToRead[9]; // sigma_sd0: not used 00611 // infoToRead[10]; 00612 00613 // infoToRead[11]; // phase_sd0: not used 00614 // infoToRead[12]; 00615 00616 results.final_crosstalk_corrected_range_mm_sd0 = (uint16_t)infoToRead[13] << 8; // high byte 00617 results.final_crosstalk_corrected_range_mm_sd0 |= infoToRead[14]; // low byte 00618 00619 results.peak_signal_count_rate_crosstalk_corrected_mcps_sd0 = (uint16_t)infoToRead[15] << 8; // high byte 00620 results.peak_signal_count_rate_crosstalk_corrected_mcps_sd0 |= infoToRead[16]; // low byte 00621 } 00622 00623 // perform Dynamic SPAD Selection calculation/update 00624 // based on VL53L1_low_power_auto_update_DSS() 00625 void VL53L1X::updateDSS() 00626 { 00627 uint16_t spadCount = results.dss_actual_effective_spads_sd0; 00628 00629 if (spadCount != 0) 00630 { 00631 // "Calc total rate per spad" 00632 00633 uint32_t totalRatePerSpad = 00634 (uint32_t)results.peak_signal_count_rate_crosstalk_corrected_mcps_sd0 + 00635 results.ambient_count_rate_mcps_sd0; 00636 00637 // "clip to 16 bits" 00638 if (totalRatePerSpad > 0xFFFF) { totalRatePerSpad = 0xFFFF; } 00639 00640 // "shift up to take advantage of 32 bits" 00641 totalRatePerSpad <<= 16; 00642 00643 totalRatePerSpad /= spadCount; 00644 00645 if (totalRatePerSpad != 0) 00646 { 00647 // "get the target rate and shift up by 16" 00648 uint32_t requiredSpads = ((uint32_t)TargetRate << 16) / totalRatePerSpad; 00649 00650 // "clip to 16 bit" 00651 if (requiredSpads > 0xFFFF) { requiredSpads = 0xFFFF; } 00652 00653 // "override DSS config" 00654 writeReg16Bit(DSS_CONFIG__MANUAL_EFFECTIVE_SPADS_SELECT, requiredSpads); 00655 // DSS_CONFIG__ROI_MODE_CONTROL should already be set to REQUESTED_EFFFECTIVE_SPADS 00656 00657 return; 00658 } 00659 } 00660 00661 // If we reached this point, it means something above would have resulted in a 00662 // divide by zero. 00663 // "We want to gracefully set a spad target, not just exit with an error" 00664 00665 // "set target to mid point" 00666 writeReg16Bit(DSS_CONFIG__MANUAL_EFFECTIVE_SPADS_SELECT, 0x8000); 00667 } 00668 00669 // get range, status, rates from results buffer 00670 // based on VL53L1_GetRangingMeasurementData() 00671 void VL53L1X::getRangingData() 00672 { 00673 // VL53L1_copy_sys_and_core_results_to_range_results() begin 00674 00675 uint16_t range = results.final_crosstalk_corrected_range_mm_sd0; 00676 00677 // "apply correction gain" 00678 // gain factor of 2011 is tuning parm default (VL53L1_TUNINGPARM_LITE_RANGING_GAIN_FACTOR_DEFAULT) 00679 // Basically, this appears to scale the result by 2011/2048, or about 98% 00680 // (with the 1024 added for proper rounding). 00681 ranging_data.range_mm = ((uint32_t)range * 2011 + 0x0400) / 0x0800; 00682 wait(.005); 00683 // VL53L1_copy_sys_and_core_results_to_range_results() end 00684 00685 // set range_status in ranging_data based on value of RESULT__RANGE_STATUS register 00686 // mostly based on ConvertStatusLite() 00687 switch(results.range_status) 00688 { 00689 case 17: // MULTCLIPFAIL 00690 case 2: // VCSELWATCHDOGTESTFAILURE 00691 case 1: // VCSELCONTINUITYTESTFAILURE 00692 case 3: // NOVHVVALUEFOUND 00693 // from SetSimpleData() 00694 ranging_data.range_status = HardwareFail; 00695 break; 00696 00697 case 13: // USERROICLIP 00698 // from SetSimpleData() 00699 ranging_data.range_status = MinRangeFail; 00700 break; 00701 00702 case 18: // GPHSTREAMCOUNT0READY 00703 ranging_data.range_status = SynchronizationInt; 00704 break; 00705 00706 case 5: // RANGEPHASECHECK 00707 ranging_data.range_status = OutOfBoundsFail; 00708 break; 00709 00710 case 4: // MSRCNOTARGET 00711 ranging_data.range_status = SignalFail; 00712 break; 00713 00714 case 6: // SIGMATHRESHOLDCHECK 00715 ranging_data.range_status = SignalFail; 00716 break; 00717 00718 case 7: // PHASECONSISTENCY 00719 ranging_data.range_status = WrapTargetFail; 00720 break; 00721 00722 case 12: // RANGEIGNORETHRESHOLD 00723 ranging_data.range_status = XtalkSignalFail; 00724 break; 00725 00726 case 8: // MINCLIP 00727 ranging_data.range_status = RangeValidMinRangeClipped; 00728 break; 00729 00730 case 9: // RANGECOMPLETE 00731 // from VL53L1_copy_sys_and_core_results_to_range_results() 00732 if (results.stream_count == 0) 00733 { 00734 ranging_data.range_status = RangeValidNoWrapCheckFail; 00735 } 00736 else 00737 { 00738 ranging_data.range_status = RangeValid; 00739 } 00740 break; 00741 00742 default: 00743 ranging_data.range_status = None; 00744 } 00745 00746 // from SetSimpleData() 00747 ranging_data.peak_signal_count_rate_MCPS = 00748 countRateFixedToFloat(results.peak_signal_count_rate_crosstalk_corrected_mcps_sd0); 00749 ranging_data.ambient_count_rate_MCPS = 00750 countRateFixedToFloat(results.ambient_count_rate_mcps_sd0); 00751 } 00752 00753 // Decode sequence step timeout in MCLKs from register value 00754 // based on VL53L1_decode_timeout() 00755 uint32_t VL53L1X::decodeTimeout(uint16_t reg_val) 00756 { 00757 return ((uint32_t)(reg_val & 0xFF) << (reg_val >> 8)) + 1; 00758 } 00759 00760 // Encode sequence step timeout register value from timeout in MCLKs 00761 // based on VL53L1_encode_timeout() 00762 uint16_t VL53L1X::encodeTimeout(uint32_t timeout_mclks) 00763 { 00764 // encoded format: "(LSByte * 2^MSByte) + 1" 00765 00766 uint32_t ls_byte = 0; 00767 uint16_t ms_byte = 0; 00768 00769 if (timeout_mclks > 0) 00770 { 00771 ls_byte = timeout_mclks - 1; 00772 00773 while ((ls_byte & 0xFFFFFF00) > 0) 00774 { 00775 ls_byte >>= 1; 00776 ms_byte++; 00777 } 00778 00779 return (ms_byte << 8) | (ls_byte & 0xFF); 00780 } 00781 else { return 0; } 00782 } 00783 00784 // Convert sequence step timeout from macro periods to microseconds with given 00785 // macro period in microseconds (12.12 format) 00786 // based on VL53L1_calc_timeout_us() 00787 uint32_t VL53L1X::timeoutMclksToMicroseconds(uint32_t timeout_mclks, uint32_t macro_period_us) 00788 { 00789 return ((uint64_t)timeout_mclks * macro_period_us + 0x800) >> 12; 00790 } 00791 00792 // Convert sequence step timeout from microseconds to macro periods with given 00793 // macro period in microseconds (12.12 format) 00794 // based on VL53L1_calc_timeout_mclks() 00795 uint32_t VL53L1X::timeoutMicrosecondsToMclks(uint32_t timeout_us, uint32_t macro_period_us) 00796 { 00797 return (((uint32_t)timeout_us << 12) + (macro_period_us >> 1)) / macro_period_us; 00798 } 00799 00800 // Calculate macro period in microseconds (12.12 format) with given VCSEL period 00801 // assumes fast_osc_frequency has been read and stored 00802 // based on VL53L1_calc_macro_period_us() 00803 uint32_t VL53L1X::calcMacroPeriod(uint8_t vcsel_period) 00804 { 00805 // from VL53L1_calc_pll_period_us() 00806 // fast osc frequency in 4.12 format; PLL period in 0.24 format 00807 uint32_t pll_period_us = ((uint32_t)0x01 << 30) / fast_osc_frequency; 00808 00809 // from VL53L1_decode_vcsel_period() 00810 uint8_t vcsel_period_pclks = (vcsel_period + 1) << 1; 00811 00812 // VL53L1_MACRO_PERIOD_VCSEL_PERIODS = 2304 00813 uint32_t macro_period_us = (uint32_t)2304 * pll_period_us; 00814 macro_period_us >>= 6; 00815 macro_period_us *= vcsel_period_pclks; 00816 macro_period_us >>= 6; 00817 00818 return macro_period_us; 00819 } 00820 00821 00822 00823 00824 00825 00826 00827 00828 00829 00830 bool VL53L1X::initReading(int addr, int timing_budget) 00831 { 00832 turnOn(); 00833 wait_ms(100); 00834 setTimeout(500); 00835 if (!init()) { 00836 didInitialize = false; 00837 return false; 00838 } 00839 // setDistanceMode(VL53L1X::Short);//Short Medium Long 00840 setAddress(addr);//change I2C address for next sensor 00841 setMeasurementTimingBudget(timing_budget);//min 20ms for Short, 33ms for Medium and Long 00842 startContinuous(50); 00843 wait_ms(100); 00844 didInitialize = true; 00845 return true; 00846 } 00847 //************************************* 00848 00849 //*********GPIO*********** 00850 void VL53L1X::turnOff(void) 00851 { 00852 //turn pin LOW 00853 _shutDown = false; 00854 } 00855 void VL53L1X::resetPin(void) 00856 { 00857 //reset pin and set it to LOW 00858 _shutDown = false; 00859 wait(.05); 00860 _shutDown = true; 00861 wait(.05); 00862 _shutDown = false; 00863 wait(.05); 00864 00865 } 00866 void VL53L1X::turnOn(void) 00867 { 00868 //turn pin HIGH 00869 _shutDown = true; 00870 } 00871 int VL53L1X::readFromOneSensor(void) 00872 { 00873 if (didInitialize) //create bool 00874 return medianFilter(); 00875 else 00876 return -1; 00877 } 00878 int VL53L1X::medianFilter(void) 00879 { 00880 rawData[1] = rawData[0]; 00881 rawData[2] = rawData[1]; 00882 rawData[0] = read(); 00883 if((rawData[0] < rawData[1] && rawData[0] > rawData[2]) || (rawData[0] > rawData[1] && rawData[0] < rawData[2])) 00884 return rawData[0]; 00885 else if((rawData[1] < rawData[0] && rawData[1] > rawData[2]) || (rawData[1] > rawData[0] && rawData[1] < rawData[2])) 00886 return rawData[1]; 00887 else 00888 return rawData[2]; 00889 }
Generated on Fri Jul 15 2022 03:32:03 by 1.7.2