prussdrv_open fails when a service is starting during boot but works when started manually

I’m trying to get a c++ application to load PRU firmware during the boot process using uio.

If I start the service manually (i.e. systemctl start ) it works fine. When I enable the service to load on boot, it fails consistently on the call to prussdrv_open(). I tried setting the systemd unit definition so it would start after specific services (i.e. cloud9), but this didn’t help. I also tried repeating the call to prussdrv_open() in a loop with a 250msec sleep.

Any suggestions would very welcome!
Thanks!
Andy

Here are details about my current configuration:

prussdrv_open() usually fails when the devices (/dev/uio[0-7]) are not accesible.

It takes some time before the uio_pruss driver is up and the devices are ready. So make sure:

  • the devices are present
  • your software has read/write access during boot process

Thanks for the quick response!

  • Is there a way to configure the systemd unit so that my service won’t start until the uio_pruss driver is ready for use (or some other method)?

  • I logged the value of geteuid() at the beginning of my application to verify that it was a 0. Is there another type of read/write permission I need to be checking?

If there are any guides to configuring a beagle board (any flavor) to boot to an application that uses the PRU via uio_pruss, please let me know. I wanted to start by setting up the pocketbeagle so that it boots to a simple example application (i.e. EBB chp13 PWM example).

Sorry for the dumb questions! I’m new to linux and there are obviously some key concepts I’m missing.

Thanks,
Andy

Hi Andy!

  • Is there a way to configure the systemd unit so that my service won’t start until the uio_pruss driver is ready for use (or some other method)?

I use a bash script (called by systemd) that loads the driver (in case of custom settings), wait for the socket nodes and starts the final programm (solar-regler in this case):

`
#!/bin/sh -e

load PRU kernel driver and device tree overlay and

start contoller (Jessie)

uio=/dev/uio5

uncomment to specify ERam size (max. 0x800000, default is 0x40000)

#modprobe uio_pruss extram_pool_sz=0x100000

load device tree overlay

echo solar > /sys/devices/platform/bone_capemgr/slots

wait until kernel driver created the socket nodes

until test -e ${uio}; do sleep 1; done

start controller

/usr/local/bin/solar-regler &

`

The script is named solar-regler.sh and gets invoked by a systemd service, looking like

`
[Unit]
Description=Load solar overlay, start controller (/etc/default/solar-regler.sh)

[Service]
Type=oneshot
ExecStart=/etc/default/solar-regler.sh
StandardOutput=tty
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

`

If there are any guides to configuring a beagle board (any flavor) to boot to an application that uses the PRU via uio_pruss, please let me know. I wanted to start by setting up the pocketbeagle so that it boots to a simple example application (i.e. EBB chp13 PWM example).

In 4.x kernel versions the boot process changed a lot, bad documentation and many bugs. The kernel developers prefer the rpmsg driver, uio_pruss is not well supported. So from my point of view 4.x kernels are still experimental (at least in case of PRU support). For better documentation switch back to the latest 3.8 kernel version.

Regards

Thanks very much for sharing the script and advice!

I’ve been tempted to run with a 3.x kernel in the past because it does seem that many of the tutorials, books, etc were based on that. I do like the universal cape approach in the recent builds and it seems easier to work with the uEnv.txt configuration. The rproc approach has a lot of nice features but I think the uio_pruss driver still seems to be a better choice when only a simple interface is needed.

One thing that still confuses me is the fact that I tried putting the call to prussdrv_open() in a loop until it didn’t return an error (250ms delay between attempts). I let it try for hundreds of seconds but it never succeeded. However, if I started the service from a shell (non-root), it worked on the first try. It seems like more of a permissions issue, but I’m not sure what’s missing.

Because of time constraints, I ended up switching to an ESP32 instead of the pocketbeagle for the project I’m working on (the ~2 minute boot time was also a concern). When I get a moment, I’ll try again to figure out how to get my service to wait for the right moment to run and/or have the right permissions.