Skip to content

I2C NACK being ignored by ioctl I2C_RDWR #5429

@jdf-advanced

Description

@jdf-advanced

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:

image

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions