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.
VL53L0X.cpp
00001 /// Most of the functionality of this library is based on the VL53L0X API 00002 // provided by ST (STSW-IMG005), and some of the explanatory comments are quoted 00003 // or paraphrased from the API source code, API user manual (UM2039), and the 00004 // VL53L0X datasheet. 00005 00006 #include "VL53L0X.h" 00007 #include "mbed.h" 00008 // Defines ///////////////////////////////////////////////////////////////////// 00009 00010 // The Arduino two-wire interface uses a 7-bit number for the address, 00011 // and sets the last bit correctly based on reads and writes 00012 #define ADDRESS_DEFAULT 0b0101001 << 1 00013 00014 // Record the current time to check an upcoming timeout against 00015 #define startTimeout() (timeout_start_ms = 0) 00016 00017 // Check if timeout is enabled (set to nonzero value) and has expired 00018 #define checkTimeoutExpired() (io_timeout > 0 && ((uint16_t)10 - timeout_start_ms) > io_timeout) 00019 00020 // Decode VCSEL (vertical cavity surface emitting laser) pulse period in PCLKs 00021 // from register value 00022 // based on VL53L0X_decode_vcsel_period() 00023 #define decodeVcselPeriod(reg_val) (((reg_val) + 1) << 1) 00024 00025 // Encode VCSEL pulse period register value from period in PCLKs 00026 // based on VL53L0X_encode_vcsel_period() 00027 #define encodeVcselPeriod(period_pclks) (((period_pclks) >> 1) - 1) 00028 00029 // Calculate macro period in *nanoseconds* from VCSEL period in PCLKs 00030 // based on VL53L0X_calc_macro_period_ps() 00031 // PLL_period_ps = 1655; macro_period_vclks = 2304 00032 #define calcMacroPeriod(vcsel_period_pclks) ((((uint32_t)2304 * (vcsel_period_pclks) * 1655) + 500) / 1000) 00033 00034 // Constructors //////////////////////////////////////////////////////////////// 00035 00036 VL53L0X::VL53L0X(PinName sda, PinName scl) : m_i2c(sda,scl),m_addr(ADDRESS_DEFAULT), io_timeout(0) // no timeout 00037 , did_timeout(false) 00038 { 00039 } 00040 00041 // Public Methods ////////////////////////////////////////////////////////////// 00042 00043 void VL53L0X::setAddress(uint8_t new_addr) 00044 { 00045 writeReg(I2C_SLAVE_DEVICE_ADDRESS, new_addr & 0x7F); 00046 address = new_addr; 00047 } 00048 00049 // Initialize sensor using sequence based on VL53L0X_DataInit(), 00050 // VL53L0X_StaticInit(), and VL53L0X_PerformRefCalibration(). 00051 // This function does not perform reference SPAD calibration 00052 // (VL53L0X_PerformRefSpadManagement()), since the API user manual says that it 00053 // is performed by ST on the bare modules; it seems like that should work well 00054 // enough unless a cover glass is added. 00055 // If io_2v8 (optional) is true or not given, the sensor is configured for 2V8 00056 // mode. 00057 bool VL53L0X::init(bool io_2v8) 00058 { 00059 // VL53L0X_DataInit() begin 00060 00061 // sensor uses 1V8 mode for I/O by default; switch to 2V8 mode if necessary 00062 if (io_2v8) 00063 { 00064 writeReg(VHV_CONFIG_PAD_SCL_SDA__EXTSUP_HV, 00065 readReg(VHV_CONFIG_PAD_SCL_SDA__EXTSUP_HV) | 0x01); // set bit 0 00066 } 00067 00068 // "Set I2C standard mode" 00069 writeReg(0x88, 0x00); 00070 00071 writeReg(0x80, 0x01); 00072 writeReg(0xFF, 0x01); 00073 writeReg(0x00, 0x00); 00074 stop_variable = readReg(0x91); 00075 writeReg(0x00, 0x01); 00076 writeReg(0xFF, 0x00); 00077 writeReg(0x80, 0x00); 00078 00079 // disable SIGNAL_RATE_MSRC (bit 1) and SIGNAL_RATE_PRE_RANGE (bit 4) limit checks 00080 writeReg(MSRC_CONFIG_CONTROL, readReg(MSRC_CONFIG_CONTROL) | 0x12); 00081 00082 // set final range signal rate limit to 0.25 MCPS (million counts per second) 00083 setSignalRateLimit(0.25); 00084 00085 writeReg(SYSTEM_SEQUENCE_CONFIG, 0xFF); 00086 00087 // VL53L0X_DataInit() end 00088 00089 // VL53L0X_StaticInit() begin 00090 00091 uint8_t spad_count; 00092 bool spad_type_is_aperture; 00093 if (!getSpadInfo(&spad_count, &spad_type_is_aperture)) { return false; } 00094 00095 // The SPAD map (RefGoodSpadMap) is read by VL53L0X_get_info_from_device() in 00096 // the API, but the same data seems to be more easily readable from 00097 // GLOBAL_CONFIG_SPAD_ENABLES_REF_0 through _6, so read it from there 00098 char ref_spad_map[6]; 00099 readMulti(GLOBAL_CONFIG_SPAD_ENABLES_REF_0, ref_spad_map, 6); 00100 00101 // -- VL53L0X_set_reference_spads() begin (assume NVM values are valid) 00102 00103 writeReg(0xFF, 0x01); 00104 writeReg(DYNAMIC_SPAD_REF_EN_START_OFFSET, 0x00); 00105 writeReg(DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD, 0x2C); 00106 writeReg(0xFF, 0x00); 00107 writeReg(GLOBAL_CONFIG_REF_EN_START_SELECT, 0xB4); 00108 00109 uint8_t first_spad_to_enable = spad_type_is_aperture ? 12 : 0; // 12 is the first aperture spad 00110 uint8_t spads_enabled = 0; 00111 00112 for (uint8_t i = 0; i < 48; i++) 00113 { 00114 if (i < first_spad_to_enable || spads_enabled == spad_count) 00115 { 00116 // This bit is lower than the first one that should be enabled, or 00117 // (reference_spad_count) bits have already been enabled, so zero this bit 00118 ref_spad_map[i / 8] &= ~(1 << (i % 8)); 00119 } 00120 else if ((ref_spad_map[i / 8] >> (i % 8)) & 0x1) 00121 { 00122 spads_enabled++; 00123 } 00124 } 00125 00126 writeMulti(GLOBAL_CONFIG_SPAD_ENABLES_REF_0, ref_spad_map, 6); 00127 00128 // -- VL53L0X_set_reference_spads() end 00129 00130 // -- VL53L0X_load_tuning_settings() begin 00131 // DefaultTuningSettings from vl53l0x_tuning.h 00132 00133 writeReg(0xFF, 0x01); 00134 writeReg(0x00, 0x00); 00135 00136 writeReg(0xFF, 0x00); 00137 writeReg(0x09, 0x00); 00138 writeReg(0x10, 0x00); 00139 writeReg(0x11, 0x00); 00140 00141 writeReg(0x24, 0x01); 00142 writeReg(0x25, 0xFF); 00143 writeReg(0x75, 0x00); 00144 00145 writeReg(0xFF, 0x01); 00146 writeReg(0x4E, 0x2C); 00147 writeReg(0x48, 0x00); 00148 writeReg(0x30, 0x20); 00149 00150 writeReg(0xFF, 0x00); 00151 writeReg(0x30, 0x09); 00152 writeReg(0x54, 0x00); 00153 writeReg(0x31, 0x04); 00154 writeReg(0x32, 0x03); 00155 writeReg(0x40, 0x83); 00156 writeReg(0x46, 0x25); 00157 writeReg(0x60, 0x00); 00158 writeReg(0x27, 0x00); 00159 writeReg(0x50, 0x06); 00160 writeReg(0x51, 0x00); 00161 writeReg(0x52, 0x96); 00162 writeReg(0x56, 0x08); 00163 writeReg(0x57, 0x30); 00164 writeReg(0x61, 0x00); 00165 writeReg(0x62, 0x00); 00166 writeReg(0x64, 0x00); 00167 writeReg(0x65, 0x00); 00168 writeReg(0x66, 0xA0); 00169 00170 writeReg(0xFF, 0x01); 00171 writeReg(0x22, 0x32); 00172 writeReg(0x47, 0x14); 00173 writeReg(0x49, 0xFF); 00174 writeReg(0x4A, 0x00); 00175 00176 writeReg(0xFF, 0x00); 00177 writeReg(0x7A, 0x0A); 00178 writeReg(0x7B, 0x00); 00179 writeReg(0x78, 0x21); 00180 00181 writeReg(0xFF, 0x01); 00182 writeReg(0x23, 0x34); 00183 writeReg(0x42, 0x00); 00184 writeReg(0x44, 0xFF); 00185 writeReg(0x45, 0x26); 00186 writeReg(0x46, 0x05); 00187 writeReg(0x40, 0x40); 00188 writeReg(0x0E, 0x06); 00189 writeReg(0x20, 0x1A); 00190 writeReg(0x43, 0x40); 00191 00192 writeReg(0xFF, 0x00); 00193 writeReg(0x34, 0x03); 00194 writeReg(0x35, 0x44); 00195 00196 writeReg(0xFF, 0x01); 00197 writeReg(0x31, 0x04); 00198 writeReg(0x4B, 0x09); 00199 writeReg(0x4C, 0x05); 00200 writeReg(0x4D, 0x04); 00201 00202 writeReg(0xFF, 0x00); 00203 writeReg(0x44, 0x00); 00204 writeReg(0x45, 0x20); 00205 writeReg(0x47, 0x08); 00206 writeReg(0x48, 0x28); 00207 writeReg(0x67, 0x00); 00208 writeReg(0x70, 0x04); 00209 writeReg(0x71, 0x01); 00210 writeReg(0x72, 0xFE); 00211 writeReg(0x76, 0x00); 00212 writeReg(0x77, 0x00); 00213 00214 writeReg(0xFF, 0x01); 00215 writeReg(0x0D, 0x01); 00216 00217 writeReg(0xFF, 0x00); 00218 writeReg(0x80, 0x01); 00219 writeReg(0x01, 0xF8); 00220 00221 writeReg(0xFF, 0x01); 00222 writeReg(0x8E, 0x01); 00223 writeReg(0x00, 0x01); 00224 writeReg(0xFF, 0x00); 00225 writeReg(0x80, 0x00); 00226 00227 // -- VL53L0X_load_tuning_settings() end 00228 00229 // "Set interrupt config to new sample ready" 00230 // -- VL53L0X_SetGpioConfig() begin 00231 00232 writeReg(SYSTEM_INTERRUPT_CONFIG_GPIO, 0x04); 00233 writeReg(GPIO_HV_MUX_ACTIVE_HIGH, readReg(GPIO_HV_MUX_ACTIVE_HIGH) & ~0x10); // active low 00234 writeReg(SYSTEM_INTERRUPT_CLEAR, 0x01); 00235 00236 // -- VL53L0X_SetGpioConfig() end 00237 00238 measurement_timing_budget_us = getMeasurementTimingBudget(); 00239 00240 // "Disable MSRC and TCC by default" 00241 // MSRC = Minimum Signal Rate Check 00242 // TCC = Target CentreCheck 00243 // -- VL53L0X_SetSequenceStepEnable() begin 00244 00245 writeReg(SYSTEM_SEQUENCE_CONFIG, 0xE8); 00246 00247 // -- VL53L0X_SetSequenceStepEnable() end 00248 00249 // "Recalculate timing budget" 00250 setMeasurementTimingBudget(measurement_timing_budget_us); 00251 00252 // VL53L0X_StaticInit() end 00253 00254 // VL53L0X_PerformRefCalibration() begin (VL53L0X_perform_ref_calibration()) 00255 00256 // -- VL53L0X_perform_vhv_calibration() begin 00257 00258 writeReg(SYSTEM_SEQUENCE_CONFIG, 0x01); 00259 if (!performSingleRefCalibration(0x40)) { return false; } 00260 00261 // -- VL53L0X_perform_vhv_calibration() end 00262 00263 // -- VL53L0X_perform_phase_calibration() begin 00264 00265 writeReg(SYSTEM_SEQUENCE_CONFIG, 0x02); 00266 if (!performSingleRefCalibration(0x00)) { return false; } 00267 00268 // -- VL53L0X_perform_phase_calibration() end 00269 00270 // "restore the previous Sequence Config" 00271 writeReg(SYSTEM_SEQUENCE_CONFIG, 0xE8); 00272 00273 // VL53L0X_PerformRefCalibration() end 00274 00275 return true; 00276 } 00277 00278 // Set the return signal rate limit check value in units of MCPS (mega counts 00279 // per second). "This represents the amplitude of the signal reflected from the 00280 // target and detected by the device"; setting this limit presumably determines 00281 // the minimum measurement necessary for the sensor to report a valid reading. 00282 // Setting a lower limit increases the potential range of the sensor but also 00283 // seems to increase the likelihood of getting an inaccurate reading because of 00284 // unwanted reflections from objects other than the intended target. 00285 // Defaults to 0.25 MCPS as initialized by the ST API and this library. 00286 bool VL53L0X::setSignalRateLimit(float limit_Mcps) 00287 { 00288 if (limit_Mcps < 0 || limit_Mcps > 511.99) { return false; } 00289 00290 // Q9.7 fixed point format (9 integer bits, 7 fractional bits) 00291 writeReg16Bit(FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT, limit_Mcps * (1 << 7)); 00292 return true; 00293 } 00294 00295 // Get the return signal rate limit check value in MCPS 00296 float VL53L0X::getSignalRateLimit(void) 00297 { 00298 return (float)readReg16Bit(FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT) / (1 << 7); 00299 } 00300 00301 // Set the measurement timing budget in microseconds, which is the time allowed 00302 // for one measurement; the ST API and this library take care of splitting the 00303 // timing budget among the sub-steps in the ranging sequence. A longer timing 00304 // budget allows for more accurate measurements. Increasing the budget by a 00305 // factor of N decreases the range measurement standard deviation by a factor of 00306 // sqrt(N). Defaults to about 33 milliseconds; the minimum is 20 ms. 00307 // based on VL53L0X_set_measurement_timing_budget_micro_seconds() 00308 bool VL53L0X::setMeasurementTimingBudget(uint32_t budget_us) 00309 { 00310 SequenceStepEnables enables; 00311 SequenceStepTimeouts timeouts; 00312 00313 uint16_t const StartOverhead = 1320; // note that this is different than the value in get_ 00314 uint16_t const EndOverhead = 960; 00315 uint16_t const MsrcOverhead = 660; 00316 uint16_t const TccOverhead = 590; 00317 uint16_t const DssOverhead = 690; 00318 uint16_t const PreRangeOverhead = 660; 00319 uint16_t const FinalRangeOverhead = 550; 00320 00321 uint32_t const MinTimingBudget = 20000; 00322 00323 if (budget_us < MinTimingBudget) { return false; } 00324 00325 uint32_t used_budget_us = StartOverhead + EndOverhead; 00326 00327 getSequenceStepEnables(&enables); 00328 getSequenceStepTimeouts(&enables, &timeouts); 00329 00330 if (enables.tcc) 00331 { 00332 used_budget_us += (timeouts.msrc_dss_tcc_us + TccOverhead); 00333 } 00334 00335 if (enables.dss) 00336 { 00337 used_budget_us += 2 * (timeouts.msrc_dss_tcc_us + DssOverhead); 00338 } 00339 else if (enables.msrc) 00340 { 00341 used_budget_us += (timeouts.msrc_dss_tcc_us + MsrcOverhead); 00342 } 00343 00344 if (enables.pre_range) 00345 { 00346 used_budget_us += (timeouts.pre_range_us + PreRangeOverhead); 00347 } 00348 00349 if (enables.final_range) 00350 { 00351 used_budget_us += FinalRangeOverhead; 00352 00353 // "Note that the final range timeout is determined by the timing 00354 // budget and the sum of all other timeouts within the sequence. 00355 // If there is no room for the final range timeout, then an error 00356 // will be set. Otherwise the remaining time will be applied to 00357 // the final range." 00358 00359 if (used_budget_us > budget_us) 00360 { 00361 // "Requested timeout too big." 00362 return false; 00363 } 00364 00365 uint32_t final_range_timeout_us = budget_us - used_budget_us; 00366 00367 // set_sequence_step_timeout() begin 00368 // (SequenceStepId == VL53L0X_SEQUENCESTEP_FINAL_RANGE) 00369 00370 // "For the final range timeout, the pre-range timeout 00371 // must be added. To do this both final and pre-range 00372 // timeouts must be expressed in macro periods MClks 00373 // because they have different vcsel periods." 00374 00375 uint16_t final_range_timeout_mclks = 00376 timeoutMicrosecondsToMclks(final_range_timeout_us, 00377 timeouts.final_range_vcsel_period_pclks); 00378 00379 if (enables.pre_range) 00380 { 00381 final_range_timeout_mclks += timeouts.pre_range_mclks; 00382 } 00383 00384 writeReg16Bit(FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI, 00385 encodeTimeout(final_range_timeout_mclks)); 00386 00387 // set_sequence_step_timeout() end 00388 00389 measurement_timing_budget_us = budget_us; // store for internal reuse 00390 } 00391 return true; 00392 } 00393 00394 // Get the measurement timing budget in microseconds 00395 // based on VL53L0X_get_measurement_timing_budget_micro_seconds() 00396 // in us 00397 uint32_t VL53L0X::getMeasurementTimingBudget(void) 00398 { 00399 SequenceStepEnables enables; 00400 SequenceStepTimeouts timeouts; 00401 00402 uint16_t const StartOverhead = 1910; // note that this is different than the value in set_ 00403 uint16_t const EndOverhead = 960; 00404 uint16_t const MsrcOverhead = 660; 00405 uint16_t const TccOverhead = 590; 00406 uint16_t const DssOverhead = 690; 00407 uint16_t const PreRangeOverhead = 660; 00408 uint16_t const FinalRangeOverhead = 550; 00409 00410 // "Start and end overhead times always present" 00411 uint32_t budget_us = StartOverhead + EndOverhead; 00412 00413 getSequenceStepEnables(&enables); 00414 getSequenceStepTimeouts(&enables, &timeouts); 00415 00416 if (enables.tcc) 00417 { 00418 budget_us += (timeouts.msrc_dss_tcc_us + TccOverhead); 00419 } 00420 00421 if (enables.dss) 00422 { 00423 budget_us += 2 * (timeouts.msrc_dss_tcc_us + DssOverhead); 00424 } 00425 else if (enables.msrc) 00426 { 00427 budget_us += (timeouts.msrc_dss_tcc_us + MsrcOverhead); 00428 } 00429 00430 if (enables.pre_range) 00431 { 00432 budget_us += (timeouts.pre_range_us + PreRangeOverhead); 00433 } 00434 00435 if (enables.final_range) 00436 { 00437 budget_us += (timeouts.final_range_us + FinalRangeOverhead); 00438 } 00439 00440 measurement_timing_budget_us = budget_us; // store for internal reuse 00441 return budget_us; 00442 } 00443 00444 // Set the VCSEL (vertical cavity surface emitting laser) pulse period for the 00445 // given period type (pre-range or final range) to the given value in PCLKs. 00446 // Longer periods seem to increase the potential range of the sensor. 00447 // Valid values are (even numbers only): 00448 // pre: 12 to 18 (initialized default: 14) 00449 // final: 8 to 14 (initialized default: 10) 00450 // based on VL53L0X_set_vcsel_pulse_period() 00451 bool VL53L0X::setVcselPulsePeriod(vcselPeriodType type, uint8_t period_pclks) 00452 { 00453 uint8_t vcsel_period_reg = encodeVcselPeriod(period_pclks); 00454 00455 SequenceStepEnables enables; 00456 SequenceStepTimeouts timeouts; 00457 00458 getSequenceStepEnables(&enables); 00459 getSequenceStepTimeouts(&enables, &timeouts); 00460 00461 // "Apply specific settings for the requested clock period" 00462 // "Re-calculate and apply timeouts, in macro periods" 00463 00464 // "When the VCSEL period for the pre or final range is changed, 00465 // the corresponding timeout must be read from the device using 00466 // the current VCSEL period, then the new VCSEL period can be 00467 // applied. The timeout then must be written back to the device 00468 // using the new VCSEL period. 00469 // 00470 // For the MSRC timeout, the same applies - this timeout being 00471 // dependant on the pre-range vcsel period." 00472 00473 00474 if (type == VcselPeriodPreRange) 00475 { 00476 // "Set phase check limits" 00477 switch (period_pclks) 00478 { 00479 case 12: 00480 writeReg(PRE_RANGE_CONFIG_VALID_PHASE_HIGH, 0x18); 00481 break; 00482 00483 case 14: 00484 writeReg(PRE_RANGE_CONFIG_VALID_PHASE_HIGH, 0x30); 00485 break; 00486 00487 case 16: 00488 writeReg(PRE_RANGE_CONFIG_VALID_PHASE_HIGH, 0x40); 00489 break; 00490 00491 case 18: 00492 writeReg(PRE_RANGE_CONFIG_VALID_PHASE_HIGH, 0x50); 00493 break; 00494 00495 default: 00496 // invalid period 00497 return false; 00498 } 00499 writeReg(PRE_RANGE_CONFIG_VALID_PHASE_LOW, 0x08); 00500 00501 // apply new VCSEL period 00502 writeReg(PRE_RANGE_CONFIG_VCSEL_PERIOD, vcsel_period_reg); 00503 00504 // update timeouts 00505 00506 // set_sequence_step_timeout() begin 00507 // (SequenceStepId == VL53L0X_SEQUENCESTEP_PRE_RANGE) 00508 00509 uint16_t new_pre_range_timeout_mclks = 00510 timeoutMicrosecondsToMclks(timeouts.pre_range_us, period_pclks); 00511 00512 writeReg16Bit(PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI, 00513 encodeTimeout(new_pre_range_timeout_mclks)); 00514 00515 // set_sequence_step_timeout() end 00516 00517 // set_sequence_step_timeout() begin 00518 // (SequenceStepId == VL53L0X_SEQUENCESTEP_MSRC) 00519 00520 uint16_t new_msrc_timeout_mclks = 00521 timeoutMicrosecondsToMclks(timeouts.msrc_dss_tcc_us, period_pclks); 00522 00523 writeReg(MSRC_CONFIG_TIMEOUT_MACROP, 00524 (new_msrc_timeout_mclks > 256) ? 255 : (new_msrc_timeout_mclks - 1)); 00525 00526 // set_sequence_step_timeout() end 00527 } 00528 else if (type == VcselPeriodFinalRange) 00529 { 00530 switch (period_pclks) 00531 { 00532 case 8: 00533 writeReg(FINAL_RANGE_CONFIG_VALID_PHASE_HIGH, 0x10); 00534 writeReg(FINAL_RANGE_CONFIG_VALID_PHASE_LOW, 0x08); 00535 writeReg(GLOBAL_CONFIG_VCSEL_WIDTH, 0x02); 00536 writeReg(ALGO_PHASECAL_CONFIG_TIMEOUT, 0x0C); 00537 writeReg(0xFF, 0x01); 00538 writeReg(ALGO_PHASECAL_LIM, 0x30); 00539 writeReg(0xFF, 0x00); 00540 break; 00541 00542 case 10: 00543 writeReg(FINAL_RANGE_CONFIG_VALID_PHASE_HIGH, 0x28); 00544 writeReg(FINAL_RANGE_CONFIG_VALID_PHASE_LOW, 0x08); 00545 writeReg(GLOBAL_CONFIG_VCSEL_WIDTH, 0x03); 00546 writeReg(ALGO_PHASECAL_CONFIG_TIMEOUT, 0x09); 00547 writeReg(0xFF, 0x01); 00548 writeReg(ALGO_PHASECAL_LIM, 0x20); 00549 writeReg(0xFF, 0x00); 00550 break; 00551 00552 case 12: 00553 writeReg(FINAL_RANGE_CONFIG_VALID_PHASE_HIGH, 0x38); 00554 writeReg(FINAL_RANGE_CONFIG_VALID_PHASE_LOW, 0x08); 00555 writeReg(GLOBAL_CONFIG_VCSEL_WIDTH, 0x03); 00556 writeReg(ALGO_PHASECAL_CONFIG_TIMEOUT, 0x08); 00557 writeReg(0xFF, 0x01); 00558 writeReg(ALGO_PHASECAL_LIM, 0x20); 00559 writeReg(0xFF, 0x00); 00560 break; 00561 00562 case 14: 00563 writeReg(FINAL_RANGE_CONFIG_VALID_PHASE_HIGH, 0x48); 00564 writeReg(FINAL_RANGE_CONFIG_VALID_PHASE_LOW, 0x08); 00565 writeReg(GLOBAL_CONFIG_VCSEL_WIDTH, 0x03); 00566 writeReg(ALGO_PHASECAL_CONFIG_TIMEOUT, 0x07); 00567 writeReg(0xFF, 0x01); 00568 writeReg(ALGO_PHASECAL_LIM, 0x20); 00569 writeReg(0xFF, 0x00); 00570 break; 00571 00572 default: 00573 // invalid period 00574 return false; 00575 } 00576 00577 // apply new VCSEL period 00578 writeReg(FINAL_RANGE_CONFIG_VCSEL_PERIOD, vcsel_period_reg); 00579 00580 // update timeouts 00581 00582 // set_sequence_step_timeout() begin 00583 // (SequenceStepId == VL53L0X_SEQUENCESTEP_FINAL_RANGE) 00584 00585 // "For the final range timeout, the pre-range timeout 00586 // must be added. To do this both final and pre-range 00587 // timeouts must be expressed in macro periods MClks 00588 // because they have different vcsel periods." 00589 00590 uint16_t new_final_range_timeout_mclks = 00591 timeoutMicrosecondsToMclks(timeouts.final_range_us, period_pclks); 00592 00593 if (enables.pre_range) 00594 { 00595 new_final_range_timeout_mclks += timeouts.pre_range_mclks; 00596 } 00597 00598 writeReg16Bit(FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI, 00599 encodeTimeout(new_final_range_timeout_mclks)); 00600 00601 // set_sequence_step_timeout end 00602 } 00603 else 00604 { 00605 // invalid type 00606 return false; 00607 } 00608 00609 // "Finally, the timing budget must be re-applied" 00610 00611 setMeasurementTimingBudget(measurement_timing_budget_us); 00612 00613 // "Perform the phase calibration. This is needed after changing on vcsel period." 00614 // VL53L0X_perform_phase_calibration() begin 00615 00616 uint8_t sequence_config = readReg(SYSTEM_SEQUENCE_CONFIG); 00617 writeReg(SYSTEM_SEQUENCE_CONFIG, 0x02); 00618 performSingleRefCalibration(0x0); 00619 writeReg(SYSTEM_SEQUENCE_CONFIG, sequence_config); 00620 00621 // VL53L0X_perform_phase_calibration() end 00622 00623 return true; 00624 } 00625 00626 // Get the VCSEL pulse period in PCLKs for the given period type. 00627 // based on VL53L0X_get_vcsel_pulse_period() 00628 uint8_t VL53L0X::getVcselPulsePeriod(vcselPeriodType type) 00629 { 00630 if (type == VcselPeriodPreRange) 00631 { 00632 return decodeVcselPeriod(readReg(PRE_RANGE_CONFIG_VCSEL_PERIOD)); 00633 } 00634 else if (type == VcselPeriodFinalRange) 00635 { 00636 return decodeVcselPeriod(readReg(FINAL_RANGE_CONFIG_VCSEL_PERIOD)); 00637 } 00638 else { return 255; } 00639 } 00640 00641 // Start continuous ranging measurements. If period_ms (optional) is 0 or not 00642 // given, continuous back-to-back mode is used (the sensor takes measurements as 00643 // often as possible); otherwise, continuous timed mode is used, with the given 00644 // inter-measurement period in milliseconds determining how often the sensor 00645 // takes a measurement. 00646 // based on VL53L0X_StartMeasurement() 00647 void VL53L0X::startContinuous(uint32_t period_ms) 00648 { 00649 writeReg(0x80, 0x01); 00650 writeReg(0xFF, 0x01); 00651 writeReg(0x00, 0x00); 00652 writeReg(0x91, stop_variable); 00653 writeReg(0x00, 0x01); 00654 writeReg(0xFF, 0x00); 00655 writeReg(0x80, 0x00); 00656 00657 if (period_ms != 0) 00658 { 00659 // continuous timed mode 00660 00661 // VL53L0X_SetInterMeasurementPeriodMilliSeconds() begin 00662 00663 uint16_t osc_calibrate_val = readReg16Bit(OSC_CALIBRATE_VAL); 00664 00665 if (osc_calibrate_val != 0) 00666 { 00667 period_ms *= osc_calibrate_val; 00668 } 00669 00670 writeReg32Bit(SYSTEM_INTERMEASUREMENT_PERIOD, period_ms); 00671 00672 // VL53L0X_SetInterMeasurementPeriodMilliSeconds() end 00673 00674 writeReg(SYSRANGE_START, 0x04); // VL53L0X_REG_SYSRANGE_MODE_TIMED 00675 } 00676 else 00677 { 00678 // continuous back-to-back mode 00679 writeReg(SYSRANGE_START, 0x02); // VL53L0X_REG_SYSRANGE_MODE_BACKTOBACK 00680 } 00681 } 00682 00683 // Stop continuous measurements 00684 // based on VL53L0X_StopMeasurement() 00685 void VL53L0X::stopContinuous(void) 00686 { 00687 writeReg(SYSRANGE_START, 0x01); // VL53L0X_REG_SYSRANGE_MODE_SINGLESHOT 00688 00689 writeReg(0xFF, 0x01); 00690 writeReg(0x00, 0x00); 00691 writeReg(0x91, 0x00); 00692 writeReg(0x00, 0x01); 00693 writeReg(0xFF, 0x00); 00694 } 00695 00696 // Returns a range reading in millimeters when continuous mode is active 00697 // (readRangeSingleMillimeters() also calls this function after starting a 00698 // single-shot range measurement) 00699 uint16_t VL53L0X::readRangeContinuousMillimeters(void) 00700 { 00701 startTimeout(); 00702 while ((readReg(RESULT_INTERRUPT_STATUS) & 0x07) == 0) 00703 { 00704 if (checkTimeoutExpired()) 00705 { 00706 did_timeout = true; 00707 return 65535; 00708 } 00709 } 00710 00711 // assumptions: Linearity Corrective Gain is 1000 (default); 00712 // fractional ranging is not enabled 00713 uint16_t range = readReg16Bit(RESULT_RANGE_STATUS + 10); 00714 00715 writeReg(SYSTEM_INTERRUPT_CLEAR, 0x01); 00716 00717 return range; 00718 } 00719 00720 // Performs a single-shot range measurement and returns the reading in 00721 // millimeters 00722 // based on VL53L0X_PerformSingleRangingMeasurement() 00723 uint16_t VL53L0X::readRangeSingleMillimeters(void) 00724 { 00725 writeReg(0x80, 0x01); 00726 writeReg(0xFF, 0x01); 00727 writeReg(0x00, 0x00); 00728 writeReg(0x91, stop_variable); 00729 writeReg(0x00, 0x01); 00730 writeReg(0xFF, 0x00); 00731 writeReg(0x80, 0x00); 00732 00733 writeReg(SYSRANGE_START, 0x01); 00734 00735 // "Wait until start bit has been cleared" 00736 startTimeout(); 00737 while (readReg(SYSRANGE_START) & 0x01) 00738 { 00739 if (checkTimeoutExpired()) 00740 { 00741 did_timeout = true; 00742 return 65535; 00743 } 00744 } 00745 00746 return readRangeContinuousMillimeters(); 00747 } 00748 00749 // Did a timeout occur in one of the read functions since the last call to 00750 // timeoutOccurred()? 00751 bool VL53L0X::timeoutOccurred() 00752 { 00753 bool tmp = did_timeout; 00754 did_timeout = false; 00755 return tmp; 00756 } 00757 00758 // Private Methods ///////////////////////////////////////////////////////////// 00759 00760 // Get reference SPAD (single photon avalanche diode) count and type 00761 // based on VL53L0X_get_info_from_device(), 00762 // but only gets reference SPAD count and type 00763 bool VL53L0X::getSpadInfo(uint8_t * count, bool * type_is_aperture) 00764 { 00765 uint8_t tmp; 00766 00767 writeReg(0x80, 0x01); 00768 writeReg(0xFF, 0x01); 00769 writeReg(0x00, 0x00); 00770 00771 writeReg(0xFF, 0x06); 00772 writeReg(0x83, readReg(0x83) | 0x04); 00773 writeReg(0xFF, 0x07); 00774 writeReg(0x81, 0x01); 00775 00776 writeReg(0x80, 0x01); 00777 00778 writeReg(0x94, 0x6b); 00779 writeReg(0x83, 0x00); 00780 startTimeout(); 00781 while (readReg(0x83) == 0x00) 00782 { 00783 if (checkTimeoutExpired()) { return false; } 00784 } 00785 writeReg(0x83, 0x01); 00786 tmp = readReg(0x92); 00787 00788 *count = tmp & 0x7f; 00789 *type_is_aperture = (tmp >> 7) & 0x01; 00790 00791 writeReg(0x81, 0x00); 00792 writeReg(0xFF, 0x06); 00793 writeReg(0x83, readReg( 0x83 & ~0x04)); 00794 writeReg(0xFF, 0x01); 00795 writeReg(0x00, 0x01); 00796 00797 writeReg(0xFF, 0x00); 00798 writeReg(0x80, 0x00); 00799 00800 return true; 00801 } 00802 00803 // Get sequence step enables 00804 // based on VL53L0X_GetSequenceStepEnables() 00805 void VL53L0X::getSequenceStepEnables(SequenceStepEnables * enables) 00806 { 00807 uint8_t sequence_config = readReg(SYSTEM_SEQUENCE_CONFIG); 00808 00809 enables->tcc = (sequence_config >> 4) & 0x1; 00810 enables->dss = (sequence_config >> 3) & 0x1; 00811 enables->msrc = (sequence_config >> 2) & 0x1; 00812 enables->pre_range = (sequence_config >> 6) & 0x1; 00813 enables->final_range = (sequence_config >> 7) & 0x1; 00814 } 00815 00816 // Get sequence step timeouts 00817 // based on get_sequence_step_timeout(), 00818 // but gets all timeouts instead of just the requested one, and also stores 00819 // intermediate values 00820 void VL53L0X::getSequenceStepTimeouts(SequenceStepEnables const * enables, SequenceStepTimeouts * timeouts) 00821 { 00822 timeouts->pre_range_vcsel_period_pclks = getVcselPulsePeriod(VcselPeriodPreRange); 00823 00824 timeouts->msrc_dss_tcc_mclks = readReg(MSRC_CONFIG_TIMEOUT_MACROP) + 1; 00825 timeouts->msrc_dss_tcc_us = 00826 timeoutMclksToMicroseconds(timeouts->msrc_dss_tcc_mclks, 00827 timeouts->pre_range_vcsel_period_pclks); 00828 00829 timeouts->pre_range_mclks = 00830 decodeTimeout(readReg16Bit(PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI)); 00831 timeouts->pre_range_us = 00832 timeoutMclksToMicroseconds(timeouts->pre_range_mclks, 00833 timeouts->pre_range_vcsel_period_pclks); 00834 00835 timeouts->final_range_vcsel_period_pclks = getVcselPulsePeriod(VcselPeriodFinalRange); 00836 00837 timeouts->final_range_mclks = 00838 decodeTimeout(readReg16Bit(FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI)); 00839 00840 if (enables->pre_range) 00841 { 00842 timeouts->final_range_mclks -= timeouts->pre_range_mclks; 00843 } 00844 00845 timeouts->final_range_us = 00846 timeoutMclksToMicroseconds(timeouts->final_range_mclks, 00847 timeouts->final_range_vcsel_period_pclks); 00848 } 00849 00850 // Decode sequence step timeout in MCLKs from register value 00851 // based on VL53L0X_decode_timeout() 00852 // Note: the original function returned a uint32_t, but the return value is 00853 // always stored in a uint16_t. 00854 uint16_t VL53L0X::decodeTimeout(uint16_t reg_val) 00855 { 00856 // format: "(LSByte * 2^MSByte) + 1" 00857 return (uint16_t)((reg_val & 0x00FF) << 00858 (uint16_t)((reg_val & 0xFF00) >> 8)) + 1; 00859 } 00860 00861 // Encode sequence step timeout register value from timeout in MCLKs 00862 // based on VL53L0X_encode_timeout() 00863 // Note: the original function took a uint16_t, but the argument passed to it 00864 // is always a uint16_t. 00865 uint16_t VL53L0X::encodeTimeout(uint16_t timeout_mclks) 00866 { 00867 // format: "(LSByte * 2^MSByte) + 1" 00868 00869 uint32_t ls_byte = 0; 00870 uint16_t ms_byte = 0; 00871 00872 if (timeout_mclks > 0) 00873 { 00874 ls_byte = timeout_mclks - 1; 00875 00876 while ((ls_byte & 0xFFFFFF00) > 0) 00877 { 00878 ls_byte >>= 1; 00879 ms_byte++; 00880 } 00881 00882 return (ms_byte << 8) | (ls_byte & 0xFF); 00883 } 00884 else { return 0; } 00885 } 00886 00887 // Convert sequence step timeout from MCLKs to microseconds with given VCSEL period in PCLKs 00888 // based on VL53L0X_calc_timeout_us() 00889 uint32_t VL53L0X::timeoutMclksToMicroseconds(uint16_t timeout_period_mclks, uint8_t vcsel_period_pclks) 00890 { 00891 uint32_t macro_period_ns = calcMacroPeriod(vcsel_period_pclks); 00892 00893 return ((timeout_period_mclks * macro_period_ns) + (macro_period_ns / 2)) / 1000; 00894 } 00895 00896 // Convert sequence step timeout from microseconds to MCLKs with given VCSEL period in PCLKs 00897 // based on VL53L0X_calc_timeout_mclks() 00898 uint32_t VL53L0X::timeoutMicrosecondsToMclks(uint32_t timeout_period_us, uint8_t vcsel_period_pclks) 00899 { 00900 uint32_t macro_period_ns = calcMacroPeriod(vcsel_period_pclks); 00901 00902 return (((timeout_period_us * 1000) + (macro_period_ns / 2)) / macro_period_ns); 00903 } 00904 00905 00906 // based on VL53L0X_perform_single_ref_calibration() 00907 bool VL53L0X::performSingleRefCalibration(uint8_t vhv_init_byte) 00908 { 00909 writeReg(SYSRANGE_START, 0x01 | vhv_init_byte); // VL53L0X_REG_SYSRANGE_MODE_START_STOP 00910 00911 startTimeout(); 00912 while ((readReg(RESULT_INTERRUPT_STATUS) & 0x07) == 0) 00913 { 00914 if (checkTimeoutExpired()) { return false; } 00915 } 00916 00917 writeReg(SYSTEM_INTERRUPT_CLEAR, 0x01); 00918 00919 writeReg(SYSRANGE_START, 0x00); 00920 00921 return true; 00922 } 00923 00924 // Write an 8-bit register 00925 void VL53L0X::writeReg(uint8_t reg, uint8_t value) 00926 { 00927 char data_write[2]; 00928 data_write[0]=reg; 00929 data_write[1]=value; 00930 m_i2c.write(m_addr,data_write,2); 00931 } 00932 00933 // Write a 16-bit register 00934 void VL53L0X::writeReg16Bit(uint8_t reg, uint16_t value) 00935 { 00936 char data_write[3]; 00937 data_write[0]=reg; 00938 data_write[1]=(value >> 8) & 0xFF; // value high byte 00939 data_write[2]=value & 0xFF; // value low byte 00940 m_i2c.write(m_addr,data_write,3); 00941 } 00942 00943 // Write a 32-bit register 00944 void VL53L0X::writeReg32Bit(uint8_t reg, uint32_t value) 00945 { 00946 char data_write[5]; 00947 data_write[0]=reg; 00948 data_write[1]=(value >> 24) & 0xFF; // value highest byte 00949 data_write[2]=(value >> 16) & 0xFF; 00950 data_write[3]=(value >> 8) & 0xFF; 00951 data_write[4]= value & 0xFF; // value lowest byte 00952 m_i2c.write(m_addr,data_write,5); 00953 } 00954 00955 // Read an 8-bit register 00956 uint8_t VL53L0X::readReg(uint8_t reg) 00957 { 00958 uint8_t value; 00959 char data_write[1]; 00960 char data_read[1]; 00961 00962 data_write[0]=reg; 00963 m_i2c.write(m_addr,data_write,1); 00964 m_i2c.read(m_addr,data_read,1); 00965 value=data_read[0]; 00966 return value; 00967 } 00968 00969 // Read a 16-bit register 00970 uint16_t VL53L0X::readReg16Bit(uint8_t reg) 00971 { 00972 uint16_t value; 00973 uint8_t data_high; 00974 uint8_t data_low; 00975 char data_write[1]; 00976 char data_read[2]; 00977 00978 data_write[0]=reg; 00979 m_i2c.write(m_addr,data_write,1); 00980 m_i2c.read(m_addr,data_read,2); 00981 data_high=data_read[0]; // value high byte 00982 data_low=data_read[1]; // value low byte 00983 value = (data_high << 8)| data_low; 00984 00985 return value; 00986 } 00987 00988 // Read a 32-bit register 00989 uint32_t VL53L0X::readReg32Bit(uint8_t reg) 00990 { 00991 uint32_t value; 00992 uint8_t data_high; 00993 uint8_t data_2; 00994 uint8_t data_1; 00995 uint8_t data_low; 00996 char data_write[1]; 00997 char data_read[4]; 00998 00999 data_write[0]=reg; 01000 m_i2c.write(m_addr,data_write,1); 01001 m_i2c.read(m_addr,data_read,4); 01002 01003 data_high=data_read[0]; 01004 data_2=data_read[1]; 01005 data_1=data_read[2]; 01006 data_low=data_read[3]; 01007 01008 value = (data_high << 24)|(data_2 << 16)|(data_1 << 8)|(data_low); // value highest byte 01009 01010 return value; 01011 } 01012 01013 // Write an arbitrary number of bytes from the given array to the sensor, 01014 // starting at the given register 01015 void VL53L0X::writeMulti(uint8_t reg, char src[], uint8_t count) 01016 { 01017 char data_write[1]; 01018 data_write[0]=reg; 01019 m_i2c.write(m_addr,data_write,1); 01020 m_i2c.write(m_addr,src,count); 01021 } 01022 01023 // Read an arbitrary number of bytes from the sensor, starting at the given 01024 // register, into the given array 01025 void VL53L0X::readMulti(uint8_t reg, char dst[], uint8_t count) 01026 { 01027 char data_write[1]; 01028 data_write[0]=reg; 01029 m_i2c.write(m_addr,data_write,1); 01030 m_i2c.read(m_addr,dst,count); 01031 }
Generated on Fri Jul 15 2022 06:34:21 by
1.7.2