From 03aba3bd4915de73e204b5baa57f6df32e69595e Mon Sep 17 00:00:00 2001 From: Neox Date: Sat, 16 May 2026 16:55:26 +0200 Subject: [PATCH] =?UTF-8?q?=20Backup=20vom=20Rp2040Zero=2016.05.2026=20hin?= =?UTF-8?q?zugef=C3=BCgt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- VL53L0X_backup.py | 649 ++++++++++++++++++++++++++++++++++++++++++++++ lcd1602_backup.py | 50 ++++ main_backup.py | 46 ++++ vl53l0x_backup.py | 544 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 1289 insertions(+) create mode 100644 VL53L0X_backup.py create mode 100644 lcd1602_backup.py create mode 100644 main_backup.py create mode 100644 vl53l0x_backup.py diff --git a/VL53L0X_backup.py b/VL53L0X_backup.py new file mode 100644 index 0000000..0ed42c8 --- /dev/null +++ b/VL53L0X_backup.py @@ -0,0 +1,649 @@ +from micropython import const +import ustruct +import utime +from machine import Timer +import time +# +_IO_TIMEOUT = 1000 +_SYSRANGE_START = const(0x00) +_EXTSUP_HV = const(0x89) +_MSRC_CONFIG = const(0x60) +_FINAL_RATE_RTN_LIMIT = const(0x44) +_SYSTEM_SEQUENCE = const(0x01) +_SPAD_REF_START = const(0x4f) +_SPAD_ENABLES = const(0xb0) +_REF_EN_START_SELECT = const(0xb6) +_SPAD_NUM_REQUESTED = const(0x4e) +_INTERRUPT_GPIO = const(0x0a) +_INTERRUPT_CLEAR = const(0x0b) +_GPIO_MUX_ACTIVE_HIGH = const(0x84) +_RESULT_INTERRUPT_STATUS = const(0x13) +_RESULT_RANGE_STATUS = const(0x14) +_OSC_CALIBRATE = const(0xf8) +_MEASURE_PERIOD = const(0x04) + +SYSRANGE_START = 0x00 + +SYSTEM_THRESH_HIGH = 0x0C +SYSTEM_THRESH_LOW = 0x0E + +SYSTEM_SEQUENCE_CONFIG = 0x01 +SYSTEM_RANGE_CONFIG = 0x09 +SYSTEM_INTERMEASUREMENT_PERIOD = 0x04 + +SYSTEM_INTERRUPT_CONFIG_GPIO = 0x0A + +GPIO_HV_MUX_ACTIVE_HIGH = 0x84 + +SYSTEM_INTERRUPT_CLEAR = 0x0B + +RESULT_INTERRUPT_STATUS = 0x13 +RESULT_RANGE_STATUS = 0x14 + +RESULT_CORE_AMBIENT_WINDOW_EVENTS_RTN = 0xBC +RESULT_CORE_RANGING_TOTAL_EVENTS_RTN = 0xC0 +RESULT_CORE_AMBIENT_WINDOW_EVENTS_REF = 0xD0 +RESULT_CORE_RANGING_TOTAL_EVENTS_REF = 0xD4 +RESULT_PEAK_SIGNAL_RATE_REF = 0xB6 + +ALGO_PART_TO_PART_RANGE_OFFSET_MM = 0x28 + +I2C_SLAVE_DEVICE_ADDRESS = 0x8A + +MSRC_CONFIG_CONTROL = 0x60 + +PRE_RANGE_CONFIG_MIN_SNR = 0x27 +PRE_RANGE_CONFIG_VALID_PHASE_LOW = 0x56 +PRE_RANGE_CONFIG_VALID_PHASE_HIGH = 0x57 +PRE_RANGE_MIN_COUNT_RATE_RTN_LIMIT = 0x64 + +FINAL_RANGE_CONFIG_MIN_SNR = 0x67 +FINAL_RANGE_CONFIG_VALID_PHASE_LOW = 0x47 +FINAL_RANGE_CONFIG_VALID_PHASE_HIGH = 0x48 +FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT = 0x44 + +PRE_RANGE_CONFIG_SIGMA_THRESH_HI = 0x61 +PRE_RANGE_CONFIG_SIGMA_THRESH_LO = 0x62 + +PRE_RANGE_CONFIG_VCSEL_PERIOD = 0x50 +PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI = 0x51 +PRE_RANGE_CONFIG_TIMEOUT_MACROP_LO = 0x52 + +SYSTEM_HISTOGRAM_BIN = 0x81 +HISTOGRAM_CONFIG_INITIAL_PHASE_SELECT = 0x33 +HISTOGRAM_CONFIG_READOUT_CTRL = 0x55 + +FINAL_RANGE_CONFIG_VCSEL_PERIOD = 0x70 +FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI = 0x71 +FINAL_RANGE_CONFIG_TIMEOUT_MACROP_LO = 0x72 +CROSSTALK_COMPENSATION_PEAK_RATE_MCPS = 0x20 + +MSRC_CONFIG_TIMEOUT_MACROP = 0x46 + +SOFT_RESET_GO2_SOFT_RESET_N = 0xBF +IDENTIFICATION_MODEL_ID = 0xC0 +IDENTIFICATION_REVISION_ID = 0xC2 + +OSC_CALIBRATE_VAL = 0xF8 + +GLOBAL_CONFIG_VCSEL_WIDTH = 0x32 +GLOBAL_CONFIG_SPAD_ENABLES_REF_0 = 0xB0 +GLOBAL_CONFIG_SPAD_ENABLES_REF_1 = 0xB1 +GLOBAL_CONFIG_SPAD_ENABLES_REF_2 = 0xB2 +GLOBAL_CONFIG_SPAD_ENABLES_REF_3 = 0xB3 +GLOBAL_CONFIG_SPAD_ENABLES_REF_4 = 0xB4 +GLOBAL_CONFIG_SPAD_ENABLES_REF_5 = 0xB5 + +GLOBAL_CONFIG_REF_EN_START_SELECT = 0xB6 +DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD = 0x4E +DYNAMIC_SPAD_REF_EN_START_OFFSET = 0x4F +POWER_MANAGEMENT_GO1_POWER_FORCE = 0x80 + +VHV_CONFIG_PAD_SCL_SDA__EXTSUP_HV = 0x89 + +ALGO_PHASECAL_LIM = 0x30 +ALGO_PHASECAL_CONFIG_TIMEOUT = 0x30 + + +class TimeoutError(RuntimeError): + pass + + +class VL53L0X: + def __init__(self, i2c, address=0x29): + self.i2c = i2c + self.address = address + self.init() + self._started = False + self.measurement_timing_budget_us = 0 + self.set_measurement_timing_budget(self.measurement_timing_budget_us) + self.enables = {"tcc": 0, + "dss": 0, + "msrc": 0, + "pre_range": 0, + "final_range": 0} + self.timeouts = {"pre_range_vcsel_period_pclks": 0, + "msrc_dss_tcc_mclks": 0, + "msrc_dss_tcc_us": 0, + "pre_range_mclks": 0, + "pre_range_us": 0, + "final_range_vcsel_period_pclks": 0, + "final_range_mclks": 0, + "final_range_us": 0 + } + self.vcsel_period_type = ["VcselPeriodPreRange", "VcselPeriodFinalRange"] + + def _registers(self, register, values=None, struct='B'): + if values is None: + size = ustruct.calcsize(struct) + data = self.i2c.readfrom_mem(self.address, register, size) + values = ustruct.unpack(struct, data) + return values + data = ustruct.pack(struct, *values) + self.i2c.writeto_mem(self.address, register, data) + + def _register(self, register, value=None, struct='B'): + if value is None: + return self._registers(register, struct=struct)[0] + self._registers(register, (value,), struct=struct) + + def _flag(self, register=0x00, bit=0, value=None): + data = self._register(register) + mask = 1 << bit + if value is None: + return bool(data & mask) + elif value: + data |= mask + else: + data &= ~mask + self._register(register, data) + + def _config(self, *config): + for register, value in config: + self._register(register, value) + + def init(self, power2v8=True): + self._flag(_EXTSUP_HV, 0, power2v8) + + # I2C standard mode + self._config( + (0x88, 0x00), + + (0x80, 0x01), + (0xff, 0x01), + (0x00, 0x00), + ) + self._stop_variable = self._register(0x91) + self._config( + (0x00, 0x01), + (0xff, 0x00), + (0x80, 0x00), + ) + + # disable signal_rate_msrc and signal_rate_pre_range limit checks + self._flag(_MSRC_CONFIG, 1, True) + self._flag(_MSRC_CONFIG, 4, True) + + # rate_limit = 0.25 + self._register(_FINAL_RATE_RTN_LIMIT, int(0.1 * (1 << 7)), + struct='>H') + + self._register(_SYSTEM_SEQUENCE, 0xff) + + spad_count, is_aperture = self._spad_info() + spad_map = bytearray(self._registers(_SPAD_ENABLES, struct='6B')) + + # set reference spads + self._config( + (0xff, 0x01), + (_SPAD_REF_START, 0x00), + (_SPAD_NUM_REQUESTED, 0x2c), + (0xff, 0x00), + (_REF_EN_START_SELECT, 0xb4), + ) + + spads_enabled = 0 + for i in range(48): + if i < 12 and is_aperture or spads_enabled >= spad_count: + spad_map[i // 8] &= ~(1 << (i >> 2)) + elif spad_map[i // 8] & (1 << (i >> 2)): + spads_enabled += 1 + + self._registers(_SPAD_ENABLES, spad_map, struct='6B') + + self._config( + (0xff, 0x01), + (0x00, 0x00), + + (0xff, 0x00), + (0x09, 0x00), + (0x10, 0x00), + (0x11, 0x00), + + (0x24, 0x01), + (0x25, 0xFF), + (0x75, 0x00), + + (0xFF, 0x01), + (0x4E, 0x2C), + (0x48, 0x00), + (0x30, 0x20), + + (0xFF, 0x00), + (0x30, 0x09), + (0x54, 0x00), + (0x31, 0x04), + (0x32, 0x03), + (0x40, 0x83), + (0x46, 0x25), + (0x60, 0x00), + (0x27, 0x00), + (0x50, 0x06), + (0x51, 0x00), + (0x52, 0x96), + (0x56, 0x08), + (0x57, 0x30), + (0x61, 0x00), + (0x62, 0x00), + (0x64, 0x00), + (0x65, 0x00), + (0x66, 0xA0), + + (0xFF, 0x01), + (0x22, 0x32), + (0x47, 0x14), + (0x49, 0xFF), + (0x4A, 0x00), + + (0xFF, 0x00), + (0x7A, 0x0A), + (0x7B, 0x00), + (0x78, 0x21), + + (0xFF, 0x01), + (0x23, 0x34), + (0x42, 0x00), + (0x44, 0xFF), + (0x45, 0x26), + (0x46, 0x05), + (0x40, 0x40), + (0x0E, 0x06), + (0x20, 0x1A), + (0x43, 0x40), + + (0xFF, 0x00), + (0x34, 0x03), + (0x35, 0x44), + + (0xFF, 0x01), + (0x31, 0x04), + (0x4B, 0x09), + (0x4C, 0x05), + (0x4D, 0x04), + + (0xFF, 0x00), + (0x44, 0x00), + (0x45, 0x20), + (0x47, 0x08), + (0x48, 0x28), + (0x67, 0x00), + (0x70, 0x04), + (0x71, 0x01), + (0x72, 0xFE), + (0x76, 0x00), + (0x77, 0x00), + + (0xFF, 0x01), + (0x0D, 0x01), + + (0xFF, 0x00), + (0x80, 0x01), + (0x01, 0xF8), + + (0xFF, 0x01), + (0x8E, 0x01), + (0x00, 0x01), + (0xFF, 0x00), + (0x80, 0x00), + ) + + self._register(_INTERRUPT_GPIO, 0x04) + self._flag(_GPIO_MUX_ACTIVE_HIGH, 4, False) + self._register(_INTERRUPT_CLEAR, 0x01) + + # XXX Need to implement this. + # budget = self._timing_budget() + # self._register(_SYSTEM_SEQUENCE, 0xe8) + # self._timing_budget(budget) + + self._register(_SYSTEM_SEQUENCE, 0x01) + self._calibrate(0x40) + self._register(_SYSTEM_SEQUENCE, 0x02) + self._calibrate(0x00) + + self._register(_SYSTEM_SEQUENCE, 0xe8) + + def _spad_info(self): + self._config( + (0x80, 0x01), + (0xff, 0x01), + (0x00, 0x00), + + (0xff, 0x06), + ) + self._flag(0x83, 3, True) + self._config( + (0xff, 0x07), + (0x81, 0x01), + + (0x80, 0x01), + + (0x94, 0x6b), + (0x83, 0x00), + ) + for timeout in range(_IO_TIMEOUT): + if self._register(0x83): + break + utime.sleep_ms(1) + else: + raise TimeoutError() + self._config( + (0x83, 0x01), + ) + value = self._register(0x92) + self._config( + (0x81, 0x00), + (0xff, 0x06), + ) + self._flag(0x83, 3, False) + self._config( + (0xff, 0x01), + (0x00, 0x01), + + (0xff, 0x00), + (0x80, 0x00), + ) + count = value & 0x7f + is_aperture = bool(value & 0b10000000) + return count, is_aperture + + def _calibrate(self, vhv_init_byte): + self._register(_SYSRANGE_START, 0x01 | vhv_init_byte) + for timeout in range(_IO_TIMEOUT): + if self._register(_RESULT_INTERRUPT_STATUS) & 0x07: + break + utime.sleep_ms(1) + else: + raise TimeoutError() + self._register(_INTERRUPT_CLEAR, 0x01) + self._register(_SYSRANGE_START, 0x00) + + def start(self, period=0): + self._config( + (0x80, 0x01), + (0xFF, 0x01), + (0x00, 0x00), + (0x91, self._stop_variable), + (0x00, 0x01), + (0xFF, 0x00), + (0x80, 0x00), + ) + if period: + oscilator = self._register(_OSC_CALIBRATE, struct='>H') + if oscilator: + period *= oscilator + self._register(_MEASURE_PERIOD, period, struct='>H') + self._register(_SYSRANGE_START, 0x04) + else: + self._register(_SYSRANGE_START, 0x02) + self._started = True + + def stop(self): + self._register(_SYSRANGE_START, 0x01) + self._config( + (0xFF, 0x01), + (0x00, 0x00), + (0x91, self._stop_variable), + (0x00, 0x01), + (0xFF, 0x00), + ) + self._started = False + + def read(self): + if not self._started: + self._config( + (0x80, 0x01), + (0xFF, 0x01), + (0x00, 0x00), + (0x91, self._stop_variable), + (0x00, 0x01), + (0xFF, 0x00), + (0x80, 0x00), + (_SYSRANGE_START, 0x01), + ) + for timeout in range(_IO_TIMEOUT): + if not self._register(_SYSRANGE_START) & 0x01: + break + utime.sleep_ms(1) + else: + raise TimeoutError() + for timeout in range(_IO_TIMEOUT): + if self._register(_RESULT_INTERRUPT_STATUS) & 0x07: + break + utime.sleep_ms(1) + else: + raise TimeoutError() + value = self._register(_RESULT_RANGE_STATUS + 10, struct='>H') + self._register(_INTERRUPT_CLEAR, 0x01) + return value + + def set_signal_rate_limit(self, limit_Mcps): + if limit_Mcps < 0 or limit_Mcps > 511.99: + return False + self._register(0x44, limit_Mcps * (1 << 7)) + return True + + def decode_Vcsel_period(self, reg_val): + return (((reg_val) + 1) << 1) + + def encode_Vcsel_period(self, period_pclks): + return (((period_pclks) >> 1) - 1) + + def set_Vcsel_pulse_period(self, type, period_pclks): + vcsel_period_reg = self.encode_Vcsel_period(period_pclks) + + self.get_sequence_step_enables() + self.get_sequence_step_timeouts() + + if type == self.vcsel_period_type[0]: + if period_pclks == 12: + self._register(PRE_RANGE_CONFIG_VALID_PHASE_HIGH, 0x18) + elif period_pclks == 14: + self._register(PRE_RANGE_CONFIG_VALID_PHASE_HIGH, 0x30) + elif period_pclks == 16: + self._register(PRE_RANGE_CONFIG_VALID_PHASE_HIGH, 0x40) + elif period_pclks == 18: + self._register(PRE_RANGE_CONFIG_VALID_PHASE_HIGH, 0x50) + else: + return False + + self._register(PRE_RANGE_CONFIG_VALID_PHASE_LOW, 0x08) + self._register(PRE_RANGE_CONFIG_VCSEL_PERIOD, vcsel_period_reg) + + new_pre_range_timeout_mclks = self.timeout_microseconds_to_Mclks(self.timeouts["pre_range_us"], + period_pclks) + self._register(PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI, self.encode_timeout(new_pre_range_timeout_mclks)) + + new_msrc_timeout_mclks = self.timeout_microseconds_to_Mclks(self.timeouts["msrc_dss_tcc_us"], + period_pclks) + self._register(MSRC_CONFIG_TIMEOUT_MACROP, 255 if new_msrc_timeout_mclks > 256 else (new_msrc_timeout_mclks - 1)) + elif type == self.vcsel_period_type[1]: + if period_pclks == 8: + self._register(FINAL_RANGE_CONFIG_VALID_PHASE_HIGH, 0x10) + self._register(FINAL_RANGE_CONFIG_VALID_PHASE_LOW, 0x08) + self._register(GLOBAL_CONFIG_VCSEL_WIDTH, 0x02) + self._(ALGO_PHASECAL_CONFIG_TIMEOUT, 0x0C) + self._register(0xFF, 0x01) + self._register(ALGO_PHASECAL_LIM, 0x30) + self._register(0xFF, 0x00) + elif period_pclks == 10: + self._register(FINAL_RANGE_CONFIG_VALID_PHASE_HIGH, 0x28) + self._register(FINAL_RANGE_CONFIG_VALID_PHASE_LOW, 0x08) + self._register(GLOBAL_CONFIG_VCSEL_WIDTH, 0x03) + self._register(ALGO_PHASECAL_CONFIG_TIMEOUT, 0x09) + self._register(0xFF, 0x01) + self._register(ALGO_PHASECAL_LIM, 0x20) + self._register(0xFF, 0x00) + elif period_pclks == 12: + self._register(FINAL_RANGE_CONFIG_VALID_PHASE_HIGH, 0x38) + self._register(FINAL_RANGE_CONFIG_VALID_PHASE_LOW, 0x08) + self._register(GLOBAL_CONFIG_VCSEL_WIDTH, 0x03) + self._register(ALGO_PHASECAL_CONFIG_TIMEOUT, 0x08) + self._register(0xFF, 0x01) + self._register(ALGO_PHASECAL_LIM, 0x20) + self._register(0xFF, 0x00) + elif period_pclks == 14: + self._register(FINAL_RANGE_CONFIG_VALID_PHASE_HIGH, 0x48) + self._register(FINAL_RANGE_CONFIG_VALID_PHASE_LOW, 0x08) + self._register(GLOBAL_CONFIG_VCSEL_WIDTH, 0x03) + self._register(ALGO_PHASECAL_CONFIG_TIMEOUT, 0x07) + self._register(0xFF, 0x01) + self._register(ALGO_PHASECAL_LIM, 0x20) + self._register(0xFF, 0x00) + else: + return False + + self._register(FINAL_RANGE_CONFIG_VCSEL_PERIOD, vcsel_period_reg) + + new_final_range_timeout_mclks = self.timeout_microseconds_to_Mclks(self.timeouts["final_range_us"], period_pclks) + + if self.enables["pre_range"]: + new_final_range_timeout_mclks += 1 + self._register(FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI, self.encode_timeout(new_final_range_timeout_mclks)) + else: + return False + self.set_measurement_timing_budget(self.measurement_timing_budget_us) + sequence_config = self._register(SYSTEM_SEQUENCE_CONFIG) + self._register(SYSTEM_SEQUENCE_CONFIG, 0x02) + self.perform_single_ref_calibration(0x0) + self._register(SYSTEM_SEQUENCE_CONFIG, sequence_config) + + return True + + def get_sequence_step_enables(self): + sequence_config = self._register(0x01) + + self.enables["tcc"] = (sequence_config >> 4) & 0x1 + self.enables["dss"] = (sequence_config >> 3) & 0x1 + self.enables["msrc"] = (sequence_config >> 2) & 0x1 + self.enables["pre_range"] = (sequence_config >> 6) & 0x1 + self.enables["final_range"] = (sequence_config >> 7) & 0x1 + + def get_vcsel_pulse_period(self, type): + if type == self.vcsel_period_type[0]: + return self.decode_Vcsel_period(0x50) + elif type == self.vcsel_period_type[1]: + return self.decode_Vcsel_period(0x70) + else: + return 255 + + def get_sequence_step_timeouts(self): + self.timeouts["pre_range_vcsel_period_pclks"] = self.get_vcsel_pulse_period(self.vcsel_period_type[0]) + self.timeouts["msrc_dss_tcc_mclks"] = int(self._register(MSRC_CONFIG_TIMEOUT_MACROP)) + 1 + self.timeouts["msrc_dss_tcc_us"] = self.timeout_Mclks_to_microseconds(self.timeouts["msrc_dss_tcc_mclks"], + self.timeouts[ + "pre_range_vcsel_period_pclks"]) + self.timeouts["pre_range_mclks"] = self.decode_timeout(PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI) + self.timeouts["pre_range_us"] = self.timeout_Mclks_to_microseconds(self.timeouts["pre_range_mclks"], + self.timeouts[ + "pre_range_vcsel_period_pclks"]) + self.timeouts["final_range_vcsel_period_pclks"] = self.get_vcsel_pulse_period(self.vcsel_period_type[1]) + self.timeouts["final_range_mclks"] = self.decode_timeout(self._register(FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI)) + + if self.enables["pre_range"]: + self.timeouts["final_range_mclks"] -= self.timeouts["pre_range_mclks"] + self.timeouts["final_range_us"] = self.timeout_Mclks_to_microseconds(self.timeouts["final_range_mclks"], + self.timeouts[ + "final_range_vcsel_period_pclks"]) + + def timeout_Mclks_to_microseconds(self, timeout_period_mclks, vcsel_period_pclks): + macro_period_ns = self.calc_macro_period(vcsel_period_pclks) + return ((timeout_period_mclks * macro_period_ns) + (macro_period_ns / 2)) / 1000 + + def timeout_microseconds_to_Mclks(self, timeout_period_us, vcsel_period_pclks): + macro_period_ns = self.calc_macro_period(vcsel_period_pclks) + return (((timeout_period_us * 1000) + (macro_period_ns / 2)) / macro_period_ns) + + def calc_macro_period(self, vcsel_period_pclks): + return (((2304 * (vcsel_period_pclks) * 1655) + 500) / 1000) + + def decode_timeout(self, reg_val): + return ((reg_val & 0x00FF) << ((reg_val & 0xFF00) >> 8)) + 1 + + def encode_timeout(self, timeout_mclks): + timeout_mclks = int(timeout_mclks) + ls_byte = 0 + ms_byte = 0 + + if timeout_mclks > 0: + ls_byte = timeout_mclks - 1 + + while (ls_byte & 0xFFFFFF00) > 0: + ls_byte >>= 1 + ms_byte += 1 + return (ms_byte << 8) or (ls_byte & 0xFF) + else: + return 0 + + def set_measurement_timing_budget(self, budget_us): + start_overhead = 1320 + end_overhead = 960 + msrc_overhead = 660 + tcc_overhead = 590 + dss_overhead = 690 + pre_range_overhead = 660 + final_range_overhead = 550 + + min_timing_budget = 20000 + + if budget_us < min_timing_budget: + return False + used_budget_us = start_overhead + end_overhead + + self.get_sequence_step_enables() + self.get_sequence_step_timeouts() + + if self.enables["tcc"]: + used_budget_us += self.timeouts["msrc_dss_tcc_us"] + tcc_overhead + if self.enables["dss"]: + used_budget_us += 2* self.timeouts["msrc_dss_tcc_us"] + dss_overhead + if self.enables["msrc"]: + used_budget_us += self.timeouts["msrc_dss_tcc_us"] + msrc_overhead + if self.enables["pre_range"]: + used_budget_us += self.timeouts["pre_range_us"] + pre_range_overhead + if self.enables["final_range"]: + used_budget_us += final_range_overhead + + if used_budget_us > budget_us: + return False + final_range_timeout_us = budget_us - used_budget_us + final_range_timeout_mclks = self.timeout_microseconds_to_Mclks(final_range_timeout_us, self.timeouts["final_range_vcsel_period_pclks"]) + + if self.enables["pre_range"]: + final_range_timeout_mclks += self.timeouts["pre_range_mclks"] + self._register(FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI, self.encode_timeout(final_range_timeout_mclks)) + self.measurement_timing_budget_us = budget_us + return True + + def perform_single_ref_calibration(self, vhv_init_byte): + chrono = Timer.Chrono() + self._register(SYSRANGE_START, 0x01|vhv_init_byte) + chrono.start() + while self._register((RESULT_INTERRUPT_STATUS & 0x07) == 0): + time_elapsed = chrono.read_ms() + if time_elapsed > _IO_TIMEOUT: + return False + self._register(SYSTEM_INTERRUPT_CLEAR, 0x01) + self._register(SYSRANGE_START, 0x00) + return True + diff --git a/lcd1602_backup.py b/lcd1602_backup.py new file mode 100644 index 0000000..84b9852 --- /dev/null +++ b/lcd1602_backup.py @@ -0,0 +1,50 @@ +import time +from machine import Pin + +class LCD1602: + def __init__(self, rs, en, d4, d5, d6, d7): + self.rs = Pin(rs, Pin.OUT) + self.en = Pin(en, Pin.OUT) + self.data_pins = [ + Pin(d4, Pin.OUT), + Pin(d5, Pin.OUT), + Pin(d6, Pin.OUT), + Pin(d7, Pin.OUT) + ] + self._init_lcd() + + def _pulse(self): + self.en.value(1) + time.sleep_us(1) + self.en.value(0) + time.sleep_us(100) + + def _send(self, value, mode=0): + self.rs.value(mode) + for i in range(2): + for j in range(4): + self.data_pins[j].value((value >> (4 * (1 - i) + j)) & 0x01) + self._pulse() + time.sleep_ms(2) + + def _init_lcd(self): + time.sleep_ms(20) + self._send(0x33) # init + self._send(0x32) # 4-bit mode + self._send(0x28) # 2 lines, 5x7 matrix + self._send(0x0C) # display on, cursor off + self._send(0x06) # entry mode + self.clear() + + def clear(self): + self._send(0x01) + time.sleep_ms(2) + + def putstr(self, string): + for char in string: + self._send(ord(char), 1) + + def move_to(self, col, row): + addr = col + (0x40 if row else 0x00) + self._send(0x80 | addr) + diff --git a/main_backup.py b/main_backup.py new file mode 100644 index 0000000..55bd9a5 --- /dev/null +++ b/main_backup.py @@ -0,0 +1,46 @@ +import time +from machine import Pin, I2C, time_pulse_us +from lcd1602 import LCD1602 +from vl53l0x import VL53L0X # muss als vl53l0x.py auf dem Board liegen + +# --- LCD Setup (RS=6, E=7, D4=8, D5=9, D6=10, D7=11) --- +lcd = LCD1602(6, 7, 8, 9, 10, 11) + +# --- HC-SR04 Setup --- +trig = Pin(3, Pin.OUT) +echo = Pin(2, Pin.IN) + +def read_hcsr04(): + trig.low() + time.sleep_us(2) + trig.high() + time.sleep_us(10) + trig.low() + try: + duration = time_pulse_us(echo, 1, 30000) # Warte max. 30ms + distance = (duration / 2) / 29.1 # cm + except OSError: + distance = -1 # kein Messwert + return distance + +# --- VL53L0X Setup --- +i2c = I2C(0, sda=Pin(4), scl=Pin(5), freq=400000) +sensor = VL53L0X(i2c) + +# --- Hauptloop --- +while True: + dist_us = read_hcsr04() + dist_tof = sensor.range/10 # Adafruit-Treiber liefert .range in mm modifiziert zu cm + + lcd.clear() + lcd.move_to(0, 0) + if dist_us >= 0: + lcd.putstr("US: {:.1f} cm".format(dist_us)) + else: + lcd.putstr("US: ---") + + lcd.move_to(0, 1) + lcd.putstr("ToF: {} cm".format(dist_tof)) + + time.sleep(0.5) + diff --git a/vl53l0x_backup.py b/vl53l0x_backup.py new file mode 100644 index 0000000..84475bd --- /dev/null +++ b/vl53l0x_backup.py @@ -0,0 +1,544 @@ +# SPDX-FileCopyrightText: 2017 Tony DiCola for Adafruit Industries +# SPDX-License-Identifier: MIT +# +# Modified by Kevin Zhu to work on the ESP32 running Micropython 1.14 +# Modified by Salvatore Sanfilippo for non-blocking API. +# +# This code is released under the MIT license. + +import math +import utime + +__version__ = "0.0.0-auto.0" +__repo__ = "https://github.com/antirez/VL53L0X.git" + +# Configuration constants: +_SYSRANGE_START = const(0x00) +_SYSTEM_THRESH_HIGH = const(0x0C) +_SYSTEM_THRESH_LOW = const(0x0E) +_SYSTEM_SEQUENCE_CONFIG = const(0x01) +_SYSTEM_RANGE_CONFIG = const(0x09) +_SYSTEM_INTERMEASUREMENT_PERIOD = const(0x04) +_SYSTEM_INTERRUPT_CONFIG_GPIO = const(0x0A) +_GPIO_HV_MUX_ACTIVE_HIGH = const(0x84) +_SYSTEM_INTERRUPT_CLEAR = const(0x0B) +_RESULT_INTERRUPT_STATUS = const(0x13) +_RESULT_RANGE_STATUS = const(0x14) +_RESULT_CORE_AMBIENT_WINDOW_EVENTS_RTN = const(0xBC) +_RESULT_CORE_RANGING_TOTAL_EVENTS_RTN = const(0xC0) +_RESULT_CORE_AMBIENT_WINDOW_EVENTS_REF = const(0xD0) +_RESULT_CORE_RANGING_TOTAL_EVENTS_REF = const(0xD4) +_RESULT_PEAK_SIGNAL_RATE_REF = const(0xB6) +_ALGO_PART_TO_PART_RANGE_OFFSET_MM = const(0x28) +_I2C_SLAVE_DEVICE_ADDRESS = const(0x8A) +_MSRC_CONFIG_CONTROL = const(0x60) +_PRE_RANGE_CONFIG_MIN_SNR = const(0x27) +_PRE_RANGE_CONFIG_VALID_PHASE_LOW = const(0x56) +_PRE_RANGE_CONFIG_VALID_PHASE_HIGH = const(0x57) +_PRE_RANGE_MIN_COUNT_RATE_RTN_LIMIT = const(0x64) +_FINAL_RANGE_CONFIG_MIN_SNR = const(0x67) +_FINAL_RANGE_CONFIG_VALID_PHASE_LOW = const(0x47) +_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH = const(0x48) +_FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT = const(0x44) +_PRE_RANGE_CONFIG_SIGMA_THRESH_HI = const(0x61) +_PRE_RANGE_CONFIG_SIGMA_THRESH_LO = const(0x62) +_PRE_RANGE_CONFIG_VCSEL_PERIOD = const(0x50) +_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI = const(0x51) +_PRE_RANGE_CONFIG_TIMEOUT_MACROP_LO = const(0x52) +_SYSTEM_HISTOGRAM_BIN = const(0x81) +_HISTOGRAM_CONFIG_INITIAL_PHASE_SELECT = const(0x33) +_HISTOGRAM_CONFIG_READOUT_CTRL = const(0x55) +_FINAL_RANGE_CONFIG_VCSEL_PERIOD = const(0x70) +_FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI = const(0x71) +_FINAL_RANGE_CONFIG_TIMEOUT_MACROP_LO = const(0x72) +_CROSSTALK_COMPENSATION_PEAK_RATE_MCPS = const(0x20) +_MSRC_CONFIG_TIMEOUT_MACROP = const(0x46) +_SOFT_RESET_GO2_SOFT_RESET_N = const(0xBF) +_IDENTIFICATION_MODEL_ID = const(0xC0) +_IDENTIFICATION_REVISION_ID = const(0xC2) +_OSC_CALIBRATE_VAL = const(0xF8) +_GLOBAL_CONFIG_VCSEL_WIDTH = const(0x32) +_GLOBAL_CONFIG_SPAD_ENABLES_REF_0 = const(0xB0) +_GLOBAL_CONFIG_SPAD_ENABLES_REF_1 = const(0xB1) +_GLOBAL_CONFIG_SPAD_ENABLES_REF_2 = const(0xB2) +_GLOBAL_CONFIG_SPAD_ENABLES_REF_3 = const(0xB3) +_GLOBAL_CONFIG_SPAD_ENABLES_REF_4 = const(0xB4) +_GLOBAL_CONFIG_SPAD_ENABLES_REF_5 = const(0xB5) +_GLOBAL_CONFIG_REF_EN_START_SELECT = const(0xB6) +_DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD = const(0x4E) +_DYNAMIC_SPAD_REF_EN_START_OFFSET = const(0x4F) +_POWER_MANAGEMENT_GO1_POWER_FORCE = const(0x80) +_VHV_CONFIG_PAD_SCL_SDA__EXTSUP_HV = const(0x89) +_ALGO_PHASECAL_LIM = const(0x30) +_ALGO_PHASECAL_CONFIG_TIMEOUT = const(0x30) +_VCSEL_PERIOD_PRE_RANGE = const(0) +_VCSEL_PERIOD_FINAL_RANGE = const(1) + + +def _decode_timeout(val): + # format: "(LSByte * 2^MSByte) + 1" + return float(val & 0xFF) * math.pow(2.0, ((val & 0xFF00) >> 8)) + 1 + + +def _encode_timeout(timeout_mclks): + # format: "(LSByte * 2^MSByte) + 1" + timeout_mclks = int(timeout_mclks) & 0xFFFF + ls_byte = 0 + ms_byte = 0 + if timeout_mclks > 0: + ls_byte = timeout_mclks - 1 + while ls_byte > 255: + ls_byte >>= 1 + ms_byte += 1 + return ((ms_byte << 8) | (ls_byte & 0xFF)) & 0xFFFF + return 0 + + +def _timeout_mclks_to_microseconds(timeout_period_mclks, vcsel_period_pclks): + macro_period_ns = ((2304 * (vcsel_period_pclks) * 1655) + 500) // 1000 + return ((timeout_period_mclks * macro_period_ns) + (macro_period_ns // 2)) // 1000 + + +def _timeout_microseconds_to_mclks(timeout_period_us, vcsel_period_pclks): + macro_period_ns = ((2304 * (vcsel_period_pclks) * 1655) + 500) // 1000 + return ((timeout_period_us * 1000) + (macro_period_ns // 2)) // macro_period_ns + + +class VL53L0X: + """Driver for the VL53L0X distance sensor.""" + + # Class-level buffer for reading and writing data with the sensor. + # This reduces memory allocations but means the code is not re-entrant or + # thread safe! + _BUFFER = bytearray(3) + + def __init__(self, i2c, address=41, io_timeout_s=0): + # pylint: disable=too-many-statements + self._i2c = i2c + self.address = address + self.io_timeout_s = io_timeout_s + self.range_started = False # True if a measure was initiated. + + # Check identification registers for expected values. + # From section 3.2 of the datasheet. + if ( + self._read_u8(0xC0) != 0xEE + or self._read_u8(0xC1) != 0xAA + or self._read_u8(0xC2) != 0x10 + ): + raise RuntimeError( + "Failed to find expected ID register values. Check wiring! C0,C1,C2:", self._i2c.readfrom_mem(self.address, 0xc0, 3) + ) + # Initialize access to the sensor. This is based on the logic from: + # https://github.com/pololu/vl53l0x-arduino/blob/master/VL53L0X.cpp + # Set I2C standard mode. + for pair in ((0x88, 0x00), (0x80, 0x01), (0xFF, 0x01), (0x00, 0x00)): + self._write_u8(pair[0], pair[1]) + self._stop_variable = self._read_u8(0x91) + for pair in ((0x00, 0x01), (0xFF, 0x00), (0x80, 0x00)): + self._write_u8(pair[0], pair[1]) + # disable SIGNAL_RATE_MSRC (bit 1) and SIGNAL_RATE_PRE_RANGE (bit 4) + # limit checks + config_control = self._read_u8(_MSRC_CONFIG_CONTROL) | 0x12 + self._write_u8(_MSRC_CONFIG_CONTROL, config_control) + # set final range signal rate limit to 0.25 MCPS (million counts per + # second) + self.signal_rate_limit = 0.25 + self._write_u8(_SYSTEM_SEQUENCE_CONFIG, 0xFF) + spad_count, spad_is_aperture = self._get_spad_info() + # The SPAD map (RefGoodSpadMap) is read by + # VL53L0X_get_info_from_device() in the API, but the same data seems to + # be more easily readable from GLOBAL_CONFIG_SPAD_ENABLES_REF_0 through + # _6, so read it from there. + ref_spad_map = bytearray(7) + self._i2c.readfrom_mem_into(self.address, _GLOBAL_CONFIG_SPAD_ENABLES_REF_0, ref_spad_map) + + for pair in ( + (0xFF, 0x01), + (_DYNAMIC_SPAD_REF_EN_START_OFFSET, 0x00), + (_DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD, 0x2C), + (0xFF, 0x00), + (_GLOBAL_CONFIG_REF_EN_START_SELECT, 0xB4), + ): + self._write_u8(pair[0], pair[1]) + + first_spad_to_enable = 12 if spad_is_aperture else 0 + spads_enabled = 0 + for i in range(48): + if i < first_spad_to_enable or spads_enabled == spad_count: + # This bit is lower than the first one that should be enabled, + # or (reference_spad_count) bits have already been enabled, so + # zero this bit. + ref_spad_map[1 + (i // 8)] &= ~(1 << (i % 8)) + elif (ref_spad_map[1 + (i // 8)] >> (i % 8)) & 0x1 > 0: + spads_enabled += 1 + self._i2c.writeto_mem(self.address, _GLOBAL_CONFIG_SPAD_ENABLES_REF_0, ref_spad_map) + for pair in ( + (0xFF, 0x01), + (0x00, 0x00), + (0xFF, 0x00), + (0x09, 0x00), + (0x10, 0x00), + (0x11, 0x00), + (0x24, 0x01), + (0x25, 0xFF), + (0x75, 0x00), + (0xFF, 0x01), + (0x4E, 0x2C), + (0x48, 0x00), + (0x30, 0x20), + (0xFF, 0x00), + (0x30, 0x09), + (0x54, 0x00), + (0x31, 0x04), + (0x32, 0x03), + (0x40, 0x83), + (0x46, 0x25), + (0x60, 0x00), + (0x27, 0x00), + (0x50, 0x06), + (0x51, 0x00), + (0x52, 0x96), + (0x56, 0x08), + (0x57, 0x30), + (0x61, 0x00), + (0x62, 0x00), + (0x64, 0x00), + (0x65, 0x00), + (0x66, 0xA0), + (0xFF, 0x01), + (0x22, 0x32), + (0x47, 0x14), + (0x49, 0xFF), + (0x4A, 0x00), + (0xFF, 0x00), + (0x7A, 0x0A), + (0x7B, 0x00), + (0x78, 0x21), + (0xFF, 0x01), + (0x23, 0x34), + (0x42, 0x00), + (0x44, 0xFF), + (0x45, 0x26), + (0x46, 0x05), + (0x40, 0x40), + (0x0E, 0x06), + (0x20, 0x1A), + (0x43, 0x40), + (0xFF, 0x00), + (0x34, 0x03), + (0x35, 0x44), + (0xFF, 0x01), + (0x31, 0x04), + (0x4B, 0x09), + (0x4C, 0x05), + (0x4D, 0x04), + (0xFF, 0x00), + (0x44, 0x00), + (0x45, 0x20), + (0x47, 0x08), + (0x48, 0x28), + (0x67, 0x00), + (0x70, 0x04), + (0x71, 0x01), + (0x72, 0xFE), + (0x76, 0x00), + (0x77, 0x00), + (0xFF, 0x01), + (0x0D, 0x01), + (0xFF, 0x00), + (0x80, 0x01), + (0x01, 0xF8), + (0xFF, 0x01), + (0x8E, 0x01), + (0x00, 0x01), + (0xFF, 0x00), + (0x80, 0x00), + ): + self._write_u8(pair[0], pair[1]) + + self._write_u8(_SYSTEM_INTERRUPT_CONFIG_GPIO, 0x04) + gpio_hv_mux_active_high = self._read_u8(_GPIO_HV_MUX_ACTIVE_HIGH) + self._write_u8( + _GPIO_HV_MUX_ACTIVE_HIGH, gpio_hv_mux_active_high & ~0x10 + ) # active low + self._write_u8(_SYSTEM_INTERRUPT_CLEAR, 0x01) + self._measurement_timing_budget_us = self.measurement_timing_budget + self._write_u8(_SYSTEM_SEQUENCE_CONFIG, 0xE8) + self.measurement_timing_budget = self._measurement_timing_budget_us + self._write_u8(_SYSTEM_SEQUENCE_CONFIG, 0x01) + self._perform_single_ref_calibration(0x40) + self._write_u8(_SYSTEM_SEQUENCE_CONFIG, 0x02) + self._perform_single_ref_calibration(0x00) + # "restore the previous Sequence Config" + self._write_u8(_SYSTEM_SEQUENCE_CONFIG, 0xE8) + + def _read_u8(self, register): + # Read an 8-bit unsigned value from the specified 8-bit address. + data = self._i2c.readfrom_mem(self.address, register, 1) + return int.from_bytes(data, 'big') + + def _read_u16(self, register): + # Read a 16-bit BE unsigned value from the specified 8-bit address. + data = self._i2c.readfrom_mem(self.address, register, 2) + return int.from_bytes(data, 'big') + + def _write_u8(self, register, val): + # Write an 8-bit unsigned value to the specified 8-bit address. + self._i2c.writeto_mem(self.address, register, val.to_bytes(1, 'big')) + + def _write_u16(self, register, val): + # Write a 16-bit BE unsigned value to the specified 8-bit address. + self._i2c.writeto_mem(self.address, register, val.to_bytes(2, 'big')) + + def _get_spad_info(self): + # Get reference SPAD count and type, returned as a 2-tuple of + # count and boolean is_aperture. Based on code from: + # https://github.com/pololu/vl53l0x-arduino/blob/master/VL53L0X.cpp + for pair in ((0x80, 0x01), (0xFF, 0x01), (0x00, 0x00), (0xFF, 0x06)): + self._write_u8(pair[0], pair[1]) + self._write_u8(0x83, self._read_u8(0x83) | 0x04) + for pair in ( + (0xFF, 0x07), + (0x81, 0x01), + (0x80, 0x01), + (0x94, 0x6B), + (0x83, 0x00), + ): + self._write_u8(pair[0], pair[1]) + start = utime.ticks_ms() / 1000 + while self._read_u8(0x83) == 0x00: + now = utime.ticks_ms() / 1000 + if now < start: + start = utime.ticks_ms() / 1000 + if ( + self.io_timeout_s > 0 + and (now - start) >= self.io_timeout_s + and now > start + ): + raise RuntimeError("Timeout waiting for VL53L0X!") + self._write_u8(0x83, 0x01) + tmp = self._read_u8(0x92) + count = tmp & 0x7F + is_aperture = ((tmp >> 7) & 0x01) == 1 + for pair in ((0x81, 0x00), (0xFF, 0x06)): + self._write_u8(pair[0], pair[1]) + self._write_u8(0x83, self._read_u8(0x83) & ~0x04) + for pair in ((0xFF, 0x01), (0x00, 0x01), (0xFF, 0x00), (0x80, 0x00)): + self._write_u8(pair[0], pair[1]) + return (count, is_aperture) + + def _perform_single_ref_calibration(self, vhv_init_byte): + # based on VL53L0X_perform_single_ref_calibration() from ST API. + self._write_u8(_SYSRANGE_START, 0x01 | vhv_init_byte & 0xFF) + start = utime.ticks_ms() / 1000 + while (self._read_u8(_RESULT_INTERRUPT_STATUS) & 0x07) == 0: + now = utime.ticks_ms() / 1000 + if now < start: + now = utime.ticks_ms() / 1000 + if ( + self.io_timeout_s > 0 + and (now - start) >= self.io_timeout_s + ): + raise RuntimeError("Timeout waiting for VL53L0X!") + self._write_u8(_SYSTEM_INTERRUPT_CLEAR, 0x01) + self._write_u8(_SYSRANGE_START, 0x00) + + def _get_vcsel_pulse_period(self, vcsel_period_type): + # pylint: disable=no-else-return + # Disable should be removed when refactor can be tested + if vcsel_period_type == _VCSEL_PERIOD_PRE_RANGE: + val = self._read_u8(_PRE_RANGE_CONFIG_VCSEL_PERIOD) + return (((val) + 1) & 0xFF) << 1 + elif vcsel_period_type == _VCSEL_PERIOD_FINAL_RANGE: + val = self._read_u8(_FINAL_RANGE_CONFIG_VCSEL_PERIOD) + return (((val) + 1) & 0xFF) << 1 + return 255 + + def _get_sequence_step_enables(self): + # based on VL53L0X_GetSequenceStepEnables() from ST API + sequence_config = self._read_u8(_SYSTEM_SEQUENCE_CONFIG) + tcc = (sequence_config >> 4) & 0x1 > 0 + dss = (sequence_config >> 3) & 0x1 > 0 + msrc = (sequence_config >> 2) & 0x1 > 0 + pre_range = (sequence_config >> 6) & 0x1 > 0 + final_range = (sequence_config >> 7) & 0x1 > 0 + return (tcc, dss, msrc, pre_range, final_range) + + def _get_sequence_step_timeouts(self, pre_range): + # based on get_sequence_step_timeout() from ST API but modified by + # pololu here: + # https://github.com/pololu/vl53l0x-arduino/blob/master/VL53L0X.cpp + pre_range_vcsel_period_pclks = self._get_vcsel_pulse_period( + _VCSEL_PERIOD_PRE_RANGE + ) + msrc_dss_tcc_mclks = (self._read_u8(_MSRC_CONFIG_TIMEOUT_MACROP) + 1) & 0xFF + msrc_dss_tcc_us = _timeout_mclks_to_microseconds( + msrc_dss_tcc_mclks, pre_range_vcsel_period_pclks + ) + pre_range_mclks = _decode_timeout( + self._read_u16(_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI) + ) + pre_range_us = _timeout_mclks_to_microseconds( + pre_range_mclks, pre_range_vcsel_period_pclks + ) + final_range_vcsel_period_pclks = self._get_vcsel_pulse_period( + _VCSEL_PERIOD_FINAL_RANGE + ) + final_range_mclks = _decode_timeout( + self._read_u16(_FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI) + ) + if pre_range: + final_range_mclks -= pre_range_mclks + final_range_us = _timeout_mclks_to_microseconds( + final_range_mclks, final_range_vcsel_period_pclks + ) + return ( + msrc_dss_tcc_us, + pre_range_us, + final_range_us, + final_range_vcsel_period_pclks, + pre_range_mclks, + ) + + @property + def signal_rate_limit(self): + """The signal rate limit in mega counts per second.""" + val = self._read_u16(_FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT) + # Return value converted from 16-bit 9.7 fixed point to float. + return val / (1 << 7) + + @signal_rate_limit.setter + def signal_rate_limit(self, val): + assert 0.0 <= val <= 511.99 + # Convert to 16-bit 9.7 fixed point value from a float. + val = int(val * (1 << 7)) + self._write_u16(_FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT, val) + + @property + def measurement_timing_budget(self): + """The measurement timing budget in microseconds.""" + budget_us = 1910 + 960 # Start overhead + end overhead. + tcc, dss, msrc, pre_range, final_range = self._get_sequence_step_enables() + step_timeouts = self._get_sequence_step_timeouts(pre_range) + msrc_dss_tcc_us, pre_range_us, final_range_us, _, _ = step_timeouts + if tcc: + budget_us += msrc_dss_tcc_us + 590 + if dss: + budget_us += 2 * (msrc_dss_tcc_us + 690) + elif msrc: + budget_us += msrc_dss_tcc_us + 660 + if pre_range: + budget_us += pre_range_us + 660 + if final_range: + budget_us += final_range_us + 550 + self._measurement_timing_budget_us = budget_us + return budget_us + + @measurement_timing_budget.setter + def measurement_timing_budget(self, budget_us): + # pylint: disable=too-many-locals + assert budget_us >= 20000 + used_budget_us = 1320 + 960 # Start (diff from get) + end overhead + tcc, dss, msrc, pre_range, final_range = self._get_sequence_step_enables() + step_timeouts = self._get_sequence_step_timeouts(pre_range) + msrc_dss_tcc_us, pre_range_us, _ = step_timeouts[:3] + final_range_vcsel_period_pclks, pre_range_mclks = step_timeouts[3:] + if tcc: + used_budget_us += msrc_dss_tcc_us + 590 + if dss: + used_budget_us += 2 * (msrc_dss_tcc_us + 690) + elif msrc: + used_budget_us += msrc_dss_tcc_us + 660 + if pre_range: + used_budget_us += pre_range_us + 660 + if final_range: + used_budget_us += 550 + # "Note that the final range timeout is determined by the timing + # budget and the sum of all other timeouts within the sequence. + # If there is no room for the final range timeout, then an error + # will be set. Otherwise the remaining time will be applied to + # the final range." + if used_budget_us > budget_us: + raise ValueError("Requested timeout too big.") + final_range_timeout_us = budget_us - used_budget_us + final_range_timeout_mclks = _timeout_microseconds_to_mclks( + final_range_timeout_us, final_range_vcsel_period_pclks + ) + if pre_range: + final_range_timeout_mclks += pre_range_mclks + self._write_u16( + _FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI, + _encode_timeout(final_range_timeout_mclks), + ) + self._measurement_timing_budget_us = budget_us + + def start_range_request(self): + if self.range_started == True: return # Already started + """Start a single reading of the range for an object in front of + the sensor. This is used both for blocking range requests (called + by the .range property), and non-blocking range requests in the form: + sensor.start_range_request() + ... + if sensor.reading_available(): + print(sensor.get_range_value()) + """ + # Adapted from readRangeSingleMillimeters & + # readRangeContinuousMillimeters in pololu code at: + # https://github.com/pololu/vl53l0x-arduino/blob/master/VL53L0X.cpp + for pair in ( + (0x80, 0x01), + (0xFF, 0x01), + (0x00, 0x00), + (0x91, self._stop_variable), + (0x00, 0x01), + (0xFF, 0x00), + (0x80, 0x00), + (_SYSRANGE_START, 0x01), + ): + self._write_u8(pair[0], pair[1]) + self.range_started = True + + # Return true if a range request initiated by start_range_request + # is available to be read via self.get_range_value(). + def reading_available(self): + if self.range_started == False: return False + if (self._read_u8(_RESULT_INTERRUPT_STATUS) & 0x07) == 0: return False + return True + + # After start_range_request(), once the sensor completed a reading + # this function will return the final range value in millimeters. + # As a side effect this function will also clear the interrupt status + # flag. + def get_range_value(self): + if self.range_started == False: return None + + # assumptions: Linearity Corrective Gain is 1000 (default) + # fractional ranging is not enabled + range_mm = self._read_u16(_RESULT_RANGE_STATUS + 10) + self._write_u8(_SYSTEM_INTERRUPT_CLEAR, 0x01) + self.range_started = False # Don't return the same data again. + return range_mm + + @property + def range(self): + # If there is a non-blocking measure ongoing, don't initiate + # a blocking one. + if self.range_started: return None + + self.start_range_request() + + start = utime.ticks_ms() + while self.reading_available() == False: + if (utime.ticks_diff(utime.ticks_ms(),start) > 1000): + raise RuntimeError("Timeout waiting for VL53L0X!") + utime.sleep_ms(5) + + return self.get_range_value() + + def set_address(self, new_address): + self._write_u8(_I2C_SLAVE_DEVICE_ADDRESS, new_address & 0x7F) + # self._device = i2c_device.I2CDevice(self._i2c, new_address) + print("new address is ") + return new_address +