Skip to main content
John E KVAM
ST Employee
July 18, 2022
Question

I2C multi-byte read and write functions with i2C byte limit.

  • July 18, 2022
  • 1 reply
  • 3963 views

How can one adapt the WrMulti() and RdMulti() I2C functions for MCUs that have an I2C length limit? 

This is an oft-asked question.

This topic has been closed for replies.

1 reply

John E KVAM
ST Employee
July 18, 2022

The ST code was written based on an STM32, which has no I2C limit on the length. But other MCUs do have a limit.

Use the following code in your platform.c. All it really does is break the long I/O operations into several 'CHUNK_SIZE' operations.

The only trick is that one has to keep track of the addresses.

This code uses a 1K chunk size, but that was arbitrary.

#define VL53L5_COMMS_CHUNK_SIZE (1 * 1024)
 
uint8_t WrMulti(
 VL53L5CX_Platform *p_platform,
 uint16_t RegisterAdress,
 uint8_t *pdata,
 uint32_t size)
{
#if 0
 uint8_t status = HAL_I2C_Mem_Write(&hi2c1, p_platform->address, RegisterAdress,
 I2C_MEMADD_SIZE_16BIT, pdata, size, 65535);
#else
 
 int32_t status = 0;
 uint32_t position = 0;
 uint32_t data_size = 0;
 uint16_t i = 0;
 uint8_t data_write[VL53L5_COMMS_CHUNK_SIZE+2];
 
 for (position = 0; position < size; position += VL53L5_COMMS_CHUNK_SIZE)
 {
 if (size > VL53L5_COMMS_CHUNK_SIZE)
 {
 if ((position + VL53L5_COMMS_CHUNK_SIZE) > size)
 {
 data_size = size - position;
 }
 else
 {
 data_size = VL53L5_COMMS_CHUNK_SIZE;
 }
 }
 else
 {
 data_size = size;
 }
 
 
 /*
 * STM32 HAL API expects I2C bytes in this format:
 * First Register(EwokMZ registers are 16 bit addresses)
 * Then, I2C bytes
 */
 data_write[0] = (RegisterAdress+position) >> 8;
 data_write[1] = (RegisterAdress+position) & 0xFF;
 for (i=0; i<data_size; i++)
 {
 data_write[i+2] = pdata[position + i];
 }
 
 //STM32 I2C api
 status = HAL_I2C_Master_Transmit(&hi2c1,
 p_platform->address,
 data_write,
 data_size + 2,
 100*data_size);
 
 if (status != HAL_OK) {
 //printf("HAL_I2C_Master_Transmit error = %ld\n", status);
 return status;
 }
 }
#endif
 return status;
}
 
uint8_t RdMulti(
 VL53L5CX_Platform *p_platform,
 uint16_t RegisterAdress,
 uint8_t *pdata,
 uint32_t size)
{
 
#if 0
 uint8_t status;
 uint8_t data_write[2];
 data_write[0] = (RegisterAdress>>8) & 0xFF;
 data_write[1] = RegisterAdress & 0xFF;
 status = HAL_I2C_Master_Transmit(&hi2c1, p_platform->address, data_write, 2, 100);
 status += HAL_I2C_Master_Receive(&hi2c1, p_platform->address, pdata, size, 100);
 
 return status;
#else
 
 int32_t status = 0;
 uint32_t position = 0;
 uint32_t data_size = 0;
 uint8_t data_write[2];
 
 for (position = 0; position < size; position += VL53L5_COMMS_CHUNK_SIZE)
 {
 if (size > VL53L5_COMMS_CHUNK_SIZE)
 {
 if ((position + VL53L5_COMMS_CHUNK_SIZE) > size)
 {
 data_size = size - position;
 }
 else
 {
 data_size = VL53L5_COMMS_CHUNK_SIZE;
 }
 }
 else
 {
 data_size = size;
 }
 
 /*
 * STM32 HAL API expects I2C bytes in this format:
 * First Register(EwokMZ registers are 16 bit addresses)
 */
 data_write[0] = (RegisterAdress + position)>>8;
 data_write[1] = (RegisterAdress + position) & 0xFF;
 //Write the register to read from
 status = HAL_I2C_Master_Transmit(&hi2c1, p_platform->address, data_write, 2, 100);
 if (status != HAL_OK)
 {
 //printf("HAL_I2C_Master_Transmit error = %ld\n", status);
 return status;
 }
 //Read the register data
 status = HAL_I2C_Master_Receive(&hi2c1, p_platform->address, pdata + position, data_size, 100);
 if (status != HAL_OK)
 {
 //printf("HAL_I2C_Master_Transmit error = %ld\n", status);
 return status;
 }
 }
 return status;
#endif
}

Tesla DeLorean
Guru
July 18, 2022

Some of the Arduino drivers (AVR?) have a 32-byte limit, but I think that's a buffering one, and I think you can keep flushing that by sending a block without a STOP bit, and then continuing.

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..