0

I have connected Rpi with Arduino using i2c communication. Pin Configuration: Rpi ---- Arduino Mega SDA SDA SCL SCL GND GND

I also have an encoder attached to Rpi. Encoder `------ Rpi 5V 5V Gnd Gnd Output A Gpio 17 (BCM layout) Output B Gpio 18 (BCM Layout)

Code is working perfectly fine, however after sometime, I am getting an error: 121, Remote I/O Error.

Also, before the error (before starting the communication), on executing i2cdetect -y 1, I see only one slave address (20) same address as my Pi.

However, after the error, on executing i2cdetect -y 1, I get 2 addresses, even tho only Arduino is connected.

Output for before communication:
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f  
00           --  -- -- -- -- -- -- -- -- -- -- -- --
10   -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20   20 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30   -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40   -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50   -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60   -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70   -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
Output after error, on executing i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f  
00           03  -- -- -- -- -- -- -- -- -- -- -- --
10   -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20   20 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30   -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40   -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50   -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60   -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70   -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
Python:
# -*- coding: utf-8 -*-
import RPi.GPIO as GPIO
import time
import serial
import os
import smbus
#import time
bus = smbus.SMBus(1)
time.sleep(1)
address = 0x20


GPIO.setmode (GPIO.BCM)
GPIO.setwarnings(True)

i=0
pin_A = 17
pin_B = 18

######################################################################
def writeNumber(value):
    bus.write_byte(address, value)
    return -1

def readNumber():
    number = bus.read_byte(address)

    return number
###################################################################
Encoder_Count = 0
A_Pos2=0
GPIO.setup (pin_A, GPIO.IN)
GPIO.setup (pin_B, GPIO.IN)
GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)#Button to GPIO23
A_Pos = 0
A_Last = "00"
STATE = {"0001":1,"0010":-1,"0100":-1,"0111":1,"1000":1,"1011":-1, "1101":-1, "1110":1}     

def Encoder1(channel1):
    global Encoder_Count,A_Pos,A_Last,STATE
    now = str(GPIO.input(17)) + str(GPIO.input(18))
    key = A_Last + now
    if key in STATE:
            direction = STATE[key]
            A_Last = now
            A_Pos +=direction


GPIO.add_event_detect (pin_A, GPIO.BOTH, callback=Encoder1)  
GPIO.add_event_detect (pin_B, GPIO.BOTH, callback=Encoder1)
i=0
#while(i<10):
while(1):
    var = 100
        button_state = GPIO.input(23)
   # ser.write(b'1')
        A_Pos2= A_Pos/(1600)
        time.sleep(0.01)
    print A_Pos2
    writeNumber(A_Pos2)
        if (A_Pos2 ==-6):
        #writeNumber(7)

        A_Pos = A_Pos % 6
        time.sleep(0.01)
    if (A_Pos2 ==6):

        #writeNumber(A_Pos2)
        #A_Pos=0
        A_Pos = A_Pos % 6
        time.sleep(0.01)

    #else:


        if button_state == False:
            # GPIO.output(24, True)
            os.system("sudo shutdown now -h")


GPIO.cleanup()

Arduino
Arduino:
#include <Wire.h>
#define SLAVE_ADDRESS 0x20
int number = 0;
void setup()
{

    Wire.begin(SLAVE_ADDRESS);
  Wire.onReceive(receiveData);

  delay(2000);

}

void loop()
{
if (number == 10)
{
// do something
}

// callback for wire communication:
void receiveData(int byteCount) {

  if (Wire.available()) {
     digitalWrite(5,HIGH);
    number = Wire.read();

    Serial.println (number);
    delay(100);

}
  • That sounds like a wiring problem. Are all the wires soldered or decent quality dupont connectors? A photo or photos clearly showing the connections between Pi and Arduino will be helpful. – joan Sep 18 at 18:52
  • While it may often work and probably is not a huge risk (potential physical damage to the Pi), connecting the Pi's 3.3V I2C bus to the Mega's 5V I2C is not a great idea. You need a level shifter in between them. – goldilocks Sep 18 at 19:10
  • @Vaibhav Thacker, Questions: (1) Why are you not using the Rpi standard I2C GPIO pins 2,3? (2) What is the "encoder" you are referring? Does this encoder converts Mega's 5V I2C pins signals to 3V3 and also does something else, like pretending to be a slave with address 0x20? – tlfong01 Sep 19 at 5:08
  • @Vaibhav Thacker, suggest the following tests, if your have Rpi4B and buster: (1) Lower I2C speed from 100kHz to 10kHz, (2) Set up four I2C channels and swap compare and contrast, (3) Other tricks as suggested in my answer below. – tlfong01 Sep 19 at 5:36
  • @goldilocks We do have i2c level shifter, still getting this error – Vaibhav Thacker Sep 19 at 10:06
0

Question

Error 121, Remote I/O Error

Answer

The above error means many things, including the following:

  1. Forgot to connect the I2C connectors.

  2. Device gets crazy.

For 2, I usually reset the device. For example MCP23017 has a reset pin which I connect to a manual reset button 10k pull up to Vcc, which can reset by hand or by Rpi. (In your case, reset Arduino, or Rpi, or both, or restart their I2C programs.)

If the device has no reset pin, then I can manual or software reset the power to the device (LM2596, LM2941, which has power reset pins, or can be a current/power switch).

To prevent I2C IO errors, there are many tricks, including the following:

  1. Use short wires, less than 30cm if possible.

  2. Twist the wires, or use CAT5 (already twisted pairs).

  3. Lower the I2C clock speed. Rpi3 has a bug and only do a flat rate of 100kHz. For Rpi4B, you set I2C speed down to as low as 10kHz. You will find all kinds of line noise, switching noise/ringing reduced, and Error 121 less frequent.

  4. Convert Rpi 3V3 I2C signals to 5V. 5V circuits usually has a higher tolerance to noise and can therefore go higher speed. I usually use TXS010x (TXB0x0x is better).

  5. Separate power supplies for Rpi and devices, separate grounding wires etc, ...

  6. Use I2C buffers and expanders (expensive, only for industrial applications)

  7. Remove onboard's 4k7/10k pull down, because Rpi I2C pins already use 1k7 pullups, which is strong enough.

  8. Rpi4B has 4 I2C channels, I usually swap channels 1, 3, 4, 5 to compare and contrast (Appendix A).

  9. Use the SPI version to compare, if there is one. For example, I got fed up with I2C MCP23017, I switch to SPI MCP23S17. Many devices have I2C and SPI pins on the same chip, and that is handy.

  10. More tricks I forgot, ... :)

References

(1) I2C Long Cables Dsicussion

(2) I2C References - NXP, TI

(3) TSX010x References - TI

(4) I2C Long Cable References - NXP

(5) I2C Switch/Expander References - TI

(6) I2C Buses Learning Notes - TI

(7) I2C and SMBus Learning Notes - Linux

(8) MCP23017 x 8 on the same I2C Bus

Appendices

(A) Testing Rpi4B buster 4 I2C Channels

I2c Bus Setup Notes

pi@raspberrypi:~ $ date Wed 28 Aug 2019 03:26:24 PM HKT

pi@raspberrypi:~ $ uname -a

Linux raspberrypi 4.19.58-v7l+ #1245 SMP Fri Jul 12 17:31:45 BST 2019 armv7l

pi@raspberrypi:~ $ sudo nano /boot/config.txt

dtoverlay=i2c1,pins_2_3 (board pins 3, 5)

dtoverlay=i2c3,pins_4_5 (board pins 7, 29)

dtoverlay=i2c4,pins_6_7 (board pins 31, 26)

dtoverlay=i2c5,pins_12_13 (board pins 32, 33)

dtoverlay=i2c6,pins_22_23 (board pins 15, 16)

pi@raspberrypi:~ $ ls /dev/i2c*

/dev/i2c-1 /dev/i2c-3 /dev/i2c-4 /dev/i2c-5 /dev/i2c-6

# fi2c62.py  tlfong01 2019aug28hkt1433

from time          import sleep
import             smbus
import             fprint53    as fprint
import             ftime53     as ftime

# I2c Bus Setup Notes
# pi@raspberrypi:~ $ date Wed 28 Aug 2019 03:26:24 PM HKT
# pi@raspberrypi:~ $ uname -a
# Linux raspberrypi 4.19.58-v7l+ #1245 SMP Fri Jul 12 17:31:45 BST 2019 armv7l GNU/Linux
# pi@raspberrypi:~ $ sudo nano /boot/config.txt
# dtoverlay=i2c1,pins_2_3  (board pins 3, 5)
# dtoverlay=i2c3,pins_4_5  (board pins 7, 29)
# dtoverlay=i2c4,pins_6_7  (board pins 31, 26)
# dtoverlay=i2c5,pins_12_13 (board pins 32, 33)
# dtoverlay=i2c6,pins_22_23 (board pins 15, 16)
# pi@raspberrypi:~ $ ls /dev/i2c*
# /dev/i2c-1  /dev/i2c-3  /dev/i2c-4  /dev/i2c-5  /dev/i2c-6

# ********************************************************************************
# ********************************************************************************

# *** I2c Bus Config ***

i2cBus1 = smbus.SMBus(1) 
i2cBus3 = smbus.SMBus(3)
i2cBus4 = smbus.SMBus(4)
i2cBus5 = smbus.SMBus(5)

i2cBusDict = {'I2cBus1': i2cBus1,
              'I2cBus3': i2cBus3,
              'I2cBus4': i2cBus4,
              'I2cBus5': i2cBus5,
             }

# *** Pca9685 I2c Slave Device Congif ***

pca9685DevAddrDict = {
                'Dev0': 0x40,
                'Dev1': 0x41,
                'Dev2': 0x42,
                'Dev3': 0x43,
                'Dev4': 0x44,
                'Dev5': 0x45,
                'Dev6': 0x46,
                'Dev7': 0x47,
              }

pca9685RegAddrDict = { 'Mode1': 0x00,
                       'Mode2': 0x01,
                     }

pca9685DataByteDict = {
                       'Mode1Reset': 0x11,

    }

# ********************************************************************************
# ********************************************************************************

# *** Read Write Print Device/Register Functions ***

def writeDevTwoBytes(i2cBus, devAddr, writeByte1, writeByte2):
    i2cBus.write_byte_data(devAddr, writeByte1, writeByte2)
    return

def writeRegOneByte(i2cBus, devAddrDict, devName, regAddrDict, regName, writeByte):
    devAddr = devAddrDict[devName]
    regAddr = regAddrDict[regName]
    writeDevTwoBytes(i2cBus, devAddr, regAddr, writeByte)
    return

def readDevOneByte(i2cBus, devAddr, readByteAddr):
    readByte = i2cBus.read_byte_data(devAddr, readByteAddr)
    return readByte

def readRegOneByte(i2cBus, devAddrDict, devName, regAddrDict, regName):
    devAddr = devAddrDict[devName]
    regAddr = regAddrDict[regName]
    readByte = i2cBus.read_byte_data(devAddr, regAddr)
    return readByte

def printRegOneByte(i2cBus, devAddrDict, devName, regAddrDict, regName):
    readByte = readRegOneByte(i2cBusName, devAddrDict, devName, regAddrDict, regName)
    print(printTitle, hex(readByte))
    return

# *** Main Test Function ***

def testWriteReadPca9685Bus1Dev0RegMode1():     
    fprint.printBeginExecFunction()

    i2cBusName = 'I2cBus1'
    devName    = 'Dev0'
    regName    = 'Mode1'

    #i2cBus      = fi2c.i2cBusDict[i2cBusName]
    i2cBus      = i2cBusDict[i2cBusName]
    devAddrDict = pca9685DevAddrDict
    regAddrDict = pca9685RegAddrDict  

    writeByte = 0x77

    writeRegOneByte(i2cBus, devAddrDict, devName, regAddrDict, regName, writeByte)
    readByte = readRegOneByte(i2cBus, devAddrDict, devName, regAddrDict, regName) 

    if readByte == writeByte:
        resultsString = 'Good'
    else:
        resultsString = 'Bad'

    devAddr = devAddrDict[devName]

    fprint.printTitleOneByteNum('PCA9685 I2C Address',             fprint.indentFormat640, devAddr)
    fprint.printTitleOneByteNum('PCA9685 MODE1 Register Written',  fprint.indentFormat640, writeByte) 
    fprint.printTitleOneByteNum('PCA9685 MODE1 Register Read',     fprint.indentFormat640, readByte)    
    fprint.printTitleString('Write/Read Results',                  fprint.indentFormat640, resultsString)

    fprint.printEndExecFunction()
    return

def testPingPca9685Bus1Dev0RegMode1():     
    fprint.printBeginExecFunction()

    i2cBusName = 'I2cBus1'
    devName    = 'Dev0'
    regName    = 'Mode1'

    #i2cBus      = fi2c.i2cBusDict[i2cBusName]
    i2cBus      = i2cBusDict[i2cBusName]
    devAddrDict = pca9685DevAddrDict
    regAddrDict = pca9685RegAddrDict

    devAddr = devAddrDict[devName]

    readByte = readRegOneByte(i2cBus, devAddrDict, devName, regAddrDict, regName)    

    compareByte = pca9685DataByteDict['Mode1Reset'] 

    if readByte == compareByte:
        resultsString = 'Good'
    else:
        resultsString = 'Bad'

    fprint.printTitleString('PCA9685 I2C Address',             fprint.indentFormat640, hex(devAddr))
    fprint.printTitleString('PCA9685 MODE1 Register Written',  fprint.indentFormat640, hex(compareByte)) 
    fprint.printTitleString('PCA9685 MODE1 Register Read',     fprint.indentFormat640, hex(readByte))    
    fprint.printTitleString('Ping Results',                    fprint.indentFormat640, resultsString)

    fprint.printEndExecFunction()
    return

# ********************************************************************************
# ********************************************************************************

# *** Main Tests ***

def mainTests():
    #ftime.testPrintDateTime()
    testPingPca9685Bus1Dev0RegMode1()
    testWriteReadPca9685Bus1Dev0RegMode1()
    return

# ********************************************************************************
# ********************************************************************************

# *** Init/Main Functions ***

# *** Init Function ***

def init():
    pass
    return

#*** Main Function ***

def main():
    init()
    mainTests()    
    return

# ********************************************************************************
# ********************************************************************************

# *** Main ***

if __name__ == '__main__':
    main()

# *** End of Program ***

# ********************************************************************************
# ********************************************************************************

.END

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.