2022-07-18 09:17 AM
How can one adapt the WrMulti() and RdMulti() I2C functions for MCUs that have an I2C length limit?
This is an oft-asked question.
2022-07-18 09:24 AM
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
}
2022-07-18 10:01 AM
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.