Backup vom Rp2040Zero 16.05.2026 hinzugefügt
This commit is contained in:
649
VL53L0X_backup.py
Normal file
649
VL53L0X_backup.py
Normal file
@@ -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
|
||||||
|
|
||||||
50
lcd1602_backup.py
Normal file
50
lcd1602_backup.py
Normal file
@@ -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)
|
||||||
|
|
||||||
46
main_backup.py
Normal file
46
main_backup.py
Normal file
@@ -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)
|
||||||
|
|
||||||
544
vl53l0x_backup.py
Normal file
544
vl53l0x_backup.py
Normal file
@@ -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
|
||||||
|
|
||||||
Reference in New Issue
Block a user