1

All, I've ported a C++ OLED library from the bcm2835 library to use i2c-smbus to prevent having to run the executable as root. (not the best from a security standpoint). However, i2c-smbus and ioctl() does not provide the ability to set the I2C bus speed (baudrate).

With the bcm2835 library, you have bcm2835_i2c_setClockDivider() which sets the I2C bus clock as a fraction of the system-clock. The specifics of the clock divider are provided by the library's enum bcm2835I2CClockDivider (note: that is based on a 250MHz system clock, so there is a multiple of ~4 for the various Raspberry Pi's)

Setting the I2C baudrate in /boot/config.txt (e.g. dtparam=i2c_arm=on,i2c_arm_baudrate=400000) isn't an alternative as any program that uses the bcm2835 to adjust the I2C clock changes the I2C clock system-wide. So it is necessary to set the I2C clock on a per-program basis to ensure a specific bus speed is used.

Is there any other way to set the I2C bus speed programmatically other than the bcm2835 library? (or version variant of that library) Is there a way do it it without being root?

2
  • Not completely sure I understand your question, but AFAIK, there would never be a way to change the i2c clock speed for an individual device on a bus... that's set at the bus level (i.e. in hardware) in the overlay (config.txt), and would apply to all devices on that bus. You didn't mention which platform, but some RPi have several additional software i2c buses (in add'n to the h/w buses) that might be configured to run independently - see the online README file.
    – Seamus
    Commented Jun 4 at 5:53
  • Thanks, the question was really about setting the i2c bus speed system wide and being able to change it to meet different needs at different times, not on a per-device basis. I basically found that to set the bus speed you have to use /dev/mem and the bcm2835 library, no simple ioctl() or otherwise to set it. I ended up just writing a short utility using bcm2835 to set the bus speed and accepted that part has to be run as root. Win some, lose some :) Commented Jun 4 at 6:46

1 Answer 1

1

I have never used i2c-smbus although I have written code in python and c to use I²C using the kernel driver either directly in c or python smbus library.

None of these allow setting clock and rely on the kernel driver.

The bcm2835 library directly accesses the GPIO registers but userspace access to clock functionality is only available using dev/mem which requires root permissions (this is the case for all libraries).

Directly accessing the GPIO registers has never been encouraged and no longer is possible on Pi5.

9
  • Well, that helps... but raises the issue, how would this be accomplished on Pi 5? Just in /boot/config.txt and then since nothing alters it -- it won't change. But... that brings up the issue of, what to do if you need to change? Not all I2C devices like the same I2C clock... But this is good confirmation that I'm not missing the obvious. I can't find anything but the bcm2835 library that does it -- and I don't like requiring root access to run an executable. I guess you can separate the parts of the program and start as root and then drop privileges after the config is set. Commented Feb 18 at 7:47
  • @DavidC.Rankin I have only had Pi5 for a week so can't offer any alternative. None of the existing libraries will work. I am unaware of any I²C device that doesn't support the standard rates and the BCM2812 is supposed to support 1MHz. It wouldn't be that difficult to write your own kernel driver if you really feel that this is necessary.
    – Milliways
    Commented Feb 18 at 8:30
  • I think that is the way to go. I'll have to go back and make friends with how to associate that driver with the various programs that make use of it. The driver writing itself, I've already found a couple of nice examples that I can draw from. Then it would be a shell wrapper around the C program to modprobe or insmod the new module before launching the program that relies on it. Thank you again for your suggestions. I'll investigate that route further. Commented Feb 18 at 9:32
  • @DavidC.Rankin Another possibility. If you have code requiring root access write a module and include a socket server which you run as root. Then a user mode program can access via a socket. This adds some overhead, but is unlikely to impact I²C performance. This is how pigpio works (pigpiod)and I have used in my library for hardware PWM (which sets clock). This works on Pi4 and earlier but writing the server on BCM2812 (Pi5) still has many unknowns.
    – Milliways
    Commented Feb 18 at 10:21
  • Yes, the pigpiod daemon provides socket access, but it takes 7.6% CPU (minimum when it is idling -- it's polling all 53 GPIOs at 2000 times per second). It spikes to 15-20% of the CPU when you are using it. That's a heck of a penalty just to have a socket backend provided that tries to provide as concurrent as possible notice of a rising or falling edge triggering on any GPIO. Evidently interrupts or polling isn't sufficient from a timing perspective. The non-root, simple approach is to mmap the GPIO mem through /dev/gpiomem which allows user access - with default perms on the file. Commented Feb 20 at 9:54

Your Answer

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

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