Description
Describe the bug
This issue is basically a followup to the following discussions related to i2c on the Pi5:
.. and is likely the same issue affecting #5784. However, I have different hardware and thought it would be best to file a different issue describing my unique experience and reproduction steps in an attempt to provide Raspberry Pi engineers with a more immediate reproduction using common hardware.
In prior discussions I discovered that I had hardware running out of spec (a level translator spec'd for 400kHz running at 1MHz). I have updated hardware now running in spec at 1MHz, but I'm still encountering communication i2c communication problems.
For this issue report, however, I have made a concerted effort to remove my custom hardware and provide a reproduction using common hardware, specifically the MCP23017.
The symptoms are:
- On the Pi 5 communication fails and results in many occurrences of "controller timed out" and "i2c_dw_handle_tx_abort: lost arbitration" messages in dmesg output. Sometimes the slave gets stuck holding SDA low requiring a power reset on the slave. Sometimes it is necessary to reboot the Pi 5 to get the i2c port to produce a signal again.
- On the Pi 4, everything works fine
Steps to reproduce the behaviour
Connect an MCP23017 to 3.3V, GND, GPIO2 and GPIO3 on the Pi. Connect A0, A1, and A2 to GND. No other hardware or connections are required.
Configure the Pi 4 with dtparam=i2c_arm=on,i2c_arm_baudrate=1000000
Configure the Pi 5 with configured with dtoverlay=i2c1,pins_2_3,baudrate=1000000
Run sudo cpufreq-set -g performance
to ensure the core clock frequency remains stable.
Verify the device can be found by running i2cdetect -y 1
and seeing the device appear with address 0x20. Occasionally this will fail on the Pi 5. Sometimes resulting in "controller timed out" and "i2c_dw_handle_tx_abort: lost arbitration" messages, sometimes not. If it succeeds, continue.
Compile the following code using gcc test.c -o test
and run ./test
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>
#define MCP23017_ADDR 0x20 // Address of MCP23017
#define IODIRA_REG 0x00 // I/O direction register A
#define IODIRB_REG 0x01 // I/O direction register B
#define GPIOA_REG 0x12 // GPIO port A
#define GPIOB_REG 0x13 // GPIO port B
unsigned long success = 0;
unsigned long fail = 0;
void print() {
printf("success: %09lu\t\tfail: %09lu\r", success, fail);
fflush(stdout);
}
int main() {
int fd, i;
// Open the I2C interface to the MCP23017
if ((fd = open("/dev/i2c-1", O_RDWR)) < 0) {
perror("Failed to open I2C interface");
return 1;
}
// Set the I2C slave address
if (ioctl(fd, I2C_SLAVE, MCP23017_ADDR) < 0) {
perror("Failed to set I2C slave address");
close(fd);
return 1;
}
// Set all pins as outputs
while (write(fd, (char[]){IODIRA_REG, 0x00}, 2) != 2) {
fail++;
print();
}
while (write(fd, (char[]){IODIRB_REG, 0x00}, 2) != 2) {
fail++;
print();
}
while (1) {
// Toggle all outputs
if (write(fd, (char[]){GPIOA_REG, 0xFF}, 2) != 2) {
//perror("Failed to write to GPIO port B");
fail++;
print();
}
else {
success++;
print();
}
if (write(fd, (char[]){GPIOB_REG, 0xFF}, 2) != 2) {
//perror("Failed to write to GPIO port B");
fail++;
print();
}
else {
success++;
print();
}
if (write(fd, (char[]){GPIOA_REG, 0x00}, 2) != 2) {
//perror("Failed to write to GPIO port A");
fail++;
print();
}
else {
success++;
print();
}
if (write(fd, (char[]){GPIOB_REG, 0x00}, 2) != 2) {
//perror("Failed to write to GPIO port B");
fail++;
print();
}
else {
success++;
print();
}
}
close(fd);
return 0;
}
On the Pi 4, it should repeatedly print a large numbers of successes.
On the Pi 5, communication fails and dmesg output shows "controller timed out" and "i2c_dw_handle_tx_abort: lost arbitration" messages. Occasionally communication will succeed briefly, but then fail thereafter printing a large number of failures.
Temperature of the Pi 5 was confirmed with vcgencmd measure_temp
to be between 40~60 degrees C.
Powering the MCP23017 with 5V instead of 3.3V, leaving SDA and SCL at 3.3V, usually results in fewer communication failures, and often no messages in dmesg when failures occur, However, communicate failures are still inevitable. Under this failure mode, it is interesting to note that the slave is not stuck holding SDA low. However, it is still very difficult to recover without power cycling everything.
Failure modes on the Pi 5 are very inconsistent making it quite difficult to convey anything other than a lot "I tried X and it sometimes resulted in A, sometimes B, but also sometimes C". If I am able to reproduce failure modes consistently, I'll report those results.
Device (s)
Raspberry Pi 5
System
$ cat /etc/rpi-issue
Raspberry Pi reference 2023-12-05
Generated using pi-gen, https://github.com/RPi-Distro/pi-gen, 70cd6f2a1e34d07f5cba7047aea5b92457372e05, stage4
$ vcgencmd version
Feb 29 2024 12:24:53
Copyright (c) 2012 Broadcom
version f4e2138c2adc8f3a92a3a65939e458f11d7298ba (clean) (release) (start)
$ uname -a
Linux raspberrypi 6.6.20-v8+ #1738 SMP PREEMPT Tue Mar 5 14:51:28 GMT 2024 aarch64 GNU/Linux
Logs
Often communication failures result the following in dmesg, but not always:
[ 43.925214] i2c_designware 1f00074000.i2c: i2c_dw_handle_tx_abort: lost arbitration
[ 44.930880] i2c_designware 1f00074000.i2c: controller timed out
[ 45.945498] i2c_designware 1f00074000.i2c: controller timed out
[ 46.960680] i2c_designware 1f00074000.i2c: controller timed out
Sometimes only the "controller timed out" message appears.
Additional context
No response