[Solved] Tutorial: GPIO/I2C/SPI-access without root-permissions
SUBSYSTEM=="spidev", GROUP="spiuser", MODE="0660"
Next, copy and paste or type these lines into the terminal as the user you want to give access to the bus:
sudo groupadd spiuser sudo adduser "$USER" spiuser
SUBSYSTEM=="i2c-dev", GROUP="i2cuser", MODE="0660"
Similar to above, copy and paste or type these lines into the terminal as the user you want to give access to the bus:
sudo groupadd i2cuser sudo adduser "$USER" i2cuser
SUBSYSTEM=="gpio*", PROGRAM="/bin/sh -c '\ chown -R root:gpiouser /sys/class/gpio && chmod -R 770 /sys/class/gpio;\ chown -R root:gpiouser /sys/devices/virtual/gpio && chmod -R 770 /sys/devices/virtual/gpio;\ chown -R root:gpiouser /sys$devpath && chmod -R 770 /sys$devpath\ '"
Again, copy and paste or type these lines into the terminal as the user you want to give access to the bus:
sudo groupadd gpiouser sudo adduser "$USER" gpiouser
Now, there is nothing else to do with the SPI-bus or I2C-bus other than to reboot.
Here is a small application in C that simply toggles a pin HIGH and LOW:
#include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <fcntl.h> #include <getopt.h> #include <sys/ioctl.h> #include <linux/gpio.h> #include <time.h> #include <mraa.h> #define HEADERPIN 11 void sleepMillis(uint32_t millis) { struct timespec sleep; sleep.tv_sec = millis / 1000; sleep.tv_nsec = (millis % 1000) * 1000000L; while(clock_nanosleep(CLOCK_MONOTONIC, 0, &sleep, &sleep) && errno == EINTR); } int main(int argc, char **argv) { mraa_init(); mraa_gpio_context gpio; if (!(gpio = mraa_gpio_init(HEADERPIN))) { fprintf(stderr, "Error exporting pin %d!\n", HEADERPIN); mraa_deinit(); exit(1); } /* Check if the binary has root-permissions: if not, sleep for 100ms to give udev time to set the GPIO-permissions correctly for us to use the pin we just initialized above. !IMPORTANT! */ /* Try uncommenting this or changing the amount of time we sleep and see what happens. */ if(geteuid()) sleepMillis(100); if(mraa_gpio_dir(gpio, MRAA_GPIO_OUT) != MRAA_SUCCESS){ fprintf(stderr, "Error setting pin-direction!\n"); mraa_gpio_close(gpio); mraa_deinit(); exit(1); } printf("Blink HIGH..\n"); mraa_gpio_write(gpio, 1); sleepMillis(1000); //Sleep one second printf("Blink LOW..\n"); mraa_gpio_write(gpio, 0); sleepMillis(1000); //Sleep one second mraa_gpio_dir(gpio, MRAA_GPIO_IN); mraa_gpio_close(gpio); mraa_deinit(); exit(0); }
As you may notice, there is a call to geteuid() after mraa_gpio_init() -- mraa_gpio_init() initializes, or exports, the pin we wish to use, then geteuid() call is used to check if the app is running with root-permissions or not. If the application is running with root-permissions, there is no need for a delay as root can access all the file they want, but for non-root permissions a call to sleepMillis() is added to sleep 100ms, so udev hopefully has enough time to set the permissions correctly.
The above convention has to be followed with other languages, too, including shell-scripts:
#!/bin/bash #Export GPIO3, or pin number 11 on the UP1-board echo 3 > /sys/class/gpio/export #Test if we have root-permissions and, if not, sleep for 100ms if [ $EUID -gt 0 ]; then sleep 0.1; fi echo out > /sys/class/gpio/gpio3/direction echo 1 > /sys/class/gpio/gpio3/value sleep 1 echo 0 > /sys/class/gpio/gpio3/value sleep 1 #Set the pin back as INPUT and unexport it echo in > /sys/class/gpio/gpio3/direction echo 3 > /sys/class/gpio/unexport
And Python:
import RPi.GPIO as GPIO import time #We need this from os import geteuid # Pin Definitions: ledPin = 4 # Pin Setup: GPIO.setmode(GPIO.BCM) GPIO.setup(ledPin, GPIO.OUT) # LED pin set as output #If we're not root, sleep 100ms in order for udev to set #the permissions on the exported GPIO right if(geteuid() > 0): time.sleep(0.1) print("Here we go! Press CTRL+C to exit") try: while 1: GPIO.output(ledPin, GPIO.HIGH) time.sleep(0.5) GPIO.output(ledPin, GPIO.LOW) time.sleep(0.5) except KeyboardInterrupt: # If CTRL+C is pressed, exit cleanly: GPIO.cleanup() # cleanup all GPIO
Comments
-
I have now added a link to this guide to the wiki, and I attached a small script that should help people quickly set everything up. The script should be applicable to Debian, Ubilinux, Ubuntu etc. Feedback and bug-reports welcome.
-
There's no info UP squared wiki about GPIO/I2C userland access and no link to this thread either. Mind you the thread would have been broken with the forum downgrade anyways.
I don't have access to edit wiki, heck, I don't even have access to change the avatar..
-
Thanks WereCat, I noticed the guide earlier, but did not notice this thread.
Luckily I had most of this information from earlier threads that you gave suggestions on how to setup udev rules for GPIO...
Thanks again
-
Hi all. I cannot get this work for SPI access. It appears to grant me GPIO access, but not SPI. Anybody else have this problem? Running the app with sudo works fine. Running gdb needs sudo as well and works fine. Also, cannot get remote debugging working, probably for same reason.
-
Did some more digging. Found that after running the above mentioned script that the files created may be interfering with stock ublinux files. Specifically, /etc/udev/rules.d/50-spi.rules was almost the same as /etc/udev/rules.d/99-spi.rules the were already out there on my system. I deleted the 50-spi and the 50-i2c, added $USER to the "spi" group and the "i2c" group (which were referenced in the 99.. files)
I then added the getuid delay to my ccode and SPI and I2C started working fine w/o need for sudo.
Remaining question, what is the 99-leds.rules.d file and do I need the 50-GPIO.rules.d? -
Goot post! Have helped me a lot !
-
Hi all,
Also, you can install the upboard-extras package to get userspace access to the HAT functionalities
https://wiki.up-community.org/Ubuntu#Enable_the_HAT_functionality_from_userspace -
@ccalde said:
Hi all,Also, you can install the upboard-extras package to get userspace access to the HAT functionalities
https://wiki.up-community.org/Ubuntu#Enable_the_HAT_functionality_from_userspaceIn ubilinx need to make gpio access by meself .
-
For a long time trying I could not understand why access to I2C does not work (on NanoPiDuo2 in my case),
it worked for me like this,
create the file '/etc/udev/rules.d/50-i2c.rules' with the following contents:
SUBSYSTEM=="i2c-dev", KERNEL=="i2c-[0-9]*", GROUP="i2cuser", MODE="0660" -
This guide is not working for me. I am able to access my i2c device with
sudo
, but otherwise I getInvalid i2c bus
.This is a major issue for me as I am using
rosrun
, which can't be paired withsudo
. -
Update: This guide doesn't work, but the installing the upboard-extras package and following the instructions in the link provided by @ccalde did the trick for me.