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:
So we decide to start our programs after generic_startup.sh
This however was not enough to set a GPIO input modes ! so we had to add into generic-startup.sh
Now this works !
But my question is, these permission is somehow set by another service later on in the Systemd startup process, but we have not been able to pinpoint when or where ?
Can anybody here shed some light on the sequence in which permissions are being applied ?
I think most of the permission attributes are set in /etc/udev/rules.d/*.
Seth
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 ?
This is what I found. There is a command further down the page on that link of freedesktop.org on their wiki page of FAQ.
Seth
P.S. Also: TipsAndTricks has some ideas. It seems it is not so easy to establish what is booted and when unless you can figure it out. Right. Right. Right.
$ systemd-cgls and man, not the man pages, it just keeps getting more difficult. I found a page that may interest you for starting .service files after boot is done: NetworkTarget .
I cannot find a way to figure out how to account for the boot (YET).
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[821]: 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.
Seth
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.
Anyway, they were saying scratch to 45 seconds to boot. Something like that idea. But, if found, one could switch out the toolchain, u-boot versioning, and kernel used. Just an idea.
I would poll the gpio files you need to access to check for ownership when your program runs. Then as soon as the ownership is set, you can continue running your software.
Probably add some sort of timeout to log an error and quit if the ownership doesn’t change within a given time.
In Python if you use pathlib you can get the owner and group of a file.
from pathlib import Path
path = Path("/path/to/your/file")
owner = path.owner()
group = path.group()
just check for group to equal ‘gpio’
I would not poll too quickly, every couple of seconds. Doing this allows for any random delays when booting.
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'