Uncategorized

I2C Speed Tests

Asked 
Active today
Viewed 35 times
2
1

This example scans for any I2C slave address current on the I2C bus.
(I am using a RPi 3B+ with raspbian buster from september release)

Script trial_smbus.py:

from smbus2 import SMBus

channel = 1

i2c = SMBus(channel)

for i2c_addr in range(127):
    try:
        read_data = i2c.read_byte_data(i2c_addr, 0)
    except Exception as e:
        if e.errno == 121: 
            pass # no ACK
        else:
            print (e)
    else:
        print ("0x{:02X} => ACK!".format (i2c_addr))

It works nicely after a fresh boot of the RPi!

This script (not in the same script) simply ‘plays’ with the same IO pins:

Script trial_gpio.py:

import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)
GPIO.setup(3, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(5, GPIO.IN, pull_up_down=GPIO.PUD_UP)

I run this script, and indeed the GPIO are set as input with pullup resistors.

Now, I run again script trial_smbus.py, and I got:

[Errno 5] Input/output error

That means 2 things: – that little trial_gpio.py script set something that SMBus2 does not like. – SMBus2 does not init everything correctly.

Now I reboot and run again script trial_smbus.py==> works:

Run again trial_gpio.py.

Run again trial_smbus.py, does not work.

Run the wiringpi tool:

gpio mode 8 alt0
gpio mode 9 alt0

Run again trial_smbus.py, does work.

The easy solution would be to call those 2 command lines with a system call from within python. however wiringpi is deprecated: http://wiringpi.com/wiringpi-deprecated/

The issue I have is that I want a robust implementation with SMBus package. As you know some people might run several other programs prior they run my program, so I want the init to be done robustly.

Is there any alternative to set the pins in the correct mode?

 New contributor
  • 1
    Hi @karelv, Ah, let me see. (1) WiringPi once worked but now deprecated, so I am saying good bye without even once saying Hello. (2) SMBus1 works most of the time, but not always, eg no bus stretching, block read is buggy, but can get around by lowering I2C speed (from 100kHz to 10kHz!), (3) I once thought SMBus2 is new so would be better than SMBus1. I was very wrong. I tried it but gave up almost immediately. My conclusion is that I can only reluctantly bear SMBus1 for a couple of more years. – tlfong01 yesterday    
  • It is difficult to see what your question is. You cannot have 2 programs setting GPIO unless you release between uses. – Milliways yesterday
  • @tlfong01 thanks for your take on SMBus2 vs SMBus1, I have the same view as you had, although for me it is not an option to lower the clock to 10kHz, as it would be way to slow; I would rather like to work at 400kHz, if you know how to do that, feel free to share! – karelv 9 hours ago
  • @Milliways, I updated the question. I agree, the 2 scripts I made to show the issue; for isolation from all other clutter I build around it… My point is not to run them in parallel, but if somebody run a program that set some GPIO, and later they run my program it does not work. I don’t like that, and I am looking for a solution. – karelv 9 hours ago
  • Hi @karelv, Rpi3B+ I2C is mission impossible: (1) raspberrypi.org/forums/… (2) raspberrypi.org/forums/…. But if you don’t need bus stretching, I heard the rumour aht you can set I2C bus higher than 100kHz. But I need to let my scope to display the real 400kHz or higher wave form to my stupid human eyes. Perhaps I can try to do the possible mission over this weekend. – tlfong01 6 hours ago   
  • Hi @karelv. GOOD NEWS! I have verified that Rpi4B buster can set I2C speed to 500 kHz without any problem. I did the following test: Ping I2C PWM controller and found every thing OK. Then I repeat ping the same controller and use a scope to display the I2C 500kHz SCL waveform and found it sharp: penzu.com/p/1d0bb304. – tlfong01 1 hour ago    
  • So I have tested that my python program can ping a device at I2C speed 500kHz. I then increased to 800kHz and found everything OK. Then greedy me tried 1Mhz and got IO error after one or two seconds repeat pinging. I fell back to 800kHz and found everything OK again. So my conclusion: 500kHz OK, 800 kHz still OK. But 1000kHz has IO errors. Fall back to 800 kHz OK again. CONCLUSION: For reliable use, don’t go over 500 kHz. 400 kHz should be OK for the following conditions:Bus 1, only two I2C devices on the bus. WIRING LESS THAN 60 CM LONG. – tlfong01 6 mins ago   
  • I forgot to mention that as the I2C speed goes up, the “RINGING” (oscillation) at the rising edge of the SCL pulse should also go up, with the result that a positive pulse cannot be read as a positive pulse, thus the I/O ERROR MESSAGE. By the way, this is the end of my comments on I2C speed testing. I will do more speed test later, as I add more and more devices on the same bus, also other that Bus 1. I also need to find out why there is one or two I2C buses configured by dt driver, but not detected, … 😦 – tlfong01 just now   Edit   

3 Answers

1

For GPIO 2/3 (pins 3/5) to operate as the I2C bus they must be in a GPIO mode called ALT0.

They are set to this mode when the Linux I2C/SMBus driver is loaded.

The RPi.GPIO module is changing the mode of GPIO 2/3 to INPUT. This stops the proper operation of the I2C bus.

You need to again set the mode to ALT0 for GPIO 2/3 for the bus to operate again.

As far as I am aware the RPi.GPIO module provides no way of setting a GPIO to this mode.

To set GPIO 2 and 3 to mode ALT0 do one of the following.

If the wiringPi gpio utility is installed you can use the command.

gpio -g mode 2 alt0
gpio -g mode 3 alt0

If the pigpio pigs utility is installed you can use the command.

sudo pigpiod # start the daemon if not already running
pigs m 2 0 m 3 0

If the raspi-gpio utility is installed you can use the command.

raspi-gpio set 2 a0
raspi-gpio set 3 a0

  • Up to gpio, I’m aligned with you, then you start with new stuff. – karelv 9 hours ago
  • 1
    pigs is installed but I got error message: socket connect failed. – karelv 9 hours ago
  • 1
    raspi-gpio is also installed, no error message, and it works! – karelv 9 hours ago
  • 1
    raspi-gpio seems part of the package ‘raspi-gpio’ (dpkg -S raspi-gpio), and was preinstalled with raspbian buster. – karelv 9 hours ago
  • 1
    I rather stick with raspi-gpio, it works of-the-shelf! Thanks for your help! – karelv 9 hours ago

2

The mode of each pin is either in, out or any of the other functions (I2C in this case). Pins 3 and 5 are in ALT0 mode by default after reboot if the I2C driver is active. Type gpio readall on the command line to see which pins are in which mode.

To do the same as

gpio mode 8 alt0
gpio mode 9 alt0

in code, you need to do something like

GPIO.setup(3, GPIO.ALT0)
GPIO.setup(5, GPIO.ALT0);

(Not sure about the exact naming at the moment, though).

  • 1
    I like your pure python approach, so I would love it works! I’ve read that RPi.GPIO is working on I2C (5 years ago), but they will NEVER support ALT0 mode as such. I might be wrong of course, so please can you verify the exact naming convention? Thanks. – karelv 9 hours ago

0

To Answer the additional question you asked in Comments:-

RPi.GPIO has a cleanup command which can be used at the end of the program to restore startup state and should resolve the problem of releasing GPIO pins.

I don’t actually use RPi.GPIOgpiozero does this automatically.

  • Thanks, but.. you know, any program can crash accidentally… so I rather work on my init, the trial_gpio,py is just do demonstrate what a wrong starting condition for the trial_smbus.py. – karelv 28 mins 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

%d bloggers like this: