Auxilius
Posts: 11
Joined: Sat Apr 03, 2021 2:11 pm

I2C, OSError: [Errno 5] EIO

Wed Sep 01, 2021 6:36 pm

Hi, I have conected Pico to I2C isolator ADUM1250 with pull up 4k7 and than to IO expander PCA9534 with pull up 4k7
I can run i2c.scan() and I get adddres 0x20 and than I need to configure inputs outputs pin. So I need write 00000011 and than 10000000.
Not sure where is sometnihg wrong, thanks for help.

Code: Select all

import machine, utime
from machine import I2C
i2c = machine.I2C(0, scl=machine.Pin(17), sda=machine.Pin(16), freq=400000)

devices = i2c.scan()

if devices:
    for d in devices:
        print(hex(d))
        utime.sleep(1)

i2c.writeto(20, b'x3')
i2c.writeto(20, 2, b'x80')

Code: Select all

>>> %Run -c $EDITOR_CONTENT
0x20
Traceback (most recent call last):
  File "<stdin>", line 12, in <module>
OSError: [Errno 5] EIO

GerryKeely
Posts: 1
Joined: Fri Jul 16, 2021 4:50 pm

Re: I2C, OSError: [Errno 5] EIO

Thu Sep 02, 2021 9:13 am

Address returned by the ic scan is 0x20 not 20

hippy
Posts: 10761
Joined: Fri Sep 09, 2011 10:34 pm
Location: UK

Re: I2C, OSError: [Errno 5] EIO

Thu Sep 02, 2021 12:49 pm

i2c.writeto(20, b'x3')

"20" is not the same as "0x20" - It most likely is as simple as that. Welcome to the "D'oh! moment" club :P

hippy
Posts: 10761
Joined: Fri Sep 09, 2011 10:34 pm
Location: UK

Re: I2C, OSError: [Errno 5] EIO

Thu Sep 02, 2021 1:00 pm

You can avoid having to identify where your I2C device is and updating code if it ever changes by using something like -

Code: Select all

devices = i2c.scan()

if len(devices) == 0:
    print("No I2C device found")
elif len(devices) > 1:
    print("Multiple I2C devices found -")
    for d in devices:
        print("  0x{:02X}".format(d))
else:
    print("I2C device found at 0x{:02X}".format(devices[0]))
    device = devices[0]
    i2c.writeto(device, b'x3')
    i2c.writeto(device, 2, b'x80')

dbrion06
Posts: 685
Joined: Tue May 28, 2019 11:57 am

Re: I2C, OSError: [Errno 5] EIO

Thu Sep 02, 2021 2:35 pm

you assume either
there is only one I2C deevice or
0x20 is the 1rst adress i2c.scan returns. If OP adds devices, program will get crazy... Better veify 0x20 is in the list of returned scanned adresses (very easy in classical python; bet micropyhon knows 'in', too)

>>> 5 in [4,5,6]
True

hippy
Posts: 10761
Joined: Fri Sep 09, 2011 10:34 pm
Location: UK

Re: I2C, OSError: [Errno 5] EIO

Fri Sep 03, 2021 2:03 pm

dbrion06 wrote:
Thu Sep 02, 2021 2:35 pm
you assume either
there is only one I2C deevice or
0x20 is the 1rst adress i2c.scan returns.
I assumed there would be only one device and the OP had connected the correct device. Seemed a reasonable assumption to make for what the OP is doing.

danjperron
Posts: 3871
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: I2C, OSError: [Errno 5] EIO

Fri Sep 03, 2021 4:53 pm

Code: Select all

i2c.writeto(20, b'x3')
i2c.writeto(20, 2, b'x80')
hum 20 , b'x3' and b'x80'

I think that it should be

Code: Select all

i2c.writeto(0x20,b'\x03')
i2c.writeto(0x20,b'\x80')
or use bytes

Code: Select all

i2c.writeto(0x20,bytes((0x3,)))
But the PCA9534 has a command byte then it is address, command and data

if you want bit 7 on input and all others on output it should be,

Code: Select all

i2c.writeto_mem(0x20,0x3,b'\x80')

Auxilius
Posts: 11
Joined: Sat Apr 03, 2021 2:11 pm

Re: I2C, OSError: [Errno 5] EIO

Sun Sep 05, 2021 5:42 pm

Thanks guys! 0x20 :lol:

Auxilius
Posts: 11
Joined: Sat Apr 03, 2021 2:11 pm

Re: I2C, OSError: [Errno 5] EIO

Sun Sep 12, 2021 7:26 pm

Hi guys, I have another issue, I search on internet (unsuccessfully) for some datasheet how to use micropython and pico wiht some periferals like PWM, I2C, ISP etc.... with detail description what is what and how to use it

Now I'm stuck with this problem, I2C slave that I want write to.
This works good

Code: Select all

i2c.writeto_mem(0x0E,0x18,b'\x7FFF')
But I need some variables for user to be able change values, something like this, but its not working

Code: Select all

val = 32767
val = hex(val)
i2c.writeto_mem(0x0E,0x18,(val))

hippy
Posts: 10761
Joined: Fri Sep 09, 2011 10:34 pm
Location: UK

Re: I2C, OSError: [Errno 5] EIO

Mon Sep 13, 2021 1:03 pm

I would suspect you will need something like this-

Code: Select all

val = 0x7FFF
val_msb = (val >> 8) & 0xFF
val_lsb = (val >> 0) & 0xFF
i2c.writeto_mem(0x0E, 0x18, bytearray(val_msb, val_lsb))
or, fewer lines and optimised -

Code: Select all

val = 0x7FFF
i2c.writeto_mem(0x0E, 0x18, bytearray((val >> 8) & 0xFF, val & 0xFF)

Auxilius
Posts: 11
Joined: Sat Apr 03, 2021 2:11 pm

Re: I2C, OSError: [Errno 5] EIO

Mon Sep 13, 2021 2:47 pm

Thanks I end up with this:
Now I can have input in decimal, its easier for me

Code: Select all

val = 32767
higherbyte = (val >> 8)
lowerbyte = (val - (higherbyte *256))
i2c.writeto_mem(0x0E,0x18,bytes([higherbyte, lowerbyte]))

User avatar
OneMadGypsy
Posts: 361
Joined: Wed Apr 28, 2021 1:57 am
Location: New Orleans, Louisiana
Contact: Website

Re: I2C, OSError: [Errno 5] EIO

Mon Sep 20, 2021 4:59 pm

I would argue that all of these "solutions" are cumbersome. All of them have you juggling transposition all the way up to the end of your method call. Why not implement a reusable solution that covers all of the bases?

Code: Select all

import math
convert  = lambda n: (n).to_bytes((0 if not n else int(math.log(n, 256)))+1, 'big')

val = 32767
i2c.writeto_mem(0x0E, 0x18, convert(val))

With this solution you don't have to do any shifting, multiplying, subtracting, separating ... any of it. Just dump your number (no matter what it is) into convert and out comes your bytes. If it has to be a bytearray, simply wrap the return in bytearray, as below.

Code: Select all

convert2 = lambda n: bytearray((n).to_bytes((0 if not n else int(math.log(n, 256)))+1, 'big'))

For anyone that needs an explanation:

to_bytes takes 2 arguments. The first is how many bytes to use, and the second is the endian. Using log we can determine how many bytes our number will consume. We want the bytes back in the same order in which we put them in, so we use big endian. In short, we stick in a number, the amount of bytes that number consumes is determined and then the number is converted to that many bytes. If you use the bytearray version all of the exact same things happen and the result gets dumped in a bytearray. That's it. Simple. In contrast you can do 3 lines of math every single time you need to call writeto_mem ... and possibly spend hours trying to track down the one time you << instead of >> (and other such issues that arise when you manually input something that should simply be a function, multiple times). Let's also not overlook that all the ways that were suggested/implemented only handle 2 bytes. My method will spit out however many bytes the largest number you can create is (8?).


SIDENOTE:

Code: Select all

val = 32767
higherbyte = (val >> 8)
lowerbyte = (val - (higherbyte *256))
i2c.writeto_mem(0x0E,0x18,bytes([higherbyte, lowerbyte]))

This code is all over the place. You use bitshifting to divide and then decimal multiplication. But what is really weird is you divide val by 256 (>>8) to make higherbyte and then multiply higherbyte by 256 to subtract it from the original value. It's not wrong. It's just not good. lowerbyte is just val&0xFF. higherbyte is the same thing, but you have to shift it over 8 places(bits) before applying the bitmask for one byte (val>>8&0xFF). Manipulating the MSB to figure out what the LSB is, is very weird.

Now I can have input in decimal, its easier for me

Hex is for you, not the device. In other words, the device doesn't care, at all, if you write 254 or 0xFE. Both are 0b11111110 as far as the device is concerned. That being said, hippy's solution would have worked fine with decimal notation, as long as that decimal is a whole number. 32767>>8 or 32767//256 or 32767//(2**8) <- these are the same result, and the 8 in the first example is equivalent to the 8 in the last example. In other words >>8 is equivalent to "floor divide by 2 to the 8th power".You should do a study on bitwise operators and become intimately familiar with bits/bytes. You think 32767 is easier than 0x7FFF, but it really isn't. 0x7FFF tells me right off the bat that the bits are 7:(0111) F:(1111) F:(1111) F:(1111). I also know that it's 2 bytes (0x7F, 0xFF). I know that the absolute MSb is not being used, and maybe it can be used for something else (parity?). I know that it can only be left shifted 1 time (within 2 bytes) before it starts eating itself, which also means the value is half-1 of the total possible value. 32767 doesn't tell me anything beyond some things that I have memorized. For instance I know that 2 full bytes is 65535 and 1 full byte is 255 so, 32767 is somewhere in 2 bytes. That's not very helpful information.
"Focus is a matter of deciding what things you're not going to do." ~ John Carmack

hippy
Posts: 10761
Joined: Fri Sep 09, 2011 10:34 pm
Location: UK

Re: I2C, OSError: [Errno 5] EIO

Mon Sep 20, 2021 7:56 pm

convert = lambda n: (n).to_bytes((0 if not n else int(math.log(n, 256)))+1, 'big')

While that will generate however many bytes are needed to hold any partcular number, the i2c,write() will normally require a fixed number of bytes no matter what its value.

i2.c.write(... , convert(65535)) will write two bytes creating a word of 0xFFFF.

A subsequent i2c.write(..., convert(0)) will only write one byte, leaving the word as 0x00FF ( or 0xFF00 depending on endianess ).

User avatar
OneMadGypsy
Posts: 361
Joined: Wed Apr 28, 2021 1:57 am
Location: New Orleans, Louisiana
Contact: Website

Re: I2C, OSError: [Errno 5] EIO

Mon Sep 20, 2021 9:51 pm

It's easy enough to fix that. Just get rid of the log and put the byte count in yourself. This will zerofill or truncate, as well. (depending on your values). However, if you are going to go that far then the below is my final answer. I like this way better anyway. The only reason I put the original in a lambda was to pack away all the ugly log fumbling. If you need specific amount of bytes every time, then you don't need the hand-holdy log part, which means you also don't need the math module or the lambda.

Code: Select all

val = 32768
i2c.writeto_mem(0x0E, 0x18, (val).to_bytes(2, 'big'))

If it has to be a bytearray (for whatever reason), then it may make sense to put it back in a lambda so you don't have to type as much. While you're at it, default the count to 2 so, you only ever have to specify the count if it isn't 2. I'm assuming that 2 is the most common scenario. If it isn't, change count to whatever the most common byte count is.

Code: Select all

int2ba = lambda n, c=2: bytearray((n).to_bytes(c, 'big'))

val = 32768
i2c.writeto_mem(0x0E, 0x18, int2ba(val))
"Focus is a matter of deciding what things you're not going to do." ~ John Carmack

Return to “MicroPython”