AP mode

Dependencies:   NetworkSocketAPI WizFi310Interface mbed

Fork of WizFi310_TCP_Echo_Server_Example by WIZnet

Committer:
maru536
Date:
Tue Oct 03 05:38:58 2017 +0000
Revision:
8:e26236864101
Parent:
2:8d119e9b8f5a
comp

Who changed what in which revision?

UserRevisionLine numberNew contents of line
maru536 2:8d119e9b8f5a 1 // Most of the functionality of this library is based on the VL53L0X API
maru536 2:8d119e9b8f5a 2 // provided by ST (STSW-IMG005), and some of the explanatory comments are quoted
maru536 2:8d119e9b8f5a 3 // or paraphrased from the API source code, API user manual (UM2039), and the
maru536 2:8d119e9b8f5a 4 // VL53L0X datasheet.
maru536 2:8d119e9b8f5a 5
maru536 2:8d119e9b8f5a 6 #include <memory>
maru536 2:8d119e9b8f5a 7 #include <VL53L0X.h>
maru536 2:8d119e9b8f5a 8
maru536 2:8d119e9b8f5a 9 // Defines /////////////////////////////////////////////////////////////////////
maru536 2:8d119e9b8f5a 10
maru536 2:8d119e9b8f5a 11 // The Arduino two-wire interface uses a 7-bit number for the address,
maru536 2:8d119e9b8f5a 12 // and sets the last bit correctly based on reads and writes
maru536 2:8d119e9b8f5a 13 #define ADDRESS_DEFAULT (0b0101001 << 1)
maru536 2:8d119e9b8f5a 14
maru536 2:8d119e9b8f5a 15 // Record the current time to check an upcoming timeout against
maru536 2:8d119e9b8f5a 16 #define startTimeout() (timeout_start_ms = millis())
maru536 2:8d119e9b8f5a 17
maru536 2:8d119e9b8f5a 18 // Check if timeout is enabled (set to nonzero value) and has expired
maru536 2:8d119e9b8f5a 19 #define checkTimeoutExpired() (io_timeout > 0 && ((uint16_t)millis() - timeout_start_ms) > io_timeout)
maru536 2:8d119e9b8f5a 20
maru536 2:8d119e9b8f5a 21 // Decode VCSEL (vertical cavity surface emitting laser) pulse period in PCLKs
maru536 2:8d119e9b8f5a 22 // from register value
maru536 2:8d119e9b8f5a 23 // based on VL53L0X_decode_vcsel_period()
maru536 2:8d119e9b8f5a 24 #define decodeVcselPeriod(reg_val) (((reg_val) + 1) << 1)
maru536 2:8d119e9b8f5a 25
maru536 2:8d119e9b8f5a 26 // Encode VCSEL pulse period register value from period in PCLKs
maru536 2:8d119e9b8f5a 27 // based on VL53L0X_encode_vcsel_period()
maru536 2:8d119e9b8f5a 28 #define encodeVcselPeriod(period_pclks) (((period_pclks) >> 1) - 1)
maru536 2:8d119e9b8f5a 29
maru536 2:8d119e9b8f5a 30 // Calculate macro period in *nanoseconds* from VCSEL period in PCLKs
maru536 2:8d119e9b8f5a 31 // based on VL53L0X_calc_macro_period_ps()
maru536 2:8d119e9b8f5a 32 // PLL_period_ps = 1655; macro_period_vclks = 2304
maru536 2:8d119e9b8f5a 33 #define calcMacroPeriod(vcsel_period_pclks) ((((uint32_t)2304 * (vcsel_period_pclks) * 1655) + 500) / 1000)
maru536 2:8d119e9b8f5a 34
maru536 2:8d119e9b8f5a 35 // Transmission status (https://www.arduino.cc/en/Reference/WireEndTransmission)
maru536 2:8d119e9b8f5a 36 #define ERR_OK 0
maru536 2:8d119e9b8f5a 37 #define ERR_NACK_ADDR 2 // received NACK on transmit of address
maru536 2:8d119e9b8f5a 38 #define ERR_NACK_DATA 3 // received NACK on transmit of data
maru536 2:8d119e9b8f5a 39 #define ERR_OTHER 4
maru536 2:8d119e9b8f5a 40
maru536 2:8d119e9b8f5a 41 #define millis() timer->read_ms()
maru536 2:8d119e9b8f5a 42
maru536 2:8d119e9b8f5a 43 // Constructors ////////////////////////////////////////////////////////////////
maru536 2:8d119e9b8f5a 44
maru536 2:8d119e9b8f5a 45 VL53L0X::VL53L0X(I2C* i2c, Timer* timer)
maru536 2:8d119e9b8f5a 46 : address(ADDRESS_DEFAULT)
maru536 2:8d119e9b8f5a 47 , io_timeout(0) // no timeout
maru536 2:8d119e9b8f5a 48 , did_timeout(false)
maru536 2:8d119e9b8f5a 49 , i2c(i2c)
maru536 2:8d119e9b8f5a 50 , timer(timer)
maru536 2:8d119e9b8f5a 51 {
maru536 2:8d119e9b8f5a 52 }
maru536 2:8d119e9b8f5a 53
maru536 2:8d119e9b8f5a 54 // Public Methods //////////////////////////////////////////////////////////////
maru536 2:8d119e9b8f5a 55
maru536 2:8d119e9b8f5a 56 void VL53L0X::setAddress(uint8_t new_addr)
maru536 2:8d119e9b8f5a 57 {
maru536 2:8d119e9b8f5a 58 writeReg(I2C_SLAVE_DEVICE_ADDRESS, new_addr & 0x7F);
maru536 2:8d119e9b8f5a 59 address = new_addr << 1;
maru536 2:8d119e9b8f5a 60 }
maru536 2:8d119e9b8f5a 61
maru536 2:8d119e9b8f5a 62 // Initialize sensor using sequence based on VL53L0X_DataInit(),
maru536 2:8d119e9b8f5a 63 // VL53L0X_StaticInit(), and VL53L0X_PerformRefCalibration().
maru536 2:8d119e9b8f5a 64 // This function does not perform reference SPAD calibration
maru536 2:8d119e9b8f5a 65 // (VL53L0X_PerformRefSpadManagement()), since the API user manual says that it
maru536 2:8d119e9b8f5a 66 // is performed by ST on the bare modules; it seems like that should work well
maru536 2:8d119e9b8f5a 67 // enough unless a cover glass is added.
maru536 2:8d119e9b8f5a 68 // If io_2v8 (optional) is true or not given, the sensor is configured for 2V8
maru536 2:8d119e9b8f5a 69 // mode.
maru536 2:8d119e9b8f5a 70 bool VL53L0X::init(bool io_2v8)
maru536 2:8d119e9b8f5a 71 {
maru536 2:8d119e9b8f5a 72 // VL53L0X_DataInit() begin
maru536 2:8d119e9b8f5a 73
maru536 2:8d119e9b8f5a 74 // sensor uses 1V8 mode for I/O by default; switch to 2V8 mode if necessary
maru536 2:8d119e9b8f5a 75 if (io_2v8)
maru536 2:8d119e9b8f5a 76 {
maru536 2:8d119e9b8f5a 77 writeReg(VHV_CONFIG_PAD_SCL_SDA__EXTSUP_HV,
maru536 2:8d119e9b8f5a 78 readReg(VHV_CONFIG_PAD_SCL_SDA__EXTSUP_HV) | 0x01); // set bit 0
maru536 2:8d119e9b8f5a 79 }
maru536 2:8d119e9b8f5a 80
maru536 2:8d119e9b8f5a 81 // "Set I2C standard mode"
maru536 2:8d119e9b8f5a 82 writeReg(0x88, 0x00);
maru536 2:8d119e9b8f5a 83
maru536 2:8d119e9b8f5a 84 writeReg(0x80, 0x01);
maru536 2:8d119e9b8f5a 85 writeReg(0xFF, 0x01);
maru536 2:8d119e9b8f5a 86 writeReg(0x00, 0x00);
maru536 2:8d119e9b8f5a 87 stop_variable = readReg(0x91);
maru536 2:8d119e9b8f5a 88 writeReg(0x00, 0x01);
maru536 2:8d119e9b8f5a 89 writeReg(0xFF, 0x00);
maru536 2:8d119e9b8f5a 90 writeReg(0x80, 0x00);
maru536 2:8d119e9b8f5a 91
maru536 2:8d119e9b8f5a 92 // disable SIGNAL_RATE_MSRC (bit 1) and SIGNAL_RATE_PRE_RANGE (bit 4) limit checks
maru536 2:8d119e9b8f5a 93 writeReg(MSRC_CONFIG_CONTROL, readReg(MSRC_CONFIG_CONTROL) | 0x12);
maru536 2:8d119e9b8f5a 94
maru536 2:8d119e9b8f5a 95 // set final range signal rate limit to 0.25 MCPS (million counts per second)
maru536 2:8d119e9b8f5a 96 setSignalRateLimit(0.25);
maru536 2:8d119e9b8f5a 97
maru536 2:8d119e9b8f5a 98 writeReg(SYSTEM_SEQUENCE_CONFIG, 0xFF);
maru536 2:8d119e9b8f5a 99
maru536 2:8d119e9b8f5a 100 // VL53L0X_DataInit() end
maru536 2:8d119e9b8f5a 101
maru536 2:8d119e9b8f5a 102 // VL53L0X_StaticInit() begin
maru536 2:8d119e9b8f5a 103
maru536 2:8d119e9b8f5a 104 uint8_t spad_count;
maru536 2:8d119e9b8f5a 105 bool spad_type_is_aperture;
maru536 2:8d119e9b8f5a 106 if (!getSpadInfo(&spad_count, &spad_type_is_aperture)) { return false; }
maru536 2:8d119e9b8f5a 107
maru536 2:8d119e9b8f5a 108 // The SPAD map (RefGoodSpadMap) is read by VL53L0X_get_info_from_device() in
maru536 2:8d119e9b8f5a 109 // the API, but the same data seems to be more easily readable from
maru536 2:8d119e9b8f5a 110 // GLOBAL_CONFIG_SPAD_ENABLES_REF_0 through _6, so read it from there
maru536 2:8d119e9b8f5a 111 uint8_t ref_spad_map[6];
maru536 2:8d119e9b8f5a 112 readMulti(GLOBAL_CONFIG_SPAD_ENABLES_REF_0, ref_spad_map, 6);
maru536 2:8d119e9b8f5a 113
maru536 2:8d119e9b8f5a 114 // -- VL53L0X_set_reference_spads() begin (assume NVM values are valid)
maru536 2:8d119e9b8f5a 115
maru536 2:8d119e9b8f5a 116 writeReg(0xFF, 0x01);
maru536 2:8d119e9b8f5a 117 writeReg(DYNAMIC_SPAD_REF_EN_START_OFFSET, 0x00);
maru536 2:8d119e9b8f5a 118 writeReg(DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD, 0x2C);
maru536 2:8d119e9b8f5a 119 writeReg(0xFF, 0x00);
maru536 2:8d119e9b8f5a 120 writeReg(GLOBAL_CONFIG_REF_EN_START_SELECT, 0xB4);
maru536 2:8d119e9b8f5a 121
maru536 2:8d119e9b8f5a 122 uint8_t first_spad_to_enable = spad_type_is_aperture ? 12 : 0; // 12 is the first aperture spad
maru536 2:8d119e9b8f5a 123 uint8_t spads_enabled = 0;
maru536 2:8d119e9b8f5a 124
maru536 2:8d119e9b8f5a 125 for (uint8_t i = 0; i < 48; i++)
maru536 2:8d119e9b8f5a 126 {
maru536 2:8d119e9b8f5a 127 if (i < first_spad_to_enable || spads_enabled == spad_count)
maru536 2:8d119e9b8f5a 128 {
maru536 2:8d119e9b8f5a 129 // This bit is lower than the first one that should be enabled, or
maru536 2:8d119e9b8f5a 130 // (reference_spad_count) bits have already been enabled, so zero this bit
maru536 2:8d119e9b8f5a 131 ref_spad_map[i / 8] &= ~(1 << (i % 8));
maru536 2:8d119e9b8f5a 132 }
maru536 2:8d119e9b8f5a 133 else if ((ref_spad_map[i / 8] >> (i % 8)) & 0x1)
maru536 2:8d119e9b8f5a 134 {
maru536 2:8d119e9b8f5a 135 spads_enabled++;
maru536 2:8d119e9b8f5a 136 }
maru536 2:8d119e9b8f5a 137 }
maru536 2:8d119e9b8f5a 138
maru536 2:8d119e9b8f5a 139 writeMulti(GLOBAL_CONFIG_SPAD_ENABLES_REF_0, ref_spad_map, 6);
maru536 2:8d119e9b8f5a 140
maru536 2:8d119e9b8f5a 141 // -- VL53L0X_set_reference_spads() end
maru536 2:8d119e9b8f5a 142
maru536 2:8d119e9b8f5a 143 // -- VL53L0X_load_tuning_settings() begin
maru536 2:8d119e9b8f5a 144 // DefaultTuningSettings from vl53l0x_tuning.h
maru536 2:8d119e9b8f5a 145
maru536 2:8d119e9b8f5a 146 writeReg(0xFF, 0x01);
maru536 2:8d119e9b8f5a 147 writeReg(0x00, 0x00);
maru536 2:8d119e9b8f5a 148
maru536 2:8d119e9b8f5a 149 writeReg(0xFF, 0x00);
maru536 2:8d119e9b8f5a 150 writeReg(0x09, 0x00);
maru536 2:8d119e9b8f5a 151 writeReg(0x10, 0x00);
maru536 2:8d119e9b8f5a 152 writeReg(0x11, 0x00);
maru536 2:8d119e9b8f5a 153
maru536 2:8d119e9b8f5a 154 writeReg(0x24, 0x01);
maru536 2:8d119e9b8f5a 155 writeReg(0x25, 0xFF);
maru536 2:8d119e9b8f5a 156 writeReg(0x75, 0x00);
maru536 2:8d119e9b8f5a 157
maru536 2:8d119e9b8f5a 158 writeReg(0xFF, 0x01);
maru536 2:8d119e9b8f5a 159 writeReg(0x4E, 0x2C);
maru536 2:8d119e9b8f5a 160 writeReg(0x48, 0x00);
maru536 2:8d119e9b8f5a 161 writeReg(0x30, 0x20);
maru536 2:8d119e9b8f5a 162
maru536 2:8d119e9b8f5a 163 writeReg(0xFF, 0x00);
maru536 2:8d119e9b8f5a 164 writeReg(0x30, 0x09);
maru536 2:8d119e9b8f5a 165 writeReg(0x54, 0x00);
maru536 2:8d119e9b8f5a 166 writeReg(0x31, 0x04);
maru536 2:8d119e9b8f5a 167 writeReg(0x32, 0x03);
maru536 2:8d119e9b8f5a 168 writeReg(0x40, 0x83);
maru536 2:8d119e9b8f5a 169 writeReg(0x46, 0x25);
maru536 2:8d119e9b8f5a 170 writeReg(0x60, 0x00);
maru536 2:8d119e9b8f5a 171 writeReg(0x27, 0x00);
maru536 2:8d119e9b8f5a 172 writeReg(0x50, 0x06);
maru536 2:8d119e9b8f5a 173 writeReg(0x51, 0x00);
maru536 2:8d119e9b8f5a 174 writeReg(0x52, 0x96);
maru536 2:8d119e9b8f5a 175 writeReg(0x56, 0x08);
maru536 2:8d119e9b8f5a 176 writeReg(0x57, 0x30);
maru536 2:8d119e9b8f5a 177 writeReg(0x61, 0x00);
maru536 2:8d119e9b8f5a 178 writeReg(0x62, 0x00);
maru536 2:8d119e9b8f5a 179 writeReg(0x64, 0x00);
maru536 2:8d119e9b8f5a 180 writeReg(0x65, 0x00);
maru536 2:8d119e9b8f5a 181 writeReg(0x66, 0xA0);
maru536 2:8d119e9b8f5a 182
maru536 2:8d119e9b8f5a 183 writeReg(0xFF, 0x01);
maru536 2:8d119e9b8f5a 184 writeReg(0x22, 0x32);
maru536 2:8d119e9b8f5a 185 writeReg(0x47, 0x14);
maru536 2:8d119e9b8f5a 186 writeReg(0x49, 0xFF);
maru536 2:8d119e9b8f5a 187 writeReg(0x4A, 0x00);
maru536 2:8d119e9b8f5a 188
maru536 2:8d119e9b8f5a 189 writeReg(0xFF, 0x00);
maru536 2:8d119e9b8f5a 190 writeReg(0x7A, 0x0A);
maru536 2:8d119e9b8f5a 191 writeReg(0x7B, 0x00);
maru536 2:8d119e9b8f5a 192 writeReg(0x78, 0x21);
maru536 2:8d119e9b8f5a 193
maru536 2:8d119e9b8f5a 194 writeReg(0xFF, 0x01);
maru536 2:8d119e9b8f5a 195 writeReg(0x23, 0x34);
maru536 2:8d119e9b8f5a 196 writeReg(0x42, 0x00);
maru536 2:8d119e9b8f5a 197 writeReg(0x44, 0xFF);
maru536 2:8d119e9b8f5a 198 writeReg(0x45, 0x26);
maru536 2:8d119e9b8f5a 199 writeReg(0x46, 0x05);
maru536 2:8d119e9b8f5a 200 writeReg(0x40, 0x40);
maru536 2:8d119e9b8f5a 201 writeReg(0x0E, 0x06);
maru536 2:8d119e9b8f5a 202 writeReg(0x20, 0x1A);
maru536 2:8d119e9b8f5a 203 writeReg(0x43, 0x40);
maru536 2:8d119e9b8f5a 204
maru536 2:8d119e9b8f5a 205 writeReg(0xFF, 0x00);
maru536 2:8d119e9b8f5a 206 writeReg(0x34, 0x03);
maru536 2:8d119e9b8f5a 207 writeReg(0x35, 0x44);
maru536 2:8d119e9b8f5a 208
maru536 2:8d119e9b8f5a 209 writeReg(0xFF, 0x01);
maru536 2:8d119e9b8f5a 210 writeReg(0x31, 0x04);
maru536 2:8d119e9b8f5a 211 writeReg(0x4B, 0x09);
maru536 2:8d119e9b8f5a 212 writeReg(0x4C, 0x05);
maru536 2:8d119e9b8f5a 213 writeReg(0x4D, 0x04);
maru536 2:8d119e9b8f5a 214
maru536 2:8d119e9b8f5a 215 writeReg(0xFF, 0x00);
maru536 2:8d119e9b8f5a 216 writeReg(0x44, 0x00);
maru536 2:8d119e9b8f5a 217 writeReg(0x45, 0x20);
maru536 2:8d119e9b8f5a 218 writeReg(0x47, 0x08);
maru536 2:8d119e9b8f5a 219 writeReg(0x48, 0x28);
maru536 2:8d119e9b8f5a 220 writeReg(0x67, 0x00);
maru536 2:8d119e9b8f5a 221 writeReg(0x70, 0x04);
maru536 2:8d119e9b8f5a 222 writeReg(0x71, 0x01);
maru536 2:8d119e9b8f5a 223 writeReg(0x72, 0xFE);
maru536 2:8d119e9b8f5a 224 writeReg(0x76, 0x00);
maru536 2:8d119e9b8f5a 225 writeReg(0x77, 0x00);
maru536 2:8d119e9b8f5a 226
maru536 2:8d119e9b8f5a 227 writeReg(0xFF, 0x01);
maru536 2:8d119e9b8f5a 228 writeReg(0x0D, 0x01);
maru536 2:8d119e9b8f5a 229
maru536 2:8d119e9b8f5a 230 writeReg(0xFF, 0x00);
maru536 2:8d119e9b8f5a 231 writeReg(0x80, 0x01);
maru536 2:8d119e9b8f5a 232 writeReg(0x01, 0xF8);
maru536 2:8d119e9b8f5a 233
maru536 2:8d119e9b8f5a 234 writeReg(0xFF, 0x01);
maru536 2:8d119e9b8f5a 235 writeReg(0x8E, 0x01);
maru536 2:8d119e9b8f5a 236 writeReg(0x00, 0x01);
maru536 2:8d119e9b8f5a 237 writeReg(0xFF, 0x00);
maru536 2:8d119e9b8f5a 238 writeReg(0x80, 0x00);
maru536 2:8d119e9b8f5a 239
maru536 2:8d119e9b8f5a 240 // -- VL53L0X_load_tuning_settings() end
maru536 2:8d119e9b8f5a 241
maru536 2:8d119e9b8f5a 242 // "Set interrupt config to new sample ready"
maru536 2:8d119e9b8f5a 243 // -- VL53L0X_SetGpioConfig() begin
maru536 2:8d119e9b8f5a 244
maru536 2:8d119e9b8f5a 245 writeReg(SYSTEM_INTERRUPT_CONFIG_GPIO, 0x04);
maru536 2:8d119e9b8f5a 246 writeReg(GPIO_HV_MUX_ACTIVE_HIGH, readReg(GPIO_HV_MUX_ACTIVE_HIGH) & ~0x10); // active low
maru536 2:8d119e9b8f5a 247 writeReg(SYSTEM_INTERRUPT_CLEAR, 0x01);
maru536 2:8d119e9b8f5a 248
maru536 2:8d119e9b8f5a 249 // -- VL53L0X_SetGpioConfig() end
maru536 2:8d119e9b8f5a 250
maru536 2:8d119e9b8f5a 251 measurement_timing_budget_us = getMeasurementTimingBudget();
maru536 2:8d119e9b8f5a 252
maru536 2:8d119e9b8f5a 253 // "Disable MSRC and TCC by default"
maru536 2:8d119e9b8f5a 254 // MSRC = Minimum Signal Rate Check
maru536 2:8d119e9b8f5a 255 // TCC = Target CentreCheck
maru536 2:8d119e9b8f5a 256 // -- VL53L0X_SetSequenceStepEnable() begin
maru536 2:8d119e9b8f5a 257
maru536 2:8d119e9b8f5a 258 writeReg(SYSTEM_SEQUENCE_CONFIG, 0xE8);
maru536 2:8d119e9b8f5a 259
maru536 2:8d119e9b8f5a 260 // -- VL53L0X_SetSequenceStepEnable() end
maru536 2:8d119e9b8f5a 261
maru536 2:8d119e9b8f5a 262 // "Recalculate timing budget"
maru536 2:8d119e9b8f5a 263 setMeasurementTimingBudget(measurement_timing_budget_us);
maru536 2:8d119e9b8f5a 264
maru536 2:8d119e9b8f5a 265 // VL53L0X_StaticInit() end
maru536 2:8d119e9b8f5a 266
maru536 2:8d119e9b8f5a 267 // VL53L0X_PerformRefCalibration() begin (VL53L0X_perform_ref_calibration())
maru536 2:8d119e9b8f5a 268
maru536 2:8d119e9b8f5a 269 // -- VL53L0X_perform_vhv_calibration() begin
maru536 2:8d119e9b8f5a 270
maru536 2:8d119e9b8f5a 271 writeReg(SYSTEM_SEQUENCE_CONFIG, 0x01);
maru536 2:8d119e9b8f5a 272 if (!performSingleRefCalibration(0x40)) { return false; }
maru536 2:8d119e9b8f5a 273
maru536 2:8d119e9b8f5a 274 // -- VL53L0X_perform_vhv_calibration() end
maru536 2:8d119e9b8f5a 275
maru536 2:8d119e9b8f5a 276 // -- VL53L0X_perform_phase_calibration() begin
maru536 2:8d119e9b8f5a 277
maru536 2:8d119e9b8f5a 278 writeReg(SYSTEM_SEQUENCE_CONFIG, 0x02);
maru536 2:8d119e9b8f5a 279 if (!performSingleRefCalibration(0x00)) { return false; }
maru536 2:8d119e9b8f5a 280
maru536 2:8d119e9b8f5a 281 // -- VL53L0X_perform_phase_calibration() end
maru536 2:8d119e9b8f5a 282
maru536 2:8d119e9b8f5a 283 // "restore the previous Sequence Config"
maru536 2:8d119e9b8f5a 284 writeReg(SYSTEM_SEQUENCE_CONFIG, 0xE8);
maru536 2:8d119e9b8f5a 285
maru536 2:8d119e9b8f5a 286 // VL53L0X_PerformRefCalibration() end
maru536 2:8d119e9b8f5a 287
maru536 2:8d119e9b8f5a 288 return true;
maru536 2:8d119e9b8f5a 289 }
maru536 2:8d119e9b8f5a 290
maru536 2:8d119e9b8f5a 291 // Write an 8-bit register
maru536 2:8d119e9b8f5a 292 void VL53L0X::writeReg(uint8_t reg, uint8_t value)
maru536 2:8d119e9b8f5a 293 {
maru536 2:8d119e9b8f5a 294 char data[] = {
maru536 2:8d119e9b8f5a 295 reg,
maru536 2:8d119e9b8f5a 296 value
maru536 2:8d119e9b8f5a 297 };
maru536 2:8d119e9b8f5a 298 if (i2c->write(address, data, 2)) {
maru536 2:8d119e9b8f5a 299 last_status = ERR_OTHER;
maru536 2:8d119e9b8f5a 300 } else {
maru536 2:8d119e9b8f5a 301 last_status = ERR_OK;
maru536 2:8d119e9b8f5a 302 }
maru536 2:8d119e9b8f5a 303 }
maru536 2:8d119e9b8f5a 304
maru536 2:8d119e9b8f5a 305 // Write a 16-bit register
maru536 2:8d119e9b8f5a 306 void VL53L0X::writeReg16Bit(uint8_t reg, uint16_t value)
maru536 2:8d119e9b8f5a 307 {
maru536 2:8d119e9b8f5a 308 char data[] = {
maru536 2:8d119e9b8f5a 309 reg,
maru536 2:8d119e9b8f5a 310 static_cast<char>((value >> 8) & 0xFF), // value high byte
maru536 2:8d119e9b8f5a 311 static_cast<char>(value & 0xFF) // value low byte
maru536 2:8d119e9b8f5a 312 };
maru536 2:8d119e9b8f5a 313 if (i2c->write(address, data, 3)) {
maru536 2:8d119e9b8f5a 314 last_status = ERR_OTHER;
maru536 2:8d119e9b8f5a 315 } else {
maru536 2:8d119e9b8f5a 316 last_status = ERR_OK;
maru536 2:8d119e9b8f5a 317 }
maru536 2:8d119e9b8f5a 318 }
maru536 2:8d119e9b8f5a 319
maru536 2:8d119e9b8f5a 320 // Write a 32-bit register
maru536 2:8d119e9b8f5a 321 void VL53L0X::writeReg32Bit(uint8_t reg, uint32_t value)
maru536 2:8d119e9b8f5a 322 {
maru536 2:8d119e9b8f5a 323 char data[] = {
maru536 2:8d119e9b8f5a 324 reg,
maru536 2:8d119e9b8f5a 325 static_cast<char>((value >> 24) & 0xFF), // value highest byte
maru536 2:8d119e9b8f5a 326 static_cast<char>((value >> 16) & 0xFF),
maru536 2:8d119e9b8f5a 327 static_cast<char>((value >> 8) & 0xFF),
maru536 2:8d119e9b8f5a 328 static_cast<char>(value & 0xFF) // value lowest byte
maru536 2:8d119e9b8f5a 329 };
maru536 2:8d119e9b8f5a 330 if (i2c->write(address, data, 5)) {
maru536 2:8d119e9b8f5a 331 last_status = ERR_OTHER;
maru536 2:8d119e9b8f5a 332 } else {
maru536 2:8d119e9b8f5a 333 last_status = ERR_OK;
maru536 2:8d119e9b8f5a 334 }
maru536 2:8d119e9b8f5a 335 }
maru536 2:8d119e9b8f5a 336
maru536 2:8d119e9b8f5a 337 // Read an 8-bit register
maru536 2:8d119e9b8f5a 338 uint8_t VL53L0X::readReg(uint8_t reg)
maru536 2:8d119e9b8f5a 339 {
maru536 2:8d119e9b8f5a 340 uint8_t value;
maru536 2:8d119e9b8f5a 341
maru536 2:8d119e9b8f5a 342 if (i2c->write(address, reinterpret_cast<char *>(&reg), 1)) {
maru536 2:8d119e9b8f5a 343 last_status = ERR_NACK_ADDR;
maru536 2:8d119e9b8f5a 344 return 0;
maru536 2:8d119e9b8f5a 345 }
maru536 2:8d119e9b8f5a 346 if (i2c->read(address, reinterpret_cast<char *>(&value), 1)) {
maru536 2:8d119e9b8f5a 347 last_status = ERR_NACK_DATA;
maru536 2:8d119e9b8f5a 348 return 0;
maru536 2:8d119e9b8f5a 349 }
maru536 2:8d119e9b8f5a 350 last_status = ERR_OK;
maru536 2:8d119e9b8f5a 351
maru536 2:8d119e9b8f5a 352 return value;
maru536 2:8d119e9b8f5a 353 }
maru536 2:8d119e9b8f5a 354
maru536 2:8d119e9b8f5a 355 // Read a 16-bit register
maru536 2:8d119e9b8f5a 356 uint16_t VL53L0X::readReg16Bit(uint8_t reg)
maru536 2:8d119e9b8f5a 357 {
maru536 2:8d119e9b8f5a 358 uint16_t value;
maru536 2:8d119e9b8f5a 359 uint8_t data[2];
maru536 2:8d119e9b8f5a 360
maru536 2:8d119e9b8f5a 361 if (i2c->write(address, reinterpret_cast<char *>(&reg), 1)) {
maru536 2:8d119e9b8f5a 362 last_status = ERR_NACK_ADDR;
maru536 2:8d119e9b8f5a 363 return 0;
maru536 2:8d119e9b8f5a 364 }
maru536 2:8d119e9b8f5a 365 if (i2c->read(address, reinterpret_cast<char *>(data), 2)) {
maru536 2:8d119e9b8f5a 366 last_status = ERR_NACK_DATA;
maru536 2:8d119e9b8f5a 367 return 0;
maru536 2:8d119e9b8f5a 368 }
maru536 2:8d119e9b8f5a 369 last_status = ERR_OK;
maru536 2:8d119e9b8f5a 370
maru536 2:8d119e9b8f5a 371 value = static_cast<uint16_t>(data[0] << 8); // value high byte
maru536 2:8d119e9b8f5a 372 value |= data[1]; // value low byte
maru536 2:8d119e9b8f5a 373
maru536 2:8d119e9b8f5a 374 return value;
maru536 2:8d119e9b8f5a 375 }
maru536 2:8d119e9b8f5a 376
maru536 2:8d119e9b8f5a 377 // Read a 32-bit register
maru536 2:8d119e9b8f5a 378 uint32_t VL53L0X::readReg32Bit(uint8_t reg)
maru536 2:8d119e9b8f5a 379 {
maru536 2:8d119e9b8f5a 380 uint32_t value;
maru536 2:8d119e9b8f5a 381 uint8_t data[4];
maru536 2:8d119e9b8f5a 382
maru536 2:8d119e9b8f5a 383 if (i2c->write(address, reinterpret_cast<char *>(&reg), 1)) {
maru536 2:8d119e9b8f5a 384 last_status = ERR_NACK_ADDR;
maru536 2:8d119e9b8f5a 385 return 0;
maru536 2:8d119e9b8f5a 386 }
maru536 2:8d119e9b8f5a 387 if (i2c->read(address, reinterpret_cast<char *>(data), 4)) {
maru536 2:8d119e9b8f5a 388 last_status = ERR_NACK_DATA;
maru536 2:8d119e9b8f5a 389 return 0;
maru536 2:8d119e9b8f5a 390 }
maru536 2:8d119e9b8f5a 391 last_status = ERR_OK;
maru536 2:8d119e9b8f5a 392
maru536 2:8d119e9b8f5a 393 value = static_cast<uint32_t>(data[0] << 24); // value highest byte
maru536 2:8d119e9b8f5a 394 value |= static_cast<uint32_t>(data[1] << 16);
maru536 2:8d119e9b8f5a 395 value |= static_cast<uint32_t>(data[2] << 8);
maru536 2:8d119e9b8f5a 396 value |= data[3]; // value lowest byte
maru536 2:8d119e9b8f5a 397
maru536 2:8d119e9b8f5a 398 return value;
maru536 2:8d119e9b8f5a 399 }
maru536 2:8d119e9b8f5a 400
maru536 2:8d119e9b8f5a 401 // Write an arbitrary number of bytes from the given array to the sensor,
maru536 2:8d119e9b8f5a 402 // starting at the given register
maru536 2:8d119e9b8f5a 403 void VL53L0X::writeMulti(uint8_t reg, uint8_t const * src, uint8_t count)
maru536 2:8d119e9b8f5a 404 {
maru536 2:8d119e9b8f5a 405 if (i2c->write(address, reinterpret_cast<char *>(&reg), 1, true)) {
maru536 2:8d119e9b8f5a 406 last_status = ERR_NACK_ADDR;
maru536 2:8d119e9b8f5a 407 return;
maru536 2:8d119e9b8f5a 408 }
maru536 2:8d119e9b8f5a 409
maru536 2:8d119e9b8f5a 410 if (i2c->write(address, const_cast<char *>(
maru536 2:8d119e9b8f5a 411 reinterpret_cast<const char *>(src)), count)) {
maru536 2:8d119e9b8f5a 412 last_status = ERR_NACK_DATA;
maru536 2:8d119e9b8f5a 413 return;
maru536 2:8d119e9b8f5a 414 }
maru536 2:8d119e9b8f5a 415 last_status = ERR_OK;
maru536 2:8d119e9b8f5a 416 }
maru536 2:8d119e9b8f5a 417
maru536 2:8d119e9b8f5a 418 // Read an arbitrary number of bytes from the sensor, starting at the given
maru536 2:8d119e9b8f5a 419 // register, into the given array
maru536 2:8d119e9b8f5a 420 void VL53L0X::readMulti(uint8_t reg, uint8_t * dst, uint8_t count)
maru536 2:8d119e9b8f5a 421 {
maru536 2:8d119e9b8f5a 422 if (i2c->write(address, reinterpret_cast<char *>(&reg), 1)) {
maru536 2:8d119e9b8f5a 423 last_status = ERR_NACK_ADDR;
maru536 2:8d119e9b8f5a 424 return;
maru536 2:8d119e9b8f5a 425 }
maru536 2:8d119e9b8f5a 426 if (i2c->read(address, reinterpret_cast<char *>(dst), count)) {
maru536 2:8d119e9b8f5a 427 last_status = ERR_NACK_DATA;
maru536 2:8d119e9b8f5a 428 return;
maru536 2:8d119e9b8f5a 429 }
maru536 2:8d119e9b8f5a 430 last_status = ERR_OK;
maru536 2:8d119e9b8f5a 431 }
maru536 2:8d119e9b8f5a 432
maru536 2:8d119e9b8f5a 433 // Set the return signal rate limit check value in units of MCPS (mega counts
maru536 2:8d119e9b8f5a 434 // per second). "This represents the amplitude of the signal reflected from the
maru536 2:8d119e9b8f5a 435 // target and detected by the device"; setting this limit presumably determines
maru536 2:8d119e9b8f5a 436 // the minimum measurement necessary for the sensor to report a valid reading.
maru536 2:8d119e9b8f5a 437 // Setting a lower limit increases the potential range of the sensor but also
maru536 2:8d119e9b8f5a 438 // seems to increase the likelihood of getting an inaccurate reading because of
maru536 2:8d119e9b8f5a 439 // unwanted reflections from objects other than the intended target.
maru536 2:8d119e9b8f5a 440 // Defaults to 0.25 MCPS as initialized by the ST API and this library.
maru536 2:8d119e9b8f5a 441 bool VL53L0X::setSignalRateLimit(float limit_Mcps)
maru536 2:8d119e9b8f5a 442 {
maru536 2:8d119e9b8f5a 443 if (limit_Mcps < 0 || limit_Mcps > 511.99) { return false; }
maru536 2:8d119e9b8f5a 444
maru536 2:8d119e9b8f5a 445 // Q9.7 fixed point format (9 integer bits, 7 fractional bits)
maru536 2:8d119e9b8f5a 446 writeReg16Bit(FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT, limit_Mcps * (1 << 7));
maru536 2:8d119e9b8f5a 447 return true;
maru536 2:8d119e9b8f5a 448 }
maru536 2:8d119e9b8f5a 449
maru536 2:8d119e9b8f5a 450 // Get the return signal rate limit check value in MCPS
maru536 2:8d119e9b8f5a 451 float VL53L0X::getSignalRateLimit(void)
maru536 2:8d119e9b8f5a 452 {
maru536 2:8d119e9b8f5a 453 return (float)readReg16Bit(FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT) / (1 << 7);
maru536 2:8d119e9b8f5a 454 }
maru536 2:8d119e9b8f5a 455
maru536 2:8d119e9b8f5a 456 // Set the measurement timing budget in microseconds, which is the time allowed
maru536 2:8d119e9b8f5a 457 // for one measurement; the ST API and this library take care of splitting the
maru536 2:8d119e9b8f5a 458 // timing budget among the sub-steps in the ranging sequence. A longer timing
maru536 2:8d119e9b8f5a 459 // budget allows for more accurate measurements. Increasing the budget by a
maru536 2:8d119e9b8f5a 460 // factor of N decreases the range measurement standard deviation by a factor of
maru536 2:8d119e9b8f5a 461 // sqrt(N). Defaults to about 33 milliseconds; the minimum is 20 ms.
maru536 2:8d119e9b8f5a 462 // based on VL53L0X_set_measurement_timing_budget_micro_seconds()
maru536 2:8d119e9b8f5a 463 bool VL53L0X::setMeasurementTimingBudget(uint32_t budget_us)
maru536 2:8d119e9b8f5a 464 {
maru536 2:8d119e9b8f5a 465 SequenceStepEnables enables;
maru536 2:8d119e9b8f5a 466 SequenceStepTimeouts timeouts;
maru536 2:8d119e9b8f5a 467
maru536 2:8d119e9b8f5a 468 uint16_t const StartOverhead = 1320; // note that this is different than the value in get_
maru536 2:8d119e9b8f5a 469 uint16_t const EndOverhead = 960;
maru536 2:8d119e9b8f5a 470 uint16_t const MsrcOverhead = 660;
maru536 2:8d119e9b8f5a 471 uint16_t const TccOverhead = 590;
maru536 2:8d119e9b8f5a 472 uint16_t const DssOverhead = 690;
maru536 2:8d119e9b8f5a 473 uint16_t const PreRangeOverhead = 660;
maru536 2:8d119e9b8f5a 474 uint16_t const FinalRangeOverhead = 550;
maru536 2:8d119e9b8f5a 475
maru536 2:8d119e9b8f5a 476 uint32_t const MinTimingBudget = 20000;
maru536 2:8d119e9b8f5a 477
maru536 2:8d119e9b8f5a 478 if (budget_us < MinTimingBudget) { return false; }
maru536 2:8d119e9b8f5a 479
maru536 2:8d119e9b8f5a 480 uint32_t used_budget_us = StartOverhead + EndOverhead;
maru536 2:8d119e9b8f5a 481
maru536 2:8d119e9b8f5a 482 getSequenceStepEnables(&enables);
maru536 2:8d119e9b8f5a 483 getSequenceStepTimeouts(&enables, &timeouts);
maru536 2:8d119e9b8f5a 484
maru536 2:8d119e9b8f5a 485 if (enables.tcc)
maru536 2:8d119e9b8f5a 486 {
maru536 2:8d119e9b8f5a 487 used_budget_us += (timeouts.msrc_dss_tcc_us + TccOverhead);
maru536 2:8d119e9b8f5a 488 }
maru536 2:8d119e9b8f5a 489
maru536 2:8d119e9b8f5a 490 if (enables.dss)
maru536 2:8d119e9b8f5a 491 {
maru536 2:8d119e9b8f5a 492 used_budget_us += 2 * (timeouts.msrc_dss_tcc_us + DssOverhead);
maru536 2:8d119e9b8f5a 493 }
maru536 2:8d119e9b8f5a 494 else if (enables.msrc)
maru536 2:8d119e9b8f5a 495 {
maru536 2:8d119e9b8f5a 496 used_budget_us += (timeouts.msrc_dss_tcc_us + MsrcOverhead);
maru536 2:8d119e9b8f5a 497 }
maru536 2:8d119e9b8f5a 498
maru536 2:8d119e9b8f5a 499 if (enables.pre_range)
maru536 2:8d119e9b8f5a 500 {
maru536 2:8d119e9b8f5a 501 used_budget_us += (timeouts.pre_range_us + PreRangeOverhead);
maru536 2:8d119e9b8f5a 502 }
maru536 2:8d119e9b8f5a 503
maru536 2:8d119e9b8f5a 504 if (enables.final_range)
maru536 2:8d119e9b8f5a 505 {
maru536 2:8d119e9b8f5a 506 used_budget_us += FinalRangeOverhead;
maru536 2:8d119e9b8f5a 507
maru536 2:8d119e9b8f5a 508 // "Note that the final range timeout is determined by the timing
maru536 2:8d119e9b8f5a 509 // budget and the sum of all other timeouts within the sequence.
maru536 2:8d119e9b8f5a 510 // If there is no room for the final range timeout, then an error
maru536 2:8d119e9b8f5a 511 // will be set. Otherwise the remaining time will be applied to
maru536 2:8d119e9b8f5a 512 // the final range."
maru536 2:8d119e9b8f5a 513
maru536 2:8d119e9b8f5a 514 if (used_budget_us > budget_us)
maru536 2:8d119e9b8f5a 515 {
maru536 2:8d119e9b8f5a 516 // "Requested timeout too big."
maru536 2:8d119e9b8f5a 517 return false;
maru536 2:8d119e9b8f5a 518 }
maru536 2:8d119e9b8f5a 519
maru536 2:8d119e9b8f5a 520 uint32_t final_range_timeout_us = budget_us - used_budget_us;
maru536 2:8d119e9b8f5a 521
maru536 2:8d119e9b8f5a 522 // set_sequence_step_timeout() begin
maru536 2:8d119e9b8f5a 523 // (SequenceStepId == VL53L0X_SEQUENCESTEP_FINAL_RANGE)
maru536 2:8d119e9b8f5a 524
maru536 2:8d119e9b8f5a 525 // "For the final range timeout, the pre-range timeout
maru536 2:8d119e9b8f5a 526 // must be added. To do this both final and pre-range
maru536 2:8d119e9b8f5a 527 // timeouts must be expressed in macro periods MClks
maru536 2:8d119e9b8f5a 528 // because they have different vcsel periods."
maru536 2:8d119e9b8f5a 529
maru536 2:8d119e9b8f5a 530 uint16_t final_range_timeout_mclks =
maru536 2:8d119e9b8f5a 531 timeoutMicrosecondsToMclks(final_range_timeout_us,
maru536 2:8d119e9b8f5a 532 timeouts.final_range_vcsel_period_pclks);
maru536 2:8d119e9b8f5a 533
maru536 2:8d119e9b8f5a 534 if (enables.pre_range)
maru536 2:8d119e9b8f5a 535 {
maru536 2:8d119e9b8f5a 536 final_range_timeout_mclks += timeouts.pre_range_mclks;
maru536 2:8d119e9b8f5a 537 }
maru536 2:8d119e9b8f5a 538
maru536 2:8d119e9b8f5a 539 writeReg16Bit(FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI,
maru536 2:8d119e9b8f5a 540 encodeTimeout(final_range_timeout_mclks));
maru536 2:8d119e9b8f5a 541
maru536 2:8d119e9b8f5a 542 // set_sequence_step_timeout() end
maru536 2:8d119e9b8f5a 543
maru536 2:8d119e9b8f5a 544 measurement_timing_budget_us = budget_us; // store for internal reuse
maru536 2:8d119e9b8f5a 545 }
maru536 2:8d119e9b8f5a 546 return true;
maru536 2:8d119e9b8f5a 547 }
maru536 2:8d119e9b8f5a 548
maru536 2:8d119e9b8f5a 549 // Get the measurement timing budget in microseconds
maru536 2:8d119e9b8f5a 550 // based on VL53L0X_get_measurement_timing_budget_micro_seconds()
maru536 2:8d119e9b8f5a 551 // in us
maru536 2:8d119e9b8f5a 552 uint32_t VL53L0X::getMeasurementTimingBudget(void)
maru536 2:8d119e9b8f5a 553 {
maru536 2:8d119e9b8f5a 554 SequenceStepEnables enables;
maru536 2:8d119e9b8f5a 555 SequenceStepTimeouts timeouts;
maru536 2:8d119e9b8f5a 556
maru536 2:8d119e9b8f5a 557 uint16_t const StartOverhead = 1910; // note that this is different than the value in set_
maru536 2:8d119e9b8f5a 558 uint16_t const EndOverhead = 960;
maru536 2:8d119e9b8f5a 559 uint16_t const MsrcOverhead = 660;
maru536 2:8d119e9b8f5a 560 uint16_t const TccOverhead = 590;
maru536 2:8d119e9b8f5a 561 uint16_t const DssOverhead = 690;
maru536 2:8d119e9b8f5a 562 uint16_t const PreRangeOverhead = 660;
maru536 2:8d119e9b8f5a 563 uint16_t const FinalRangeOverhead = 550;
maru536 2:8d119e9b8f5a 564
maru536 2:8d119e9b8f5a 565 // "Start and end overhead times always present"
maru536 2:8d119e9b8f5a 566 uint32_t budget_us = StartOverhead + EndOverhead;
maru536 2:8d119e9b8f5a 567
maru536 2:8d119e9b8f5a 568 getSequenceStepEnables(&enables);
maru536 2:8d119e9b8f5a 569 getSequenceStepTimeouts(&enables, &timeouts);
maru536 2:8d119e9b8f5a 570
maru536 2:8d119e9b8f5a 571 if (enables.tcc)
maru536 2:8d119e9b8f5a 572 {
maru536 2:8d119e9b8f5a 573 budget_us += (timeouts.msrc_dss_tcc_us + TccOverhead);
maru536 2:8d119e9b8f5a 574 }
maru536 2:8d119e9b8f5a 575
maru536 2:8d119e9b8f5a 576 if (enables.dss)
maru536 2:8d119e9b8f5a 577 {
maru536 2:8d119e9b8f5a 578 budget_us += 2 * (timeouts.msrc_dss_tcc_us + DssOverhead);
maru536 2:8d119e9b8f5a 579 }
maru536 2:8d119e9b8f5a 580 else if (enables.msrc)
maru536 2:8d119e9b8f5a 581 {
maru536 2:8d119e9b8f5a 582 budget_us += (timeouts.msrc_dss_tcc_us + MsrcOverhead);
maru536 2:8d119e9b8f5a 583 }
maru536 2:8d119e9b8f5a 584
maru536 2:8d119e9b8f5a 585 if (enables.pre_range)
maru536 2:8d119e9b8f5a 586 {
maru536 2:8d119e9b8f5a 587 budget_us += (timeouts.pre_range_us + PreRangeOverhead);
maru536 2:8d119e9b8f5a 588 }
maru536 2:8d119e9b8f5a 589
maru536 2:8d119e9b8f5a 590 if (enables.final_range)
maru536 2:8d119e9b8f5a 591 {
maru536 2:8d119e9b8f5a 592 budget_us += (timeouts.final_range_us + FinalRangeOverhead);
maru536 2:8d119e9b8f5a 593 }
maru536 2:8d119e9b8f5a 594
maru536 2:8d119e9b8f5a 595 measurement_timing_budget_us = budget_us; // store for internal reuse
maru536 2:8d119e9b8f5a 596 return budget_us;
maru536 2:8d119e9b8f5a 597 }
maru536 2:8d119e9b8f5a 598
maru536 2:8d119e9b8f5a 599 // Set the VCSEL (vertical cavity surface emitting laser) pulse period for the
maru536 2:8d119e9b8f5a 600 // given period type (pre-range or final range) to the given value in PCLKs.
maru536 2:8d119e9b8f5a 601 // Longer periods seem to increase the potential range of the sensor.
maru536 2:8d119e9b8f5a 602 // Valid values are (even numbers only):
maru536 2:8d119e9b8f5a 603 // pre: 12 to 18 (initialized default: 14)
maru536 2:8d119e9b8f5a 604 // final: 8 to 14 (initialized default: 10)
maru536 2:8d119e9b8f5a 605 // based on VL53L0X_set_vcsel_pulse_period()
maru536 2:8d119e9b8f5a 606 bool VL53L0X::setVcselPulsePeriod(vcselPeriodType type, uint8_t period_pclks)
maru536 2:8d119e9b8f5a 607 {
maru536 2:8d119e9b8f5a 608 uint8_t vcsel_period_reg = encodeVcselPeriod(period_pclks);
maru536 2:8d119e9b8f5a 609
maru536 2:8d119e9b8f5a 610 SequenceStepEnables enables;
maru536 2:8d119e9b8f5a 611 SequenceStepTimeouts timeouts;
maru536 2:8d119e9b8f5a 612
maru536 2:8d119e9b8f5a 613 getSequenceStepEnables(&enables);
maru536 2:8d119e9b8f5a 614 getSequenceStepTimeouts(&enables, &timeouts);
maru536 2:8d119e9b8f5a 615
maru536 2:8d119e9b8f5a 616 // "Apply specific settings for the requested clock period"
maru536 2:8d119e9b8f5a 617 // "Re-calculate and apply timeouts, in macro periods"
maru536 2:8d119e9b8f5a 618
maru536 2:8d119e9b8f5a 619 // "When the VCSEL period for the pre or final range is changed,
maru536 2:8d119e9b8f5a 620 // the corresponding timeout must be read from the device using
maru536 2:8d119e9b8f5a 621 // the current VCSEL period, then the new VCSEL period can be
maru536 2:8d119e9b8f5a 622 // applied. The timeout then must be written back to the device
maru536 2:8d119e9b8f5a 623 // using the new VCSEL period.
maru536 2:8d119e9b8f5a 624 //
maru536 2:8d119e9b8f5a 625 // For the MSRC timeout, the same applies - this timeout being
maru536 2:8d119e9b8f5a 626 // dependant on the pre-range vcsel period."
maru536 2:8d119e9b8f5a 627
maru536 2:8d119e9b8f5a 628
maru536 2:8d119e9b8f5a 629 if (type == VcselPeriodPreRange)
maru536 2:8d119e9b8f5a 630 {
maru536 2:8d119e9b8f5a 631 // "Set phase check limits"
maru536 2:8d119e9b8f5a 632 switch (period_pclks)
maru536 2:8d119e9b8f5a 633 {
maru536 2:8d119e9b8f5a 634 case 12:
maru536 2:8d119e9b8f5a 635 writeReg(PRE_RANGE_CONFIG_VALID_PHASE_HIGH, 0x18);
maru536 2:8d119e9b8f5a 636 break;
maru536 2:8d119e9b8f5a 637
maru536 2:8d119e9b8f5a 638 case 14:
maru536 2:8d119e9b8f5a 639 writeReg(PRE_RANGE_CONFIG_VALID_PHASE_HIGH, 0x30);
maru536 2:8d119e9b8f5a 640 break;
maru536 2:8d119e9b8f5a 641
maru536 2:8d119e9b8f5a 642 case 16:
maru536 2:8d119e9b8f5a 643 writeReg(PRE_RANGE_CONFIG_VALID_PHASE_HIGH, 0x40);
maru536 2:8d119e9b8f5a 644 break;
maru536 2:8d119e9b8f5a 645
maru536 2:8d119e9b8f5a 646 case 18:
maru536 2:8d119e9b8f5a 647 writeReg(PRE_RANGE_CONFIG_VALID_PHASE_HIGH, 0x50);
maru536 2:8d119e9b8f5a 648 break;
maru536 2:8d119e9b8f5a 649
maru536 2:8d119e9b8f5a 650 default:
maru536 2:8d119e9b8f5a 651 // invalid period
maru536 2:8d119e9b8f5a 652 return false;
maru536 2:8d119e9b8f5a 653 }
maru536 2:8d119e9b8f5a 654 writeReg(PRE_RANGE_CONFIG_VALID_PHASE_LOW, 0x08);
maru536 2:8d119e9b8f5a 655
maru536 2:8d119e9b8f5a 656 // apply new VCSEL period
maru536 2:8d119e9b8f5a 657 writeReg(PRE_RANGE_CONFIG_VCSEL_PERIOD, vcsel_period_reg);
maru536 2:8d119e9b8f5a 658
maru536 2:8d119e9b8f5a 659 // update timeouts
maru536 2:8d119e9b8f5a 660
maru536 2:8d119e9b8f5a 661 // set_sequence_step_timeout() begin
maru536 2:8d119e9b8f5a 662 // (SequenceStepId == VL53L0X_SEQUENCESTEP_PRE_RANGE)
maru536 2:8d119e9b8f5a 663
maru536 2:8d119e9b8f5a 664 uint16_t new_pre_range_timeout_mclks =
maru536 2:8d119e9b8f5a 665 timeoutMicrosecondsToMclks(timeouts.pre_range_us, period_pclks);
maru536 2:8d119e9b8f5a 666
maru536 2:8d119e9b8f5a 667 writeReg16Bit(PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI,
maru536 2:8d119e9b8f5a 668 encodeTimeout(new_pre_range_timeout_mclks));
maru536 2:8d119e9b8f5a 669
maru536 2:8d119e9b8f5a 670 // set_sequence_step_timeout() end
maru536 2:8d119e9b8f5a 671
maru536 2:8d119e9b8f5a 672 // set_sequence_step_timeout() begin
maru536 2:8d119e9b8f5a 673 // (SequenceStepId == VL53L0X_SEQUENCESTEP_MSRC)
maru536 2:8d119e9b8f5a 674
maru536 2:8d119e9b8f5a 675 uint16_t new_msrc_timeout_mclks =
maru536 2:8d119e9b8f5a 676 timeoutMicrosecondsToMclks(timeouts.msrc_dss_tcc_us, period_pclks);
maru536 2:8d119e9b8f5a 677
maru536 2:8d119e9b8f5a 678 writeReg(MSRC_CONFIG_TIMEOUT_MACROP,
maru536 2:8d119e9b8f5a 679 (new_msrc_timeout_mclks > 256) ? 255 : (new_msrc_timeout_mclks - 1));
maru536 2:8d119e9b8f5a 680
maru536 2:8d119e9b8f5a 681 // set_sequence_step_timeout() end
maru536 2:8d119e9b8f5a 682 }
maru536 2:8d119e9b8f5a 683 else if (type == VcselPeriodFinalRange)
maru536 2:8d119e9b8f5a 684 {
maru536 2:8d119e9b8f5a 685 switch (period_pclks)
maru536 2:8d119e9b8f5a 686 {
maru536 2:8d119e9b8f5a 687 case 8:
maru536 2:8d119e9b8f5a 688 writeReg(FINAL_RANGE_CONFIG_VALID_PHASE_HIGH, 0x10);
maru536 2:8d119e9b8f5a 689 writeReg(FINAL_RANGE_CONFIG_VALID_PHASE_LOW, 0x08);
maru536 2:8d119e9b8f5a 690 writeReg(GLOBAL_CONFIG_VCSEL_WIDTH, 0x02);
maru536 2:8d119e9b8f5a 691 writeReg(ALGO_PHASECAL_CONFIG_TIMEOUT, 0x0C);
maru536 2:8d119e9b8f5a 692 writeReg(0xFF, 0x01);
maru536 2:8d119e9b8f5a 693 writeReg(ALGO_PHASECAL_LIM, 0x30);
maru536 2:8d119e9b8f5a 694 writeReg(0xFF, 0x00);
maru536 2:8d119e9b8f5a 695 break;
maru536 2:8d119e9b8f5a 696
maru536 2:8d119e9b8f5a 697 case 10:
maru536 2:8d119e9b8f5a 698 writeReg(FINAL_RANGE_CONFIG_VALID_PHASE_HIGH, 0x28);
maru536 2:8d119e9b8f5a 699 writeReg(FINAL_RANGE_CONFIG_VALID_PHASE_LOW, 0x08);
maru536 2:8d119e9b8f5a 700 writeReg(GLOBAL_CONFIG_VCSEL_WIDTH, 0x03);
maru536 2:8d119e9b8f5a 701 writeReg(ALGO_PHASECAL_CONFIG_TIMEOUT, 0x09);
maru536 2:8d119e9b8f5a 702 writeReg(0xFF, 0x01);
maru536 2:8d119e9b8f5a 703 writeReg(ALGO_PHASECAL_LIM, 0x20);
maru536 2:8d119e9b8f5a 704 writeReg(0xFF, 0x00);
maru536 2:8d119e9b8f5a 705 break;
maru536 2:8d119e9b8f5a 706
maru536 2:8d119e9b8f5a 707 case 12:
maru536 2:8d119e9b8f5a 708 writeReg(FINAL_RANGE_CONFIG_VALID_PHASE_HIGH, 0x38);
maru536 2:8d119e9b8f5a 709 writeReg(FINAL_RANGE_CONFIG_VALID_PHASE_LOW, 0x08);
maru536 2:8d119e9b8f5a 710 writeReg(GLOBAL_CONFIG_VCSEL_WIDTH, 0x03);
maru536 2:8d119e9b8f5a 711 writeReg(ALGO_PHASECAL_CONFIG_TIMEOUT, 0x08);
maru536 2:8d119e9b8f5a 712 writeReg(0xFF, 0x01);
maru536 2:8d119e9b8f5a 713 writeReg(ALGO_PHASECAL_LIM, 0x20);
maru536 2:8d119e9b8f5a 714 writeReg(0xFF, 0x00);
maru536 2:8d119e9b8f5a 715 break;
maru536 2:8d119e9b8f5a 716
maru536 2:8d119e9b8f5a 717 case 14:
maru536 2:8d119e9b8f5a 718 writeReg(FINAL_RANGE_CONFIG_VALID_PHASE_HIGH, 0x48);
maru536 2:8d119e9b8f5a 719 writeReg(FINAL_RANGE_CONFIG_VALID_PHASE_LOW, 0x08);
maru536 2:8d119e9b8f5a 720 writeReg(GLOBAL_CONFIG_VCSEL_WIDTH, 0x03);
maru536 2:8d119e9b8f5a 721 writeReg(ALGO_PHASECAL_CONFIG_TIMEOUT, 0x07);
maru536 2:8d119e9b8f5a 722 writeReg(0xFF, 0x01);
maru536 2:8d119e9b8f5a 723 writeReg(ALGO_PHASECAL_LIM, 0x20);
maru536 2:8d119e9b8f5a 724 writeReg(0xFF, 0x00);
maru536 2:8d119e9b8f5a 725 break;
maru536 2:8d119e9b8f5a 726
maru536 2:8d119e9b8f5a 727 default:
maru536 2:8d119e9b8f5a 728 // invalid period
maru536 2:8d119e9b8f5a 729 return false;
maru536 2:8d119e9b8f5a 730 }
maru536 2:8d119e9b8f5a 731
maru536 2:8d119e9b8f5a 732 // apply new VCSEL period
maru536 2:8d119e9b8f5a 733 writeReg(FINAL_RANGE_CONFIG_VCSEL_PERIOD, vcsel_period_reg);
maru536 2:8d119e9b8f5a 734
maru536 2:8d119e9b8f5a 735 // update timeouts
maru536 2:8d119e9b8f5a 736
maru536 2:8d119e9b8f5a 737 // set_sequence_step_timeout() begin
maru536 2:8d119e9b8f5a 738 // (SequenceStepId == VL53L0X_SEQUENCESTEP_FINAL_RANGE)
maru536 2:8d119e9b8f5a 739
maru536 2:8d119e9b8f5a 740 // "For the final range timeout, the pre-range timeout
maru536 2:8d119e9b8f5a 741 // must be added. To do this both final and pre-range
maru536 2:8d119e9b8f5a 742 // timeouts must be expressed in macro periods MClks
maru536 2:8d119e9b8f5a 743 // because they have different vcsel periods."
maru536 2:8d119e9b8f5a 744
maru536 2:8d119e9b8f5a 745 uint16_t new_final_range_timeout_mclks =
maru536 2:8d119e9b8f5a 746 timeoutMicrosecondsToMclks(timeouts.final_range_us, period_pclks);
maru536 2:8d119e9b8f5a 747
maru536 2:8d119e9b8f5a 748 if (enables.pre_range)
maru536 2:8d119e9b8f5a 749 {
maru536 2:8d119e9b8f5a 750 new_final_range_timeout_mclks += timeouts.pre_range_mclks;
maru536 2:8d119e9b8f5a 751 }
maru536 2:8d119e9b8f5a 752
maru536 2:8d119e9b8f5a 753 writeReg16Bit(FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI,
maru536 2:8d119e9b8f5a 754 encodeTimeout(new_final_range_timeout_mclks));
maru536 2:8d119e9b8f5a 755
maru536 2:8d119e9b8f5a 756 // set_sequence_step_timeout end
maru536 2:8d119e9b8f5a 757 }
maru536 2:8d119e9b8f5a 758 else
maru536 2:8d119e9b8f5a 759 {
maru536 2:8d119e9b8f5a 760 // invalid type
maru536 2:8d119e9b8f5a 761 return false;
maru536 2:8d119e9b8f5a 762 }
maru536 2:8d119e9b8f5a 763
maru536 2:8d119e9b8f5a 764 // "Finally, the timing budget must be re-applied"
maru536 2:8d119e9b8f5a 765
maru536 2:8d119e9b8f5a 766 setMeasurementTimingBudget(measurement_timing_budget_us);
maru536 2:8d119e9b8f5a 767
maru536 2:8d119e9b8f5a 768 // "Perform the phase calibration. This is needed after changing on vcsel period."
maru536 2:8d119e9b8f5a 769 // VL53L0X_perform_phase_calibration() begin
maru536 2:8d119e9b8f5a 770
maru536 2:8d119e9b8f5a 771 uint8_t sequence_config = readReg(SYSTEM_SEQUENCE_CONFIG);
maru536 2:8d119e9b8f5a 772 writeReg(SYSTEM_SEQUENCE_CONFIG, 0x02);
maru536 2:8d119e9b8f5a 773 performSingleRefCalibration(0x0);
maru536 2:8d119e9b8f5a 774 writeReg(SYSTEM_SEQUENCE_CONFIG, sequence_config);
maru536 2:8d119e9b8f5a 775
maru536 2:8d119e9b8f5a 776 // VL53L0X_perform_phase_calibration() end
maru536 2:8d119e9b8f5a 777
maru536 2:8d119e9b8f5a 778 return true;
maru536 2:8d119e9b8f5a 779 }
maru536 2:8d119e9b8f5a 780
maru536 2:8d119e9b8f5a 781 // Get the VCSEL pulse period in PCLKs for the given period type.
maru536 2:8d119e9b8f5a 782 // based on VL53L0X_get_vcsel_pulse_period()
maru536 2:8d119e9b8f5a 783 uint8_t VL53L0X::getVcselPulsePeriod(vcselPeriodType type)
maru536 2:8d119e9b8f5a 784 {
maru536 2:8d119e9b8f5a 785 if (type == VcselPeriodPreRange)
maru536 2:8d119e9b8f5a 786 {
maru536 2:8d119e9b8f5a 787 return decodeVcselPeriod(readReg(PRE_RANGE_CONFIG_VCSEL_PERIOD));
maru536 2:8d119e9b8f5a 788 }
maru536 2:8d119e9b8f5a 789 else if (type == VcselPeriodFinalRange)
maru536 2:8d119e9b8f5a 790 {
maru536 2:8d119e9b8f5a 791 return decodeVcselPeriod(readReg(FINAL_RANGE_CONFIG_VCSEL_PERIOD));
maru536 2:8d119e9b8f5a 792 }
maru536 2:8d119e9b8f5a 793 else { return 255; }
maru536 2:8d119e9b8f5a 794 }
maru536 2:8d119e9b8f5a 795
maru536 2:8d119e9b8f5a 796 // Start continuous ranging measurements. If period_ms (optional) is 0 or not
maru536 2:8d119e9b8f5a 797 // given, continuous back-to-back mode is used (the sensor takes measurements as
maru536 2:8d119e9b8f5a 798 // often as possible); otherwise, continuous timed mode is used, with the given
maru536 2:8d119e9b8f5a 799 // inter-measurement period in milliseconds determining how often the sensor
maru536 2:8d119e9b8f5a 800 // takes a measurement.
maru536 2:8d119e9b8f5a 801 // based on VL53L0X_StartMeasurement()
maru536 2:8d119e9b8f5a 802 void VL53L0X::startContinuous(uint32_t period_ms)
maru536 2:8d119e9b8f5a 803 {
maru536 2:8d119e9b8f5a 804 writeReg(0x80, 0x01);
maru536 2:8d119e9b8f5a 805 writeReg(0xFF, 0x01);
maru536 2:8d119e9b8f5a 806 writeReg(0x00, 0x00);
maru536 2:8d119e9b8f5a 807 writeReg(0x91, stop_variable);
maru536 2:8d119e9b8f5a 808 writeReg(0x00, 0x01);
maru536 2:8d119e9b8f5a 809 writeReg(0xFF, 0x00);
maru536 2:8d119e9b8f5a 810 writeReg(0x80, 0x00);
maru536 2:8d119e9b8f5a 811
maru536 2:8d119e9b8f5a 812 if (period_ms != 0)
maru536 2:8d119e9b8f5a 813 {
maru536 2:8d119e9b8f5a 814 // continuous timed mode
maru536 2:8d119e9b8f5a 815
maru536 2:8d119e9b8f5a 816 // VL53L0X_SetInterMeasurementPeriodMilliSeconds() begin
maru536 2:8d119e9b8f5a 817
maru536 2:8d119e9b8f5a 818 uint16_t osc_calibrate_val = readReg16Bit(OSC_CALIBRATE_VAL);
maru536 2:8d119e9b8f5a 819
maru536 2:8d119e9b8f5a 820 if (osc_calibrate_val != 0)
maru536 2:8d119e9b8f5a 821 {
maru536 2:8d119e9b8f5a 822 period_ms *= osc_calibrate_val;
maru536 2:8d119e9b8f5a 823 }
maru536 2:8d119e9b8f5a 824
maru536 2:8d119e9b8f5a 825 writeReg32Bit(SYSTEM_INTERMEASUREMENT_PERIOD, period_ms);
maru536 2:8d119e9b8f5a 826
maru536 2:8d119e9b8f5a 827 // VL53L0X_SetInterMeasurementPeriodMilliSeconds() end
maru536 2:8d119e9b8f5a 828
maru536 2:8d119e9b8f5a 829 writeReg(SYSRANGE_START, 0x04); // VL53L0X_REG_SYSRANGE_MODE_TIMED
maru536 2:8d119e9b8f5a 830 }
maru536 2:8d119e9b8f5a 831 else
maru536 2:8d119e9b8f5a 832 {
maru536 2:8d119e9b8f5a 833 // continuous back-to-back mode
maru536 2:8d119e9b8f5a 834 writeReg(SYSRANGE_START, 0x02); // VL53L0X_REG_SYSRANGE_MODE_BACKTOBACK
maru536 2:8d119e9b8f5a 835 }
maru536 2:8d119e9b8f5a 836 }
maru536 2:8d119e9b8f5a 837
maru536 2:8d119e9b8f5a 838 // Stop continuous measurements
maru536 2:8d119e9b8f5a 839 // based on VL53L0X_StopMeasurement()
maru536 2:8d119e9b8f5a 840 void VL53L0X::stopContinuous(void)
maru536 2:8d119e9b8f5a 841 {
maru536 2:8d119e9b8f5a 842 writeReg(SYSRANGE_START, 0x01); // VL53L0X_REG_SYSRANGE_MODE_SINGLESHOT
maru536 2:8d119e9b8f5a 843
maru536 2:8d119e9b8f5a 844 writeReg(0xFF, 0x01);
maru536 2:8d119e9b8f5a 845 writeReg(0x00, 0x00);
maru536 2:8d119e9b8f5a 846 writeReg(0x91, 0x00);
maru536 2:8d119e9b8f5a 847 writeReg(0x00, 0x01);
maru536 2:8d119e9b8f5a 848 writeReg(0xFF, 0x00);
maru536 2:8d119e9b8f5a 849 }
maru536 2:8d119e9b8f5a 850
maru536 2:8d119e9b8f5a 851 // Returns a range reading in millimeters when continuous mode is active
maru536 2:8d119e9b8f5a 852 // (readRangeSingleMillimeters() also calls this function after starting a
maru536 2:8d119e9b8f5a 853 // single-shot range measurement)
maru536 2:8d119e9b8f5a 854 uint16_t VL53L0X::readRangeContinuousMillimeters(void)
maru536 2:8d119e9b8f5a 855 {
maru536 2:8d119e9b8f5a 856 startTimeout();
maru536 2:8d119e9b8f5a 857 while ((readReg(RESULT_INTERRUPT_STATUS) & 0x07) == 0)
maru536 2:8d119e9b8f5a 858 {
maru536 2:8d119e9b8f5a 859 if (checkTimeoutExpired())
maru536 2:8d119e9b8f5a 860 {
maru536 2:8d119e9b8f5a 861 did_timeout = true;
maru536 2:8d119e9b8f5a 862 return 65535;
maru536 2:8d119e9b8f5a 863 }
maru536 2:8d119e9b8f5a 864 }
maru536 2:8d119e9b8f5a 865
maru536 2:8d119e9b8f5a 866 // assumptions: Linearity Corrective Gain is 1000 (default);
maru536 2:8d119e9b8f5a 867 // fractional ranging is not enabled
maru536 2:8d119e9b8f5a 868 uint16_t range = readReg16Bit(RESULT_RANGE_STATUS + 10);
maru536 2:8d119e9b8f5a 869
maru536 2:8d119e9b8f5a 870 writeReg(SYSTEM_INTERRUPT_CLEAR, 0x01);
maru536 2:8d119e9b8f5a 871
maru536 2:8d119e9b8f5a 872 return range;
maru536 2:8d119e9b8f5a 873 }
maru536 2:8d119e9b8f5a 874
maru536 2:8d119e9b8f5a 875 // Performs a single-shot range measurement and returns the reading in
maru536 2:8d119e9b8f5a 876 // millimeters
maru536 2:8d119e9b8f5a 877 // based on VL53L0X_PerformSingleRangingMeasurement()
maru536 2:8d119e9b8f5a 878 uint16_t VL53L0X::readRangeSingleMillimeters(void)
maru536 2:8d119e9b8f5a 879 {
maru536 2:8d119e9b8f5a 880 writeReg(0x80, 0x01);
maru536 2:8d119e9b8f5a 881 writeReg(0xFF, 0x01);
maru536 2:8d119e9b8f5a 882 writeReg(0x00, 0x00);
maru536 2:8d119e9b8f5a 883 writeReg(0x91, stop_variable);
maru536 2:8d119e9b8f5a 884 writeReg(0x00, 0x01);
maru536 2:8d119e9b8f5a 885 writeReg(0xFF, 0x00);
maru536 2:8d119e9b8f5a 886 writeReg(0x80, 0x00);
maru536 2:8d119e9b8f5a 887
maru536 2:8d119e9b8f5a 888 writeReg(SYSRANGE_START, 0x01);
maru536 2:8d119e9b8f5a 889
maru536 2:8d119e9b8f5a 890 // "Wait until start bit has been cleared"
maru536 2:8d119e9b8f5a 891 startTimeout();
maru536 2:8d119e9b8f5a 892 while (readReg(SYSRANGE_START) & 0x01)
maru536 2:8d119e9b8f5a 893 {
maru536 2:8d119e9b8f5a 894 if (checkTimeoutExpired())
maru536 2:8d119e9b8f5a 895 {
maru536 2:8d119e9b8f5a 896 did_timeout = true;
maru536 2:8d119e9b8f5a 897 return 65535;
maru536 2:8d119e9b8f5a 898 }
maru536 2:8d119e9b8f5a 899 }
maru536 2:8d119e9b8f5a 900
maru536 2:8d119e9b8f5a 901 return readRangeContinuousMillimeters();
maru536 2:8d119e9b8f5a 902 }
maru536 2:8d119e9b8f5a 903
maru536 2:8d119e9b8f5a 904 // Did a timeout occur in one of the read functions since the last call to
maru536 2:8d119e9b8f5a 905 // timeoutOccurred()?
maru536 2:8d119e9b8f5a 906 bool VL53L0X::timeoutOccurred()
maru536 2:8d119e9b8f5a 907 {
maru536 2:8d119e9b8f5a 908 bool tmp = did_timeout;
maru536 2:8d119e9b8f5a 909 did_timeout = false;
maru536 2:8d119e9b8f5a 910 return tmp;
maru536 2:8d119e9b8f5a 911 }
maru536 2:8d119e9b8f5a 912
maru536 2:8d119e9b8f5a 913 // Private Methods /////////////////////////////////////////////////////////////
maru536 2:8d119e9b8f5a 914
maru536 2:8d119e9b8f5a 915 // Get reference SPAD (single photon avalanche diode) count and type
maru536 2:8d119e9b8f5a 916 // based on VL53L0X_get_info_from_device(),
maru536 2:8d119e9b8f5a 917 // but only gets reference SPAD count and type
maru536 2:8d119e9b8f5a 918 bool VL53L0X::getSpadInfo(uint8_t * count, bool * type_is_aperture)
maru536 2:8d119e9b8f5a 919 {
maru536 2:8d119e9b8f5a 920 uint8_t tmp;
maru536 2:8d119e9b8f5a 921
maru536 2:8d119e9b8f5a 922 writeReg(0x80, 0x01);
maru536 2:8d119e9b8f5a 923 writeReg(0xFF, 0x01);
maru536 2:8d119e9b8f5a 924 writeReg(0x00, 0x00);
maru536 2:8d119e9b8f5a 925
maru536 2:8d119e9b8f5a 926 writeReg(0xFF, 0x06);
maru536 2:8d119e9b8f5a 927 writeReg(0x83, readReg(0x83) | 0x04);
maru536 2:8d119e9b8f5a 928 writeReg(0xFF, 0x07);
maru536 2:8d119e9b8f5a 929 writeReg(0x81, 0x01);
maru536 2:8d119e9b8f5a 930
maru536 2:8d119e9b8f5a 931 writeReg(0x80, 0x01);
maru536 2:8d119e9b8f5a 932
maru536 2:8d119e9b8f5a 933 writeReg(0x94, 0x6b);
maru536 2:8d119e9b8f5a 934 writeReg(0x83, 0x00);
maru536 2:8d119e9b8f5a 935 startTimeout();
maru536 2:8d119e9b8f5a 936 while (readReg(0x83) == 0x00)
maru536 2:8d119e9b8f5a 937 {
maru536 2:8d119e9b8f5a 938 if (checkTimeoutExpired()) { return false; }
maru536 2:8d119e9b8f5a 939 }
maru536 2:8d119e9b8f5a 940 writeReg(0x83, 0x01);
maru536 2:8d119e9b8f5a 941 tmp = readReg(0x92);
maru536 2:8d119e9b8f5a 942
maru536 2:8d119e9b8f5a 943 *count = tmp & 0x7f;
maru536 2:8d119e9b8f5a 944 *type_is_aperture = (tmp >> 7) & 0x01;
maru536 2:8d119e9b8f5a 945
maru536 2:8d119e9b8f5a 946 writeReg(0x81, 0x00);
maru536 2:8d119e9b8f5a 947 writeReg(0xFF, 0x06);
maru536 2:8d119e9b8f5a 948 writeReg(0x83, readReg( 0x83 & ~0x04));
maru536 2:8d119e9b8f5a 949 writeReg(0xFF, 0x01);
maru536 2:8d119e9b8f5a 950 writeReg(0x00, 0x01);
maru536 2:8d119e9b8f5a 951
maru536 2:8d119e9b8f5a 952 writeReg(0xFF, 0x00);
maru536 2:8d119e9b8f5a 953 writeReg(0x80, 0x00);
maru536 2:8d119e9b8f5a 954
maru536 2:8d119e9b8f5a 955 return true;
maru536 2:8d119e9b8f5a 956 }
maru536 2:8d119e9b8f5a 957
maru536 2:8d119e9b8f5a 958 // Get sequence step enables
maru536 2:8d119e9b8f5a 959 // based on VL53L0X_GetSequenceStepEnables()
maru536 2:8d119e9b8f5a 960 void VL53L0X::getSequenceStepEnables(SequenceStepEnables * enables)
maru536 2:8d119e9b8f5a 961 {
maru536 2:8d119e9b8f5a 962 uint8_t sequence_config = readReg(SYSTEM_SEQUENCE_CONFIG);
maru536 2:8d119e9b8f5a 963
maru536 2:8d119e9b8f5a 964 enables->tcc = (sequence_config >> 4) & 0x1;
maru536 2:8d119e9b8f5a 965 enables->dss = (sequence_config >> 3) & 0x1;
maru536 2:8d119e9b8f5a 966 enables->msrc = (sequence_config >> 2) & 0x1;
maru536 2:8d119e9b8f5a 967 enables->pre_range = (sequence_config >> 6) & 0x1;
maru536 2:8d119e9b8f5a 968 enables->final_range = (sequence_config >> 7) & 0x1;
maru536 2:8d119e9b8f5a 969 }
maru536 2:8d119e9b8f5a 970
maru536 2:8d119e9b8f5a 971 // Get sequence step timeouts
maru536 2:8d119e9b8f5a 972 // based on get_sequence_step_timeout(),
maru536 2:8d119e9b8f5a 973 // but gets all timeouts instead of just the requested one, and also stores
maru536 2:8d119e9b8f5a 974 // intermediate values
maru536 2:8d119e9b8f5a 975 void VL53L0X::getSequenceStepTimeouts(SequenceStepEnables const * enables, SequenceStepTimeouts * timeouts)
maru536 2:8d119e9b8f5a 976 {
maru536 2:8d119e9b8f5a 977 timeouts->pre_range_vcsel_period_pclks = getVcselPulsePeriod(VcselPeriodPreRange);
maru536 2:8d119e9b8f5a 978
maru536 2:8d119e9b8f5a 979 timeouts->msrc_dss_tcc_mclks = readReg(MSRC_CONFIG_TIMEOUT_MACROP) + 1;
maru536 2:8d119e9b8f5a 980 timeouts->msrc_dss_tcc_us =
maru536 2:8d119e9b8f5a 981 timeoutMclksToMicroseconds(timeouts->msrc_dss_tcc_mclks,
maru536 2:8d119e9b8f5a 982 timeouts->pre_range_vcsel_period_pclks);
maru536 2:8d119e9b8f5a 983
maru536 2:8d119e9b8f5a 984 timeouts->pre_range_mclks =
maru536 2:8d119e9b8f5a 985 decodeTimeout(readReg16Bit(PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI));
maru536 2:8d119e9b8f5a 986 timeouts->pre_range_us =
maru536 2:8d119e9b8f5a 987 timeoutMclksToMicroseconds(timeouts->pre_range_mclks,
maru536 2:8d119e9b8f5a 988 timeouts->pre_range_vcsel_period_pclks);
maru536 2:8d119e9b8f5a 989
maru536 2:8d119e9b8f5a 990 timeouts->final_range_vcsel_period_pclks = getVcselPulsePeriod(VcselPeriodFinalRange);
maru536 2:8d119e9b8f5a 991
maru536 2:8d119e9b8f5a 992 timeouts->final_range_mclks =
maru536 2:8d119e9b8f5a 993 decodeTimeout(readReg16Bit(FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI));
maru536 2:8d119e9b8f5a 994
maru536 2:8d119e9b8f5a 995 if (enables->pre_range)
maru536 2:8d119e9b8f5a 996 {
maru536 2:8d119e9b8f5a 997 timeouts->final_range_mclks -= timeouts->pre_range_mclks;
maru536 2:8d119e9b8f5a 998 }
maru536 2:8d119e9b8f5a 999
maru536 2:8d119e9b8f5a 1000 timeouts->final_range_us =
maru536 2:8d119e9b8f5a 1001 timeoutMclksToMicroseconds(timeouts->final_range_mclks,
maru536 2:8d119e9b8f5a 1002 timeouts->final_range_vcsel_period_pclks);
maru536 2:8d119e9b8f5a 1003 }
maru536 2:8d119e9b8f5a 1004
maru536 2:8d119e9b8f5a 1005 // Decode sequence step timeout in MCLKs from register value
maru536 2:8d119e9b8f5a 1006 // based on VL53L0X_decode_timeout()
maru536 2:8d119e9b8f5a 1007 // Note: the original function returned a uint32_t, but the return value is
maru536 2:8d119e9b8f5a 1008 // always stored in a uint16_t.
maru536 2:8d119e9b8f5a 1009 uint16_t VL53L0X::decodeTimeout(uint16_t reg_val)
maru536 2:8d119e9b8f5a 1010 {
maru536 2:8d119e9b8f5a 1011 // format: "(LSByte * 2^MSByte) + 1"
maru536 2:8d119e9b8f5a 1012 return (uint16_t)((reg_val & 0x00FF) <<
maru536 2:8d119e9b8f5a 1013 (uint16_t)((reg_val & 0xFF00) >> 8)) + 1;
maru536 2:8d119e9b8f5a 1014 }
maru536 2:8d119e9b8f5a 1015
maru536 2:8d119e9b8f5a 1016 // Encode sequence step timeout register value from timeout in MCLKs
maru536 2:8d119e9b8f5a 1017 // based on VL53L0X_encode_timeout()
maru536 2:8d119e9b8f5a 1018 // Note: the original function took a uint16_t, but the argument passed to it
maru536 2:8d119e9b8f5a 1019 // is always a uint16_t.
maru536 2:8d119e9b8f5a 1020 uint16_t VL53L0X::encodeTimeout(uint16_t timeout_mclks)
maru536 2:8d119e9b8f5a 1021 {
maru536 2:8d119e9b8f5a 1022 // format: "(LSByte * 2^MSByte) + 1"
maru536 2:8d119e9b8f5a 1023
maru536 2:8d119e9b8f5a 1024 uint32_t ls_byte = 0;
maru536 2:8d119e9b8f5a 1025 uint16_t ms_byte = 0;
maru536 2:8d119e9b8f5a 1026
maru536 2:8d119e9b8f5a 1027 if (timeout_mclks > 0)
maru536 2:8d119e9b8f5a 1028 {
maru536 2:8d119e9b8f5a 1029 ls_byte = timeout_mclks - 1;
maru536 2:8d119e9b8f5a 1030
maru536 2:8d119e9b8f5a 1031 while ((ls_byte & 0xFFFFFF00) > 0)
maru536 2:8d119e9b8f5a 1032 {
maru536 2:8d119e9b8f5a 1033 ls_byte >>= 1;
maru536 2:8d119e9b8f5a 1034 ms_byte++;
maru536 2:8d119e9b8f5a 1035 }
maru536 2:8d119e9b8f5a 1036
maru536 2:8d119e9b8f5a 1037 return (ms_byte << 8) | (ls_byte & 0xFF);
maru536 2:8d119e9b8f5a 1038 }
maru536 2:8d119e9b8f5a 1039 else { return 0; }
maru536 2:8d119e9b8f5a 1040 }
maru536 2:8d119e9b8f5a 1041
maru536 2:8d119e9b8f5a 1042 // Convert sequence step timeout from MCLKs to microseconds with given VCSEL period in PCLKs
maru536 2:8d119e9b8f5a 1043 // based on VL53L0X_calc_timeout_us()
maru536 2:8d119e9b8f5a 1044 uint32_t VL53L0X::timeoutMclksToMicroseconds(uint16_t timeout_period_mclks, uint8_t vcsel_period_pclks)
maru536 2:8d119e9b8f5a 1045 {
maru536 2:8d119e9b8f5a 1046 uint32_t macro_period_ns = calcMacroPeriod(vcsel_period_pclks);
maru536 2:8d119e9b8f5a 1047
maru536 2:8d119e9b8f5a 1048 return ((timeout_period_mclks * macro_period_ns) + (macro_period_ns / 2)) / 1000;
maru536 2:8d119e9b8f5a 1049 }
maru536 2:8d119e9b8f5a 1050
maru536 2:8d119e9b8f5a 1051 // Convert sequence step timeout from microseconds to MCLKs with given VCSEL period in PCLKs
maru536 2:8d119e9b8f5a 1052 // based on VL53L0X_calc_timeout_mclks()
maru536 2:8d119e9b8f5a 1053 uint32_t VL53L0X::timeoutMicrosecondsToMclks(uint32_t timeout_period_us, uint8_t vcsel_period_pclks)
maru536 2:8d119e9b8f5a 1054 {
maru536 2:8d119e9b8f5a 1055 uint32_t macro_period_ns = calcMacroPeriod(vcsel_period_pclks);
maru536 2:8d119e9b8f5a 1056
maru536 2:8d119e9b8f5a 1057 return (((timeout_period_us * 1000) + (macro_period_ns / 2)) / macro_period_ns);
maru536 2:8d119e9b8f5a 1058 }
maru536 2:8d119e9b8f5a 1059
maru536 2:8d119e9b8f5a 1060
maru536 2:8d119e9b8f5a 1061 // based on VL53L0X_perform_single_ref_calibration()
maru536 2:8d119e9b8f5a 1062 bool VL53L0X::performSingleRefCalibration(uint8_t vhv_init_byte)
maru536 2:8d119e9b8f5a 1063 {
maru536 2:8d119e9b8f5a 1064 writeReg(SYSRANGE_START, 0x01 | vhv_init_byte); // VL53L0X_REG_SYSRANGE_MODE_START_STOP
maru536 2:8d119e9b8f5a 1065
maru536 2:8d119e9b8f5a 1066 startTimeout();
maru536 2:8d119e9b8f5a 1067 while ((readReg(RESULT_INTERRUPT_STATUS) & 0x07) == 0)
maru536 2:8d119e9b8f5a 1068 {
maru536 2:8d119e9b8f5a 1069 if (checkTimeoutExpired()) { return false; }
maru536 2:8d119e9b8f5a 1070 }
maru536 2:8d119e9b8f5a 1071
maru536 2:8d119e9b8f5a 1072 writeReg(SYSTEM_INTERRUPT_CLEAR, 0x01);
maru536 2:8d119e9b8f5a 1073
maru536 2:8d119e9b8f5a 1074 writeReg(SYSRANGE_START, 0x00);
maru536 2:8d119e9b8f5a 1075
maru536 2:8d119e9b8f5a 1076 return true;
maru536 2:8d119e9b8f5a 1077 }