Search code examples
raspberry-pic++17clioni2cunistd.h

Why is the I2C communication failing on a second pass through the same code?


The landscape - I have a MCU that performs a lot of tasks. It exposes an I2C slave communication to a Raspberry Pi. There a number of 'registers' I have created in code on the MCU. All of these are working fine. I previously had a nano hooked up and tested everything on the MCU so I am fairly sure the MCU is behaving correctly. Most of my I2C communications are working on the Pi too. Except for one. It is a little different in that it writes three bytes.

This is my code for the RPi:

std::string i2cServo(uint8_t reg, uint8_t angle){
    std::string error;
    uint8_t TxBuf[3];
    TxBuf[0] = 11;         // The register.
    TxBuf[1] = reg;        // The first parameter.
    TxBuf[2] = angle;      // The second parameter.
    close_fd();
    if (!fd) {
        if (open_fd_wronly() == -1) {
            error = "Failed to open I2C bus.";
        } else {
            if (write(fd, &TxBuf, 3) != 3) {
                std::cerr << errno << std::endl;
                error = "Could not set servo.";
            }
        }
    }
    return error;
}

This code gets executed twice. The first time everything is fine, the second I get errno 5. Which is EIO.

This is the logic analyser output: Logic

You can see the first pass is fine. The second pass is also fine till the end when a stop is expected.

I would suspect the MCU if it wasn't for the fact the nano behaves correctly, and the first pass of the code works fine.

Any ideas?

This is the fd opening:

int open_fd_wronly(){
    error_flag = false;
    if (fd) {
        close_fd();
        fd = 0;
    }
    if ((fd = open(devicefile.c_str(), O_WRONLY)) < 0)
        return errorMsg("ERROR opening: " + devicefile + "\n");
    if (ioctl(fd, I2C_SLAVE, slave_address) < 0)
        return errorMsg("ERROR address: " + std::to_string(slave_address) + "\n");
    return 0;
}

Solution

  • Sorry, no sooner posted the question. Than the answer dawned on me. It really helps to share a problem. The first register call prompts a write to EEPROM the second call was just arriving too fast triggering another write to the EEPROM and causing a crash. A little delay between the two calls solved the problem. Many thanks.