Skip to content

Pi5 i2c troubles using MCP23017 #6043

Closed
@JinShil

Description

@JinShil

Describe the bug

This issue is basically a followup to the following discussions related to i2c on the Pi5:

#5853
#5916
#5802

.. 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

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