123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560 |
- #include "AP_RangeFinder_VL53L1X.h"
- #include <utility>
- #include <AP_HAL/AP_HAL.h>
- #include <AP_HAL/utility/sparse-endian.h>
- #include <stdio.h>
- extern const AP_HAL::HAL& hal;
- AP_RangeFinder_VL53L1X::AP_RangeFinder_VL53L1X(RangeFinder::RangeFinder_State &_state, AP_RangeFinder_Params &_params, AP_HAL::OwnPtr<AP_HAL::I2CDevice> _dev)
- : AP_RangeFinder_Backend(_state, _params)
- , dev(std::move(_dev)) {}
- AP_RangeFinder_Backend *AP_RangeFinder_VL53L1X::detect(RangeFinder::RangeFinder_State &_state, AP_RangeFinder_Params &_params, AP_HAL::OwnPtr<AP_HAL::I2CDevice> dev)
- {
- if (!dev) {
- return nullptr;
- }
- AP_RangeFinder_VL53L1X *sensor
- = new AP_RangeFinder_VL53L1X(_state, _params, std::move(dev));
- if (!sensor) {
- delete sensor;
- return nullptr;
- }
- sensor->dev->get_semaphore()->take_blocking();
- if (!sensor->check_id() || !sensor->init()) {
- sensor->dev->get_semaphore()->give();
- delete sensor;
- return nullptr;
- }
- sensor->dev->get_semaphore()->give();
- return sensor;
- }
- bool AP_RangeFinder_VL53L1X::check_id(void)
- {
- uint8_t v1, v2;
- if (!(read_register(0x010F, v1) &&
- read_register(0x0110, v2))) {
- return false;
- }
- if ((v1 != 0xEA) ||
- (v2 != 0xCC)) {
- return false;
- }
- printf("Detected VL53L1X on bus 0x%x\n", dev->get_bus_id());
- return true;
- }
- bool AP_RangeFinder_VL53L1X::init()
- {
- uint8_t pad_i2c_hv_extsup_config = 0;
- uint16_t mm_config_outer_offset_mm = 0;
- if (!(
- read_register(PAD_I2C_HV__EXTSUP_CONFIG, pad_i2c_hv_extsup_config) &&
- write_register(PAD_I2C_HV__EXTSUP_CONFIG,
- pad_i2c_hv_extsup_config | 0x01) &&
-
- read_register16(OSC_MEASURED__FAST_OSC__FREQUENCY, fast_osc_frequency) &&
- read_register16(RESULT__OSC_CALIBRATE_VAL, osc_calibrate_val) &&
-
- write_register16(DSS_CONFIG__TARGET_TOTAL_RATE_MCPS, TargetRate) &&
- write_register(GPIO__TIO_HV_STATUS, 0x02) &&
- write_register(SIGMA_ESTIMATOR__EFFECTIVE_PULSE_WIDTH_NS, 8) &&
- write_register(SIGMA_ESTIMATOR__EFFECTIVE_AMBIENT_WIDTH_NS, 16) &&
- write_register(ALGO__CROSSTALK_COMPENSATION_VALID_HEIGHT_MM, 0x01) &&
- write_register(ALGO__RANGE_IGNORE_VALID_HEIGHT_MM, 0xFF) &&
- write_register(ALGO__RANGE_MIN_CLIP, 0) &&
- write_register(ALGO__CONSISTENCY_CHECK__TOLERANCE, 2) &&
-
- write_register16(SYSTEM__THRESH_RATE_HIGH, 0x0000) &&
- write_register16(SYSTEM__THRESH_RATE_LOW, 0x0000) &&
- write_register(DSS_CONFIG__APERTURE_ATTENUATION, 0x38) &&
-
- write_register16(RANGE_CONFIG__SIGMA_THRESH, 360) &&
- write_register16(RANGE_CONFIG__MIN_COUNT_RATE_RTN_LIMIT_MCPS, 192) &&
-
- write_register(SYSTEM__GROUPED_PARAMETER_HOLD_0, 0x01) &&
- write_register(SYSTEM__GROUPED_PARAMETER_HOLD_1, 0x01) &&
- write_register(SD_CONFIG__QUANTIFIER, 2) &&
-
-
-
-
- write_register(SYSTEM__GROUPED_PARAMETER_HOLD, 0x00) &&
- write_register(SYSTEM__SEED_CONFIG, 1) &&
-
- write_register(SYSTEM__SEQUENCE_CONFIG, 0x8B) &&
- write_register16(DSS_CONFIG__MANUAL_EFFECTIVE_SPADS_SELECT, 200 << 8) &&
- write_register(DSS_CONFIG__ROI_MODE_CONTROL, 2) &&
- read_register16(MM_CONFIG__OUTER_OFFSET_MM, mm_config_outer_offset_mm) &&
- setDistanceMode(Long) &&
- setMeasurementTimingBudget(40000) &&
-
-
- write_register16(ALGO__PART_TO_PART_RANGE_OFFSET_MM, mm_config_outer_offset_mm * 4) &&
-
- startContinuous(50)
- )) {
- return false;
- }
-
- dev->register_periodic_callback(50000,
- FUNCTOR_BIND_MEMBER(&AP_RangeFinder_VL53L1X::timer, void));
- return true;
- }
- bool AP_RangeFinder_VL53L1X::setDistanceMode(DistanceMode distance_mode)
- {
-
- uint32_t budget_us = 0;
- if (!getMeasurementTimingBudget(budget_us)) {
- return false;
- }
- switch (distance_mode) {
- case Short:
-
- if (!(
- write_register(RANGE_CONFIG__VCSEL_PERIOD_A, 0x07) &&
- write_register(RANGE_CONFIG__VCSEL_PERIOD_B, 0x05) &&
- write_register(RANGE_CONFIG__VALID_PHASE_HIGH, 0x38) &&
-
- write_register(SD_CONFIG__WOI_SD0, 0x07) &&
- write_register(SD_CONFIG__WOI_SD1, 0x05) &&
- write_register(SD_CONFIG__INITIAL_PHASE_SD0, 6) &&
- write_register(SD_CONFIG__INITIAL_PHASE_SD1, 6))) {
- return false;
- }
- break;
- case Medium:
-
- if (!(
- write_register(RANGE_CONFIG__VCSEL_PERIOD_A, 0x0B) &&
- write_register(RANGE_CONFIG__VCSEL_PERIOD_B, 0x09) &&
- write_register(RANGE_CONFIG__VALID_PHASE_HIGH, 0x78) &&
-
- write_register(SD_CONFIG__WOI_SD0, 0x0B) &&
- write_register(SD_CONFIG__WOI_SD1, 0x09) &&
- write_register(SD_CONFIG__INITIAL_PHASE_SD0, 10) &&
- write_register(SD_CONFIG__INITIAL_PHASE_SD1, 10))) {
- return false;
- }
- break;
- case Long:
-
- if (!(
- write_register(RANGE_CONFIG__VCSEL_PERIOD_A, 0x0F) &&
- write_register(RANGE_CONFIG__VCSEL_PERIOD_B, 0x0D) &&
- write_register(RANGE_CONFIG__VALID_PHASE_HIGH, 0xB8) &&
-
- write_register(SD_CONFIG__WOI_SD0, 0x0F) &&
- write_register(SD_CONFIG__WOI_SD1, 0x0D) &&
- write_register(SD_CONFIG__INITIAL_PHASE_SD0, 14) &&
- write_register(SD_CONFIG__INITIAL_PHASE_SD1, 14))) {
- return false;
- }
- break;
- default:
-
- return false;
- }
-
- return setMeasurementTimingBudget(budget_us);
- }
- bool AP_RangeFinder_VL53L1X::setMeasurementTimingBudget(uint32_t budget_us)
- {
-
- if (budget_us <= TimingGuard) {
- return false;
- }
- uint32_t range_config_timeout_us = budget_us - TimingGuard;
- if (range_config_timeout_us > 1100000) {
- return false;
- }
- range_config_timeout_us /= 2;
-
- uint8_t range_config_vcsel_period = 0;
- if (!read_register(RANGE_CONFIG__VCSEL_PERIOD_A, range_config_vcsel_period)) {
- return false;
- }
-
- uint32_t macro_period_us = calcMacroPeriod(range_config_vcsel_period);
-
-
-
- uint32_t phasecal_timeout_mclks = timeoutMicrosecondsToMclks(1000, macro_period_us);
- if (phasecal_timeout_mclks > 0xFF) {
- phasecal_timeout_mclks = 0xFF;
- }
- if (!( write_register(PHASECAL_CONFIG__TIMEOUT_MACROP, phasecal_timeout_mclks) &&
-
-
-
-
-
-
-
- write_register16(MM_CONFIG__TIMEOUT_MACROP_A, encodeTimeout(
- timeoutMicrosecondsToMclks(1, macro_period_us))) &&
-
- write_register16(RANGE_CONFIG__TIMEOUT_MACROP_A, encodeTimeout(
- timeoutMicrosecondsToMclks(range_config_timeout_us, macro_period_us))) &&
-
- read_register(RANGE_CONFIG__VCSEL_PERIOD_B, range_config_vcsel_period)
- )) {
- return false;
- }
-
- macro_period_us = calcMacroPeriod(range_config_vcsel_period);
-
-
- return write_register16(MM_CONFIG__TIMEOUT_MACROP_B, encodeTimeout(
- timeoutMicrosecondsToMclks(1, macro_period_us))) &&
-
- write_register16(RANGE_CONFIG__TIMEOUT_MACROP_B, encodeTimeout(
- timeoutMicrosecondsToMclks(range_config_timeout_us, macro_period_us)));
- }
- bool AP_RangeFinder_VL53L1X::getMeasurementTimingBudget(uint32_t &budget)
- {
-
-
-
- uint8_t range_config_vcsel_period_a = 0;
- if (!read_register(RANGE_CONFIG__VCSEL_PERIOD_A, range_config_vcsel_period_a)) {
- return false;
- }
- uint32_t macro_period_us = calcMacroPeriod(range_config_vcsel_period_a);
- uint16_t timeout_macrop_a = 0;
- if (!read_register16(RANGE_CONFIG__TIMEOUT_MACROP_A, timeout_macrop_a)) {
- return false;
- }
-
- uint32_t range_config_timeout_us = timeoutMclksToMicroseconds(decodeTimeout(timeout_macrop_a), macro_period_us);
- budget = 2 * range_config_timeout_us + TimingGuard;
- return true;
- }
- bool AP_RangeFinder_VL53L1X::startContinuous(uint32_t period_ms)
- {
-
- uint32_t adjusted_period_ms = period_ms + (period_ms * 64 / 1000);
-
- return write_register32(SYSTEM__INTERMEASUREMENT_PERIOD, adjusted_period_ms * osc_calibrate_val) &&
- write_register(SYSTEM__INTERRUPT_CLEAR, 0x01) &&
- write_register(SYSTEM__MODE_START, 0x40);
- }
- uint32_t AP_RangeFinder_VL53L1X::decodeTimeout(uint16_t reg_val)
- {
- return ((uint32_t)(reg_val & 0xFF) << (reg_val >> 8)) + 1;
- }
- uint16_t AP_RangeFinder_VL53L1X::encodeTimeout(uint32_t timeout_mclks)
- {
-
- uint32_t ls_byte = 0;
- uint16_t ms_byte = 0;
- if (timeout_mclks > 0) {
- ls_byte = timeout_mclks - 1;
- while ((ls_byte & 0xFFFFFF00) > 0) {
- ls_byte >>= 1;
- ms_byte++;
- }
- return (ms_byte << 8) | (ls_byte & 0xFF);
- }
- else {
- return 0;
- }
- }
- uint32_t AP_RangeFinder_VL53L1X::timeoutMclksToMicroseconds(uint32_t timeout_mclks, uint32_t macro_period_us)
- {
- return ((uint64_t)timeout_mclks * macro_period_us + 0x800) >> 12;
- }
- uint32_t AP_RangeFinder_VL53L1X::timeoutMicrosecondsToMclks(uint32_t timeout_us, uint32_t macro_period_us)
- {
- return (((uint32_t)timeout_us << 12) + (macro_period_us >> 1)) / macro_period_us;
- }
- uint32_t AP_RangeFinder_VL53L1X::calcMacroPeriod(uint8_t vcsel_period)
- {
-
-
- uint32_t pll_period_us = ((uint32_t)0x01 << 30) / fast_osc_frequency;
-
- uint8_t vcsel_period_pclks = (vcsel_period + 1) << 1;
-
- uint32_t macro_period_us = (uint32_t)2304 * pll_period_us;
- macro_period_us >>= 6;
- macro_period_us *= vcsel_period_pclks;
- macro_period_us >>= 6;
- return macro_period_us;
- }
- bool AP_RangeFinder_VL53L1X::setupManualCalibration(void)
- {
- uint8_t saved_vhv_init = 0;
- uint8_t saved_vhv_timeout = 0;
- uint8_t phasecal_result_vcsel_start = 0;
- return
- read_register(VHV_CONFIG__INIT, saved_vhv_init) &&
- read_register(VHV_CONFIG__TIMEOUT_MACROP_LOOP_BOUND, saved_vhv_timeout) &&
-
- write_register(VHV_CONFIG__INIT, saved_vhv_init & 0x7F) &&
-
- write_register(VHV_CONFIG__TIMEOUT_MACROP_LOOP_BOUND,
- (saved_vhv_timeout & 0x03) + (3 << 2)) &&
-
- write_register(PHASECAL_CONFIG__OVERRIDE, 0x01) &&
- read_register(PHASECAL_RESULT__VCSEL_START, phasecal_result_vcsel_start) &&
- write_register(CAL_CONFIG__VCSEL_START, phasecal_result_vcsel_start);
- }
- bool AP_RangeFinder_VL53L1X::dataReady(void)
- {
- uint8_t gpio_tio_hv_status = 0;
- return read_register(GPIO__TIO_HV_STATUS, gpio_tio_hv_status) &&
- ((gpio_tio_hv_status & 0x01) == 0);
- }
- bool AP_RangeFinder_VL53L1X::get_reading(uint16_t &reading_mm)
- {
- uint8_t tries = 10;
- while (!dataReady()) {
- tries--;
- hal.scheduler->delay(1);
- if (tries == 0) {
- return false;
- }
- }
- uint8_t range_status = 0;
- if (!(read_register(RESULT__RANGE_STATUS, range_status) &&
- read_register16(RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0, reading_mm))) {
- return false;
- }
-
-
-
-
- reading_mm = ((uint32_t)reading_mm * 2011 + 0x0400) / 0x0800;
- if (!write_register(SYSTEM__INTERRUPT_CLEAR, 0x01)) {
- return false;
- }
- switch ((DeviceError)range_status) {
- case RANGECOMPLETE:
- break;
- default:
- #ifdef VL53L1X_DEBUG
- hal.console->printf("VL53L1X: %d ms status %d\n", AP_HAL::millis(), (int)range_status);
- #endif
- return false;
- }
- if (!calibrated) {
- calibrated = setupManualCalibration();
- }
- return calibrated;
- }
- bool AP_RangeFinder_VL53L1X::read_register(uint16_t reg, uint8_t &value)
- {
- uint8_t b[2] = { uint8_t(reg >> 8), uint8_t(reg & 0xFF) };
- return dev->transfer(b, 2, &value, 1);
- }
- bool AP_RangeFinder_VL53L1X::read_register16(uint16_t reg, uint16_t & value)
- {
- uint16_t v = 0;
- uint8_t b[2] = { uint8_t(reg >> 8), uint8_t(reg & 0xFF) };
- if (!dev->transfer(b, 2, (uint8_t *)&v, 2)) {
- return false;
- }
- value = be16toh(v);
- return true;
- }
- bool AP_RangeFinder_VL53L1X::write_register(uint16_t reg, uint8_t value)
- {
- uint8_t b[3] = { uint8_t(reg >> 8), uint8_t(reg & 0xFF), value };
- return dev->transfer(b, 3, nullptr, 0);
- }
- bool AP_RangeFinder_VL53L1X::write_register16(uint16_t reg, uint16_t value)
- {
- uint8_t b[4] = { uint8_t(reg >> 8), uint8_t(reg & 0xFF), uint8_t(value >> 8), uint8_t(value & 0xFF) };
- return dev->transfer(b, 4, nullptr, 0);
- }
- bool AP_RangeFinder_VL53L1X::write_register32(uint16_t reg, uint32_t value)
- {
- uint8_t b[6] = { uint8_t(reg >> 8),
- uint8_t(reg & 0xFF),
- uint8_t((value >> 24) & 0xFF),
- uint8_t((value >> 16) & 0xFF),
- uint8_t((value >> 8) & 0xFF),
- uint8_t((value) & 0xFF) };
- return dev->transfer(b, 6, nullptr, 0);
- }
- void AP_RangeFinder_VL53L1X::timer(void)
- {
- uint16_t range_mm;
- if ((get_reading(range_mm)) && (range_mm <= 4000)) {
- WITH_SEMAPHORE(_sem);
- sum_mm += range_mm;
- counter++;
- }
- }
- void AP_RangeFinder_VL53L1X::update(void)
- {
- WITH_SEMAPHORE(_sem);
- if (counter > 0) {
- state.distance_cm = sum_mm / (10*counter);
- state.last_reading_ms = AP_HAL::millis();
- update_status();
- sum_mm = 0;
- counter = 0;
- } else if (AP_HAL::millis() - state.last_reading_ms > 200) {
-
- set_status(RangeFinder::RangeFinder_NoData);
- }
- }
|