-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
Describe the bug
I'm using C to interface with some I2C devices, but I've come across a corner case that I think could cause really infrequent issues. I want to see if a community has spotted a way round it, or if I'm doing something wrong.
I'm using ioctl with I2C_RDWR to do a read of a register using a repeated start. The ideal procedure is this:
[START CONDITION]
[SEND DEVICE ADDR + W]
[RECEIVE ACK]
[SEND REGISTER ADDR]
[RECEIVE ACK]
[START CONDITION]
[SEND DEVICE ADDR + R]
[RECEIVE ACK]
loop {
[RECEIVE DATA]
[SEND ACK]
}
[STOP CONDITION]
If the first ACK is instead a NACK (i.e. the slave doesn't respond to it's address) I'd expect the master (the pi) to send a STOP condition and cease the transmission. Instead it proceeds to do a repeated start and try the read anyway.
If the initial NACK is caused by the slave device being busy, but it's not busy by the time the read is attempted, this could result in invalid data being received, and possibly unintended behaviour from the slave.
It could cause issues if a slave device performs some sort of state change (clearing interrupts, kicking off the next ADC sample conversion etc.) when a read occurs. As far as the slave is concerned, it may have just done a perfectly valid read, but the master has ignored the data.
Steps to reproduce the behaviour
To reliably simulate this happening, I've been doing the write to a device that doesn't exist, and then a read from a device that does. Here's the code:
file_i2c = open("/dev/i2c-1", O_RDWR);
uint8_t inbuf[20];
uint8_t outbuf[20];
struct i2c_rdwr_ioctl_data packets;
struct i2c_msg messages[2];
outbuf[0] = 0x40;
messages[0].addr = 0x36;
messages[0].flags = 0;
messages[0].len = 1;
messages[0].buf = outbuf;
messages[1].addr = 0x49;
messages[1].flags = I2C_M_RD;
messages[1].len = 4;
messages[1].buf = inbuf;
packets.msgs = messages;
packets.nmsgs = 2;
int result = ioctl(file_i2c, I2C_RDWR, &packets);
This is the logic analyser's output of what's happening:
ioctl does report the error. In the above case result would be -1
, so we know it's failing. However, the read still shouldn't happen.
Device (s)
Raspberry Pi CM4, Raspberry Pi CM4 Lite
System
I'm using a custom busybox build so I don't have /etc/rpi-issue
or vcgencmd
, and haven't tested this using raspberry pi OS yet.
The kernel version for busybox is:
Linux secure 5.15.72-v7l #1 SMP Fri Jan 27 13:03:09 GMT 2023 armv7l GNU/Linux
Logs
No response
Additional context
No response