Skip to main content
John E KVAM
ST Employee
June 3, 2025
Solved

Init Failures on VL53L5, L7 and L8 due to long I2C writes

  • June 3, 2025
  • 3 replies
  • 929 views

The most viewed and commented post on the Imaging page had to do with an Init failure on the multizone part.

These parts have large I2C writes at the beginning, which is downloading the Firmware (on the L5 and L7) and downloading patch updates on the L8. 

The solution was:

uint8_t WrMulti(VL53L8CX_Platform *p_platform, uint16_t RegisterAddress, uint8_t *p_values, uint32_t size) {
 uint8_t status = HAL_OK; // Initialize status as HAL_OK
 uint32_t remaining_size = size; // Calculate remaining size to write
 uint16_t current_address = RegisterAddress; // Initialize current address
 // Loop until all data is written
 while (remaining_size > 0) {
 // Calculate the current chunk size to write
 uint32_t current_chunk_size = (remaining_size > chunk_size) ? chunk_size : remaining_size;

 // Perform write operation for current chunk
 status = HAL_I2C_Mem_Write(&hi2c2, addr, current_address, I2C_MEMADD_SIZE_16BIT, p_values, current_chunk_size, 100);

 // Check for error
 if (status != HAL_OK) {
 APP_LOG(TS_ON, 3, "[WrMulti] error. status %d, regADDR %d, size %d, remaining_size %d\n", status, current_address, size, remaining_size);
 return status; // Return error status
 }

 // Update remaining size and pointer to move to the next chunk
 remaining_size -= current_chunk_size;
 current_address += current_chunk_size; // Increment register address for next chunk
 p_values += current_chunk_size;
 HAL_Delay(10);
 }

 return status; // Return status (HAL_OK if all writes were successful)
}

Notice how he used the HAL command to write 16-bit addr and had to manually recalculate the current address before each loop. 

chunk_size was defined as:

#define chunk_size (1<<8)

The same has to be done for RdMulti. as it tries to read 420 bytes at once at some point.

 

Do not try to read the registers after downloading firmware, to check if they match with the firmware, you just downloaded it. It will make init fail. And of course he used the default firmware download code.

Best answer by Maxime_MARCHETTO

Hello @John E KVAM,

Thanks for sharing this case and the solution you found. ​

To make this post more visible and easier to find by others who may face the same issue, I mark my reply as the solution.

Regards,
Maxime


@John E KVAM wrote:

The most viewed and commented post on the Imaging page had to do with an Init failure on the multizone part.

These parts have large I2C writes at the beginning, which is downloading the Firmware (on the L5 and L7) and downloading patch updates on the L8. 

The solution was:

uint8_t WrMulti(VL53L8CX_Platform *p_platform, uint16_t RegisterAddress, uint8_t *p_values, uint32_t size) {
 uint8_t status = HAL_OK; // Initialize status as HAL_OK
 uint32_t remaining_size = size; // Calculate remaining size to write
 uint16_t current_address = RegisterAddress; // Initialize current address
 // Loop until all data is written
 while (remaining_size > 0) {
 // Calculate the current chunk size to write
 uint32_t current_chunk_size = (remaining_size > chunk_size) ? chunk_size : remaining_size;

 // Perform write operation for current chunk
 status = HAL_I2C_Mem_Write(&hi2c2, addr, current_address, I2C_MEMADD_SIZE_16BIT, p_values, current_chunk_size, 100);

 // Check for error
 if (status != HAL_OK) {
 APP_LOG(TS_ON, 3, "[WrMulti] error. status %d, regADDR %d, size %d, remaining_size %d\n", status, current_address, size, remaining_size);
 return status; // Return error status
 }

 // Update remaining size and pointer to move to the next chunk
 remaining_size -= current_chunk_size;
 current_address += current_chunk_size; // Increment register address for next chunk
 p_values += current_chunk_size;
 HAL_Delay(10);
 }

 return status; // Return status (HAL_OK if all writes were successful)
}

Notice how he used the HAL command to write 16-bit addr and had to manually recalculate the current address before each loop. 

chunk_size was defined as:

#define chunk_size (1<<8)

The same has to be done for RdMulti. as it tries to read 420 bytes at once at some point.

 

Do not try to read the registers after downloading firmware, to check if they match with the firmware, you just downloaded it. It will make init fail. And of course he used the default firmware download code.




3 replies

Maxime_MARCHETTOBest answer
ST Employee
August 25, 2025

Hello @John E KVAM,

Thanks for sharing this case and the solution you found. ​

To make this post more visible and easier to find by others who may face the same issue, I mark my reply as the solution.

Regards,
Maxime


@John E KVAM wrote:

The most viewed and commented post on the Imaging page had to do with an Init failure on the multizone part.

These parts have large I2C writes at the beginning, which is downloading the Firmware (on the L5 and L7) and downloading patch updates on the L8. 

The solution was:

uint8_t WrMulti(VL53L8CX_Platform *p_platform, uint16_t RegisterAddress, uint8_t *p_values, uint32_t size) {
 uint8_t status = HAL_OK; // Initialize status as HAL_OK
 uint32_t remaining_size = size; // Calculate remaining size to write
 uint16_t current_address = RegisterAddress; // Initialize current address
 // Loop until all data is written
 while (remaining_size > 0) {
 // Calculate the current chunk size to write
 uint32_t current_chunk_size = (remaining_size > chunk_size) ? chunk_size : remaining_size;

 // Perform write operation for current chunk
 status = HAL_I2C_Mem_Write(&hi2c2, addr, current_address, I2C_MEMADD_SIZE_16BIT, p_values, current_chunk_size, 100);

 // Check for error
 if (status != HAL_OK) {
 APP_LOG(TS_ON, 3, "[WrMulti] error. status %d, regADDR %d, size %d, remaining_size %d\n", status, current_address, size, remaining_size);
 return status; // Return error status
 }

 // Update remaining size and pointer to move to the next chunk
 remaining_size -= current_chunk_size;
 current_address += current_chunk_size; // Increment register address for next chunk
 p_values += current_chunk_size;
 HAL_Delay(10);
 }

 return status; // Return status (HAL_OK if all writes were successful)
}

Notice how he used the HAL command to write 16-bit addr and had to manually recalculate the current address before each loop. 

chunk_size was defined as:

#define chunk_size (1<<8)

The same has to be done for RdMulti. as it tries to read 420 bytes at once at some point.

 

Do not try to read the registers after downloading firmware, to check if they match with the firmware, you just downloaded it. It will make init fail. And of course he used the default firmware download code.




​In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question.
onderdelen
Associate II
October 15, 2025

The STM32 HAL I2C library will not send more than 255 bytes in one go, even when using DMA. I found this out trying to use the firmware api to bring up the VL53L5CXV which is mounted on the B-U585 IOT board.

My solution was to implement a SW block transfer method that limits the number of bytes sent in one transfer to 255. The method keeps track of reading and writing addresses so it circumvents this hardware limitation. Too bad this powerful microcontroller (STM32U585) has an I2C perif that has this limitation. I guess that is the price for staying compatible with older STM32 variants.

It would be nice to be able to use SPI to do the transferring of 86 KBytes of firmware for this ranging sensor, since SPI has no 255 bytes limitation.

 

My last remark deals with the platform

void VL53L5CX_SwapBuffer

function.

The example stated is okay, but why not use the Cortex-M byte in word reverse (REV) function? Below is my (C++) implementation:

UInt32 CortexMProcessor::REV(const UInt32 value)
{
UInt32 result=0u;

__ASM volatile ("rev %0, %1" : "=r" (result) : "r" (value) );
return(result);
}

I can then do this (also C++ but easily adaptable to C):

for (auto i = 0u; i < size; i = i + 4)
{
auto *buffer32Value= reinterpret_cast<UInt32 *>(&buffer[i]);
const auto iw = *buffer32Value;
const auto resValue = CortexMProcessor::REV(iw);
*buffer32Value = resValue;
}

 No messy manual swapping and calling memcpy anymore, much more compact and faster.

 

Visitor II
November 19, 2025

When transmitting the firmware image for L7, do you need to write to the page register before sending every chunk?

status |= WrByte(&(p_dev->platform), 0x7fff, 0x09);