From bc865905fc97085f40ca9edab478210c01195fde Mon Sep 17 00:00:00 2001 From: "Kevin (Pololu)" Date: Tue, 20 Aug 2024 18:39:12 -0700 Subject: [PATCH] optimized some larger data transfers to use I2C block reads/writes --- README.md | 8 +++++--- src/VL53L4CD.cpp | 46 +++++++++++++++++++++++++++++++++++++++------- src/VL53L4CD.h | 3 ++- 3 files changed, 46 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 4b96eb8..a611c30 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ Most of the functionality of this library is based on the [VL53L4CD Ultra Lite D Range reading from the last measurement, in millimeters. (This reading can also be obtained as the return value of `read()`.) * `uint8_t range_status`
Status of the last measurement; see the API user manual UM2931 for descriptions of the possible statuses. A status of 0 means there were no problems with the measurement. - * `uint16_t number_of_spad`
+ * `uint8_t number_of_spad`
The number of SPADs (single photon avalanche diodes) enabled for the last measurement. More SPADs will be activated for sensing distant and less reflective targets. * `uint16_t signal_rate_kcps`
Quantity of photons measured during the last measurement, in units of kilo counts per second. @@ -81,6 +81,8 @@ Most of the functionality of this library is based on the [VL53L4CD Ultra Lite D Signal rate divided by number of SPADs. * `uint16_t ambient_per_spad_kcps`
Ambient rate divided by number of SPADs. + * `uint16_t sigma_mm`
+ An estimate of the noise (standard deviation) in the last range measurement. * `uint8_t last_status`
The status of the last I²C write transmission. See the [`Wire.endTransmission()` documentation](http://arduino.cc/en/Reference/WireEndTransmission) for return values. @@ -95,7 +97,7 @@ Most of the functionality of this library is based on the [VL53L4CD Ultra Lite D Returns a pointer to the I²C bus this object is using. * `void setAddress(uint8_t new_addr)`
- Changes the I²C slave device address of the VL53L4CD to the given value (7-bit). + Changes the I²C target device address of the VL53L4CD to the given value (7-bit). * `uint8_t getAddress()`
Returns the current I²C address. @@ -168,4 +170,4 @@ Most of the functionality of this library is based on the [VL53L4CD Ultra Lite D ## Version history -* 1.0.0 (2024-08-19): Original release. +* 1.0.0 (2024-08-20): Original release. diff --git a/src/VL53L4CD.cpp b/src/VL53L4CD.cpp index b6299f8..b16faa2 100644 --- a/src/VL53L4CD.cpp +++ b/src/VL53L4CD.cpp @@ -166,9 +166,22 @@ bool VL53L4CD::init(bool io_2v8, bool fast_mode_plus) put 0x40 in location 0x87 */ }; - for (uint8_t reg = 0x30; reg <= 0x87; reg++) + // Load the rest of the default config (0x30-0x87) with a few block writes. + // The Wire library for AVR uses a 32-byte tx buffer, and 2 bytes are needed + // for the starting register address of each write, so we can write 30 + // registers at a time. + const uint8_t block_size = 30; + for (uint8_t start_reg = 0x30; start_reg <= 0x87; start_reg += block_size) { - writeReg(reg, pgm_read_byte(VL53L4CD_DEFAULT_CONFIGURATION + reg - 0x30)); + bus->beginTransmission(address); + bus->write(0); // reg high byte + bus->write(start_reg); // reg low byte + for (uint8_t reg = start_reg; (reg < start_reg + block_size) && (reg <= 0x87); reg++) + { + bus->write(pgm_read_byte(VL53L4CD_DEFAULT_CONFIGURATION + reg - 0x30)); + } + last_status = bus->endTransmission(); + if (last_status) { return false; } } // "Start VHV" @@ -472,14 +485,33 @@ void VL53L4CD::readResults() 0, 255, 255, 9, 13, 255, 255, 255, 255, 10, 6, 255, 255, 11, 12 }; - uint8_t status = readReg(RESULT__RANGE_STATUS) & 0x1F; + // Block read 15 bytes from 0x89 (RESULT__RANGE_STATUS) to 0x97 (lower byte of + // RESULT_DISTANCE). This is faster than reading each register individually. + + bus->beginTransmission(address); + bus->write((uint8_t)(RESULT__RANGE_STATUS >> 8)); // reg high byte + bus->write((uint8_t)(RESULT__RANGE_STATUS)); // reg low byte + last_status = bus->endTransmission(); + + bus->requestFrom(address, (uint8_t)15); + + uint8_t buffer[15]; + for (uint8_t i = 0; i < 15; i++) + { + buffer[i] = bus->read(); + } + + uint8_t status = buffer[0] & 0x1F; // 0x89 if (status < 24) { status = status_rtn[status]; } ranging_data.range_status = status; - ranging_data.number_of_spad = readReg16Bit(RESULT__SPAD_NB) / 256; - ranging_data.signal_rate_kcps = readReg16Bit(RESULT__SIGNAL_RATE) * 8; - ranging_data.ambient_rate_kcps = readReg16Bit(RESULT__AMBIENT_RATE) * 8; - ranging_data.range_mm = readReg16Bit(RESULT__DISTANCE); + // The ULD reads RESULT__SPAD_NB as a 16-bit reg but then divides the value by + // 256, so we can just ignore the lower byte entirely. + ranging_data.number_of_spad = buffer[3]; // 0x8C + ranging_data.signal_rate_kcps = ((uint16_t)buffer[5] << 8 | buffer[6]) * 8; // 0x8E, 0x8F + ranging_data.ambient_rate_kcps = ((uint16_t)buffer[7] << 8 | buffer[8]) * 8; // 0x90, 0x91 + ranging_data.sigma_mm = ((uint16_t)buffer[9] << 8 | buffer[10]) / 4; // 0x92, 0x93 + ranging_data.range_mm = (uint16_t)buffer[13] << 8 | buffer[14]; // 0x96, 0x97 ranging_data.signal_per_spad_kcps = ranging_data.signal_rate_kcps / ranging_data.number_of_spad; ranging_data.ambient_per_spad_kcps = ranging_data.ambient_rate_kcps / ranging_data.number_of_spad; diff --git a/src/VL53L4CD.h b/src/VL53L4CD.h index 0048e04..60c3d9f 100644 --- a/src/VL53L4CD.h +++ b/src/VL53L4CD.h @@ -46,11 +46,12 @@ class VL53L4CD { uint16_t range_mm; uint8_t range_status; - uint16_t number_of_spad; + uint8_t number_of_spad; uint16_t signal_rate_kcps; uint16_t ambient_rate_kcps; uint16_t signal_per_spad_kcps; uint16_t ambient_per_spad_kcps; + uint16_t sigma_mm; }; RangingData ranging_data;