FastArduino v1.10
C++ library to build fast but small Arduino/AVR projects
Loading...
Searching...
No Matches
vl53l0x.h
Go to the documentation of this file.
1// Copyright 2016-2023 Jean-Francois Poilpret
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
16
31#ifndef VL53L0X_H
32#define VL53L0X_H
33
34#include "../array.h"
35#include "../flash.h"
36#include "../i2c.h"
37#include "../functors.h"
38#include "../future.h"
39#include "../realtime_timer.h"
40#include "../time.h"
41#include "../utilities.h"
42#include "../i2c_handler.h"
43#include "../i2c_device.h"
44#include "../i2c_device_utilities.h"
45#include "vl53l0x_internals.h"
46#include "vl53l0x_registers.h"
47#include "vl53l0x_types.h"
48
49namespace devices
50{
59 namespace vl53l0x
60 {
61 }
62}
63
64namespace devices::vl53l0x
65{
67 namespace internals = vl53l0x_internals;
69
107 template<typename MANAGER>
108 class VL53L0X : public i2c::I2CDevice<MANAGER>
109 {
110 private:
112 using ABSTRACT_FUTURE = typename MANAGER::ABSTRACT_FUTURE;
113
114 template<Register REGISTER, typename T = uint8_t>
115 using TReadRegisterFuture =
117 template<Register REGISTER, typename T = uint8_t>
118 using TWriteRegisterFuture =
120
122
123 public:
129 explicit VL53L0X(MANAGER& manager) : PARENT{manager, DEFAULT_DEVICE_ADDRESS, i2c::I2C_FAST, false} {}
130
143 bool set_address(uint8_t device_address)
144 {
145 static constexpr uint8_t ADDRESS_MASK = 0x7F;
147 device_address &= ADDRESS_MASK;
148 if (!this->template sync_write<SetAddressFuture>(device_address)) return false;
149 this->set_device(uint8_t(device_address << 1));
150 return true;
151 }
152
175 bool begin(Profile profile)
176 {
177 static constexpr uint8_t LONG_RANGE_MASK = 0x01;
178 static constexpr uint8_t ACCURATE_MASK = 0x02;
179 static constexpr uint8_t FAST_MASK = 0x04;
180 static constexpr uint32_t ACCURATE_TIMING_BUDGET = 200'000UL;
181 static constexpr uint32_t FAST_TIMING_BUDGET = 20'000UL;
182 static constexpr uint8_t LONG_RANGE_VCSEL_PERIOD_PRE = 18;
183 static constexpr uint8_t LONG_RANGE_VCSEL_PERIOD_FINAL = 14;
184
185 if (!init_data_first()) return false;
186 uint8_t prof = uint8_t(profile);
188 SequenceSteps::create().pre_range().final_range().dss()))
189 return false;
190 if (!perform_ref_calibration()) return false;
191 if (prof & LONG_RANGE_MASK)
192 {
193 // long range
194 if (!set_vcsel_pulse_period<VcselPeriodType::PRE_RANGE>(LONG_RANGE_VCSEL_PERIOD_PRE)) return false;
195 if (!set_vcsel_pulse_period<VcselPeriodType::FINAL_RANGE>(LONG_RANGE_VCSEL_PERIOD_FINAL)) return false;
196 if (!set_signal_rate_limit(0.1)) return false;
197 }
198 if (prof & ACCURATE_MASK)
199 {
200 // accurate
201 if (!set_measurement_timing_budget(ACCURATE_TIMING_BUDGET)) return false;
202 }
203 else if (prof & FAST_MASK)
204 {
205 // fast
206 if (!set_measurement_timing_budget(FAST_TIMING_BUDGET)) return false;
207 }
208 return true;
209 }
210
233 template<board::Timer TIMER>
234 bool await_single_range(timer::RTT<TIMER>& rtt, uint16_t& range_mm, uint16_t timeout_ms = DEFAULT_TIMEOUT_MS)
235 {
236 time::RTTTime end = rtt.time() + time::RTTTime{timeout_ms, 0};
239 if (!use_stop_variable()) return false;
240 if (!this->template sync_write<WRITE_SYSRANGE>(uint8_t(0x01))) return false;
241 // Read SYSRANGE until != 0x01
242 while (rtt.time() < end)
243 {
244 uint8_t sys_range = 0;
245 if (!this->template sync_read<READ_SYSRANGE>(sys_range)) return false;
246 if ((sys_range & 0x01) == 0)
247 {
248 // Replace timeout_ms with remaining time only
249 time::RTTTime now = rtt.time();
250 timeout_ms = (end > now) ? (end - now).millis() : 0;
251 if (timeout_ms == 0) timeout_ms = 1U;
252 return await_continuous_range(rtt, range_mm, timeout_ms);
253 }
254 }
255 return false;
256 }
257
287 bool start_continuous_ranging(uint16_t period_ms = 0)
288 {
292 if (!use_stop_variable()) return false;
293 uint8_t sys_range_start = 0x02;
294 if (period_ms)
295 {
296 uint16_t osc_calibrate = 0;
297 if (!this->template sync_read<READ_OSC_CAL>(osc_calibrate)) return false;
298 uint32_t actual_period = period_ms;
299 if (osc_calibrate) actual_period *= osc_calibrate;
300 if (!this->template sync_write<WRITE_PERIOD>(actual_period)) return false;
301 sys_range_start = 0x04;
302 }
303 return this->template sync_write<WRITE_SYSRANGE>(sys_range_start);
304 }
305
329 template<board::Timer TIMER> bool await_continuous_range(
330 timer::RTT<TIMER>& rtt, uint16_t& range_mm, uint16_t timeout_ms = DEFAULT_TIMEOUT_MS)
331 {
332 if (!await_interrupt(rtt, timeout_ms)) return false;
333 if (!get_direct_range(range_mm)) return false;
334 return clear_interrupt();
335 }
336
349 {
350 return await_same_future_group(
351 internals::stop_continuous_ranging::BUFFER, internals::stop_continuous_ranging::BUFFER_SIZE);
352 }
353
371 {
372 static constexpr uint16_t RESET_DELAY_US = 100U;
374 // Set reset bit
375 if (!this->template sync_write<WRITE_RESET>(uint8_t(0x00))) return false;
376 // Wait for some time
377 uint8_t model = 0xFF;
378 do
379 {
380 get_model(model);
381 }
382 while (model != 0);
383 time::delay_us(RESET_DELAY_US);
384
385 // Release reset
386 if (!this->template sync_write<WRITE_RESET>(uint8_t(0x01))) return false;
387 // Wait until correct boot-up
388 model = 0x00;
389 do
390 {
391 get_model(model);
392 }
393 while (model == 0);
394 time::delay_us(RESET_DELAY_US);
395 return true;
396 }
397
423 {
424 // 1. Force 2.8V for I/O (instead of default 1.8V)
425 if (!force_io_2_8V()) return false;
426 // 2. Set I2C standard mode
427 if (!set_I2C_mode()) return false;
428 // 3. Read stop variable here
429 if (!read_stop_variable()) return false;
430 // 4. Disable SIGNAL_RATE_MSRC and SIGNAL_RATE_PRE_RANGE limit checks
431 if (!disable_signal_rate_limit_check()) return false;
432 // 5. Set signal rate limit to 0.25 MCPS (million counts per second) in FP9.7 format
433 if (!set_signal_rate_limit(0.25)) return false;
434 // 6. Enable all sequence steps by default
435 return set_sequence_steps((SequenceSteps) 0xFF);
436 }
437
460 bool init_static_second(const GPIOSettings& settings,
461 SequenceSteps steps = SequenceSteps::create().pre_range().final_range().dss())
462 {
463 // 1. Get SPAD info
464 SPADInfo info;
465 if (!get_SPAD_info(info)) return false;
466 // 2. Get reference SPADs from NVM
467 SPADReference ref_spads;
468 if (!get_reference_SPADs(ref_spads)) return false;
469 // 3. Calculate SPADs and set reference SPADs
470 calculate_reference_SPADs(ref_spads.spad_refs(), info);
471 if (!set_reference_SPADs(ref_spads)) return false;
472 // 4. Load tuning settings
473 if (!load_tuning_settings()) return false;
474 // 5. Set GPIO settings
475 if (!set_GPIO_settings(settings)) return false;
476 // 6. Get current timing budget
477 uint32_t budget_us = 0UL;
478 if (!get_measurement_timing_budget(budget_us)) return false;
479 // 7. Set sequence steps by default?
480 if (!set_sequence_steps(steps)) return false;
481 // 8. Recalculate timing budget and set it
482 return set_measurement_timing_budget(budget_us);
483 }
484
502 {
503 static constexpr uint8_t CODE_VHV_CALIBRATION = 0x01;
504 static constexpr uint8_t CODE_PHASE_CALIBRATION = 0x02;
506 // 1. Read current sequence steps
507 SequenceSteps steps;
508 if (!get_sequence_steps(steps)) return false;
509 // 2. Set steps for VHV calibration
510 if (!this->template sync_write<WRITE_STEPS>(CODE_VHV_CALIBRATION)) return false;
511 // 3. Perform single VHV calibration
512 if (!perform_single_ref_calibration(SingleRefCalibrationTarget::VHV_CALIBRATION)) return false;
513 // 4. Set steps for Phase calibration
514 if (!this->template sync_write<WRITE_STEPS>(CODE_PHASE_CALIBRATION)) return false;
515 // 5. Perform single Phase calibration
516 if (!perform_single_ref_calibration(SingleRefCalibrationTarget::PHASE_CALIBRATION)) return false;
517 // 6. Restore sequence steps (NOTE: 0x00 is used as marker by the future to actually restore saved sequence)
518 return set_sequence_steps(steps);
519 }
520
526
543 {
544 return this->async_read(future);
545 }
546
559 bool get_range_status(DeviceStatus& range_status)
560 {
561 return this->template sync_read<GetRangeStatusFuture>(range_status);
562 }
563
569 {
570 using PARENT = I2CFuturesGroup;
571 public:
573 GetGPIOSettingsFuture() : PARENT{futures_, NUM_FUTURES}
574 {
576 PARENT::init(futures_);
577 }
579 {
581 }
582
583 bool get(vl53l0x::GPIOSettings& settings)
584 {
585 static constexpr uint8_t GPIO_ACTIVE_LEVEL_MASK = 0x10;
586 if (this->await() != future::FutureStatus::READY)
587 return false;
589 read_config_.get(function);
590 uint8_t active_high = 0;
591 read_GPIO_active_high_.get(active_high);
592 uint16_t low_threshold = 0;
593 read_low_threshold_.get(low_threshold);
594 uint16_t high_threshold = 0;
595 read_high_threshold_.get(high_threshold);
596 settings = vl53l0x::GPIOSettings{
597 function, bool(active_high & GPIO_ACTIVE_LEVEL_MASK), low_threshold, high_threshold};
598 return true;
599 }
601
602 private:
607
608 static constexpr uint8_t NUM_FUTURES = 4;
609 ABSTRACT_FUTURE* futures_[NUM_FUTURES] =
610 {
611 &read_config_,
612 &read_GPIO_active_high_,
613 &read_low_threshold_,
614 &read_high_threshold_
615 };
616
618 friend VL53L0X<MANAGER>;
619 };
620
638 {
639 return (future.start(*this) ? 0 : future.error());
640 }
641
656 {
658 if (get_GPIO_settings(future) != 0) return false;
659 return future.get(settings);
660 }
661
667 {
668 using PARENT = I2CFuturesGroup;
669 public:
671 explicit SetGPIOSettingsFuture(const vl53l0x::GPIOSettings& settings)
672 : PARENT{futures_, NUM_FUTURES},
673 write_config_{settings.function()},
674 // The following hard-coded values look OK but this is not how it should be done!
675 //TODO GPIO_HV_MUX_ACTIVE_HIGH should first be read and then bit 4 clear or set
676 write_GPIO_active_high_{uint8_t(settings.high_polarity() ? GPIO_LEVEL_HIGH : GPIO_LEVEL_LOW)},
677 // Threshold values must be divided by 2, but nobody knows why
678 write_low_threshold_{settings.low_threshold() / 2},
679 write_high_threshold_{settings.high_threshold() / 2}
680 {
682 PARENT::init(futures_);
683 }
685 {
687 }
689
690 private:
691 static constexpr uint8_t GPIO_LEVEL_HIGH = 0x11;
692 static constexpr uint8_t GPIO_LEVEL_LOW = 0x01;
698
699 static constexpr uint8_t NUM_FUTURES = 5;
700 ABSTRACT_FUTURE* futures_[NUM_FUTURES] =
701 {
702 &write_config_,
703 &write_GPIO_active_high_,
704 &write_low_threshold_,
705 &write_high_threshold_,
706 &clear_interrupt_
707 };
708
709 friend VL53L0X<MANAGER>;
710 };
711
729 {
730 return (future.start(*this) ? 0 : future.error());
731 }
732
745 bool set_GPIO_settings(const GPIOSettings& settings)
746 {
748 if (set_GPIO_settings(future) != 0) return false;
749 return (future.await() == future::FutureStatus::READY);
750 }
751
757
775 {
776 return this->async_read(future);
777 }
778
792 bool get_interrupt_status(InterruptStatus& status)
793 {
794 return this->template sync_read<GetInterruptStatusFuture>(status);
795 }
796
802
820 {
821 return this->async_write(future);
822 }
823
836 bool clear_interrupt(uint8_t clear_mask = 0x01)
837 {
838 return this->template sync_write<ClearInterruptFuture>(clear_mask);
839 }
840
857 template<board::Timer TIMER>
858 bool await_interrupt(timer::RTT<TIMER>& rtt, uint16_t timeout_ms = DEFAULT_TIMEOUT_MS)
859 {
860 time::RTTTime end = rtt.time() + time::RTTTime{timeout_ms, 0};
861 while (rtt.time() < end)
862 {
863 InterruptStatus status;
864 if (!this->template sync_read<GetInterruptStatusFuture>(status)) return false;
865 if (uint8_t(status) != 0)
866 return true;
867 }
868 return false;
869 }
870
876
903 {
904 return this->async_read(future);
905 }
906
926 bool get_direct_range(uint16_t& range_mm)
927 {
928 return this->template sync_read<GetDirectRangeFuture>(range_mm);
929 }
930
947 bool set_measurement_timing_budget(uint32_t budget_us)
948 {
950 SequenceSteps steps;
951 if (!get_sequence_steps(steps)) return false;
952 SequenceStepsTimeout timeouts;
953 if (!get_sequence_steps_timeout(timeouts)) return false;
954 // Calculate budget
955 uint16_t budget = calculate_final_range_timeout(steps, timeouts, budget_us);
956 if (budget == 0) return false;
957 return this->template sync_write<WRITE_BUDGET>(budget);
958 }
959
975 bool get_measurement_timing_budget(uint32_t& budget_us)
976 {
977 // Get steps and timeouts
978 SequenceSteps steps{};
979 if (!get_sequence_steps(steps)) return false;
980 SequenceStepsTimeout timeouts{};
981 if (!get_sequence_steps_timeout(timeouts)) return false;
982 // Calculate timing budget
983 budget_us = calculate_measurement_budget_us(true, steps, timeouts);
984 return true;
985 }
986
1001 {
1003 return this->template sync_write<SetSequenceStepsFuture>(sequence_steps);
1004 }
1005
1020 bool get_sequence_steps(SequenceSteps& sequence_steps)
1021 {
1023 return this->template sync_read<GetSequenceStepsFuture>(sequence_steps);
1024 }
1025
1044 template<VcselPeriodType TYPE>
1045 bool set_vcsel_pulse_period(uint8_t period)
1046 {
1047 return set_vcsel_pulse_period(TYPE, period);
1048 }
1049
1065 template<VcselPeriodType TYPE>
1066 bool get_vcsel_pulse_period(uint8_t& period)
1067 {
1068 using GetVcselPulsePeriodFuture = TReadRegisterFuture<Register((uint8_t) TYPE)>;
1069 if (!this->template sync_read<GetVcselPulsePeriodFuture>(period)) return false;
1070 period = decode_vcsel_period(period);
1071 return true;
1072 }
1073
1089 bool set_signal_rate_limit(float signal_rate)
1090 {
1091 if ((signal_rate <= 0.0) || (signal_rate > 1.0)) return false;
1092 using SetSignalRateLimitFuture =
1094 return this->template sync_write<SetSignalRateLimitFuture>(FixPoint9_7::convert(signal_rate));
1095 }
1096
1113 bool get_signal_rate_limit(float& signal_rate)
1114 {
1115 using GetSignalRateLimitFuture =
1117 uint16_t temp = 0;
1118 if (!this->template sync_read<GetSignalRateLimitFuture>(temp)) return false;
1119 signal_rate = FixPoint9_7::convert(temp);
1120 return true;
1121 }
1122
1132 bool get_power_mode(PowerMode& power_mode)
1133 {
1135 return this->template sync_read<GetPowerModeFuture>(power_mode);
1136 }
1137
1149 bool get_model(uint8_t& model)
1150 {
1152 return this->template sync_read<GetModelFuture>(model);
1153 }
1154
1166 bool get_revision(uint8_t& revision)
1167 {
1169 return this->template sync_read<GetRevisionFuture>(revision);
1170 }
1171
1188 bool await_interrupt(uint16_t loops = MAX_LOOP)
1189 {
1190 // Read interrupt until !=0
1191 while (loops--)
1192 {
1193 InterruptStatus status;
1194 if (!this->template sync_read<GetInterruptStatusFuture>(status)) return false;
1195 if (uint8_t(status) != 0)
1196 return true;
1197 }
1198 return false;
1199 }
1200
1223 bool await_continuous_range(uint16_t& range_mm, uint16_t loops = MAX_LOOP)
1224 {
1225 if (!await_interrupt(loops)) return false;
1226 if (!get_direct_range(range_mm)) return false;
1227 return clear_interrupt();
1228 }
1229
1250 bool await_single_range(uint16_t& range_mm, uint16_t loops = MAX_LOOP)
1251 {
1254 if (!use_stop_variable()) return false;
1255 if (!this->template sync_write<WRITE_SYSRANGE>(uint8_t(0x01))) return false;
1256 // Read SYSRANGE until != 0x01
1257 while (loops--)
1258 {
1259 uint8_t sys_range = 0;
1260 if (!this->template sync_read<READ_SYSRANGE>(sys_range)) return false;
1261 if ((sys_range & 0x01) == 0)
1262 return await_continuous_range(range_mm, loops);
1263 }
1264 return false;
1265 }
1266
1281 {
1282 using GetReferenceSPADsFuture =
1284 return this->template sync_read<GetReferenceSPADsFuture, SPADReference>(spad_ref);
1285 }
1286
1300 {
1301 using SetReferenceSPADsFuture =
1303 if (!await_same_future_group(
1304 internals::set_reference_spads::BUFFER, internals::set_reference_spads::BUFFER_SIZE))
1305 return false;
1306 return this->template sync_write<SetReferenceSPADsFuture, SPADReference>(spad_ref);
1307 }
1308
1321 {
1325 // 1. Write initial registers
1326 if (!await_same_future_group(internals::spad_info::BUFFER1, internals::spad_info::BUFFER1_SIZE))
1327 return false;
1328 // 2. Force strobe (read/write)
1329 uint8_t strobe = 0;
1330 if (!this->template sync_read<READ_STROBE>(strobe)) return false;
1331 strobe |= 0x04U;
1332 if (!this->template sync_write<WRITE_STROBE>(strobe)) return false;
1333 // 3. Write 2nd pass registers
1334 if (!await_same_future_group(internals::spad_info::BUFFER2, internals::spad_info::BUFFER2_SIZE))
1335 return false;
1336 // 4. Wait for strobe
1337 if (!await_device_strobe()) return false;
1338 // 5. Read spad info
1339 if (!this->template sync_read<READ_SPAD>(info)) return false;
1340 // 6. Write 3rd pass registers
1341 if (!await_same_future_group(internals::spad_info::BUFFER3, internals::spad_info::BUFFER3_SIZE))
1342 return false;
1343 // 7. Force strobe
1344 strobe = 0;
1345 if (!this->template sync_read<READ_STROBE>(strobe)) return false;
1346 strobe &= ~0x04U;
1347 if (!this->template sync_write<WRITE_STROBE>(strobe)) return false;
1348 // 8. Write last pass registers
1349 return await_same_future_group(internals::spad_info::BUFFER4, internals::spad_info::BUFFER4_SIZE);
1350 }
1351
1364 {
1367 using READ_FINALRANGE_TIMEOUT =
1369
1370 uint8_t pre_range_vcsel_period_pclks = 0;
1371 if (!get_vcsel_pulse_period<VcselPeriodType::PRE_RANGE>(pre_range_vcsel_period_pclks)) return false;
1372 uint8_t final_range_vcsel_period_pclks = 0;
1373 if (!get_vcsel_pulse_period<VcselPeriodType::FINAL_RANGE>(final_range_vcsel_period_pclks)) return false;
1374 uint8_t msrc_dss_tcc_mclks = 0;
1375 if (!this->template sync_read<READ_MSRC_TIMEOUT>(msrc_dss_tcc_mclks)) return false;
1376 uint16_t pre_range_mclks = 0;
1377 if (!this->template sync_read<READ_PRERANGE_TIMEOUT>(pre_range_mclks)) return false;
1378 uint16_t final_range_mclks = 0;
1379 if (!this->template sync_read<READ_FINALRANGE_TIMEOUT>(final_range_mclks)) return false;
1380
1382 pre_range_vcsel_period_pclks, final_range_vcsel_period_pclks,
1383 msrc_dss_tcc_mclks, pre_range_mclks, final_range_mclks};
1384 return true;
1385 }
1386
1407 template<Register REGISTER, typename T = uint8_t>
1409 {
1410 return this->async_read(future);
1411 }
1412
1433 template<Register REGISTER, typename T = uint8_t>
1435 {
1436 return this->async_write(future);
1437 }
1438
1456 template<Register REGISTER, typename T = uint8_t>
1457 bool get_register(T& value)
1458 {
1459 using GetRegisterFuture = TReadRegisterFuture<REGISTER, T>;
1460 return this->template sync_read<GetRegisterFuture>(value);
1461 }
1462
1479 template<Register REGISTER, typename T = uint8_t>
1480 bool set_register(T value)
1481 {
1482 using SetRegisterFuture = TWriteRegisterFuture<REGISTER, T>;
1483 return this->template sync_write<SetRegisterFuture>(value);
1484 }
1485
1486 private:
1487 bool force_io_2_8V()
1488 {
1489 using READ_VHV_CONFIG = TReadRegisterFuture<Register::VHV_CONFIG_PAD_SCL_SDA_EXTSUP_HV>;
1490 using WRITE_VHV_CONFIG = TWriteRegisterFuture<Register::VHV_CONFIG_PAD_SCL_SDA_EXTSUP_HV>;
1491 uint8_t config = 0;
1492 if (!this->template sync_read<READ_VHV_CONFIG>(config)) return false;
1493 config |= 0x01;
1494 return this->template sync_write<WRITE_VHV_CONFIG>(config);
1495 }
1496
1497 bool set_I2C_mode()
1498 {
1499 using WRITE_I2C_MODE = TWriteRegisterFuture<Register::SYSTEM_CONFIG_I2C_MODE>;
1500 return this->template sync_write<WRITE_I2C_MODE>(uint8_t(0x00));
1501 }
1502
1503 bool read_stop_variable()
1504 {
1505 // Write prefix
1506 if (!await_same_future_group(
1507 internals::stop_variable::PRE_BUFFER, internals::stop_variable::PRE_BUFFER_SIZE))
1508 return false;
1509
1510 // Read stop variable
1511 using READ_STOP_VAR = TReadRegisterFuture<Register::SYSTEM_STOP_VARIABLE>;
1512 if (!this->template sync_read<READ_STOP_VAR>(stop_variable_)) return false;
1513
1514 // Write suffix
1515 return await_same_future_group(
1516 internals::stop_variable::POST_BUFFER, internals::stop_variable::POST_BUFFER_SIZE);
1517 }
1518
1519 bool use_stop_variable()
1520 {
1521 // Write prefix
1522 if (!await_same_future_group(
1523 internals::stop_variable::PRE_BUFFER, internals::stop_variable::PRE_BUFFER_SIZE))
1524 return false;
1525
1526 // Read stop variable
1527 using WRITE_STOP_VAR = TWriteRegisterFuture<Register::SYSTEM_STOP_VARIABLE>;
1528 if (!this->template sync_write<WRITE_STOP_VAR>(stop_variable_)) return false;
1529
1530 // Write suffix
1531 return await_same_future_group(
1532 internals::stop_variable::POST_BUFFER, internals::stop_variable::POST_BUFFER_SIZE);
1533 }
1534
1535 bool disable_signal_rate_limit_check()
1536 {
1537 using READ_MSRC_CONFIG = TReadRegisterFuture<Register::MSRC_CONFIG_CONTROL>;
1538 using WRITE_MSRC_CONFIG = TWriteRegisterFuture<Register::MSRC_CONFIG_CONTROL>;
1539 uint8_t config = 0;
1540 if (!this->template sync_read<READ_MSRC_CONFIG>(config)) return false;
1541 config |= 0x12;
1542 return this->template sync_write<WRITE_MSRC_CONFIG>(config);
1543 }
1544
1545 bool load_tuning_settings()
1546 {
1547 return await_same_future_group(
1548 internals::load_tuning_settings::BUFFER, internals::load_tuning_settings::BUFFER_SIZE);
1549 }
1550
1551 static constexpr const uint16_t MAX_LOOP = 2000;
1552 static constexpr uint16_t DEFAULT_TIMEOUT_MS = 100;
1553
1554 enum class SingleRefCalibrationTarget : uint8_t
1555 {
1556 PHASE_CALIBRATION = 0x01,
1557 VHV_CALIBRATION = 0x41
1558 };
1559
1560 bool perform_single_ref_calibration(SingleRefCalibrationTarget target)
1561 {
1562 using WRITE_SYS_RANGE = TWriteRegisterFuture<Register::SYSRANGE_START>;
1563 // 1. Write to register SYS RANGE
1564 if (!this->template sync_write<WRITE_SYS_RANGE>(uint8_t(target))) return false;
1565 // 2. Read interrupt status until interrupt occurs
1566 uint16_t loops = MAX_LOOP;
1567 while (loops--)
1568 {
1569 InterruptStatus status;
1570 if (!get_interrupt_status(status)) return false;
1571 if (uint8_t(status) != 0)
1572 {
1573 // 3. Clear interrupt
1574 if (!clear_interrupt(0x01)) return false;
1575 // 4. Write to register SYS RANGE
1576 return this->template sync_write<WRITE_SYS_RANGE>(uint8_t(0x00));
1577 }
1578 }
1579 return false;
1580 }
1581
1582 bool await_same_future_group(const uint8_t* buffer, uint8_t size)
1583 {
1584 return i2c::await_same_future_group<MANAGER>(*this, buffer, size);
1585 }
1586
1587 bool await_device_strobe()
1588 {
1589 using READ_STROBE = TReadRegisterFuture<Register::DEVICE_STROBE>;
1590 using WRITE_STROBE = TWriteRegisterFuture<Register::DEVICE_STROBE>;
1591 // 1. Clear strobe
1592 if (!this->template sync_write<WRITE_STROBE>(uint8_t(0x00))) return false;
1593 // 2. Read strobe until !=0
1594 uint16_t loops = MAX_LOOP;
1595 while (loops--)
1596 {
1597 uint8_t strobe = 0;
1598 if (!this->template sync_read<READ_STROBE>(strobe)) return false;
1599 if (strobe != 0)
1600 // 3. Set strobe
1601 return this->template sync_write<WRITE_STROBE>(uint8_t(0x01));
1602 }
1603 return false;
1604 }
1605
1606 bool set_vcsel_pulse_period(VcselPeriodType type, uint8_t period)
1607 {
1608 // 0. Check period
1609 if (!check_vcsel_period(type, period)) return false;
1610 // 0'. Encode period
1611 uint8_t vcsel_period = encode_vcsel_period(period);
1612 // 0". Read current measurement timing budget
1613 uint32_t timing_budget = 0UL;
1614 if (!get_measurement_timing_budget(timing_budget)) return false;
1615 // 1. Read sequence steps enables
1616 SequenceSteps steps;
1617 if (!get_sequence_steps(steps)) return false;
1618 // 2. Read sequence steps timeouts
1619 SequenceStepsTimeout timeouts;
1620 if (!get_sequence_steps_timeout(timeouts)) return false;
1621 if (type == VcselPeriodType::PRE_RANGE)
1622 {
1623 if (!set_vcsel_period_pre_range(period, vcsel_period, timeouts)) return false;
1624 }
1625 else
1626 {
1627 if (!set_vcsel_period_final_range(period, vcsel_period, steps.is_pre_range(), timeouts))
1628 return false;
1629 }
1630 // 4. Set measurement timing budget as before
1631 if (!set_measurement_timing_budget(timing_budget)) return false;
1632 // 5. Perform phase calibration
1633 using WRITE_STEPS = TWriteRegisterFuture<Register::SYSTEM_SEQUENCE_CONFIG>;
1634 if (!this->template sync_write<WRITE_STEPS>(uint8_t(0x02))) return false;
1635 perform_single_ref_calibration(SingleRefCalibrationTarget::PHASE_CALIBRATION);
1636 if (!set_sequence_steps(steps)) return false;
1637 return true;
1638 }
1639
1640 bool set_vcsel_period_pre_range(
1641 uint8_t period, uint8_t vcsel_period, const SequenceStepsTimeout& timeouts)
1642 {
1643 // 3.1. [PRE_RANGE]
1644 using WRITE_PHASE_HIGH = TWriteRegisterFuture<Register::PRE_RANGE_CONFIG_VALID_PHASE_HIGH>;
1645 using WRITE_PHASE_LOW = TWriteRegisterFuture<Register::PRE_RANGE_CONFIG_VALID_PHASE_LOW>;
1646 using WRITE_VCSEL = TWriteRegisterFuture<Register::PRE_RANGE_CONFIG_VCSEL_PERIOD>;
1647 using WRITE_RANGE_TIMEOUT = TWriteRegisterFuture<Register::PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI, uint16_t>;
1648 using WRITE_MSRC_TIMEOUT = TWriteRegisterFuture<Register::MSRC_CONFIG_TIMEOUT_MACROP>;
1649
1650 // 3.1.1. Write PRE_RANGE_CONFIG_VALID_PHASE_HIGH
1651 uint8_t phase_high = 0;
1652 switch (period)
1653 {
1654 case 12:
1655 phase_high = 0x18;
1656 break;
1657
1658 case 14:
1659 phase_high = 0x30;
1660 break;
1661
1662 case 16:
1663 phase_high = 0x40;
1664 break;
1665
1666 case 18:
1667 phase_high = 0x50;
1668 break;
1669
1670 default:
1671 break;
1672 }
1673 if (!this->template sync_write<WRITE_PHASE_HIGH>(phase_high)) return false;
1674 // 3.1.2. Write PRE_RANGE_CONFIG_VALID_PHASE_LOW
1675 if (!this->template sync_write<WRITE_PHASE_LOW>(uint8_t(0x08))) return false;
1676 // 3.1.3. Write PRE_RANGE_CONFIG_VCSEL_PERIOD
1677 if (!this->template sync_write<WRITE_VCSEL>(vcsel_period)) return false;
1678 // 3.1.4. Write PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI
1679 // Calculate new pre-range timeout
1680 uint16_t pre_range_mclks = vl53l0x::TimeoutUtilities::encode_timeout(
1681 vl53l0x::TimeoutUtilities::calculate_timeout_mclks(timeouts.pre_range_us(), period));
1682 if (!this->template sync_write<WRITE_RANGE_TIMEOUT>(pre_range_mclks)) return false;
1683 // 3.1.5. Write MSRC_CONFIG_TIMEOUT_MACROP
1684 // Calculate new MSRC timeout
1685 uint16_t msrc_mclks = vl53l0x::TimeoutUtilities::calculate_timeout_mclks(
1686 timeouts.msrc_dss_tcc_us(), period);
1687 msrc_mclks = (msrc_mclks > (UINT8_MAX + 1)) ? UINT8_MAX : (msrc_mclks - 1);
1688 return this->template sync_write<WRITE_MSRC_TIMEOUT>(uint8_t(msrc_mclks));
1689 }
1690
1691 bool set_vcsel_period_final_range(
1692 uint8_t period, uint8_t vcsel_period, bool has_pre_range, const SequenceStepsTimeout& timeouts)
1693 {
1694 // 3.2. [FINAL_RANGE]
1695 using WRITE_PHASE_HIGH = TWriteRegisterFuture<Register::FINAL_RANGE_CONFIG_VALID_PHASE_HIGH>;
1696 using WRITE_PHASE_LOW = TWriteRegisterFuture<Register::FINAL_RANGE_CONFIG_VALID_PHASE_LOW>;
1697 using WRITE_VCSEL_WIDTH = TWriteRegisterFuture<Register::GLOBAL_CONFIG_VCSEL_WIDTH>;
1698 using WRITE_PHASECAL_TIMEOUT = TWriteRegisterFuture<Register::ALGO_PHASECAL_CONFIG_TIMEOUT>;
1699 using WRITE_PHASECAL_LIMIT = TWriteRegisterFuture<Register::ALGO_PHASECAL_LIM>;
1700 using WRITE_RANGE_TIMEOUT = TWriteRegisterFuture<Register::FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI, uint16_t>;
1701 using WRITE_VCSEL = TWriteRegisterFuture<Register::FINAL_RANGE_CONFIG_VCSEL_PERIOD>;
1702 // Determine values to write based on provided period
1703 uint8_t phase_high = 0;
1704 uint8_t vcsel_width = 0;
1705 uint8_t phasecal_timeout = 0;
1706 uint8_t phasecal_limit = 0;
1707 switch (period)
1708 {
1709 case 8:
1710 phase_high = 0x10;
1711 vcsel_width = 0x02;
1712 phasecal_timeout = 0x0C;
1713 phasecal_limit = 0x30;
1714 break;
1715
1716 case 10:
1717 phase_high = 0x28;
1718 vcsel_width = 0x03;
1719 phasecal_timeout = 0x09;
1720 phasecal_limit = 0x20;
1721 break;
1722
1723 case 12:
1724 phase_high = 0x38;
1725 vcsel_width = 0x03;
1726 phasecal_timeout = 0x08;
1727 phasecal_limit = 0x20;
1728 break;
1729
1730 case 14:
1731 phase_high = 0x48;
1732 vcsel_width = 0x03;
1733 phasecal_timeout = 0x07;
1734 phasecal_limit = 0x20;
1735 break;
1736
1737 default:
1738 break;
1739 }
1740 // 3.2.1. Write FINAL_RANGE_CONFIG_VALID_PHASE_HIGH
1741 if (!this->template sync_write<WRITE_PHASE_HIGH>(phase_high)) return false;
1742 // 3.2.2. Write FINAL_RANGE_CONFIG_VALID_PHASE_LOW
1743 if (!this->template sync_write<WRITE_PHASE_LOW>(uint8_t(0x08))) return false;
1744 // 3.2.3. Write GLOBAL_CONFIG_VCSEL_WIDTH
1745 if (!this->template sync_write<WRITE_VCSEL_WIDTH>(vcsel_width)) return false;
1746 // 3.2.4. Write ALGO_PHASECAL_CONFIG_TIMEOUT
1747 if (!this->template sync_write<WRITE_PHASECAL_TIMEOUT>(phasecal_timeout)) return false;
1748 // 3.2.5. Write ALGO_PHASECAL_LIM
1749 if (!this->template sync_write<WRITE_PHASECAL_LIMIT>(phasecal_limit)) return false;
1750 // 3.2.6. Write FINAL_RANGE_CONFIG_VCSEL_PERIOD
1751 if (!this->template sync_write<WRITE_VCSEL>(vcsel_period)) return false;
1752 // 3.2.7. Write FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI
1753 // Calculate new final-range timeout
1754 uint16_t final_range_mclks = vl53l0x::TimeoutUtilities::encode_timeout(
1755 vl53l0x::TimeoutUtilities::calculate_timeout_mclks(
1756 timeouts.final_range_us(has_pre_range), period));
1757 return this->template sync_write<WRITE_RANGE_TIMEOUT>(final_range_mclks);
1758 }
1759
1760 static constexpr bool check_vcsel_period(VcselPeriodType type, uint8_t period)
1761 {
1762 if (type == VcselPeriodType::PRE_RANGE)
1763 return check_vcsel_period_pre_range(period);
1764 else
1765 return check_vcsel_period_final_range(period);
1766 }
1767
1768 static constexpr bool check_vcsel_period_pre_range(uint8_t period)
1769 {
1770 switch (period)
1771 {
1772 case 12:
1773 case 14:
1774 case 16:
1775 case 18:
1776 return true;
1777
1778 default:
1779 return false;
1780 }
1781 }
1782
1783 static constexpr bool check_vcsel_period_final_range(uint8_t period)
1784 {
1785 switch (period)
1786 {
1787 case 8:
1788 case 10:
1789 case 12:
1790 case 14:
1791 return true;
1792
1793 default:
1794 return false;
1795 }
1796 }
1797
1798 static constexpr uint8_t encode_vcsel_period(uint8_t period)
1799 {
1800 return (period >> 1U) - 1U;
1801 }
1802 static constexpr uint8_t decode_vcsel_period(uint8_t value)
1803 {
1804 return (value + 1U) << 1U;
1805 }
1806
1807 static constexpr const uint8_t NUM_REF_SPADS = 48;
1808 static constexpr const uint8_t SPADS_PER_BYTE = 8;
1809 static constexpr const uint8_t NUM_REF_SPADS_BYTES = NUM_REF_SPADS / SPADS_PER_BYTE;
1810
1811 static constexpr const uint8_t FIRST_APERTURE_SPAD = 12;
1812 static void calculate_reference_SPADs(uint8_t ref_spads[NUM_REF_SPADS_BYTES], vl53l0x::SPADInfo info)
1813 {
1814 const uint8_t count = info.count();
1815 const uint8_t first_spad = (info.is_aperture() ? FIRST_APERTURE_SPAD : 0);
1816 uint8_t enabled_spads = 0;
1817 uint8_t spad = 0;
1818 for (uint8_t i = 0; i < NUM_REF_SPADS_BYTES; ++i)
1819 {
1820 uint8_t& ref_spad = ref_spads[i];
1821 for (uint8_t j = 0; j < SPADS_PER_BYTE; ++j)
1822 {
1823 if ((spad < first_spad) || (enabled_spads == count))
1824 // Disable this SPAD as it should not be enabled
1825 ref_spad &= bits::CBV8(j);
1826 else if (ref_spad & bits::BV8(j))
1827 // Just count the current SPAD as enabled
1828 ++enabled_spads;
1829 ++spad;
1830 }
1831 }
1832 }
1833
1834 static constexpr const uint32_t MIN_TIMING_BUDGET = 20'000UL;
1835 static constexpr const uint16_t START_OVERHEAD_SET = 1320U;
1836 static constexpr const uint16_t START_OVERHEAD_GET = 1910U;
1837 static constexpr const uint16_t END_OVERHEAD = 960U;
1838 static constexpr const uint16_t MSRC_OVERHEAD = 660U;
1839 static constexpr const uint16_t TCC_OVERHEAD = 590U;
1840 static constexpr const uint16_t DSS_OVERHEAD = 690U;
1841 static constexpr const uint16_t PRE_RANGE_OVERHEAD = 660U;
1842 static constexpr const uint16_t FINAL_RANGE_OVERHEAD = 550U;
1843
1844 static uint32_t calculate_measurement_budget_us(
1845 bool get, const vl53l0x::SequenceSteps steps, const vl53l0x::SequenceStepsTimeout& timeouts)
1846 {
1847 // start and end overhead times always present
1848 uint32_t budget_us = (get ? START_OVERHEAD_GET : START_OVERHEAD_SET) + END_OVERHEAD;
1849
1850 if (steps.is_tcc())
1851 budget_us += timeouts.msrc_dss_tcc_us() + TCC_OVERHEAD;
1852
1853 if (steps.is_dss())
1854 budget_us += 2 * (timeouts.msrc_dss_tcc_us() + DSS_OVERHEAD);
1855 else if (steps.is_msrc())
1856 budget_us += timeouts.msrc_dss_tcc_us() + MSRC_OVERHEAD;
1857
1858 if (steps.is_pre_range())
1859 budget_us += timeouts.pre_range_us() + PRE_RANGE_OVERHEAD;
1860
1861 if (steps.is_final_range())
1862 budget_us += timeouts.final_range_us(steps.is_pre_range()) + FINAL_RANGE_OVERHEAD;
1863
1864 return budget_us;
1865 }
1866
1867 static uint16_t calculate_final_range_timeout(
1868 const vl53l0x::SequenceSteps steps, const vl53l0x::SequenceStepsTimeout& timeouts, uint32_t budget_us)
1869 {
1870 // Requested budget must be be above minimum allowed
1871 if (budget_us < MIN_TIMING_BUDGET) return 0;
1872 // This calculation is useless if there is no final range step
1873 if (!steps.is_final_range()) return 0;
1874
1875 // Calculate current used budget without final range
1876 uint32_t used_budget_us =
1877 calculate_measurement_budget_us(false, steps.no_final_range(), timeouts);
1878
1879 // Now include final range and calculate difference
1880 used_budget_us += FINAL_RANGE_OVERHEAD;
1881 // Requested budget must be above calculated budget for all other steps
1882 if (used_budget_us > budget_us) return 0;
1883
1884 // Calculate final range timeout in us
1885 const uint32_t final_range_timeout_us = budget_us - used_budget_us;
1886
1887 // Deduce final range timeout in mclks
1888 uint32_t final_range_timeout_mclks = vl53l0x::TimeoutUtilities::calculate_timeout_mclks(
1889 final_range_timeout_us, timeouts.final_range_vcsel_period_pclks());
1890 if (steps.is_pre_range())
1891 final_range_timeout_mclks += timeouts.pre_range_mclks();
1892
1893 return vl53l0x::TimeoutUtilities::encode_timeout(final_range_timeout_mclks);
1894 }
1895
1896 static constexpr const uint8_t DEFAULT_DEVICE_ADDRESS = 0x52;
1897
1898 // Stop variable used across device invocations
1899 uint8_t stop_variable_ = 0;
1900 };
1901}
1902
1903#endif /* VL53L0X_H */
Status of device as retrieved by VL53L0X::get_range_status().
static constexpr uint16_t convert(float value)
Convert a float value into an 9.7 fix-point.
Definition: vl53l0x_types.h:73
Settings for behavior of VL53L0X GPIO pin.
bool high_polarity() const
Return the current polarity level of GPIO interrupts.
static constexpr GPIOSettings sample_ready(bool high_polarity=false)
Create GPIOSettings for interrupt triggered when range sample is ready.
static constexpr GPIOSettings low_threshold(uint16_t threshold, bool high_polarity=false)
Create GPIOSettings for interrupt triggered when range is under threshold.
static constexpr GPIOSettings high_threshold(uint16_t threshold, bool high_polarity=false)
Create GPIOSettings for interrupt triggered when range is above threshold.
GPIOFunction function() const
Return the current GPIO interrupt trigger source.
Hold SPAD information from VL53L0X device.
Hold reference SPADs (Single Photon Avalanche Diode).
const uint8_t * spad_refs() const
Get a pointer to the 6-byte array stored in this SPADReference instance.
Hold VL53L0X sequence steps to use for ranging.
static constexpr SequenceSteps create()
Create an empty step sequence for further adding individual steps.
Hold VL53L0X sequence steps timeouts and other related settings used for ranging.
Future to get device current GPIO settings.
Definition: vl53l0x.h:569
Future to set device GPIO settings.
Definition: vl53l0x.h:667
I2C device driver for the VL53L0X ToF ranging chip.
Definition: vl53l0x.h:109
TWriteRegisterFuture< Register::SYSTEM_INTERRUPT_CLEAR > ClearInterruptFuture
Future to clear device interrupt status.
Definition: vl53l0x.h:801
bool get_sequence_steps(SequenceSteps &sequence_steps)
Get current measurement steps executed in sequence by the device during ranging.
Definition: vl53l0x.h:1020
bool get_vcsel_pulse_period(uint8_t &period)
Get current pulse period of the VCSEL for pre-range or final-range step.
Definition: vl53l0x.h:1066
bool get_SPAD_info(SPADInfo &info)
Get current SPAD information (number of SPAD aperture or not).
Definition: vl53l0x.h:1320
bool get_measurement_timing_budget(uint32_t &budget_us)
Get current "measurement timing budget" for this device.
Definition: vl53l0x.h:975
bool set_GPIO_settings(const GPIOSettings &settings)
Set new GPIOSettings for this device.
Definition: vl53l0x.h:745
int get_register(TReadRegisterFuture< REGISTER, T > &future)
Directly get value of a VL53L0X register.
Definition: vl53l0x.h:1408
bool init_data_first()
Perform 1st stage initialization of this VL53L0X device.
Definition: vl53l0x.h:422
bool await_interrupt(uint16_t loops=MAX_LOOP)
Wait for an interrupt condition on VL53L0X device.
Definition: vl53l0x.h:1188
int get_GPIO_settings(GetGPIOSettingsFuture &future)
Get current GPIOSettings from this device.
Definition: vl53l0x.h:637
bool set_register(T value)
Directly set value of a VL53L0X register.
Definition: vl53l0x.h:1480
bool get_register(T &value)
Directly get value of a VL53L0X register.
Definition: vl53l0x.h:1457
bool get_range_status(DeviceStatus &range_status)
Get current DeviceStatus from this device.
Definition: vl53l0x.h:559
bool get_signal_rate_limit(float &signal_rate)
Get current signal rate limit for ranging.
Definition: vl53l0x.h:1113
bool set_vcsel_pulse_period(uint8_t period)
Set new pulse period of the VCSEL for pre-range or final-range step.
Definition: vl53l0x.h:1045
bool get_sequence_steps_timeout(SequenceStepsTimeout &timeouts)
Get current timeouts associated to each ranging step.
Definition: vl53l0x.h:1363
bool init_static_second(const GPIOSettings &settings, SequenceSteps steps=SequenceSteps::create().pre_range().final_range().dss())
Perform 2nd stage initialization of this VL53L0X device.
Definition: vl53l0x.h:460
bool get_direct_range(uint16_t &range_mm)
Get range measured by this device.
Definition: vl53l0x.h:926
bool set_address(uint8_t device_address)
Change the I2C address of this VL53L0X device.
Definition: vl53l0x.h:143
bool set_measurement_timing_budget(uint32_t budget_us)
Set new "measurement timing budget" for this device.
Definition: vl53l0x.h:947
bool get_interrupt_status(InterruptStatus &status)
Get current InterruptStatus from this device.
Definition: vl53l0x.h:792
bool clear_interrupt(uint8_t clear_mask=0x01)
Clear interrupt status from this device.
Definition: vl53l0x.h:836
bool get_model(uint8_t &model)
Get model of this VL53L0X register.
Definition: vl53l0x.h:1149
bool perform_ref_calibration()
Perform VL53L0X VHV and Phase calibration.
Definition: vl53l0x.h:501
bool stop_continuous_ranging()
Stop continuous ranging on this VL53L0X device.
Definition: vl53l0x.h:348
bool set_signal_rate_limit(float signal_rate)
Set new signal rate limit for ranging.
Definition: vl53l0x.h:1089
bool set_sequence_steps(SequenceSteps sequence_steps)
Set measurement steps to be executed in sequence by the device during ranging.
Definition: vl53l0x.h:1000
bool begin(Profile profile)
Fully initialize this VL53L0X device and configures it with provided profile.
Definition: vl53l0x.h:175
bool await_continuous_range(timer::RTT< TIMER > &rtt, uint16_t &range_mm, uint16_t timeout_ms=DEFAULT_TIMEOUT_MS)
Wait for the next continuous ranging measure on VL53L0X device to be ready and return the result.
Definition: vl53l0x.h:329
bool await_continuous_range(uint16_t &range_mm, uint16_t loops=MAX_LOOP)
Wait for the next continuous ranging measure on VL53L0X device to be ready and return the result.
Definition: vl53l0x.h:1223
int get_range_status(GetRangeStatusFuture &future)
Get current DeviceStatus from this device.
Definition: vl53l0x.h:542
bool await_single_range(uint16_t &range_mm, uint16_t loops=MAX_LOOP)
Perform a single range action on VL53L0X device, and wait for the measurement result.
Definition: vl53l0x.h:1250
bool start_continuous_ranging(uint16_t period_ms=0)
Start continuous ranging on this VL53L0X device.
Definition: vl53l0x.h:287
bool get_reference_SPADs(SPADReference &spad_ref)
Get the reference SPADs status (enabled or not).
Definition: vl53l0x.h:1280
bool get_GPIO_settings(GPIOSettings &settings)
Get current GPIOSettings from this device.
Definition: vl53l0x.h:655
bool await_interrupt(timer::RTT< TIMER > &rtt, uint16_t timeout_ms=DEFAULT_TIMEOUT_MS)
Wait for an interrupt condition on VL53L0X device.
Definition: vl53l0x.h:858
bool get_revision(uint8_t &revision)
Get revision of this VL53L0X register.
Definition: vl53l0x.h:1166
bool await_single_range(timer::RTT< TIMER > &rtt, uint16_t &range_mm, uint16_t timeout_ms=DEFAULT_TIMEOUT_MS)
Perform a single range action on VL53L0X device, and wait for the measurement result.
Definition: vl53l0x.h:234
int set_register(TWriteRegisterFuture< REGISTER, T > &future)
Directly set value of a VL53L0X register.
Definition: vl53l0x.h:1434
bool get_power_mode(PowerMode &power_mode)
Get current power mode of this VL53L0X register.
Definition: vl53l0x.h:1132
bool set_reference_SPADs(const SPADReference &spad_ref)
Set the reference SPADs status (enabled or not).
Definition: vl53l0x.h:1299
int get_direct_range(GetDirectRangeFuture &future)
Get range measured by this device.
Definition: vl53l0x.h:902
int set_GPIO_settings(SetGPIOSettingsFuture &future)
Set new GPIOSettings for this device.
Definition: vl53l0x.h:728
int clear_interrupt(ClearInterruptFuture &future)
Clear interrupt status from this device.
Definition: vl53l0x.h:819
VL53L0X(MANAGER &manager)
Create a new device driver for a VL53L0X chip.
Definition: vl53l0x.h:129
int get_interrupt_status(GetInterruptStatusFuture &future)
Get current InterruptStatus from this device.
Definition: vl53l0x.h:774
bool reset_device()
Reset VL53L0X device.
Definition: vl53l0x.h:370
Endianness change functor: will change from big to little or little to big endian format on integer t...
Definition: functors.h:170
Base class for all I2C devices.
Definition: i2c_device.h:84
void set_device(uint8_t device)
Change the I2C address of this device.
Definition: i2c_device.h:146
int async_write(F &future, bool stop=true)
Helper method that asynchronously launches I2C commands for a simple Future performing only one write...
Definition: i2c_device.h:357
MANAGER MANAGER
the type of I2C Manager that can handle this device.
Definition: i2c_device.h:87
int async_read(F &future, bool stop=true)
Helper method that asynchronously launches I2C commands for a simple Future performing one write foll...
Definition: i2c_device.h:309
Abstract class to allow aggregation of several futures in relation to I2C transactions.
Generic Future that can be used to read an I2C device register.
Generic Future that can be used to write to an I2C device register.
Structure used to hold a time value with microsecond precision.
Definition: time.h:50
uint32_t millis() const
Number of elapsed milliseconds.
Definition: time.h:125
API to handle a real-time timer.
time::RTTTime time() const
Elapsed time, in milliseconds and microseconds, since this timer has started.
#define DECL_FUTURE_LISTENERS_FRIEND
This macro shall be used in a class containing a private callback method void on_status_change(const ...
Definition: future.h:178
static constexpr uint8_t CBV8(uint8_t bit)
Create a uint8_t inverted bitmask for the given bit number.
Definition: bits.h:137
static constexpr uint8_t BV8(uint8_t bit)
Create a uint8_t bitmask for the given bit number.
Definition: bits.h:41
Defines API for VL53L0X Time-of-Flight ranging sensor chip usage.
Definition: vl53l0x.h:60
VcselPeriodType
Type of pulse period configured for VL53L0X device VCSEL (Vertical Cavity Surface Emitting Laser).
PowerMode
Possible power modes of VL53L0X device as returned by VL53L0X::get_power_mode().
GPIOFunction
Possible triggers for VL53L0X GPIO pin.
@ DISABLED
No interrupt triggered on GPIO pin.
Profile
Possible profiles of ranging for VL53L0X top-level API VL53L0X::begin().
Defines all API for all external devices supported by FastArduino.
Contains the API around Future implementation.
Definition: future.h:312
@ READY
The status of a Future once its output value has been fully set by a provider.
Define API to define and manage I2C devices.
Definition: i2c.h:51
void register_handler(Handler &handler)
Register a class instance containing methods that shall be called back by an ISR.
Definition: interrupts.h:185
void unregister_handler(Handler &handler)
Unregister a class instance that was previously registered with interrupt::register_handler.
Definition: interrupts.h:207
void delay_us(uint16_t us) INLINE
Delay program execution for the given amount of microseconds.
Definition: time.h:334
API to handle Time-of-Flight ranging sensor VL53L0X I2C chip.