Uncategorized

pcf8591 notes

Asked 
Active yesterday
Viewed 53 times
1

I have been trying to create a retropie unit, and I’m in the midst of writing a script to inject uinput events for the analog axis values. This is the code I’ve written so far, but the issue is that I get IOERROR: (Errno 121) Remote I/O error.

When I use the command i2cdetect -y 1, the module shows up at address 0x48.

from evdev import UInput, ecodes as e;
import smbus;
from time import sleep;

def analogRead(pin):
    global bus;
    return bus.read_byte(0x48+pin);


bus = smbus.SMBus(1);
ui = UInput();

bus.write_byte_data(0x48,0x40 | (0 & 0x03) | (1 & 0x03) | (2 & 0x03), 0 | 1 | 2);

sleep(0.2);

bus.read_byte(0x48);

sleep(0.2);

bus.read_byte(0x49);

sleep(0.2);

bus.read_byte(0x50);

sleep(0.2);

while True:
    if analogRead(0)  <= 10:
        ui.write(e.EV_KEY, e.KEY_S, 0);
        ui.write(e.EV_KEY, e.KEY_W, 1);
    elif analogRead(0) >= 245:
        ui.write(e.EV_KEY, e.KEY_S, 1);
        ui.write(e.EV_KEY, e.KEY_W, 0);
    else:
        ui.write(e.EV_KEY, e.KEY_S, 0);
        ui.write(e.EV_KEY, e.KEY_W, 0);

    if analogRead(1)  <= 10:
        ui.write(e.EV_KEY, e.KEY_D, 0);
        ui.write(e.EV_KEY, e.KEY_A, 1);
    elif analogRead(1) >= 245:
        ui.write(e.EV_KEY, e.KEY_D, 1);
        ui.write(e.EV_KEY, e.KEY_A, 0);
    else:
        ui.write(e.EV_KEY, e.KEY_D, 0);
        ui.write(e.EV_KEY, e.KEY_A, 0);

EDIT: This issue occurs every time I attempt to run the python script.

The goal is to use a single pcf8591, and read three separate inputs: y-axis, x-axis, and the button press.

REVISED CODE:

from evdev import UInput, ecodes as e;
import smbus;
from time import sleep;

bus = smbus.SMBus(1);
ui = UInput();

bus.read_byte(0x48);

The revised, smaller sample, allows me to get a value of 128, which I assume references the first analog output, the y-axis. How can I access the other two analog inputs( button and x-axis )? I tried to increment the address by one to 0x49, but that is what produces my IOERROR.

 New contributor
  • Hi @Ian Rosenberg, Welcome. Ah, let me see. The error “IOERROR: (Errno 121) Remote I/O error” is a common error of I2C transmission. The “i2cdetect -y 1” detects you I2C device OK usually means the i2cdetect utility reads the device at address 0x48 OK. But there a couple of reasons that there are transmission error afterwards, including: (1) Wiring too long, (2) I2C speed too high, … Usually get arounds include: (1) Reboot Rpi, (2) Shorten connecting wires, … – tlfong01 Nov 14 at 3:49   
  • You can find more get arounds in my answer to the following question: raspberrypi.stackexchange.com/questions/98116/…. – tlfong01 Nov 14 at 3:58   
  • When do you get the error? Always? Occasionally? Please edit your question to include this information. – joan Nov 14 at 8:25
  • I found your program a bit confusing. Please confirm if you are doing 3 ADCs at the same time. I would suggest to start with only one ADC, to make troubleshooting easier. If you simplify your program to do just one channel, I am more encouraged to read you a bit long program. 🙂 – tlfong01 Nov 14 at 9:43   
  • Just now I have quickly read my pcf8591 programming cheat sheet to refresh my memory. Now I am ready to read your program, IF simplified. imgur.com/gallery/j4OKFt3 – tlfong01 Nov 14 at 9:46   
  • I am not near my pi at the moment, but the issue occurs when I run the progrm every single time. I have a single PCF8591 which reads 3 analog inputs from a PS2 joystick: Y, X, and Button. I will update the question when I am near my pi again. – Ian Rosenberg Nov 14 at 14:19
  • Ha, I am sorry I did not bother to read your frighteningly long code before I gave my first comments. Now I have read your very short revised code and short comment, which is actually a hint to the cause of your I2C IO error #121. I think you have confused the ADC device’s I2C address with the device’s input analog channel number. Don’t bother to do any more update to your question. I will give a more detailed clarification and perhaps try to verify my guess with a demo code later. – tlfong01 Nov 15 at 0:55   
  • Now let me suggest to eat the big elephant bite by bite, say, in 3 bites: (1) Make the problem as simple as possible – just convert one analog input channel, 0~5V, to 8 bit digital value. In other words, just consider one axis of the joystick, (2) Then consider how to use one PCF8591 to convert 3 input analog channels, as your 3 joystick inputs, (3) Just to clarify things, how to use, say 2 PCF8591s (addresses 0x48, 0x49) to convert a total of 4 x 2 = 8 analog inputs. – tlfong01 Nov 15 at 1:26   
  • Now first thing first, read the friendly datasheet. I have summarized the programming part in the following picture. You might like to stare at my picture for 3 minutes, and then spend another 10 minutes to skim the datasheet, at the figures referred in my picture: imgur.com/gallery/6cvATYy. – tlfong01 Nov 15 at 1:32   
  • The critical and confusing part is the control word. You need to read the datasheet’s spec on the control word very carefully, to make sure you understand how to (1) Select which input channel, (2) Select input channel type (single ended, or differential), (3) How to select A/D or D/A, by enabling/disabling analog output. – tlfong01 Nov 15 at 1:37   
  • To troubleshoot, I usually try to make things as simple as possible, but not simpler (Occam’s Razor). Now the python “evdev” module you import is far from simple, for two reasons: (1) It is sort of interrupt/event driven thing, which is difficult to debug. I always prefer to first use stupid blocking loops instead. You can always changed it to event driven programming later. (2) Did you compile the driver yourself, or just copy and paste a binary image? There might be a driver OS version incompatibility problem. My config is Rpi4B buster 2019sep26. Please confirm your Rpi and OS version. – tlfong01 Nov 15 at 3:50    
  • Now I am tidying up my old I2C python programming notes, and ready to write a demo program to to do PCF8591 A/D conversion of one single ended input channel: imgur.com/gallery/suoZ2EW – tlfong01 Nov 15 at 6:59    
  • Now I have placed two PCF8591 modules on bus I2C-4, and set a very low I2C baudrate of 10 kHz. Next step is python programming: imgur.com/gallery/K8RWQrX. – tlfong01 Nov 15 at 14:14    

2

SMBus’s write_byte_data is the function I needed. I had to specify which register I was using per analog input.

The I/O error I had was the result of only having a single pcf8591 located at 0x48.

 New contributor
  • (1) Yes, need to write to address 0x48 and only address 0x48, not 0x49. (2) Yes and no, you need to use two write-byte data commands, and one read-Byte command. (3) You don’t need to specify any register, because THERE IS NO REGISTER to specify (only channels which are NOT registers). (4) Perhaps you can simplify your code, removing “evdev”, and just play with one axis, instead of all three axis. You might like to update question with a simple code, then I can see any causes of error. I am checking out if or too I2C low speed cause sample and hold cap leaks charge and cause error, … – tlfong01 7 hours ago   

Categories: Uncategorized

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: