Setup Raspberry Pi Hardware Permissions

Raspberry Pi hardware permissions can be quite tricky.

So, you are using hardware functionalities with your Raspberry Pi 4 (or 3B, 3B+), and always getting errors such as “Permission denied”?

This might be the case if you use I2C, SPI, UART, or simply the GPIOs on the Pi, with a user that isn’t root.

In this post I’ll show you, in a basic way, how to manage your Raspberry Pi hardware permissions so you can use hardware in your code without having to execute your programs with “sudo”.

Enable hardware on your Raspberry Pi

First of all you have to enable hardware in boot config files, before you even think about permissions. If I2C, SPI or UART are not enabled, you simply won’t be able to do anything.

Find the file /boot/config.txt and edit it with admin rights (use “sudo”):


You are learning how to use Raspberry Pi to build your own projects?

Check out Raspberry Pi For Beginners and learn step by step.


Enable I2C

Uncomment the line dtparam=i2c_arm=on (if “off”, change to “on”).

Enable SPI

Uncomment the line dtparam=spi=on (if “off”, change to “on”).

Enable UART

Uncomment the line dtparam=uart0=on or set enable_uart=1.

Once you have changed a setting in the /boot/config.txt, you must reboot your Pi in order to apply the change. Don’t forget this part, this will save you from huge headaches!

If you want to disable a specific hardware interface, you just need to comment the line and reboot again.

Add a user to a hardware group

Once a specific hardware functionality is enabled, you may have to do an additional step in order to use it. If you’re not running your programs as root (which you should not do anyway), you may encounter permission issues at this point.

First, run the groups command line tool to see in which groups you belong. Let’s assume that your username is simply “your_username”.

$ groups your_username
your_username : your_username adm cdrom sudo dip video plugdev input lpadmin gpio i2c sambashare

In this example, you can see that your user has access to the “i2c” group. It means that you have access to the I2C functionalities (which have been previously enabled).

Let’s see what are all groups available on your Raspberry Pi.

$ groups
your_username adm cdrom sudo dip video plugdev input lpadmin sambashare spi i2c gpio

If you type groups without any argument, you’ll see all groups.

Here you can notice that your user is not in the “spi” group, which can lead to “Permission denied” errors when trying to execute a program using SPI.

To add a user in a group, use adduser with sudo:

$ sudo adduser your_username spi
Adding user `your_username' to group `spi' ...
Adding user your_username to group spi
Done.

Now, if we check in which group your user belongs to:

$ groups your_username
your_username : your_username adm cdrom sudo dip video plugdev input lpadmin gpio i2c spi sambashare

Tadaa, spi is here! Note that in order to work, you may have to reboot your Pi (or re-login).

Also, at any point, if you want to remove a user from a group – for example you want to remove access for a certain user without having to completely disable a hardware interface, you can do that with deluser:

$ sudo deluser your_username spi
Removing user `your_username' from group `spi' ...
Done.

Groups per hardware interface

You just saw how to add a user to a hardware group, and more specifically for SPI. Groups may vary depending on what hardware interface you want to use.

Here is a non-exhaustive list of the groups you’ll need to belong to if you need to use the associated hardware interface.

Also check out this Raspberry Pi pin description to know which hardware pins are related to which interface.

SPI

Add user to group “spi”: sudo adduser your_username spi.

I2C

Add user to group “i2c”: sudo adduser your_username i2c.

USB/Serial ports

This concerns USB devices that appear as /dev/ttyUSB0, /dev/ttyACM0, etc. Add your user to the “dialout” group: sudo adduser your_username dialout.

Hardware/Serial ports (RX/TX pins)

A quick warning before you continue. By default, from Raspberry Pi 3 and later, the “true” hardware UART, named PL011, has been re-wired for Bluetooth, letting a mini-uart available for Serial communication over UART pins. You can have a complete explanation here, but basically it means that by default, the UART you’re using has a not-so-great clock and performance.

To use the real UART for your RX/TX pins (this will disable Bluetooth), add dtoverlay=pi3-disable-bt into your /boot/config.txt file, and remove anything that looks like console=serial0,115200, console=tty1 in your /boot/cmdline.txt file. Then reboot and you should be able to use the real UART.

Once you’ve done this, you will be able to use the device named /dev/ttyAMA0. If you prefer keeping the Bluetooth interface, and use the mini-uart, then you’ll use the device named /dev/ttyS0.

Anyway, once you’ve setup that, you need to add your user to the “dialout” group: sudo adduser your_username dialout. This part is the same as for USB Serial ports.

GPIOs

Add your user to the “gpio” group: sudo adduser your_username gpio.

You might also have to check if /dev/gpiomem has the necessary permissions.

$ ls -l /dev/gpiomem
crw-rw---- 1 root gpio 244, 0 Dec 12 14:35 /dev/gpiomem

If not, execute those commands:

$ sudo chown root.gpio /dev/gpiomem
$ sudo chmod g+rw /dev/gpiomem

Give hardware permissions with udev rules

You may still encounter permission issues with hardware on your Raspberry Pi for various reasons. If your permissions reset after rebooting, or you need to use an unprivileged user, here’s another solution. You can make globally accessible hardware interfaces with a udev rule.

Note: try the steps in the previous sections of this tutorial before you do that. This may be “dangerous” if someone has access to your Raspberry Pi. They will be able to directly access hardware. If only you have access to your Pi then it should be ok.

Go into the /etc/udev/rules.d folder and add a new file named “local.rules”:

$ cd /etc/udev/rules.d/
$ sudo touch local.rules

Then, edit this file with admin rights (sudo), using whatever text editor you prefer – Vim, Nano, etc.

Add one line for each hardware interface you want to make available.

For example, for the “dialout” group, you should add ACTION=="add", KERNEL=="dialout", MODE="0666". With permission 0666, everyone will be able to read and write to this interface.

Here is an example of what your file could look like, with some of the hardware interfaces we saw previously.

ACTION=="add", KERNEL=="spidev0.0", MODE="0666"
ACTION=="add", KERNEL=="i2c-[0-1]*", MODE="0666"
ACTION=="add", KERNEL=="dialout", MODE="0666"
ACTION=="add", KERNEL=="ttyACM0", MODE="0666"
ACTION=="add", KERNEL=="ttyAMA0", MODE="0666"
ACTION=="add", KERNEL=="gpio", MODE="0666"

Only add the lines that you truly need! Don’t give permission for something you don’t use yet.

Once you’ve made some changes here, don’t forget to reboot, and it should work!

Raspberry Pi hardware permissions: conclusion

It can be quite tricky to setup Raspberry Pi hardware permissions, but once you’ve done it, you don’t need to worry about it anymore.

Just make sure that you understand (at least a little) what you’re doing when setting up permissions, and your Pi should be all right.

Did you find this tutorial useful?

Do you want to learn how to build awesome projects with Raspberry Pi?

If yes, this course is for you:

Raspberry Pi For Beginners - Complete Course

>> Raspberry Pi For Beginners <<