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.
Uncomment the line
dtparam=i2c_arm=on (if “off”, change to “on”).
Uncomment the line
dtparam=spi=on (if “off”, change to “on”).
Uncomment the line
dtparam=uart0=on or set
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
$ 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.
Add user to group “spi”:
sudo adduser your_username spi.
Add user to group “i2c”:
sudo adduser your_username i2c.
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=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.
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.