Use the gpio port without being root on jetson tk1

Hello,

I develop a program in c ++ with qtcreator on a jetson tk1 card. I try to access the gpio port of the card to control relays. I use the library from this site GPIO Interfacing - NVIDIA Jetson TK1 - JetsonHacks

For my application I want to be able to use gpio ports without running my program as root. I followed the instructions given by Accessing TX1 GPIO as a Non-root User (ubuntu) (for jetson tx1) to create a rule and to be able to execute the code without su privilege.

When I do some tests, everything goes well. I can execute these commands without sudo, the voltage varies as expected from 0 to 1.8 V:

echo 165> / sys / class / gpio / export
echo out> / sys / class / gpio / gpio165 / direction
echo 1> / sys / class / gpio / gpio165 / value

Now, if I use the library GPIO Interfacing - NVIDIA Jetson TK1 - JetsonHacks in my code in C ++ I can export the ports but then I can’t change the direction or read the values. For example, I have the following error message:

gpioSetDirection not enabled gpio165: Permission denied

I checked the permissions of the files and everything seems ok (the session user is a member of gpio group):

ubuntu @ tegra-ubuntu: / sys / class / gpio / gpio165 $ ls -l
total 0
-rw-rw-r-- 1 root gpio 4096 Mar 9 10:32 AM active_low
lrwxrwxrwx 1 root root 0 Mar 9 10:39 device -> ../../../6000d000.gpio
-rw-rw-r-- 1 root gpio 4096 Mar 9 10:33 direction
-rw-rw-r-- 1 root gpio 4096 Mar 9 10:32 edge
drwxr-xr-x 2 root root 0 Mar 9 10:39 power
lrwxrwxrwx 1 root root 0 Mar 9 10:39 subsystem -> ../../../../../class/gpio
-rw-r - r-- 1 root root 4096 Mar 9 10:32 uevent
-rw-rw-r-- 1 root gpio 4096 Mar 9 10:35 value

Now if I run my code with:

sudo ./my_c++_program

everything is working normally.

I don’t understand why I can access gpio ports in command line terminal without being root and that I have to be root for my c++ code to work. An idea ?

Thanks!

Did you manually add group “gpio”? Normally this is user/group of root/root (I’m looking at L4T R21.6…you haven’t mentioned which L4T release you are looking at). Something like that might work if your user has supplementary group of “gpio” and make it writable for that group.

I’m using L4T R21.6. Yes, I added the group manually with the following command :

sudo groupadd gpio
sudo usermod -a -G gpio ubuntu

If I check the gpio group member with :

getent group gpio

the result is

gpio:x:1001:ubuntu

.

How can I check for the permissions ?

I haven’t looked at the program source code…does it use file I/O to the “/sys” files, or does it use a system call (an API call directly to the kernel not through file I/O)?

In the case of the files, “ls -l” for /sys/class/gpio/ “export” and “unexport” should show write-only, without read permission, such as:

ubuntu@tk1:/sys/class/gpio$ ls -l
total 0
--w--w---- 1 root gpio 4096 Mar 13 16:11 export
lrwxrwxrwx 1 root root    0 Jan  1  2000 gpio143 -> ../../devices/platform/6000d000.gpio/gpio/gpio143
lrwxrwxrwx 1 root root    0 Jan  1  2000 gpiochip0 -> ../../devices/platform/6000d000.gpio/gpio/gpiochip0
lrwxrwxrwx 1 root root    0 Jan  1  2000 gpiochip1016 -> ../../devices/platform/tegra12-i2c.4/i2c-4/4-0040/as3722-pinctrl/gpio/gpiochip1016
--w--w---- 1 root gpio 4096 Mar 13 16:11 unexport

The “read” permission of those files should not exist. The file is not a real file, this is really an interface to a driver. The driver was not coded to output data for those files, it was only coded as data input. In my case when I added group “gpio” I used the “-r” option to make this a system group and not a general group (“groupadd -r gpio”). I don’t know if this would cause a difference or not, but the echo statements work for me as user ubuntu.

There are symbolic links to some forms of access through “/sys”, it is possible your C++ program uses the end point of a link instead of the export/unexport files.

This won’t necessarily fix anything, but I’d suggest you start with this:

<b>sudo -s</b>
groupdel gpio
groupadd -r gpio
usermod -a -G gpio ubuntu
chgrp gpio /sys/class/gpio/export /sys/class/gpio/*export
chmod 220 /sys/class/gpio/*export
<b>exit</b>
# Test...you should now be user ubuntu again without sudo:
echo 165 > /sys/class/gpio/export
echo 165 > /sys/class/gpio/unexport

If the interface being used isn’t file I/O then this won’t help.

The library use file I/O from the /sys files. Here is the export function (from www.jetsonhacks.com developped by RidgeRun) that works well :

#define SYSFS_GPIO_DIR "/sys/class/gpio"
#define POLL_TIMEOUT (3 * 1000) /* 3 seconds */
#define MAX_BUF 64

int gpioExport ( jetsonGPIO gpio )
{
    int fileDescriptor, length;
    char commandBuffer[MAX_BUF];

    fileDescriptor = open(SYSFS_GPIO_DIR "/export", O_WRONLY);
    if (fileDescriptor < 0) {
        char errorBuffer[128] ;
        snprintf(errorBuffer,sizeof(errorBuffer), "gpioExport unable to open gpio%d",gpio) ;
        perror(errorBuffer);
        return fileDescriptor;
    }

    length = snprintf(commandBuffer, sizeof(commandBuffer), "%d", gpio);
    if (write(fileDescriptor, commandBuffer, length) != length) {
        perror("gpioExport");
        return fileDescriptor ;

    }
    close(fileDescriptor);

    return 0;
}

and the setDirection function that doesn’t work (gpioSetDirection unable to open gpio166: Permission denied) :

int gpioSetDirection ( jetsonGPIO gpio, unsigned int out_flag )
{
    int fileDescriptor;
    char commandBuffer[MAX_BUF];

    snprintf(commandBuffer, sizeof(commandBuffer), SYSFS_GPIO_DIR  "/gpio%d/direction", gpio);

    fileDescriptor = open(commandBuffer, O_WRONLY);
    if (fileDescriptor < 0) {
        char errorBuffer[128] ;
        snprintf(errorBuffer,sizeof(errorBuffer), "gpioSetDirection unable to open gpio%d",gpio) ;
        perror(errorBuffer);
        return fileDescriptor;
    }

    if (out_flag) {
        if (write(fileDescriptor, "out", 4) != 4) {
            perror("gpioSetDirection") ;
            return fileDescriptor ;
        }
    }
    else {
        if (write(fileDescriptor, "in", 3) != 3) {
            perror("gpioSetDirection") ;
            return fileDescriptor ;
        }
    }
    close(fileDescriptor);
    return 0;
}

I tried to delete the group and recreate it with your indications but it still does not work. I have the same issue as before :

  • everything is working well in the command line
  • only export and unexport work in my program
ubuntu@tegra-ubuntu:~$ ls -l /sys/class/gpio/
total 0
--w--w---- 1 root gpio 4096 Mar 14 08:41 export
lrwxrwxrwx 1 root gpio    0 Mar 14 08:41 gpio143 -> ../../devices/platform/6000d000.gpio/gpio/gpio143
lrwxrwxrwx 1 root gpio    0 Mar 14 08:44 gpio160 -> ../../devices/platform/6000d000.gpio/gpio/gpio160
lrwxrwxrwx 1 root gpio    0 Mar 14 08:44 gpio161 -> ../../devices/platform/6000d000.gpio/gpio/gpio161
lrwxrwxrwx 1 root gpio    0 Mar 14 08:44 gpio163 -> ../../devices/platform/6000d000.gpio/gpio/gpio163
lrwxrwxrwx 1 root gpio    0 Mar 14 08:44 gpio164 -> ../../devices/platform/6000d000.gpio/gpio/gpio164
lrwxrwxrwx 1 root gpio    0 Mar 14 08:44 gpio165 -> ../../devices/platform/6000d000.gpio/gpio/gpio165
lrwxrwxrwx 1 root gpio    0 Mar 14 08:44 gpio166 -> ../../devices/platform/6000d000.gpio/gpio/gpio166
lrwxrwxrwx 1 root gpio    0 Mar 14 08:41 gpiochip0 -> ../../devices/platform/6000d000.gpio/gpio/gpiochip0
lrwxrwxrwx 1 root gpio    0 Mar 14 08:41 gpiochip1016 -> ../../devices/platform/tegra12-i2c.4/i2c-4/4-0040/as3722-pinctrl/gpio/gpiochip1016
--w--w---- 1 root gpio 4096 Mar 14 08:44 unexport

I am guessing you probably ran the chgrp and/or necessary chmod before running your command, but I should still ask since each reboot will revert to root/root owner/group and permissions unless you’ve created a udev rule.

In my case I have no issue with doing this with echo on command line. For the case of your program you might try using strace to see what the system is rejecting. This creates a huge amount of logging (a C-like syntax for every system call made), but most of what you’ll be interested in will be near the last 100 lines or so. To create a log (as your user ubuntu while in membership of group gpio and while the relevant files are group “gpio” with group write permission):

strace </what/ever/your/program/is> -o tracelog.txt
# Now examine tracelog.txt, look for anything "permission" which isn't locale...
# One way:
egrep -i 'permission' tracelog.txt | egrep -v 'locale'
# Or browse with a text editor...

NOTE: It may end up a directory containing the file needs group gpio and group write added.

Yes, I’m using udev rules.

Here is the result of strace :

I don’t know if these lines concern my problem but there is a permission error :

access("/dev/tegra_sema", R_OK|W_OK)    = -1 ENOENT (No such file or directory)
open("/dev/mem", O_RDWR|O_DSYNC)        = -1 EACCES (Permission denied)
access("/dev/tegra_sema", R_OK|W_OK)    = -1 ENOENT (No such file or directory)
open("/dev/mem", O_RDWR|O_DSYNC)        = -1 EACCES (Permission denied)
open("/sys/devices/virtual/misc/nvmap/heap-camera/usage", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/dev/nvmap", O_RDWR|O_DSYNC|O_CLOEXEC) = 5
open("/dev/nvhost-ctrl", O_RDWR|O_DSYNC) = 6

The gpio part :

.....
open("/sys/class/gpio/export", O_WRONLY) = 26
write(26, "166", 3)                     = 3
close(26)                               = 0
open("/sys/class/gpio/export", O_WRONLY) = 26
write(26, "165", 3)                     = 3
close(26)                               = 0
open("/sys/class/gpio/export", O_WRONLY) = 26
write(26, "160", 3)                     = 3
close(26)                               = 0
open("/sys/class/gpio/export", O_WRONLY) = 26
write(26, "161", 3)                     = 3
close(26)                               = 0
open("/sys/class/gpio/export", O_WRONLY) = 26
write(26, "163", 3)                     = 3
close(26)                               = 0
open("/sys/class/gpio/export", O_WRONLY) = 26
write(26, "164", 3)                     = 3
close(26)                               = 0
open("/sys/class/gpio/gpio166/direction", O_WRONLY) = -1 EACCES (Permission denied)
dup(2)                                  = 26
fcntl64(26, F_GETFL)                    = 0x2 (flags O_RDWR)
fstat64(26, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 14), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xa7e07000
_llseek(26, 0, 0xbef4bd20, SEEK_CUR)    = -1 ESPIPE (Illegal seek)
write(26, "gpioSetDirection unable to open "..., 59) = 59
close(26)                               = 0
munmap(0xa7e07000, 4096)                = 0
open("/sys/class/gpio/gpio165/direction", O_WRONLY) = -1 EACCES (Permission denied)
dup(2)                                  = 26
fcntl64(26, F_GETFL)                    = 0x2 (flags O_RDWR)
fstat64(26, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 14), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xa7e07000
_llseek(26, 0, 0xbef4bd20, SEEK_CUR)    = -1 ESPIPE (Illegal seek)
write(26, "gpioSetDirection unable to open "..., 59) = 59
close(26)                               = 0
munmap(0xa7e07000, 4096)                = 0
open("/sys/class/gpio/gpio160/direction", O_WRONLY) = -1 EACCES (Permission denied)
dup(2)                                  = 26
fcntl64(26, F_GETFL)                    = 0x2 (flags O_RDWR)
fstat64(26, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 14), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xa7e07000
_llseek(26, 0, 0xbef4bd20, SEEK_CUR)    = -1 ESPIPE (Illegal seek)
write(26, "gpioSetDirection unable to open "..., 59) = 59
close(26)                               = 0
munmap(0xa7e07000, 4096)                = 0
open("/sys/class/gpio/gpio161/direction", O_WRONLY) = -1 EACCES (Permission denied)
dup(2)                                  = 26
fcntl64(26, F_GETFL)                    = 0x2 (flags O_RDWR)
fstat64(26, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 14), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xa7e07000
_llseek(26, 0, 0xbef4bd20, SEEK_CUR)    = -1 ESPIPE (Illegal seek)
write(26, "gpioSetDirection unable to open "..., 59) = 59
close(26)                               = 0
munmap(0xa7e07000, 4096)                = 0
open("/sys/class/gpio/gpio163/direction", O_WRONLY) = -1 EACCES (Permission denied)
dup(2)                                  = 26
fcntl64(26, F_GETFL)                    = 0x2 (flags O_RDWR)
fstat64(26, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 14), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xa7e07000
_llseek(26, 0, 0xbef4bd20, SEEK_CUR)    = -1 ESPIPE (Illegal seek)
write(26, "gpioSetDirection unable to open "..., 59) = 59
close(26)                               = 0
munmap(0xa7e07000, 4096)                = 0
open("/sys/class/gpio/gpio164/direction", O_WRONLY) = -1 EACCES (Permission denied)
dup(2)                                  = 26
fcntl64(26, F_GETFL)                    = 0x2 (flags O_RDWR)
fstat64(26, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 14), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xa7e07000
_llseek(26, 0, 0xbef4bd20, SEEK_CUR)    = -1 ESPIPE (Illegal seek)
write(26, "gpioSetDirection unable to open "..., 59) = 59
close(26)                               = 0
munmap(0xa7e07000, 4096)                = 0
write(14, "\1\0\0\0\0\0\0\0", 8)        = 8
.....
open("/sys/class/gpio/unexport", O_WRONLY) = 27
write(27, "166", 3)                     = 3
close(27)                               = 0
open("/sys/class/gpio/unexport", O_WRONLY) = 27
write(27, "165", 3)                     = 3
close(27)                               = 0
open("/sys/class/gpio/unexport", O_WRONLY) = 27
write(27, "160", 3)                     = 3
close(27)                               = 0
open("/sys/class/gpio/unexport", O_WRONLY) = 27
write(27, "161", 3)                     = 3
close(27)                               = 0
open("/sys/class/gpio/unexport", O_WRONLY) = 27
write(27, "163", 3)                     = 3
close(27)                               = 0
open("/sys/class/gpio/unexport", O_WRONLY) = 27
write(27, "164", 3)                     = 3
close(27)                               = 0
shmdt(0xa57b5000)                       = 0
shmctl(1933321, IPC_64|IPC_RMID, 0)     = 0
....

Thanks for your help !

It looks like your program is doing more than just echo to those sys files, so there may still be a permission error if you are reading “/dev/mem” once other issues are figured out.

Here is the part which is of interested:

write(26, "164", 3)                     = 3
close(26)                               = 0
open("/sys/class/gpio/gpio166/direction", O_WRONLY) = -1 EACCES (Permission denied)

I have not gone through your code, but here are some questions to think about.

Prior to the failure you wrote 3 bytes (“164” attempted 3 byte write, return value says you got 3 bytes), then the descriptor closed. Every call which was previous to this followed this routine…open the export file, echo the bytes to the file, close the descriptor. Just prior to the “166” echo there was no open. In fact it looks like you batched the export of each GPIO into a group and are now attempting to select direction. The problem though is you opened the file for write in the case of the exports, but never opened the file for write to “direction” (at least not that I can see in that subset of the trace…opening a lot of descriptors all at once would be a bigger mistake). With what is shown here I’d say the permission issue is on the “direction” and not on the “export” file, and that perhaps the descriptor was never opened for write (the descriptor could not have been opened for write prior to the echo to export 166 so if there was no other strace I’m missing then there is an obvious logic flaw because the “direction” did not exist until after that).

Just FYI, opening and closing descriptors a lot can be a very expensive operation. I suggest you open export only once, do all echos (there might be a reason this won’t work, but I’d try it and find out), and then close export (perhaps you might need to print a NULL byte between numbers when export is opened once for many writes…I’ve never tried, so it would be an experiment to open once, do all writes, and then close). You have to open and close each “direction” individually, it’s something you can’t get around.

So, I found my mistake. I try to set the direction too quickly after making an export. If I do this:

gpioExport(gpio166);

gpioSetDirection(gpio166,inputPin);

it does not work but if I do this (sleep 1 second between the 2 command):

gpioExport(gpio166);

utility::msleep(1000);

gpioSetDirection(gpio166,inputPin);

it works.

Thanks linuxdev for your help !