Getting IOError: [Errno 121] Remote I/O error with smbus on python (raspberry) while trying to get data over I2C from Arduino

d s picture d s · Oct 10, 2018 · Viewed 19.2k times · Source

I am facing problems, that pyhton throws me on my raspberry pi 3 sometimes this IOError during starting a script which is requesting data from an Arduino over I2C.

Electrical connection is perfect so this is not the issues. Furthermore I also dont get any errors while using i2cget -y 1 0x04

Only the python scripts sucks sometime and I dont know why.

This is my Arduino Code:

I register an onReceive and an onRequestEvent. onReceive Callback will define what kind of data should be send back to the raspberry. onRequest Callback does the response.

    #include <CommonFunction.h>
#include <Wire.h>

#define I2C_ADDRESS 0x4

commonFunc GetCountsEverySecond;
int g_iOnRequestActionCode = 0;
unsigned long g_lSecondsSinceStart = 0;

void setup() 
{
    Wire.begin(I2C_ADDRESS);
    Wire.onRequest(sendDataOverI2CGateway);
    Wire.onReceive(defineOnRequestAction);
}


void loop() 
{
    tickSeconds();
}

void tickSeconds()
{
    if (GetCountsEverySecond.TimeTriggerAt(1000))
    {
        g_lSecondsSinceStart++;
    }
}

void sendOperationTimeDataOverI2C()
{
    unsigned long longInt = g_lSecondsSinceStart;
    byte size = sizeof(longInt);

    byte arr[size];
    for (int i = 0; i < size; i++)
    {
        int iBitShift = 8 * (size - i - 1);
        if (iBitShift >= 8)
            arr[i] = ((longInt >> iBitShift) & 0xFF);
        else
            arr[i] = (longInt & 0xFF);
    }
    Wire.write(arr, size);
    g_bI2CSending = true;
}

void sendDataOverI2CGateway()
{
    switch(g_iOnRequestActionCode)
    {
        case 0:
            sendRainDataOverI2C();
            break;
        case 1: // send firmware version
            sendVersionDataOverI2C();
            break;
        case 2: // send operation time of arduino in seconds from start
            sendOperationTimeDataOverI2C();
            break;
        default: break;
    }
}

void defineOnRequestAction(int iBuffer) 
{
    while (Wire.available())
    {
        g_iOnRequestActionCode = Wire.read();
    }
}

Here is my python Code. Pretty straight forward but it causes some headache.

import smbus
import time
bus = smbus.SMBus(1)
while True:
        data = bus.read_i2c_block_data(0x04,0x02,4)
        result = 0
        for b in data:
                result = result * 256 + int(b)
        print(result)
        time.sleep(1)

After executing my python script I am getting sometime this error:

pi@WeatherStation:~/workspace $ sudo python readTimeOperationData.py
Traceback (most recent call last):
  File "readTimeOperationData.py", line 5, in <module>
    data = bus.read_i2c_block_data(0x04,0x02,4)
IOError: [Errno 121] Remote I/O error

Can anyone help me to fix this issue?

Cheers Dieter

Answer

d s picture d s · Oct 10, 2018

I solved it!!

I got a hint from this post: https://www.raspberrypi.org/forums/viewtopic.php?t=203286

By adding a delay after bus = smbus.SMBus(1) solved this issue. It seems that a short delay is somehow needed so that the I2C can settle.

Working Code tested by calling script 100times without issues.

import smbus
import time
bus = smbus.SMBus(1)
time.sleep(1) #wait here to avoid 121 IO Error
while True:
    data = bus.read_i2c_block_data(0x04,0x02,4)
    result = 0
    for b in data:
        result = result * 256 + int(b)
    print(result)
    time.sleep(1)