1

I have four MCP23017's connected to a Rpi4 on i2c bus 1, and a HT12K33 on bus 2 which is on gpio pins 27 and 17. I made a chess board with the MCP's checking reed switches for open/closed, hence the sheer number of inputs. The code below will run fine at start, with the switches being read correctly and the LEDs being lit, until I start opening and closing the switches with magnets embedded into the chess pieces. Then it will error out in a call to smbus.py in the read_i2c_block_data function call. All wiring connections are correct, they have been double, triple, and quadrouple checked. All devices are present with the terminal commands "i2cdetect -y 1" and "i2cdetect -y 2" (the second bus I made on the gpio pins) immediately before running the code and immediately after the error occurs. The pin it errors out on seems to be random (it changes every time, say I open A12 and the error is on B5).

What I have left uncommented is not enough to cause it to error out, but it gives you the gist of what I am doing. The entirety of the code if it is uncommented is what gives me the error.

import time
import board
import busio
from adafruit_ht16k33 import matrix
from adafruit_extended_bus import ExtendedI2C as I2C
from digitalio import Direction, Pull
from adafruit_mcp230xx.mcp23017 import MCP23017

#i2c = busio.I2C(board.D17, board.D27)
i2c = I2C(1)
i2c2 = I2C(2)

matrix = matrix.Matrix8x8(i2c2)

matrix.fill(0)
time.sleep(0.5)
matrix.fill(1)
time.sleep(0.5)
matrix.fill(0)
time.sleep(0.5)

pxA = MCP23017(i2c, address=0x24)
pxB = MCP23017(i2c, address=0x22)
pxC = MCP23017(i2c, address=0x21)
pxD = MCP23017(i2c, address=0x20)

#pxA
pinA0 = pxA.get_pin(0)
pinA0.direction = Direction.INPUT
pinA0.pull = Pull.UP
pinA1 = pxA.get_pin(1)
pinA1.direction = Direction.INPUT
pinA1.pull = Pull.UP
# pinA2 = pxA.get_pin(2)
# pinA2.direction = Direction.INPUT
# pinA2.pull = Pull.UP
# pinA3 = pxA.get_pin(3)
# pinA3.direction = Direction.INPUT
# pinA3.pull = Pull.UP
# pinA4 = pxA.get_pin(4)
# pinA4.direction = Direction.INPUT
# pinA4.pull = Pull.UP
# pinA5 = pxA.get_pin(5)
# pinA5.direction = Direction.INPUT
# pinA5.pull = Pull.UP
# pinA6 = pxA.get_pin(6)
# pinA6.direction = Direction.INPUT
# pinA6.pull = Pull.UP
# pinA7 = pxA.get_pin(7)
# pinA7.direction = Direction.INPUT
# pinA7.pull = Pull.UP
# pinA8 = pxA.get_pin(8)
# pinA8.direction = Direction.INPUT
# pinA8.pull = Pull.UP
# pinA9 = pxA.get_pin(9)
# pinA9.direction = Direction.INPUT
# pinA9.pull = Pull.UP
# pinA10 = pxA.get_pin(10)
# pinA10.direction = Direction.INPUT
# pinA10.pull = Pull.UP
# pinA11 = pxA.get_pin(11)
# pinA11.direction = Direction.INPUT
# pinA11.pull = Pull.UP
# pinA12 = pxA.get_pin(12)
# pinA12.direction = Direction.INPUT
# pinA12.pull = Pull.UP
# pinA13 = pxA.get_pin(13)
# pinA13.direction = Direction.INPUT
# pinA13.pull = Pull.UP
# pinA14 = pxA.get_pin(14)
# pinA14.direction = Direction.INPUT
# pinA14.pull = Pull.UP
# pinA15 = pxA.get_pin(15)
# pinA15.direction = Direction.INPUT
# pinA15.pull = Pull.UP

#pxB
pinB0 = pxB.get_pin(0)
pinB0.direction = Direction.INPUT
pinB0.pull = Pull.UP
pinB1 = pxB.get_pin(1)
pinB1.direction = Direction.INPUT
pinB1.pull = Pull.UP
# pinB2 = pxB.get_pin(2)
# pinB2.direction = Direction.INPUT
# pinB2.pull = Pull.UP
# pinB3 = pxB.get_pin(3)
# pinB3.direction = Direction.INPUT
# pinB3.pull = Pull.UP
# pinB4 = pxB.get_pin(4)
# pinB4.direction = Direction.INPUT
# pinB4.pull = Pull.UP
# pinB5 = pxB.get_pin(5)
# pinB5.direction = Direction.INPUT
# pinB5.pull = Pull.UP
# pinB6 = pxB.get_pin(6)
# pinB6.direction = Direction.INPUT
# pinB6.pull = Pull.UP
# pinB7 = pxB.get_pin(7)
# pinB7.direction = Direction.INPUT
# pinB7.pull = Pull.UP
# pinB8 = pxB.get_pin(8)
# pinB8.direction = Direction.INPUT
# pinB8.pull = Pull.UP
# pinB9 = pxB.get_pin(9)
# pinB9.direction = Direction.INPUT
# pinB9.pull = Pull.UP
# pinB10 = pxB.get_pin(10)
# pinB10.direction = Direction.INPUT
# pinB10.pull = Pull.UP
# pinB11 = pxB.get_pin(11)
# pinB11.direction = Direction.INPUT
# pinB11.pull = Pull.UP
# pinB12 = pxB.get_pin(12)
# pinB12.direction = Direction.INPUT
# pinB12.pull = Pull.UP
# pinB13 = pxB.get_pin(13)
# pinB13.direction = Direction.INPUT
# pinB13.pull = Pull.UP
# pinB14 = pxB.get_pin(14)
# pinB14.direction = Direction.INPUT
# pinB14.pull = Pull.UP
# pinB15 = pxB.get_pin(15)
# pinB15.direction = Direction.INPUT
# pinB15.pull = Pull.UP

#pxC
pinC0 = pxC.get_pin(0)
pinC0.direction = Direction.INPUT
pinC0.pull = Pull.UP
pinC1 = pxC.get_pin(1)
pinC1.direction = Direction.INPUT
pinC1.pull = Pull.UP
# pinC2 = pxC.get_pin(2)
# pinC2.direction = Direction.INPUT
# pinC2.pull = Pull.UP
# pinC3 = pxC.get_pin(3)
# pinC3.direction = Direction.INPUT
# pinC3.pull = Pull.UP
# pinC4 = pxC.get_pin(4)
# pinC4.direction = Direction.INPUT
# pinC4.pull = Pull.UP
# pinC5 = pxC.get_pin(5)
# pinC5.direction = Direction.INPUT
# pinC5.pull = Pull.UP
# pinC6 = pxC.get_pin(6)
# pinC6.direction = Direction.INPUT
# pinC6.pull = Pull.UP
# pinC7 = pxC.get_pin(7)
# pinC7.direction = Direction.INPUT
# pinC7.pull = Pull.UP
# pinC8 = pxC.get_pin(8)
# pinC8.direction = Direction.INPUT
# pinC8.pull = Pull.UP
# pinC9 = pxC.get_pin(9)
# pinC9.direction = Direction.INPUT
# pinC9.pull = Pull.UP
# pinC10 = pxC.get_pin(10)
# pinC10.direction = Direction.INPUT
# pinC10.pull = Pull.UP
# pinC11 = pxC.get_pin(11)
# pinC11.direction = Direction.INPUT
# pinC11.pull = Pull.UP
# pinC12 = pxC.get_pin(12)
# pinC12.direction = Direction.INPUT
# pinC12.pull = Pull.UP
# pinC13 = pxC.get_pin(13)
# pinC13.direction = Direction.INPUT
# pinC13.pull = Pull.UP
# pinC14 = pxC.get_pin(14)
# pinC14.direction = Direction.INPUT
# pinC14.pull = Pull.UP
# pinC15 = pxC.get_pin(15)
# pinC15.direction = Direction.INPUT
# pinC15.pull = Pull.UP

#pxD
pinD0 = pxD.get_pin(0)
pinD0.direction = Direction.INPUT
pinD0.pull = Pull.UP
pinD1 = pxD.get_pin(1)
pinD1.direction = Direction.INPUT
pinD1.pull = Pull.UP
# pinD2 = pxD.get_pin(2)
# pinD2.direction = Direction.INPUT
# pinD2.pull = Pull.UP
# pinD3 = pxD.get_pin(3)
# pinD3.direction = Direction.INPUT
# pinD3.pull = Pull.UP
# pinD4 = pxD.get_pin(4)
# pinD4.direction = Direction.INPUT
# pinD4.pull = Pull.UP
# pinD5 = pxD.get_pin(5)
# pinD5.direction = Direction.INPUT
# pinD5.pull = Pull.UP
# pinD6 = pxD.get_pin(6)
# pinD6.direction = Direction.INPUT
# pinD6.pull = Pull.UP
# pinD7 = pxD.get_pin(7)
# pinD7.direction = Direction.INPUT
# pinD7.pull = Pull.UP
# pinD8 = pxD.get_pin(8)
# pinD8.direction = Direction.INPUT
# pinD8.pull = Pull.UP
# pinD9 = pxD.get_pin(9)
# pinD9.direction = Direction.INPUT
# pinD9.pull = Pull.UP
# pinD10 = pxD.get_pin(10)
# pinD10.direction = Direction.INPUT
# pinD10.pull = Pull.UP
# pinD11 = pxD.get_pin(11)
# pinD11.direction = Direction.INPUT
# pinD11.pull = Pull.UP
# pinD12 = pxD.get_pin(12)
# pinD12.direction = Direction.INPUT
# pinD12.pull = Pull.UP
# pinD13 = pxD.get_pin(13)
# pinD13.direction = Direction.INPUT
# pinD13.pull = Pull.UP
# pinD14 = pxD.get_pin(14)
# pinD14.direction = Direction.INPUT
# pinD14.pull = Pull.UP
# pinD15 = pxD.get_pin(15)
# pinD15.direction = Direction.INPUT
# pinD15.pull = Pull.UP

#light leds
while True:    
    #pxA
    if pinA0.value == True:
        matrix[0,0] = 0
    elif pinA0.value == False:
        matrix[0,0] = 1
    if pinA1.value == True:
        matrix[0,1] = 0
    elif pinA1.value == False:
        matrix[0,1] = 1
#     if pinA2.value == True:
#         matrix[0,2] = 0
#     elif pinA2.value == False:
#         matrix[0,2] = 1
#     if pinA3.value == True:
#         matrix[0,3] = 0
#     elif pinA3.value == False:
#         matrix[0,3] = 1
#     if pinA4.value == True:
#         matrix[0,4] = 0
#     elif pinA4.value == False:
#         matrix[0,4] = 1
#     if pinA5.value == True:
#         matrix[0,5] = 0
#     elif pinA5.value == False:
#         matrix[0,5] = 1
#     if pinA6.value == True:
#         matrix[0,6] = 0
#     elif pinA6.value == False:
#         matrix[0,6] = 1
#     if pinA7.value == True:
#         matrix[0,7] = 0
#     elif pinA7.value == False:
#         matrix[0,7] = 1
#     if pinA8.value == True:
#         matrix[1,0] = 0
#     elif pinA8.value == False:
#         matrix[1,0] = 1
#     if pinA9.value == True:
#         matrix[1,1] = 0
#     elif pinA9.value == False:
#         matrix[1,1] = 1
#     if pinA10.value == True:
#         matrix[1,2] = 0
#     elif pinA10.value == False:
#         matrix[1,2] = 1
#     if pinA11.value == True:
#         matrix[1,3] = 0
#     elif pinA11.value == False:
#         matrix[1,3] = 1
#     if pinA12.value == True:
#         matrix[1,4] = 0
#     elif pinA12.value == False:
#         matrix[1,4] = 1
#     if pinA13.value == True:
#         matrix[1,5] = 0
#     elif pinA13.value == False:
#         matrix[1,5] = 1
#     if pinA14.value == True:
#         matrix[1,6] = 0
#     elif pinA14.value == False:
#         matrix[1,6] = 1
#     if pinA15.value == True:
#         matrix[1,7] = 0
#     elif pinA15.value == False:
        matrix[1,7] = 1
    
    #pxB
    if pinB0.value == True:
        matrix[2,0] = 0
    elif pinB0.value == False:
        matrix[2,0] = 1
    if pinB1.value == True:
        matrix[2,1] = 0
    elif pinB1.value == False:
        matrix[2,1] = 1
#     if pinB2.value == True:
#         matrix[2,2] = 0
#     elif pinB2.value == False:
#         matrix[2,2] = 1
#     if pinB3.value == True:
#         matrix[2,3] = 0
#     elif pinB3.value == False:
#         matrix[2,3] = 1
#     if pinB4.value == True:
#         matrix[2,4] = 0
#     elif pinB4.value == False:
#         matrix[2,4] = 1
#     if pinB5.value == True:
#         matrix[2,5] = 0
#     elif pinB5.value == False:
#         matrix[2,5] = 1
#     if pinB6.value == True:
#         matrix[2,6] = 0
#     elif pinB6.value == False:
#         matrix[2,6] = 1
#     if pinB7.value == True:
#         matrix[2,7] = 0
#     elif pinB7.value == False:
#         matrix[2,7] = 1
#     if pinB8.value == True:
#         matrix[3,0] = 0
#     elif pinB8.value == False:
#         matrix[3,0] = 1
#     if pinB9.value == True:
#         matrix[3,1] = 0
#     elif pinB9.value == False:
#         matrix[3,1] = 1
#     if pinB10.value == True:
#         matrix[3,2] = 0
#     elif pinB10.value == False:
#         matrix[3,2] = 1
#     if pinB11.value == True:
#         matrix[3,3] = 0
#     elif pinB11.value == False:
#         matrix[3,3] = 1
#     if pinB12.value == True:
#         matrix[3,4] = 0
#     elif pinB12.value == False:
#         matrix[3,4] = 1
#     if pinB13.value == True:
#         matrix[3,5] = 0
#     elif pinB13.value == False:
#         matrix[3,5] = 1
#     if pinB14.value == True:
#         matrix[3,6] = 0
#     elif pinB14.value == False:
#         matrix[3,6] = 1
#     if pinB15.value == True:
#         matrix[3,7] = 0
#     elif pinB15.value == False:
#         matrix[3,7] = 1
        
    #pxC
    if pinC0.value == True:
        matrix[4,0] = 0
    elif pinC0.value == False:
        matrix[4,0] = 1
    if pinC1.value == True:
        matrix[4,1] = 0
    elif pinC1.value == False:
        matrix[4,1] = 1
#     if pinC2.value == True:
#         matrix[4,2] = 0
#     elif pinC2.value == False:
#         matrix[4,2] = 1
#     if pinC3.value == True:
#         matrix[4,3] = 0
#     elif pinC3.value == False:
#         matrix[4,3] = 1
#     if pinC4.value == True:
#         matrix[4,4] = 0
#     elif pinC4.value == False:
#         matrix[4,4] = 1
#     if pinC5.value == True:
#         matrix[4,5] = 0
#     elif pinC5.value == False:
#         matrix[4,5] = 1
#     if pinC6.value == True:
#         matrix[4,6] = 0
#     elif pinC6.value == False:
#         matrix[4,6] = 1
#     if pinC7.value == True:
#         matrix[4,7] = 0
#     elif pinC7.value == False:
#         matrix[4,7] = 1
#     if pinC8.value == True:
#         matrix[5,0] = 0
#     elif pinC8.value == False:
#         matrix[5,0] = 1
#     if pinC9.value == True:
#         matrix[5,1] = 0
#     elif pinC9.value == False:
#         matrix[5,1] = 1
#     if pinC10.value == True:
#         matrix[5,2] = 0
#     elif pinC10.value == False:
#         matrix[5,2] = 1
#     if pinC11.value == True:
#         matrix[5,3] = 0
#     elif pinC11.value == False:
#         matrix[5,3] = 1
#     if pinC12.value == True:
#         matrix[5,4] = 0
#     elif pinC12.value == False:
#         matrix[5,4] = 1
#     if pinC13.value == True:
#         matrix[5,5] = 0
#     elif pinC13.value == False:
#         matrix[5,5] = 1
#     if pinC14.value == True:
#         matrix[5,6] = 0
#     elif pinC14.value == False:
#         matrix[5,6] = 1
#     if pinC15.value == True:
#         matrix[5,7] = 0
#     elif pinC15.value == False:
#         matrix[5,7] = 1
        
    #pxD
    if pinD0.value == True:
        matrix[6,0] = 0
    elif pinD0.value == False:
        matrix[6,0] = 1
    if pinD1.value == True:
        matrix[6,1] = 0
    elif pinD1.value == False:
        matrix[6,1] = 1
#     if pinD2.value == True:
#         matrix[6,2] = 0
#     elif pinD2.value == False:
#         matrix[6,2] = 1
#     if pinD3.value == True:
#         matrix[6,3] = 0
#     elif pinD3.value == False:
#         matrix[6,3] = 1
#     if pinD4.value == True:
#         matrix[6,4] = 0
#     elif pinD4.value == False:
#         matrix[6,4] = 1
#     if pinD5.value == True:
#         matrix[6,5] = 0
#     elif pinD5.value == False:
#         matrix[6,5] = 1
#     if pinD6.value == True:
#         matrix[6,6] = 0
#     elif pinD6.value == False:
#         matrix[6,6] = 1
#     if pinD7.value == True:
#         matrix[6,7] = 0
#     elif pinD7.value == False:
#         matrix[6,7] = 1
#     if pinD8.value == True:
#         matrix[7,0] = 0
#     elif pinD8.value == False:
#         matrix[7,0] = 1
#     if pinD9.value == True:
#         matrix[7,1] = 0
#     elif pinD9.value == False:
#         matrix[7,1] = 1
#     if pinD10.value == True:
#         matrix[7,2] = 0
#     elif pinD10.value == False:
#         matrix[7,2] = 1
#     if pinD11.value == True:
#         matrix[7,3] = 0
#     elif pinD11.value == False:
#         matrix[7,3] = 1
#     if pinD12.value == True:
#         matrix[7,4] = 0
#     elif pinD12.value == False:
#         matrix[7,4] = 1
#     if pinD13.value == True:
#         matrix[7,5] = 0
#     elif pinD13.value == False:
#         matrix[7,5] = 1
#     if pinD14.value == True:
#         matrix[7,6] = 0
#     elif pinD14.value == False:
#         matrix[7,6] = 1
#     if pinD15.value == True:
#         matrix[7,7] = 0
#     elif pinD15.value == False:
#         matrix[7,7] = 1

The error code is:

Traceback (most recent call last):
  File "/home/pi/Documents/led_mtx.py", line 507, in <module>
    if pinD15.value == True:
  File "/usr/local/lib/python3.7/dist-packages/adafruit_mcp230xx/digital_inout.py", line 80, in value
    return _get_bit(self._mcp.gpio, self._pin)
  File "/usr/local/lib/python3.7/dist-packages/adafruit_mcp230xx/mcp23017.py", line 63, in gpio
    return self._read_u16le(_MCP23017_GPIOA)
  File "/usr/local/lib/python3.7/dist-packages/adafruit_mcp230xx/mcp230xx.py", line 39, in _read_u16le
    i2c.write_then_readinto(_BUFFER, _BUFFER, out_end=1, in_start=1, in_end=3)
  File "/usr/local/lib/python3.7/dist-packages/adafruit_bus_device/i2c_device.py", line 131, in write_then_readinto
    in_end=in_end,
  File "/usr/local/lib/python3.7/dist-packages/busio.py", line 141, in writeto_then_readfrom
    stop=stop,
  File "/usr/local/lib/python3.7/dist-packages/adafruit_blinka/microcontroller/generic_linux/i2c.py", line 88, in writeto_then_readfrom
    address, buffer_out[out_start:out_end], in_end - in_start
  File "/usr/local/lib/python3.7/dist-packages/Adafruit_PureIO/smbus.py", line 273, in read_i2c_block_data
    ioctl(self._device.fileno(), I2C_RDWR, request)
OSError: [Errno 121] Remote I/O error

Why is this error occuring when using all 64 of the pins, but not when using just the 8?

Edit: It actually does still error out with just the 8 pins active, it just takes a little longer it seems.

1
  • A wiring diagram may help identify an issue.
    – CoderMike
    Jan 25, 2022 at 7:57

1 Answer 1

0

[Error 121] is perhaps the most common I2C transceive error, usually caused by:

  1. Bad hardware wiring, eg, too long (over 30 cm), therefore too capacitive, exceeding 400pF.

  2. Bus overloaded with too many devices, also causing impedance over 400pF limit.

One simple and effective workaround is:

  1. Remove all pullups (errata: pulldowns should read pullups) except those on Rpi board.

You might like to google/search "[Error 121]" for more detailed answers.

4
  • @tflong I don’t have any pull downs connected, and the input pins of the MCP’s are set to pull ups purely because they have to be to read the inputs. Could be that the wires are too long, but that’s not something I can get around. Why would it detect the devices then all of a sudden not be able to? If it were a case of too many devices, does that pertain to everything connected through the MCP’s or just the four MCP’s themselves? The latter I can get around by creating a new bus, the former I cannot.
    – tcolbert
    Apr 30, 2021 at 5:50
  • Just a quick reply. Big apologies and errata: (1) All "pull downs" should read "pull ups". I only used through hole.23017 in my first two years learning. Afterwards, I always used modules (017 and 17). Almost always these I2C modules have build in 4k7 pullups, which you should remove, because Rpi I2C pins already have strong 1k8 pullups. (2) Intermittent detect/no detect, [Error 121] etc are usual, because I2C off board, longer that 30cm is unpredictable (Yes, I have over 100 hours practical painful experience, you can search rpi.org.forum for my old MCP23017/S17/S08/001 posts.)
    – tlfong01
    Apr 30, 2021 at 6:41
  • MCP23017 is almost the worst I2C device I experienced. I always warn newbies that the learning curve is very steep. I estimate is that 90% of those brace newbies try and failed, similar to those brave "startup" guys. Many thank for help pointing out my careless type mistake. Cheers. Please feel free to ask more newbie questions.
    – tlfong01
    Apr 30, 2021 at 6:45
  • I just searched my old 017 posts and found about 180. If you skim them you should find how I struggled to put 8 mcp23017 on one bus, and also many references and useful tricks: (1) Search found 178 matches: mcp23017 tlfong01 - rpi.org/forum raspberrypi.org/forums/…. Cheers.
    – tlfong01
    Apr 30, 2021 at 6:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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