How to remove start bit from an I2C transfer in zephyr

Hello,

I am developing a driver for the vl53l5cx TOF sensor from ST, however their sequential write format looks as such:

This is problematic for me since I can get the address, and register index sent correctly with the stop bit at the end, however zephyr always sends a start bit for the data being written and I have not found a way to disable this. How can I do this using sdk 1.9.1?

Thanks,

Jacob

  • Hey,
    Can you please share your driver for vl53l5cx on zephyr?
    I'm interested in it too.
    Thanks!

  • Turns out there was an error in their datasheet and it should comply with the usual I2C spec. I filled the WrMulti and RdMulti the following way:

    uint8_t RdMulti(
    	VL53L5CX_Platform *p_platform,
    	uint16_t RegisterAddress,
    	uint8_t *p_values,
    	uint32_t num_read)
    {
    	uint8_t status = 0;
    	int offset = 0;
    
    	while (num_read > 0)
    	{
    		writeBuf[0] = (RegisterAddress >> 8) & 0xFF;
    		writeBuf[1] = RegisterAddress & 0xFF;
    
    		if (num_read >= MAX_RX_BUFFER)
    		{
    			status |= i2c_write(p_platform->i2c_dev, writeBuf, 2U, p_platform->address);
    			status |= i2c_read(p_platform->i2c_dev, p_values + offset, MAX_RX_BUFFER, p_platform->address);
    
    			num_read -= MAX_RX_BUFFER;
    			RegisterAddress += MAX_RX_BUFFER;
    			offset += MAX_RX_BUFFER;
    		}
    		else
    		{
    			status |= i2c_write(p_platform->i2c_dev, writeBuf, 2U, p_platform->address);
    			status |= i2c_read(p_platform->i2c_dev, p_values + offset, num_read, p_platform->address);
    			break;
    		}
    	}
    
    	return (status);
    }
    
    uint8_t WrMulti(
    	VL53L5CX_Platform *p_platform,
    	uint16_t RegisterAddress,
    	uint8_t *p_values,
    	uint32_t num_write)
    {
    	uint8_t status = 0;
    	uint32_t offset = 0;
    
    	while (num_write > 0)
    	{
    		writeBuf[0] = (RegisterAddress >> 8) & 0xFF;
    		writeBuf[1] = RegisterAddress & 0xFF;
    		memcpy(&(writeBuf[2]), &(p_values[offset]), (MAX_TX_BUFFER - 2));
    
    		if (num_write >= (MAX_TX_BUFFER - 2))
    		{
    			status |= i2c_write(p_platform->i2c_dev, writeBuf, MAX_TX_BUFFER, p_platform->address);
    
    			num_write -= (MAX_TX_BUFFER - 2);
    			RegisterAddress += (MAX_TX_BUFFER - 2);
    			offset += (MAX_TX_BUFFER - 2);
    		}
    		else
    		{
    			status |= i2c_write(p_platform->i2c_dev, writeBuf, num_write + 2, p_platform->address);
    			break;
    		}
    	}
    
    	return (status);
    }

    and WrByte/RdByte work in the same way just without the while loop since the size is only 1.

  • I'm struggling with this part in Zephyr too and am trying to test your solution. Have you defined writeBuf, MAX_TX_BUFFER and MAX_RX_BUFFER globally somewhere? I was using a similar implementation to your earlier one but something is definitely wrong

    uint8_t RdMulti(VL53L5CX_Platform *p_platform, uint16_t RegisterAdress, uint8_t *p_values,
    		uint32_t size)
    {
    	uint8_t data_write[2];
    
    	sys_put_be16(RegisterAdress, data_write);
    
    	return i2c_write_read_dt(p_platform->i2c, data_write, sizeof(data_write),
    				 p_values, size);
    }
    
    uint8_t WrMulti(VL53L5CX_Platform *p_platform, uint16_t RegisterAdress, uint8_t *p_values,
    		uint32_t size)
    {
    	struct i2c_msg msg[2];
    	uint8_t data_write[2];
    
    	sys_put_be16(RegisterAdress, data_write);
    
    	msg[0].buf = data_write;
    	msg[0].len = sizeof(data_write);
    	msg[0].flags = I2C_MSG_WRITE;
    
    	msg[1].buf = (uint8_t *)p_values;
    	msg[1].len = size;
    	msg[1].flags = I2C_MSG_WRITE | I2C_MSG_STOP;
    	
    	return i2c_transfer_dt(p_platform->i2c, msg, 2);
    }

Related