We have been working on a Python application that uses Adafruits GPIO library.
We are using Systemd to start our program, and Systemd is set to execute as a user which is a member of the GPIO group.
Now, the problem is when our program starts to early in the boot process, we get a permission denied
trying to setup the GPIO pin mode (input/output).
If we delay program startup long enough, some service or udev rule will eventually get arround to setting the permission, and our program is able to control GPIO’s just fine.
Looking into the /opt/scripts/boot/generic-startup.sh, reveals that some group permissions for GPIO are applied here:
I think most of the permission attributes are set in /etc/udev/rules.d/*.
P.S. You can search that dir. and all the files in it, specifically gpio, to figure out how things are situated on the filesystem in Linux for the beagleboard.org images. I am not sure about the sequence of what boots first in the image you are using.
Thanks, we have been looking at the rules.d scripts.
As the GPIO’s are “created” by the device tree, my guess is that the udev rules are not triggered since no new hardware has been detected, and that must be why setting permissions are done in the generic-startup script.
I might be wrong ?
Robert is right, it becomes very blurry to determine when udev rules are applied.
Enabling udev_log=debug in /etc/udev/udev.conf, and analyzing journald or syslog,
does show a lot of information (udev is very busy…)
Early in the boot process systemd-udev-trigger.service is executed, it’s my understanding that this will make udev rules apply to already existing devices (such as GPIOs). I imagine it traverses the device tree, and this takes time !
In our case, from udev detecting/queuing the first GPIO entry until the last GPIO udev rule has been applied, takes arround 50s.
It also seems like udev has a maximum queue size, which also could influence processing time.
this line is seen throughout syslog, many times:
systemd-udevd: Maximum number (10) of children reached.
I have not found a way, to determine when udev is done traversing all installed hardware.
Our objective is to make sure that our services are able to start correctly, when being started by systemd.
Currently we added force setting GPIO permissions manually, in a bash script (similar to generic-board.startup), and have our other services start hereafter.
Udev will get arround to setting the same permissions, but only a bit later …
Seth here. Um, he is usually right for whatever reason. Outside of that idea, are you building your own image or relying on the beagleboard.org images?
I ask b/c there are many ideas so far that help people enable a quicker boot time on the am335x boards like the BBB, BBG, and so on.
I cannot remember the actual post. It is too bad I did not doc. it.
P.S. There may even be an older couple of ideas on the blog. Let me link you to the blog after I review the content. It may help in a quick boot time if this can help you start your services quicker b/c of the lack of overhead and strong, heavy repos: Beagle Board Blog | Learn More about the lastes News and content will show some ideas for using u-boot to handle booting into Linux and the distro w/ the required .dtbo file or .dtb depending on the actual use case.
At the moment we are using the official IOT image.
We did think about going the Yocto way, but time was critical, so we decided to focus on our application
rather than building everything from scratch at this point.
At the moment our boot time is app. 1min, which is I believe to be expected.
Im sure there are nuances to your case that I’m not aware of, but it would be pretty pythonic to simply handle the IO exception gracefully in the app, and retry accessing the gpio fd until the stat call is successful.
You could also consider a pre-start routine in your unit file to wait for permissions to change before starting your service. Something like ExecStartPre=/bin/bash -c '(while ! sudo -u gpio_user test -w /gpio/dir/or/file; do echo "Waiting for GPIO permissions update..."; sleep 2; done); sleep 1'