2021-08-11 02:47 AM
The Ultra Light Driver (STSW-IMG023) init function vl53l5cx_init() fails in this section :
/* Get offset NVM data and store them into the offset buffer */
status |= WrMulti(&(p_dev->platform), 0x2fd8,
(uint8_t*)VL53L5CX_GET_NVM_CMD, sizeof(VL53L5CX_GET_NVM_CMD));
status |= _vl53l5cx_poll_for_answer(p_dev, 4, 0,
VL53L5CX_UI_CMD_STATUS, 0xff, 2);
The sensor does not answer with '2' as expected by _vl53l5cx_poll_for_answer. (The senosr answers '0')
This results in a failed initialization.
How can this be fixed?
2022-06-07 03:00 PM
Did you end up solving this issue?
2022-07-15 01:11 PM
Like so many of you, I have visited this site trying to get an answer on making this sensor work. I didn’t get any usable guidance, but I figured quite a few things out, so here’s a few answers.
The reason why initialization fails at /* Get offset NVM data and store them into the offset buffer */ Is because this is where the ToF sensor is asked to start responding to commands from the firmware that was downloaded in the previous steps. I don’t know what is checked during the comment /* Check if FW correctly downloaded */, but it’s not a CRC or anything that verifies the firmware transfer. This exposes the first issue with the sensor, and that’s that it requires the firmware to be transferred in rather large, 32KB chunks. Whatever I2C driver you are using needs to handle transfers of that size. You cannot break the transfer up into smaller blocks, it must be sent as called in the API. Make sure your driver can handle that size, and in the case of Nordic, you may have to copy the FLASH transfer over to RAM, because the DMA cannot handle transfers originating in FLASH.
The second issue is that the API is written in such a way that it requires an enormous amount of stack space. Many compilers optimize their code so that the stack space inside a function is not reserved until an instruction inside the function addresses the local variable. I am using Zephyr with Nordic’s nRF52, and the code would always fail during a memcpy(), rather than at the start of the function that blew the stack. The cure here is to declare variables static so that they are not being created on the stack. In example1() this would be:
static VL53L5CX_Configuration Dev ; /* Sensor configuration */
static VL53L5CX_ResultsData Results; /* Results data from VL53L5CX */
The other examples have additional variables that you will want to make static or global, just to keep them off the stack. I presently have everything running in nRF52’s Zephyr, and also in Nordic’s SDK.
I hope this helps, and if anyone needs some details, let me know.
2022-07-19 11:01 AM
I was able to get it working by breaking up the transfer. Things to keep in mind in doing so is incrementing the register address accordingly when breaking it up, and comply with the standard I2C spec as there is an error in one of their diagrams in the datasheet.
2022-07-19 02:44 PM
I stand corrected, I have also able to break the transfer into pieces.
2022-07-19 02:47 PM
2024-01-25 08:16 AM
I am also getting an error here:
/* Get offset NVM data and store them into the offset buffer */
status |= WrMulti(&(p_dev->platform), 0x2fd8,(uint8_t*)VL53L5CX_GET_NVM_CMD, sizeof(VL53L5CX_GET_NVM_CMD));
status |= _vl53l5cx_poll_for_answer(p_dev, 4, 0, VL53L5CX_UI_CMD_STATUS, 0xff, 2);
status |= RdMulti(&(p_dev->platform), VL53L5CX_UI_CMD_START, p_dev->temp_buffer, VL53L5CX_NVM_DATA_SIZE)); //ErrorHere
status errors with VL53L5CX_COMMS_ERROR thrown by the following use in "platforms.c": int32_t write_read_multi function:
if (ioctl(fd, I2C_RDWR, &packets) < 0)
return VL53L5CX_COMMS_ERROR;
position += data_size;
It appears that ioctl throws an error:
do {
data_size = (count - position) > VL53L5CX_COMMS_CHUNK_SIZE ? VL53L5CX_COMMS_CHUNK_SIZE : (count - position);
i2c_buffer[0] = (reg_address + position) >> 8;
i2c_buffer[1] = (reg_address + position) & 0xFF;
messages[0].addr = i2c_address >> 1;
messages[0].flags = 0; //I2C_M_WR;
messages[0].len = 2;
messages[0].buf = i2c_buffer;
messages[1].addr = i2c_address >> 1;
messages[1].flags = I2C_M_RD;
messages[1].len = data_size;
messages[1].buf = pdata + position;
packets.msgs = messages;
packets.nmsgs = 2;
// int ret = ioctl(fd, I2C_RDWR, &packets);
// if (ret < 0){ //throws error here
// return VL53L5CX_COMMS_ERROR;
// }
if (ioctl(fd, I2C_RDWR, &packets) < 0)
return VL53L5CX_COMMS_ERROR;
position += data_size;
} while (position < count);
I'm struggling to find the issue, as this read function is used regularly throughout the initialisation before the error occurs.
How can this be fixed?
2024-02-14 07:48 AM
I have the same exact issue. It stops at the VL53L8CX_UI_CMD_STATUS with a timeout after not receiving the number 2 as answer.
I rewrote my WrMulti to deal with bigger data and break it down into chunks:
uint8_t WrMulti(VL53L8CX_Platform *p_platform, uint16_t RegisterAddress, uint8_t *p_values, uint32_t size) {
// Initialize buffer for register address
uint8_t regBuff[2] = { RegisterAddress >> 8, RegisterAddress & 0xFF };
// Loop through the data in chunks of 255 bytes
for (uint32_t offset = 0; offset < size; offset += 255) {
uint8_t chunkSize = (size - offset > 255) ? 255 : (size - offset);
// Send register address
if (HAL_I2C_Master_Transmit(&hi2c2, addr, regBuff, 2, 5000) != HAL_OK) {
APP_LOG(TS_ON, 3, "[PLAT] WrMulti Send register address failed\n");
return -1;
}
// Write data chunk
if (HAL_I2C_Master_Transmit(&hi2c2, addr, p_values + offset, chunkSize, 5000) != HAL_OK) {
APP_LOG(TS_ON, 3, "[PLAT] WrMulti Write data chunk failed\n");
return -1;
}
// Delay between chunks
HAL_Delay(2);
}
return 0;
}
This code should write only chunks of 255 bytes at once and adjust the register perfectly. This seems to work until we reach the dreaded lines:
status |= _vl53l8cx_poll_for_answer(p_dev, 4, 0,VL53L8CX_UI_CMD_STATUS, 0xff, 2); // ### ERROR HERE!!! TIMEOUT !!!
The status is always 0 up until this line where it changes into a 1. looking into it its a timeout issue because we never receive the 2 as answer.
Please advise on how to get the 8x8 ToF to work properly.
2024-02-14 09:17 AM
I think I see your issue.
The chip starts when the last byte is written.
But your chunk size of 255 is not a sub-multiple of the larger write.
So, you end up needing one last write to complete the download.
2024-02-15 07:32 AM
i rewrote it to this:
uint8_t WrMulti(VL53L8CX_Platform *p_platform, uint16_t RegisterAddress, uint8_t *p_values, uint32_t size) {
// Send register address
uint8_t regBuff[2] = { RegisterAddress >> 8, RegisterAddress & 0xFF };
if (HAL_I2C_Master_Transmit(&hi2c2, addr, regBuff, 2, 5000) != HAL_OK) {
APP_LOG(TS_ON, 3, "[PLAT] WrMulti Send register address failed\n");
return -1;
}
// Loop through the data in chunks of 255 bytes // #define chunk 1<<8
for (uint32_t offset = 0; offset < size; offset += chunk) {
uint8_t chunkSize = (size - offset > chunk) ? chunk : (size - offset);
// Write data chunk
if (HAL_I2C_Master_Transmit(&hi2c2, addr, p_values + offset, chunkSize, 5000) != HAL_OK) {
APP_LOG(TS_ON, 3, "[PLAT] WrMulti Write data chunk failed\n");
return -1;
}
}
// If the size is not a multiple of 255, we need to write the remaining bytes
if (size % chunk != 0) {
// Write remaining data
if (HAL_I2C_Master_Transmit(&hi2c2, addr, p_values + size - (size % chunk), size % chunk, 5000) != HAL_OK) {
APP_LOG(TS_ON, 3, "[PLAT] WrMulti Write remaining data failed\n");
return -1;
}
}
return 0;
}
However the same problem occurs.
this passes:
VL53L8CX_GET_NVM_CMD returns status 0 -> success
however this does not
VL53L8CX_UI_CMD_STATUS returns status 1 -> fail
2024-02-15 07:35 AM - edited 2024-02-15 07:38 AM
i also tried this version where i resend the register addresses and adjust them according to the offset of already sent data. the same error and behaviour occurs:
uint8_t WrMulti(VL53L8CX_Platform *p_platform, uint16_t RegisterAddress, uint8_t *p_values, uint32_t size) {
//#define addr (uint16_t)0x29<<1
// Loop through the data in chunks of 255 bytes
for (uint32_t offset = 0; offset < size; offset += chunk) {
// Initialize buffer for register address, adjusting it with the offset
uint16_t currentRegisterAddress = RegisterAddress + offset;
uint8_t regBuff[2] = { currentRegisterAddress >> 8, currentRegisterAddress & 0xFF };
uint8_t chunkSize = (size - offset > chunk) ? chunk : (size - offset);
// Send register address
if (HAL_I2C_Master_Transmit(&hi2c2, addr, regBuff, 2, 5000) != HAL_OK) {
APP_LOG(TS_ON, 3, "[PLAT] WrMulti Send register address failed\n");
return -1;
}
// Write data chunk
if (HAL_I2C_Master_Transmit(&hi2c2, addr, p_values + offset, chunkSize, 5000) != HAL_OK) {
APP_LOG(TS_ON, 3, "[PLAT] WrMulti Write data chunk failed\n");
return -1;
}
// Delay between chunks
HAL_Delay(2);
}
// If the size is not a multiple of 255, we need to write the remaining bytes
if (size % chunk != 0) {
// Initialize buffer for register address, adjusting it with the offset
uint16_t currentRegisterAddress = RegisterAddress + size - (size % chunk);
uint8_t regBuff[2] = { currentRegisterAddress >> 8, currentRegisterAddress & 0xFF };
// Send register address
if (HAL_I2C_Master_Transmit(&hi2c2, addr, regBuff, 2, 5000) != HAL_OK) {
APP_LOG(TS_ON, 3, "[PLAT] WrMulti Send register address failed\n");
return -1;
}
// Write remaining data
if (HAL_I2C_Master_Transmit(&hi2c2, addr, p_values + size - (size % chunk), size % chunk, 5000) != HAL_OK) {
APP_LOG(TS_ON, 3, "[PLAT] WrMulti Write remaining data failed\n");
return -1;
}
// Delay after writing remaining data
HAL_Delay(2);
}
return 0;
}