cancel
Showing results for 
Search instead for 
Did you mean: 

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

John E KVAM
ST Employee

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

This is an oft-asked question.


If this or any post solves your issue, please mark them as 'Accept as Solution' It really helps. And if you notice anything wrong do not hesitate to 'Report Inappropriate Content'. Someone will review it.
2 REPLIES 2
John E KVAM
ST Employee

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
}


If this or any post solves your issue, please mark them as 'Accept as Solution' It really helps. And if you notice anything wrong do not hesitate to 'Report Inappropriate Content'. Someone will review it.

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 Venmo
Up vote any posts that you find helpful, it shows what's working..