2 * This file is part of INAV.
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
6 * You can obtain one at http://mozilla.org/MPL/2.0/.
8 * Alternatively, the contents of this file may be used under the terms
9 * of the GNU General Public License Version 3, as described below:
11 * This file is free software: you may copy, redistribute and/or modify
12 * it under the terms of the GNU General Public License as published by the
13 * Free Software Foundation, either version 3 of the License, or (at your
14 * option) any later version.
16 * This file is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
19 * Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program. If not, see http://www.gnu.org/licenses/.
24 * =================================================================
25 * Substantial part of VL53L0X API is derived from Pololu VL53L0X library.
26 * The following applies to code derived from Pololu libraries:
28 * Copyright (c) 2017 Pololu Corporation. For more information, see
30 * https://www.pololu.com/
31 * https://forum.pololu.com/
33 * Permission is hereby granted, free of charge, to any person
34 * obtaining a copy of this software and associated documentation
35 * files (the "Software"), to deal in the Software without
36 * restriction, including without limitation the rights to use,
37 * copy, modify, merge, publish, distribute, sublicense, and/or sell
38 * copies of the Software, and to permit persons to whom the
39 * Software is furnished to do so, subject to the following
42 * The above copyright notice and this permission notice shall be
43 * included in all copies or substantial portions of the Software.
45 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
46 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
47 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
48 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
49 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
50 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
51 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
52 * OTHER DEALINGS IN THE SOFTWARE.
54 * =================================================================
56 * Most of the functionality of this library is based on the VL53L0X
57 * API provided by ST (STSW-IMG005), and some of the explanatory
58 * comments are quoted or paraphrased from the API source code, API
59 * user manual (UM2039), and the VL53L0X datasheet.
61 * The following applies to source code reproduced or derived from
64 * -----------------------------------------------------------------
66 * Copyright © 2016, STMicroelectronics International N.V. All
69 * Redistribution and use in source and binary forms, with or
70 * without modification, are permitted provided that the following
72 * - Redistributions of source code must retain the above copyright
73 * notice, this list of conditions and the following disclaimer.
74 * - Redistributions in binary form must reproduce the above
75 * copyright notice, this list of conditions and the following
76 * disclaimer in the documentation and/or other materials provided
77 * with the distribution.
78 * - Neither the name of STMicroelectronics nor the
79 * names of its contributors may be used to endorse or promote
80 * products derived from this software without specific prior
83 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
84 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
85 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
86 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
87 * NON-INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS ARE DISCLAIMED.
88 * IN NO EVENT SHALL STMICROELECTRONICS INTERNATIONAL N.V. BE LIABLE
89 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
90 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
91 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
92 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
93 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
94 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
95 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
102 #include "platform.h"
104 #if defined(USE_RANGEFINDER) && defined(USE_RANGEFINDER_VL53L0X)
106 #include "build/build_config.h"
108 #include "drivers/time.h"
109 #include "drivers/bus_i2c.h"
111 #include "drivers/rangefinder/rangefinder.h"
112 #include "drivers/rangefinder/rangefinder_vl53l0x.h"
114 #include "build/debug.h"
116 #define VL53L0X_MAX_RANGE_CM 250
117 #define VL53L0X_DETECTION_CONE_DECIDEGREES 900
119 #define VL53L0X_I2C_ADDRESS 0x29
121 /** @defgroup VL53L0X_DefineRegisters_group Define Registers
122 * @brief List of all the defined registers
125 #define VL53L0X_REG_SYSRANGE_START 0x00
126 #define VL53L0X_REG_SYSTEM_THRESH_HIGH 0x0C
127 #define VL53L0X_REG_SYSTEM_THRESH_LOW 0x0E
128 #define VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG 0x01
129 #define VL53L0X_REG_SYSTEM_RANGE_CONFIG 0x09
130 #define VL53L0X_REG_SYSTEM_INTERMEASUREMENT_PERIOD 0x04
131 #define VL53L0X_REG_SYSTEM_INTERRUPT_CONFIG_GPIO 0x0A
132 #define VL53L0X_REG_GPIO_HV_MUX_ACTIVE_HIGH 0x84
133 #define VL53L0X_REG_SYSTEM_INTERRUPT_CLEAR 0x0B
135 /* Result registers */
136 #define VL53L0X_REG_RESULT_INTERRUPT_STATUS 0x13
137 #define VL53L0X_REG_RESULT_RANGE_STATUS 0x14
139 #define VL53L0X_REG_RESULT_CORE_PAGE 1
140 #define VL53L0X_REG_RESULT_CORE_AMBIENT_WINDOW_EVENTS_RTN 0xBC
141 #define VL53L0X_REG_RESULT_CORE_RANGING_TOTAL_EVENTS_RTN 0xC0
142 #define VL53L0X_REG_RESULT_CORE_AMBIENT_WINDOW_EVENTS_REF 0xD0
143 #define VL53L0X_REG_RESULT_CORE_RANGING_TOTAL_EVENTS_REF 0xD4
144 #define VL53L0X_REG_RESULT_PEAK_SIGNAL_RATE_REF 0xB6
147 #define VL53L0X_REG_ALGO_PART_TO_PART_RANGE_OFFSET_MM 0x28
149 #define VL53L0X_REG_I2C_SLAVE_DEVICE_ADDRESS 0x8a
151 /* Check Limit registers */
152 #define VL53L0X_REG_MSRC_CONFIG_CONTROL 0x60
154 #define VL53L0X_REG_PRE_RANGE_CONFIG_MIN_SNR 0x27
155 #define VL53L0X_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW 0x56
156 #define VL53L0X_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH 0x57
157 #define VL53L0X_REG_PRE_RANGE_MIN_COUNT_RATE_RTN_LIMIT 0x64
159 #define VL53L0X_REG_FINAL_RANGE_CONFIG_MIN_SNR 0x67
160 #define VL53L0X_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW 0x47
161 #define VL53L0X_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH 0x48
162 #define VL53L0X_REG_FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT 0x44
165 #define VL53L0X_REG_PRE_RANGE_CONFIG_SIGMA_THRESH_HI 0x61
166 #define VL53L0X_REG_PRE_RANGE_CONFIG_SIGMA_THRESH_LO 0x62
168 /* PRE RANGE registers */
169 #define VL53L0X_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD 0x50
170 #define VL53L0X_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI 0x51
171 #define VL53L0X_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_LO 0x52
173 #define VL53L0X_REG_SYSTEM_HISTOGRAM_BIN 0x81
174 #define VL53L0X_REG_HISTOGRAM_CONFIG_INITIAL_PHASE_SELECT 0x33
175 #define VL53L0X_REG_HISTOGRAM_CONFIG_READOUT_CTRL 0x55
177 #define VL53L0X_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD 0x70
178 #define VL53L0X_REG_FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI 0x71
179 #define VL53L0X_REG_FINAL_RANGE_CONFIG_TIMEOUT_MACROP_LO 0x72
180 #define VL53L0X_REG_CROSSTALK_COMPENSATION_PEAK_RATE_MCPS 0x20
182 #define VL53L0X_REG_MSRC_CONFIG_TIMEOUT_MACROP 0x46
185 #define VL53L0X_REG_SOFT_RESET_GO2_SOFT_RESET_N 0xbf
186 #define VL53L0X_REG_IDENTIFICATION_MODEL_ID 0xc0
187 #define VL53L0X_REG_IDENTIFICATION_REVISION_ID 0xc2
189 #define VL53L0X_REG_OSC_CALIBRATE_VAL 0xf8
191 #define VL53L0X_REG_GLOBAL_CONFIG_VCSEL_WIDTH 0x32
192 #define VL53L0X_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_0 0xB0
193 #define VL53L0X_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_1 0xB1
194 #define VL53L0X_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_2 0xB2
195 #define VL53L0X_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_3 0xB3
196 #define VL53L0X_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_4 0xB4
197 #define VL53L0X_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_5 0xB5
199 #define VL53L0X_REG_GLOBAL_CONFIG_REF_EN_START_SELECT 0xB6
200 #define VL53L0X_REG_DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD 0x4E /* 0x14E */
201 #define VL53L0X_REG_DYNAMIC_SPAD_REF_EN_START_OFFSET 0x4F /* 0x14F */
202 #define VL53L0X_REG_POWER_MANAGEMENT_GO1_POWER_FORCE 0x80
204 #define VL53L0X_REG_VHV_CONFIG_PAD_SCL_SDA__EXTSUP_HV 0x89
206 #define VL53L0X_REG_ALGO_PHASECAL_LIM 0x30 /* 0x130 */
207 #define VL53L0X_REG_ALGO_PHASECAL_CONFIG_TIMEOUT 0x30
209 #define setTimeout(timeout) {timeoutValueMs = timeout;}
210 #define getTimeout() (timeoutValueMs)
211 #define startTimeout() (timeoutStartMs = millis())
212 #define checkTimeoutExpired() (timeoutValueMs > 0 && ((uint16_t)millis() - timeoutStartMs) > timeoutValueMs)
213 #define decodeVcselPeriod(reg_val) (((reg_val) + 1) << 1)
214 #define encodeVcselPeriod(period_pclks) (((period_pclks) >> 1) - 1)
215 #define calcMacroPeriod(vcsel_period_pclks) ((((uint32_t)2304 * (vcsel_period_pclks) * 1655) + 500) / 1000)
219 VcselPeriodFinalRange
226 } measurementSteps_e
;
234 } sequenceStepEnables_t
;
237 uint16_t pre_range_vcsel_period_pclks
;
238 uint16_t final_range_vcsel_period_pclks
;
239 uint16_t msrc_dss_tcc_mclks
;
240 uint16_t pre_range_mclks
;
241 uint16_t final_range_mclks
;
242 uint32_t msrc_dss_tcc_us
;
243 uint16_t pre_range_us
;
244 uint16_t final_range_us
;
245 } sequenceStepTimeouts_t
;
247 static int32_t lastMeasurementCm
= RANGEFINDER_OUT_OF_RANGE
;
248 static bool lastMeasurementIsNew
= false;
249 static uint8_t stopVariable
= 0; // StopVariable field of VL53L0X_DevData_t structure in ST's API
250 static bool isInitialized
= false;
251 static bool isResponding
= true;
252 static uint32_t measurementTimingBudgetUs
;
253 static timeMs_t timeoutStartMs
= 0;
254 static timeMs_t timeoutValueMs
= 0;
255 static measurementSteps_e measSteps
= MEASUREMENT_START
;
257 static uint8_t readReg(busDevice_t
* busDev
, uint8_t reg
)
260 isResponding
= busRead(busDev
, reg
, &byte
);
264 static uint16_t readReg16(busDevice_t
* busDev
, uint8_t reg
)
267 isResponding
= busReadBuf(busDev
, reg
, bytes
, 2);
268 return ((uint16_t)bytes
[0] << 8) |
269 ((uint16_t)bytes
[1] << 0);
272 static void readMulti(busDevice_t
* busDev
, uint8_t reg
, uint8_t * dst
, uint8_t count
)
274 isResponding
= busReadBuf(busDev
, reg
, dst
, count
);
277 static void writeReg(busDevice_t
* busDev
, uint8_t reg
, uint8_t value
)
279 isResponding
= busWrite(busDev
, reg
, value
);
282 static void writeReg16(busDevice_t
* busDev
, uint8_t reg
, uint16_t value
)
285 bytes
[0] = (value
>> 8) & 0xFF;
286 bytes
[1] = (value
>> 0) & 0xFF;
287 isResponding
= busWriteBuf(busDev
, reg
, bytes
, 2);
291 static void writeReg32(busDevice_t * busDev, uint8_t reg, uint16_t value)
294 bytes[0] = (value >> 24) & 0xFF;
295 bytes[1] = (value >> 16) & 0xFF;
296 bytes[2] = (value >> 8) & 0xFF;
297 bytes[3] = (value >> 0) & 0xFF;
298 isResponding = busWriteBuf(busDev, reg, bytes, 4);
302 static void writeMulti(busDevice_t
* busDev
, uint8_t reg
, uint8_t const * src
, uint8_t count
)
304 isResponding
= busWriteBuf(busDev
, reg
, src
, count
);
308 // Convert sequence step timeout from MCLKs to microseconds with given VCSEL period in PCLKs
309 // based on VL53L0X_calc_timeout_us()
310 uint32_t timeoutMclksToMicroseconds(uint16_t timeout_period_mclks
, uint8_t vcsel_period_pclks
)
312 uint32_t macro_period_ns
= calcMacroPeriod(vcsel_period_pclks
);
313 return ((timeout_period_mclks
* macro_period_ns
) + (macro_period_ns
/ 2)) / 1000;
316 // Convert sequence step timeout from microseconds to MCLKs with given VCSEL period in PCLKs
317 // based on VL53L0X_calc_timeout_mclks()
318 uint32_t timeoutMicrosecondsToMclks(uint32_t timeout_period_us
, uint8_t vcsel_period_pclks
)
320 uint32_t macro_period_ns
= calcMacroPeriod(vcsel_period_pclks
);
321 return (((timeout_period_us
* 1000) + (macro_period_ns
/ 2)) / macro_period_ns
);
324 // Decode sequence step timeout in MCLKs from register value
325 // based on VL53L0X_decode_timeout()
326 // Note: the original function returned a uint32_t, but the return value is
327 // always stored in a uint16_t.
328 uint16_t decodeTimeout(uint16_t reg_val
)
330 // format: "(LSByte * 2^MSByte) + 1"
331 return (uint16_t)((reg_val
& 0x00FF) << (uint16_t)((reg_val
& 0xFF00) >> 8)) + 1;
334 // Encode sequence step timeout register value from timeout in MCLKs
335 // based on VL53L0X_encode_timeout()
336 // Note: the original function took a uint16_t, but the argument passed to it
337 // is always a uint16_t.
338 uint16_t encodeTimeout(uint16_t timeout_mclks
)
340 // format: "(LSByte * 2^MSByte) + 1"
342 uint32_t ls_byte
= 0;
343 uint16_t ms_byte
= 0;
345 if (timeout_mclks
> 0) {
346 ls_byte
= timeout_mclks
- 1;
348 while ((ls_byte
& 0xFFFFFF00) > 0) {
353 return (ms_byte
<< 8) | (ls_byte
& 0xFF);
360 // Set the return signal rate limit check value in units of MCPS (mega counts
361 // per second). "This represents the amplitude of the signal reflected from the
362 // target and detected by the device"; setting this limit presumably determines
363 // the minimum measurement necessary for the sensor to report a valid reading.
364 // Setting a lower limit increases the potential range of the sensor but also
365 // seems to increase the likelihood of getting an inaccurate reading because of
366 // unwanted reflections from objects other than the intended target.
367 // Defaults to 0.25 MCPS as initialized by the ST API and this library.
368 bool setSignalRateLimit(busDevice_t
* busDev
, float limit_Mcps
)
370 if (limit_Mcps
< 0 || limit_Mcps
> 511.99f
) {
374 // Q9.7 fixed point format (9 integer bits, 7 fractional bits)
375 writeReg16(busDev
, VL53L0X_REG_FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT
, limit_Mcps
* (1 << 7));
379 // Get the return signal rate limit check value in MCPS
380 float getSignalRateLimit(busDevice_t
* busDev
)
382 return (float)readReg16(busDev
, VL53L0X_REG_FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT
) / (1 << 7);
385 // based on VL53L0X_perform_single_ref_calibration()
386 bool performSingleRefCalibration(busDevice_t
* busDev
, uint8_t vhv_init_byte
)
388 writeReg(busDev
, VL53L0X_REG_SYSRANGE_START
, 0x01 | vhv_init_byte
); // VL53L0X_REG_SYSRANGE_MODE_START_STOP
391 while ((readReg(busDev
, VL53L0X_REG_RESULT_INTERRUPT_STATUS
) & 0x07) == 0) {
392 if (checkTimeoutExpired()) {
397 writeReg(busDev
, VL53L0X_REG_SYSTEM_INTERRUPT_CLEAR
, 0x01);
399 writeReg(busDev
, VL53L0X_REG_SYSRANGE_START
, 0x00);
404 // Get sequence step enables
405 // based on VL53L0X_GetSequenceStepEnables()
406 void getSequenceStepEnables(busDevice_t
* busDev
, sequenceStepEnables_t
* enables
)
408 uint8_t sequence_config
= readReg(busDev
, VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG
);
410 enables
->tcc
= (sequence_config
>> 4) & 0x1;
411 enables
->dss
= (sequence_config
>> 3) & 0x1;
412 enables
->msrc
= (sequence_config
>> 2) & 0x1;
413 enables
->pre_range
= (sequence_config
>> 6) & 0x1;
414 enables
->final_range
= (sequence_config
>> 7) & 0x1;
417 // Get the VCSEL pulse period in PCLKs for the given period type.
418 // based on VL53L0X_get_vcsel_pulse_period()
419 uint8_t getVcselPulsePeriod(busDevice_t
* busDev
, vcselPeriodType_e type
)
421 if (type
== VcselPeriodPreRange
) {
422 return decodeVcselPeriod(readReg(busDev
, VL53L0X_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD
));
424 else if (type
== VcselPeriodFinalRange
) {
425 return decodeVcselPeriod(readReg(busDev
, VL53L0X_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD
));
432 // Get sequence step timeouts
433 // based on get_sequence_step_timeout(),
434 // but gets all timeouts instead of just the requested one, and also stores
435 // intermediate values
436 void getSequenceStepTimeouts(busDevice_t
* busDev
, sequenceStepEnables_t
const * enables
, sequenceStepTimeouts_t
* timeouts
)
438 timeouts
->pre_range_vcsel_period_pclks
= getVcselPulsePeriod(busDev
, VcselPeriodPreRange
);
440 timeouts
->msrc_dss_tcc_mclks
= readReg(busDev
, VL53L0X_REG_MSRC_CONFIG_TIMEOUT_MACROP
) + 1;
441 timeouts
->msrc_dss_tcc_us
= timeoutMclksToMicroseconds(timeouts
->msrc_dss_tcc_mclks
, timeouts
->pre_range_vcsel_period_pclks
);
443 timeouts
->pre_range_mclks
= decodeTimeout(readReg16(busDev
, VL53L0X_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI
));
444 timeouts
->pre_range_us
= timeoutMclksToMicroseconds(timeouts
->pre_range_mclks
, timeouts
->pre_range_vcsel_period_pclks
);
446 timeouts
->final_range_vcsel_period_pclks
= getVcselPulsePeriod(busDev
, VcselPeriodFinalRange
);
448 timeouts
->final_range_mclks
= decodeTimeout(readReg16(busDev
, VL53L0X_REG_FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI
));
450 if (enables
->pre_range
) {
451 timeouts
->final_range_mclks
-= timeouts
->pre_range_mclks
;
454 timeouts
->final_range_us
= timeoutMclksToMicroseconds(timeouts
->final_range_mclks
, timeouts
->final_range_vcsel_period_pclks
);
457 // Set the measurement timing budget in microseconds, which is the time allowed
458 // for one measurement; the ST API and this library take care of splitting the
459 // timing budget among the sub-steps in the ranging sequence. A longer timing
460 // budget allows for more accurate measurements. Increasing the budget by a
461 // factor of N decreases the range measurement standard deviation by a factor of
462 // sqrt(N). Defaults to about 33 milliseconds; the minimum is 20 ms.
463 // based on VL53L0X_set_measurement_timing_budget_micro_seconds()
464 bool setMeasurementTimingBudget(busDevice_t
* busDev
, uint32_t budget_us
)
466 sequenceStepEnables_t enables
;
467 sequenceStepTimeouts_t timeouts
;
469 const uint16_t StartOverhead
= 1320; // note that this is different than the value in get_
470 const uint16_t EndOverhead
= 960;
471 const uint16_t MsrcOverhead
= 660;
472 const uint16_t TccOverhead
= 590;
473 const uint16_t DssOverhead
= 690;
474 const uint16_t PreRangeOverhead
= 660;
475 const uint16_t FinalRangeOverhead
= 550;
477 uint32_t const MinTimingBudget
= 20000;
479 if (budget_us
< MinTimingBudget
) { return false; }
481 uint32_t used_budget_us
= StartOverhead
+ EndOverhead
;
483 getSequenceStepEnables(busDev
, &enables
);
484 getSequenceStepTimeouts(busDev
, &enables
, &timeouts
);
487 used_budget_us
+= (timeouts
.msrc_dss_tcc_us
+ TccOverhead
);
491 used_budget_us
+= 2 * (timeouts
.msrc_dss_tcc_us
+ DssOverhead
);
493 else if (enables
.msrc
) {
494 used_budget_us
+= (timeouts
.msrc_dss_tcc_us
+ MsrcOverhead
);
497 if (enables
.pre_range
) {
498 used_budget_us
+= (timeouts
.pre_range_us
+ PreRangeOverhead
);
501 if (enables
.final_range
) {
502 used_budget_us
+= FinalRangeOverhead
;
504 // "Note that the final range timeout is determined by the timing
505 // budget and the sum of all other timeouts within the sequence.
506 // If there is no room for the final range timeout, then an error
507 // will be set. Otherwise the remaining time will be applied to
510 if (used_budget_us
> budget_us
) {
511 // "Requested timeout too big."
515 uint32_t final_range_timeout_us
= budget_us
- used_budget_us
;
517 // set_sequence_step_timeout() begin
518 // (SequenceStepId == VL53L0X_SEQUENCESTEP_FINAL_RANGE)
520 // "For the final range timeout, the pre-range timeout
521 // must be added. To do this both final and pre-range
522 // timeouts must be expressed in macro periods MClks
523 // because they have different vcsel periods."
525 uint16_t final_range_timeout_mclks
=
526 timeoutMicrosecondsToMclks(final_range_timeout_us
, timeouts
.final_range_vcsel_period_pclks
);
528 if (enables
.pre_range
) {
529 final_range_timeout_mclks
+= timeouts
.pre_range_mclks
;
532 writeReg16(busDev
, VL53L0X_REG_FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI
, encodeTimeout(final_range_timeout_mclks
));
534 // set_sequence_step_timeout() end
536 measurementTimingBudgetUs
= budget_us
; // store for internal reuse
542 // Get the measurement timing budget in microseconds
543 // based on VL53L0X_get_measurement_timing_budget_micro_seconds()
545 uint32_t getMeasurementTimingBudget(busDevice_t
* busDev
)
547 sequenceStepEnables_t enables
;
548 sequenceStepTimeouts_t timeouts
;
550 const uint16_t StartOverhead
= 1910; // note that this is different than the value in set_
551 const uint16_t EndOverhead
= 960;
552 const uint16_t MsrcOverhead
= 660;
553 const uint16_t TccOverhead
= 590;
554 const uint16_t DssOverhead
= 690;
555 const uint16_t PreRangeOverhead
= 660;
556 const uint16_t FinalRangeOverhead
= 550;
558 // "Start and end overhead times always present"
559 uint32_t budget_us
= StartOverhead
+ EndOverhead
;
561 getSequenceStepEnables(busDev
, &enables
);
562 getSequenceStepTimeouts(busDev
, &enables
, &timeouts
);
565 budget_us
+= (timeouts
.msrc_dss_tcc_us
+ TccOverhead
);
569 budget_us
+= 2 * (timeouts
.msrc_dss_tcc_us
+ DssOverhead
);
571 else if (enables
.msrc
) {
572 budget_us
+= (timeouts
.msrc_dss_tcc_us
+ MsrcOverhead
);
575 if (enables
.pre_range
) {
576 budget_us
+= (timeouts
.pre_range_us
+ PreRangeOverhead
);
579 if (enables
.final_range
) {
580 budget_us
+= (timeouts
.final_range_us
+ FinalRangeOverhead
);
583 measurementTimingBudgetUs
= budget_us
; // store for internal reuse
587 // Set the VCSEL (vertical cavity surface emitting laser) pulse period for the
588 // given period type (pre-range or final range) to the given value in PCLKs.
589 // Longer periods seem to increase the potential range of the sensor.
590 // Valid values are (even numbers only):
591 // pre: 12 to 18 (initialized default: 14)
592 // final: 8 to 14 (initialized default: 10)
593 // based on VL53L0X_set_vcsel_pulse_period()
594 bool setVcselPulsePeriod(busDevice_t
* busDev
, vcselPeriodType_e type
, uint8_t period_pclks
)
596 uint8_t vcsel_period_reg
= encodeVcselPeriod(period_pclks
);
598 sequenceStepEnables_t enables
;
599 sequenceStepTimeouts_t timeouts
;
601 getSequenceStepEnables(busDev
, &enables
);
602 getSequenceStepTimeouts(busDev
, &enables
, &timeouts
);
604 // "Apply specific settings for the requested clock period"
605 // "Re-calculate and apply timeouts, in macro periods"
607 // "When the VCSEL period for the pre or final range is changed,
608 // the corresponding timeout must be read from the device using
609 // the current VCSEL period, then the new VCSEL period can be
610 // applied. The timeout then must be written back to the device
611 // using the new VCSEL period.
613 // For the MSRC timeout, the same applies - this timeout being
614 // dependant on the pre-range vcsel period."
617 if (type
== VcselPeriodPreRange
) {
618 // "Set phase check limits"
619 switch (period_pclks
) {
621 writeReg(busDev
, VL53L0X_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH
, 0x18);
625 writeReg(busDev
, VL53L0X_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH
, 0x30);
629 writeReg(busDev
, VL53L0X_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH
, 0x40);
633 writeReg(busDev
, VL53L0X_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH
, 0x50);
641 writeReg(busDev
, VL53L0X_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW
, 0x08);
643 // apply new VCSEL period
644 writeReg(busDev
, VL53L0X_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD
, vcsel_period_reg
);
648 // set_sequence_step_timeout() begin
649 // (SequenceStepId == VL53L0X_SEQUENCESTEP_PRE_RANGE)
651 uint16_t new_pre_range_timeout_mclks
= timeoutMicrosecondsToMclks(timeouts
.pre_range_us
, period_pclks
);
653 writeReg16(busDev
, VL53L0X_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI
, encodeTimeout(new_pre_range_timeout_mclks
));
655 // set_sequence_step_timeout() end
657 // set_sequence_step_timeout() begin
658 // (SequenceStepId == VL53L0X_SEQUENCESTEP_MSRC)
660 uint16_t new_msrc_timeout_mclks
= timeoutMicrosecondsToMclks(timeouts
.msrc_dss_tcc_us
, period_pclks
);
662 writeReg(busDev
, VL53L0X_REG_MSRC_CONFIG_TIMEOUT_MACROP
, (new_msrc_timeout_mclks
> 256) ? 255 : (new_msrc_timeout_mclks
- 1));
664 // set_sequence_step_timeout() end
666 else if (type
== VcselPeriodFinalRange
) {
667 switch (period_pclks
) {
669 writeReg(busDev
, VL53L0X_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH
, 0x10);
670 writeReg(busDev
, VL53L0X_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW
, 0x08);
671 writeReg(busDev
, VL53L0X_REG_GLOBAL_CONFIG_VCSEL_WIDTH
, 0x02);
672 writeReg(busDev
, VL53L0X_REG_ALGO_PHASECAL_CONFIG_TIMEOUT
, 0x0C);
673 writeReg(busDev
, 0xFF, 0x01);
674 writeReg(busDev
, VL53L0X_REG_ALGO_PHASECAL_LIM
, 0x30);
675 writeReg(busDev
, 0xFF, 0x00);
679 writeReg(busDev
, VL53L0X_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH
, 0x28);
680 writeReg(busDev
, VL53L0X_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW
, 0x08);
681 writeReg(busDev
, VL53L0X_REG_GLOBAL_CONFIG_VCSEL_WIDTH
, 0x03);
682 writeReg(busDev
, VL53L0X_REG_ALGO_PHASECAL_CONFIG_TIMEOUT
, 0x09);
683 writeReg(busDev
, 0xFF, 0x01);
684 writeReg(busDev
, VL53L0X_REG_ALGO_PHASECAL_LIM
, 0x20);
685 writeReg(busDev
, 0xFF, 0x00);
689 writeReg(busDev
, VL53L0X_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH
, 0x38);
690 writeReg(busDev
, VL53L0X_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW
, 0x08);
691 writeReg(busDev
, VL53L0X_REG_GLOBAL_CONFIG_VCSEL_WIDTH
, 0x03);
692 writeReg(busDev
, VL53L0X_REG_ALGO_PHASECAL_CONFIG_TIMEOUT
, 0x08);
693 writeReg(busDev
, 0xFF, 0x01);
694 writeReg(busDev
, VL53L0X_REG_ALGO_PHASECAL_LIM
, 0x20);
695 writeReg(busDev
, 0xFF, 0x00);
699 writeReg(busDev
, VL53L0X_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH
, 0x48);
700 writeReg(busDev
, VL53L0X_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW
, 0x08);
701 writeReg(busDev
, VL53L0X_REG_GLOBAL_CONFIG_VCSEL_WIDTH
, 0x03);
702 writeReg(busDev
, VL53L0X_REG_ALGO_PHASECAL_CONFIG_TIMEOUT
, 0x07);
703 writeReg(busDev
, 0xFF, 0x01);
704 writeReg(busDev
, VL53L0X_REG_ALGO_PHASECAL_LIM
, 0x20);
705 writeReg(busDev
, 0xFF, 0x00);
713 // apply new VCSEL period
714 writeReg(busDev
, VL53L0X_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD
, vcsel_period_reg
);
718 // set_sequence_step_timeout() begin
719 // (SequenceStepId == VL53L0X_SEQUENCESTEP_FINAL_RANGE)
721 // "For the final range timeout, the pre-range timeout
722 // must be added. To do this both final and pre-range
723 // timeouts must be expressed in macro periods MClks
724 // because they have different vcsel periods."
726 uint16_t new_final_range_timeout_mclks
= timeoutMicrosecondsToMclks(timeouts
.final_range_us
, period_pclks
);
728 if (enables
.pre_range
) {
729 new_final_range_timeout_mclks
+= timeouts
.pre_range_mclks
;
732 writeReg16(busDev
, VL53L0X_REG_FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI
, encodeTimeout(new_final_range_timeout_mclks
));
733 // set_sequence_step_timeout end
740 // "Finally, the timing budget must be re-applied"
741 setMeasurementTimingBudget(busDev
, measurementTimingBudgetUs
);
743 // "Perform the phase calibration. This is needed after changing on vcsel period."
744 // VL53L0X_perform_phase_calibration() begin
746 uint8_t sequence_config
= readReg(busDev
, VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG
);
747 writeReg(busDev
, VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG
, 0x02);
748 performSingleRefCalibration(busDev
, 0x0);
749 writeReg(busDev
, VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG
, sequence_config
);
751 // VL53L0X_perform_phase_calibration() end
756 // Get reference SPAD (single photon avalanche diode) count and type
757 // based on VL53L0X_get_info_from_device(),
758 // but only gets reference SPAD count and type
759 bool getSpadInfo(busDevice_t
* busDev
, uint8_t * count
, bool * type_is_aperture
)
763 writeReg(busDev
, 0x80, 0x01);
764 writeReg(busDev
, 0xFF, 0x01);
765 writeReg(busDev
, 0x00, 0x00);
767 writeReg(busDev
, 0xFF, 0x06);
768 writeReg(busDev
, 0x83, readReg(busDev
, 0x83) | 0x04);
769 writeReg(busDev
, 0xFF, 0x07);
770 writeReg(busDev
, 0x81, 0x01);
772 writeReg(busDev
, 0x80, 0x01);
774 writeReg(busDev
, 0x94, 0x6b);
775 writeReg(busDev
, 0x83, 0x00);
778 while (readReg(busDev
, 0x83) == 0x00)
780 if (checkTimeoutExpired()) {
785 writeReg(busDev
, 0x83, 0x01);
786 tmp
= readReg(busDev
, 0x92);
789 *type_is_aperture
= (tmp
>> 7) & 0x01;
791 writeReg(busDev
, 0x81, 0x00);
792 writeReg(busDev
, 0xFF, 0x06);
793 writeReg(busDev
, 0x83, readReg(busDev
, 0x83) & ~0x04);
794 writeReg(busDev
, 0xFF, 0x01);
795 writeReg(busDev
, 0x00, 0x01);
797 writeReg(busDev
, 0xFF, 0x00);
798 writeReg(busDev
, 0x80, 0x00);
803 static void vl53l0x_Init(rangefinderDev_t
* rangefinder
)
806 isInitialized
= false;
808 // During init set timeout to a higher value
811 // VL53L0X_DataInit() begin
812 // Switch sensor to 2.8V mode
813 byte
= readReg(rangefinder
->busDev
, VL53L0X_REG_VHV_CONFIG_PAD_SCL_SDA__EXTSUP_HV
);
814 writeReg(rangefinder
->busDev
, VL53L0X_REG_VHV_CONFIG_PAD_SCL_SDA__EXTSUP_HV
, byte
| 0x01);
816 // Set I2C standard mode
817 writeReg(rangefinder
->busDev
, 0x88, 0x00);
819 writeReg(rangefinder
->busDev
, 0x80, 0x01);
820 writeReg(rangefinder
->busDev
, 0xFF, 0x01);
821 writeReg(rangefinder
->busDev
, 0x00, 0x00);
822 stopVariable
= readReg(rangefinder
->busDev
, 0x91);
823 writeReg(rangefinder
->busDev
, 0x00, 0x01);
824 writeReg(rangefinder
->busDev
, 0xFF, 0x00);
825 writeReg(rangefinder
->busDev
, 0x80, 0x00);
827 // disable SIGNAL_RATE_MSRC (bit 1) and SIGNAL_RATE_PRE_RANGE (bit 4) limit checks
828 byte
= readReg(rangefinder
->busDev
, VL53L0X_REG_MSRC_CONFIG_CONTROL
);
829 writeReg(rangefinder
->busDev
, VL53L0X_REG_MSRC_CONFIG_CONTROL
, byte
| 0x12);
831 // set final range signal rate limit to 0.25 MCPS (million counts per second)
832 setSignalRateLimit(rangefinder
->busDev
, 0.25);
834 writeReg(rangefinder
->busDev
, VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG
, 0xFF);
836 // VL53L0X_StaticInit() begin
839 bool spad_type_is_aperture
;
840 if (!getSpadInfo(rangefinder
->busDev
, &spad_count
, &spad_type_is_aperture
)) {
845 // The SPAD map (RefGoodSpadMap) is read by VL53L0X_get_info_from_device() in
846 // the API, but the same data seems to be more easily readable from
847 // GLOBAL_CONFIG_SPAD_ENABLES_REF_0 through _6, so read it from there
848 uint8_t ref_spad_map
[6];
849 readMulti(rangefinder
->busDev
, VL53L0X_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_0
, ref_spad_map
, 6);
851 // VL53L0X_set_reference_spads() begin (assume NVM values are valid)
852 writeReg(rangefinder
->busDev
, 0xFF, 0x01);
853 writeReg(rangefinder
->busDev
, VL53L0X_REG_DYNAMIC_SPAD_REF_EN_START_OFFSET
, 0x00);
854 writeReg(rangefinder
->busDev
, VL53L0X_REG_DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD
, 0x2C);
855 writeReg(rangefinder
->busDev
, 0xFF, 0x00);
856 writeReg(rangefinder
->busDev
, VL53L0X_REG_GLOBAL_CONFIG_REF_EN_START_SELECT
, 0xB4);
858 uint8_t first_spad_to_enable
= spad_type_is_aperture
? 12 : 0; // 12 is the first aperture spad
859 uint8_t spads_enabled
= 0;
861 for (uint8_t i
= 0; i
< 48; i
++)
863 if (i
< first_spad_to_enable
|| spads_enabled
== spad_count
)
865 // This bit is lower than the first one that should be enabled, or
866 // (reference_spad_count) bits have already been enabled, so zero this bit
867 ref_spad_map
[i
/ 8] &= ~(1 << (i
% 8));
869 else if ((ref_spad_map
[i
/ 8] >> (i
% 8)) & 0x1)
875 writeMulti(rangefinder
->busDev
, VL53L0X_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_0
, ref_spad_map
, 6);
877 // -- VL53L0X_load_tuning_settings() begin
878 // DefaultTuningSettings from vl53l0x_tuning.h
880 writeReg(rangefinder
->busDev
, 0xFF, 0x01);
881 writeReg(rangefinder
->busDev
, 0x00, 0x00);
883 writeReg(rangefinder
->busDev
, 0xFF, 0x00);
884 writeReg(rangefinder
->busDev
, 0x09, 0x00);
885 writeReg(rangefinder
->busDev
, 0x10, 0x00);
886 writeReg(rangefinder
->busDev
, 0x11, 0x00);
888 writeReg(rangefinder
->busDev
, 0x24, 0x01);
889 writeReg(rangefinder
->busDev
, 0x25, 0xFF);
890 writeReg(rangefinder
->busDev
, 0x75, 0x00);
892 writeReg(rangefinder
->busDev
, 0xFF, 0x01);
893 writeReg(rangefinder
->busDev
, 0x4E, 0x2C);
894 writeReg(rangefinder
->busDev
, 0x48, 0x00);
895 writeReg(rangefinder
->busDev
, 0x30, 0x20);
897 writeReg(rangefinder
->busDev
, 0xFF, 0x00);
898 writeReg(rangefinder
->busDev
, 0x30, 0x09);
899 writeReg(rangefinder
->busDev
, 0x54, 0x00);
900 writeReg(rangefinder
->busDev
, 0x31, 0x04);
901 writeReg(rangefinder
->busDev
, 0x32, 0x03);
902 writeReg(rangefinder
->busDev
, 0x40, 0x83);
903 writeReg(rangefinder
->busDev
, 0x46, 0x25);
904 writeReg(rangefinder
->busDev
, 0x60, 0x00);
905 writeReg(rangefinder
->busDev
, 0x27, 0x00);
906 writeReg(rangefinder
->busDev
, 0x50, 0x06);
907 writeReg(rangefinder
->busDev
, 0x51, 0x00);
908 writeReg(rangefinder
->busDev
, 0x52, 0x96);
909 writeReg(rangefinder
->busDev
, 0x56, 0x08);
910 writeReg(rangefinder
->busDev
, 0x57, 0x30);
911 writeReg(rangefinder
->busDev
, 0x61, 0x00);
912 writeReg(rangefinder
->busDev
, 0x62, 0x00);
913 writeReg(rangefinder
->busDev
, 0x64, 0x00);
914 writeReg(rangefinder
->busDev
, 0x65, 0x00);
915 writeReg(rangefinder
->busDev
, 0x66, 0xA0);
917 writeReg(rangefinder
->busDev
, 0xFF, 0x01);
918 writeReg(rangefinder
->busDev
, 0x22, 0x32);
919 writeReg(rangefinder
->busDev
, 0x47, 0x14);
920 writeReg(rangefinder
->busDev
, 0x49, 0xFF);
921 writeReg(rangefinder
->busDev
, 0x4A, 0x00);
923 writeReg(rangefinder
->busDev
, 0xFF, 0x00);
924 writeReg(rangefinder
->busDev
, 0x7A, 0x0A);
925 writeReg(rangefinder
->busDev
, 0x7B, 0x00);
926 writeReg(rangefinder
->busDev
, 0x78, 0x21);
928 writeReg(rangefinder
->busDev
, 0xFF, 0x01);
929 writeReg(rangefinder
->busDev
, 0x23, 0x34);
930 writeReg(rangefinder
->busDev
, 0x42, 0x00);
931 writeReg(rangefinder
->busDev
, 0x44, 0xFF);
932 writeReg(rangefinder
->busDev
, 0x45, 0x26);
933 writeReg(rangefinder
->busDev
, 0x46, 0x05);
934 writeReg(rangefinder
->busDev
, 0x40, 0x40);
935 writeReg(rangefinder
->busDev
, 0x0E, 0x06);
936 writeReg(rangefinder
->busDev
, 0x20, 0x1A);
937 writeReg(rangefinder
->busDev
, 0x43, 0x40);
939 writeReg(rangefinder
->busDev
, 0xFF, 0x00);
940 writeReg(rangefinder
->busDev
, 0x34, 0x03);
941 writeReg(rangefinder
->busDev
, 0x35, 0x44);
943 writeReg(rangefinder
->busDev
, 0xFF, 0x01);
944 writeReg(rangefinder
->busDev
, 0x31, 0x04);
945 writeReg(rangefinder
->busDev
, 0x4B, 0x09);
946 writeReg(rangefinder
->busDev
, 0x4C, 0x05);
947 writeReg(rangefinder
->busDev
, 0x4D, 0x04);
949 writeReg(rangefinder
->busDev
, 0xFF, 0x00);
950 writeReg(rangefinder
->busDev
, 0x44, 0x00);
951 writeReg(rangefinder
->busDev
, 0x45, 0x20);
952 writeReg(rangefinder
->busDev
, 0x47, 0x08);
953 writeReg(rangefinder
->busDev
, 0x48, 0x28);
954 writeReg(rangefinder
->busDev
, 0x67, 0x00);
955 writeReg(rangefinder
->busDev
, 0x70, 0x04);
956 writeReg(rangefinder
->busDev
, 0x71, 0x01);
957 writeReg(rangefinder
->busDev
, 0x72, 0xFE);
958 writeReg(rangefinder
->busDev
, 0x76, 0x00);
959 writeReg(rangefinder
->busDev
, 0x77, 0x00);
961 writeReg(rangefinder
->busDev
, 0xFF, 0x01);
962 writeReg(rangefinder
->busDev
, 0x0D, 0x01);
964 writeReg(rangefinder
->busDev
, 0xFF, 0x00);
965 writeReg(rangefinder
->busDev
, 0x80, 0x01);
966 writeReg(rangefinder
->busDev
, 0x01, 0xF8);
968 writeReg(rangefinder
->busDev
, 0xFF, 0x01);
969 writeReg(rangefinder
->busDev
, 0x8E, 0x01);
970 writeReg(rangefinder
->busDev
, 0x00, 0x01);
971 writeReg(rangefinder
->busDev
, 0xFF, 0x00);
972 writeReg(rangefinder
->busDev
, 0x80, 0x00);
974 // -- VL53L0X_SetGpioConfig() begin
976 writeReg(rangefinder
->busDev
, VL53L0X_REG_SYSTEM_INTERRUPT_CONFIG_GPIO
, 0x04);
977 writeReg(rangefinder
->busDev
, VL53L0X_REG_GPIO_HV_MUX_ACTIVE_HIGH
, readReg(rangefinder
->busDev
, VL53L0X_REG_GPIO_HV_MUX_ACTIVE_HIGH
) & ~0x10); // active low
978 writeReg(rangefinder
->busDev
, VL53L0X_REG_SYSTEM_INTERRUPT_CLEAR
, 0x01);
980 measurementTimingBudgetUs
= getMeasurementTimingBudget(rangefinder
->busDev
);
982 // "Disable MSRC and TCC by default"
983 // MSRC = Minimum Signal Rate Check
984 // TCC = Target CentreCheck
985 // -- VL53L0X_SetSequenceStepEnable() begin
987 writeReg(rangefinder
->busDev
, VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG
, 0xE8);
989 // "Recalculate timing budget"
990 setMeasurementTimingBudget(rangefinder
->busDev
, measurementTimingBudgetUs
);
992 // -- VL53L0X_perform_vhv_calibration() begin
993 writeReg(rangefinder
->busDev
, VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG
, 0x01);
994 if (!performSingleRefCalibration(rangefinder
->busDev
, 0x40)) {
998 // -- VL53L0X_perform_phase_calibration() begin
1000 writeReg(rangefinder
->busDev
, VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG
, 0x02);
1001 if (!performSingleRefCalibration(rangefinder
->busDev
, 0x00)) {
1005 // "restore the previous Sequence Config"
1006 writeReg(rangefinder
->busDev
, VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG
, 0xE8);
1008 // Apply range parameters
1010 setSignalRateLimit(rangefinder
->busDev
, 0.25f
);
1011 setVcselPulsePeriod(rangefinder
->busDev
, VcselPeriodPreRange
, 18);
1012 setVcselPulsePeriod(rangefinder
->busDev
, VcselPeriodFinalRange
, 14);
1018 // We are initialized
1019 isInitialized
= true;
1022 void vl53l0x_Update(rangefinderDev_t
* rangefinder
)
1024 if (!isInitialized
) {
1028 #if 1 // SINGLE MEASUREMENT MODE
1029 switch (measSteps
) {
1030 case MEASUREMENT_START
:
1031 // Initiate new measurement
1032 writeReg(rangefinder
->busDev
, 0x80, 0x01);
1033 writeReg(rangefinder
->busDev
, 0xFF, 0x01);
1034 writeReg(rangefinder
->busDev
, 0x00, 0x00);
1035 writeReg(rangefinder
->busDev
, 0x91, stopVariable
);
1036 writeReg(rangefinder
->busDev
, 0x00, 0x01);
1037 writeReg(rangefinder
->busDev
, 0xFF, 0x00);
1038 writeReg(rangefinder
->busDev
, 0x80, 0x00);
1039 writeReg(rangefinder
->busDev
, VL53L0X_REG_SYSRANGE_START
, 0x01);
1042 measSteps
= MEASUREMENT_WAIT
;
1045 case MEASUREMENT_WAIT
:
1046 // Wait for data and read the measurement
1047 if (readReg(rangefinder
->busDev
, VL53L0X_REG_SYSRANGE_START
) & 0x01) {
1048 if (checkTimeoutExpired()) {
1049 lastMeasurementCm
= RANGEFINDER_OUT_OF_RANGE
;
1050 measSteps
= MEASUREMENT_START
;
1055 measSteps
= MEASUREMENT_READ
;
1059 case MEASUREMENT_READ
:
1060 if ((readReg(rangefinder
->busDev
, VL53L0X_REG_RESULT_INTERRUPT_STATUS
) & 0x07) == 0) {
1061 if (checkTimeoutExpired()) {
1062 lastMeasurementCm
= RANGEFINDER_OUT_OF_RANGE
;
1063 measSteps
= MEASUREMENT_START
;
1067 // assumptions: Linearity Corrective Gain is 1000 (default);
1068 uint16_t raw
= readReg16(rangefinder
->busDev
, VL53L0X_REG_RESULT_RANGE_STATUS
+ 10);
1069 writeReg(rangefinder
->busDev
, VL53L0X_REG_SYSTEM_INTERRUPT_CLEAR
, 0x01);
1071 lastMeasurementCm
= raw
/ 10;
1072 lastMeasurementIsNew
= true;
1073 measSteps
= MEASUREMENT_START
;
1077 #else // CONTINUOUS MEASUREMENT MODE
1078 switch (measSteps
) {
1079 case MEASUREMENT_START
:
1080 // Initiate new measurement
1081 writeReg(rangefinder
->busDev
, 0x80, 0x01);
1082 writeReg(rangefinder
->busDev
, 0xFF, 0x01);
1083 writeReg(rangefinder
->busDev
, 0x00, 0x00);
1084 writeReg(rangefinder
->busDev
, 0x91, stopVariable
);
1085 writeReg(rangefinder
->busDev
, 0x00, 0x01);
1086 writeReg(rangefinder
->busDev
, 0xFF, 0x00);
1087 writeReg(rangefinder
->busDev
, 0x80, 0x00);
1089 uint16_t osc_calibrate_val
= readReg16(VL53L0X_REG_OSC_CALIBRATE_VAL
);
1091 if (osc_calibrate_val
!= 0) {
1092 writeReg32(rangefinder
->busDev
, VL53L0X_REG_SYSTEM_INTERMEASUREMENT_PERIOD
, 50 * osc_calibrate_val
);
1095 writeReg32(rangefinder
->busDev
, VL53L0X_REG_SYSTEM_INTERMEASUREMENT_PERIOD
, 50);
1098 writeReg(rangefinder
->busDev
, VL53L0X_REG_SYSRANGE_START
, 0x02); // VL53L0X_REG_SYSRANGE_MODE_BACKTOBACK
1101 measSteps
= MEASUREMENT_READ
;
1104 case MEASUREMENT_READ
:
1106 if ((readReg(rangefinder
->busDev
, VL53L0X_REG_RESULT_INTERRUPT_STATUS
) & 0x07) == 0) {
1107 if (checkTimeoutExpired()) {
1108 lastMeasurementCm
= RANGEFINDER_OUT_OF_RANGE
;
1112 measSteps
= MEASUREMENT_READ
;
1116 // assumptions: Linearity Corrective Gain is 1000 (default);
1117 uint16_t raw
= readReg16(rangefinder
->busDev
, VL53L0X_REG_RESULT_RANGE_STATUS
+ 10);
1118 writeReg(rangefinder
->busDev
, VL53L0X_REG_SYSTEM_INTERRUPT_CLEAR
, 0x01);
1120 lastMeasurementCm
= raw
/ 10;
1124 measSteps
= MEASUREMENT_READ
;
1131 int32_t vl53l0x_GetDistance(rangefinderDev_t
*dev
)
1135 if (isResponding
&& isInitialized
) {
1136 if (lastMeasurementIsNew
) {
1137 lastMeasurementIsNew
= false;
1138 return lastMeasurementCm
< VL53L0X_MAX_RANGE_CM
? lastMeasurementCm
: RANGEFINDER_OUT_OF_RANGE
;
1141 return RANGEFINDER_NO_NEW_DATA
;
1145 return RANGEFINDER_HARDWARE_FAILURE
;
1149 static bool deviceDetect(busDevice_t
* busDev
)
1151 for (int retry
= 0; retry
< 5; retry
++) {
1156 bool ack
= busRead(busDev
, VL53L0X_REG_IDENTIFICATION_MODEL_ID
, &model_id
);
1157 if (ack
&& model_id
== 0xEE) {
1166 bool vl53l0xDetect(rangefinderDev_t
* rangefinder
)
1168 rangefinder
->busDev
= busDeviceInit(BUSTYPE_I2C
, DEVHW_VL53L0X
, 0, OWNER_RANGEFINDER
);
1169 if (rangefinder
->busDev
== NULL
) {
1173 if (!deviceDetect(rangefinder
->busDev
)) {
1174 busDeviceDeInit(rangefinder
->busDev
);
1178 rangefinder
->delayMs
= RANGEFINDER_VL53L0X_TASK_PERIOD_MS
;
1179 rangefinder
->maxRangeCm
= VL53L0X_MAX_RANGE_CM
;
1180 rangefinder
->detectionConeDeciDegrees
= VL53L0X_DETECTION_CONE_DECIDEGREES
;
1181 rangefinder
->detectionConeExtendedDeciDegrees
= VL53L0X_DETECTION_CONE_DECIDEGREES
;
1183 rangefinder
->init
= &vl53l0x_Init
;
1184 rangefinder
->update
= &vl53l0x_Update
;
1185 rangefinder
->read
= &vl53l0x_GetDistance
;