I’m trying to integrate a time of flight sensor with the Verdin Plus over i2c. To do this, I need to load 32,768 bytes of data in a single i2c write without a stop condition. The issue is that I can’t seem to transfer over 8 kB of data in one go due to some strictly defined buffer size somewhere. I’ve tried many things, including ioctl calls and the i2c-dev.h library. The 8 kB buffer size limit remains constant. Are there any workarounds?
It seems the source of the problem comes from the Linux kernel’s linux/i2c-dev.c:
For whatever reason, the TwoWire library from Arduino is able to handle this without issues when implemented on a teensy 3.6:
/ // Chunk I2C transactions into limit of 32 bytes (or wireMaxPacketSize)
uint8_t i2cError = 0;
uint32_t startSpot = 0;
uint32_t bytesToSend = bufferSize;
while (bytesToSend > 0)
{
uint32_t len = bytesToSend;
if (len > (wireMaxPacketSize - 2)) // Allow 2 byte for register address
len = (wireMaxPacketSize - 2);
_i2cPort->beginTransmission((uint8_t)_address);
_i2cPort->write(highByte(registerAddress));
_i2cPort->write(lowByte(registerAddress));
// TODO write a subsection of the buffer rather than byte wise
for (uint16_t x = 0; x < len; x++)
_i2cPort->write(buffer[startSpot + x]); // Write a portion of the payload to the bus
i2cError = _i2cPort->endTransmission(); // Release bus because we are writing the address each time
if (i2cError != 0)
return (i2cError); // Sensor did not ACK
startSpot += len; // Move the pointer forward
bytesToSend -= len;
registerAddress += len; // Move register address forward
}
return (i2cError);
Code from the provided sensor library:
/* Download FW into VL53L5 */
status |= WrByte(&(p_dev->platform), 0x7fff, 0x09);
status |= WrMulti(&(p_dev->platform), 0, (uint8_t *) &VL53L5CX_FIRMWARE[0], 0x8000);
status |= WrByte(&(p_dev->platform), 0x7fff, 0x0a);
status |= WrMulti(&(p_dev->platform), 0, (uint8_t *) & VL53L5CX_FIRMWARE[0x8000], 0x8000);
status |= WrByte(&(p_dev->platform), 0x7fff, 0x0b);
status |= WrMulti(&(p_dev->platform), 0, (uint8_t *) & VL53L5CX_FIRMWARE[0x10000], 0x5000);
status |= WrByte(&(p_dev->platform), 0x7fff, 0x01);
My i2c_write function:
writeData[0] = addConvert.regAddr_8[1];
writeData[1] = addConvert.regAddr_8[0];
for(i=0; i<count; i++) writeData[i+2]=data[i];
// send the bytes
ret = write(i2c[bus].fd, writeData, count+2);
// write should have returned the correct # bytes written
if(unlikely(ret!=(signed)(count+2))){
fprintf(stderr,"ERROR in rc_i2c_write_bytes, bus wrote %d bytes, expected %zu\n", ret, count+2);
i2c[bus].lock = old_lock;
return -1;
}