Best way to get elapsed milliseconds

I have a BBB Wireless running Linux beaglebone 4.14.108-ti-r106 #1 SMP PREEMPT Fri May 24 22:12:34 UTC 2019 armv7l GNU/Linux

I am writing in C.

I turn a valve on and then need to read some sensors for N milliseconds and then turn the valve off.

What’s the best way to read milliseconds on the BBBw? I don’t have a RTC on this particular unit but could add one using I2C. I have an Adafruit 4282 with a DS3231 RTC on it on another BBBw that I could use temporarily to prove it works. What other options are available?

Depending on how precise you need to be, I would go for the PRU-ICSS. They can control the GPIOs pretty easily.

The PRUs can give you 10’s of ns timing, which is more than good enough for milliseconds, but might be over kill.

I’d think using C on the ARM processor should be fast enough. I’d use gpiod[1].

If you really want the ns timing of the PRUs, check out the PRU Cookbook[2]


[1] GitHub - starnight/libgpiod-example: Examples for using libgpiod
[2] GitHub - MarkAYoder/PRUCookbook: This is a cookbook of the Programmable Realtime Unit on the BeagleBoard

I really don’t need ns. The valve ‘on time’ is going to be in the range of 500 ms to 2 seconds probably.

I will review the PRUCookbook! Thanks!


Hi Walter,

I don’t think you need an RTC for relative time. clock_gettime should do the job (

There are also more intuitive ways to manipulate timespec structs in the RCL (


You are correct that this application does not need to know the actual real time but only the relative (elapsed) time since the subroutine began. I’m familiar with clock_gettime but didn’t think it could give me subsecond information. I’ll explore it!




I got the latest PRUCookbook downloaded and when trying to make the hello.pru0.c program in 1.6, I got this error.

debian@beaglebone:/var/lib/cloud9/PRUCookbook/docs/02start/code$ make TARGET=hello.pru0
/var/lib/cloud9/common/Makefile:29: MODEL=TI_AM335x_BeagleBone_Black,TARGET=hello.pru0
- Stopping PRU 0
/bin/sh: 1: cannot create /dev/remoteproc/pruss-core0/state: Directory nonexistent
Cannot stop 0
CC hello.pru0.c
“/var/lib/cloud9/common/prugpio.h”, line 53: warning #1181-D: #warning directive: “Found am335x”
LD /tmp/cloud9-examples/hello.pru0.o
- copying firmware file /tmp/cloud9-examples/hello.pru0.out to /lib/firmware/am335x-pru0-fw
cp: cannot create regular file ‘/lib/firmware/am335x-pru0-fw’: Permission denied
/var/lib/cloud9/common/Makefile:180: recipe for target ‘install’ failed
make: *** [install] Error 1
rm /tmp/cloud9-examples/hello.pru0.o

Initially, I did not have a folder called /var/lib/cloud9/common. To remedy this I copied the contents of /var/lib/cloud9/PRUCookbook/docs/common to /var/lib/cloud9/common. Maybe this created a problem?Nevertheless, I found some other discussions that suggested updating the scripts and kernels from which I did. I am now running…

Linux beaglebone 4.14.108-ti-r137 #1stretch SMP PREEMPT Tue Aug 25 01:48:39 UTC 2020 armv7l GNU/Linux

And the output of is

debian@beaglebone:/$ sudo opt/scripts/tools/
[sudo] password for debian:
dogtag:[ Debian Image 2018-10-07]
bootloader:[microSD-(push-button)]:[/dev/mmcblk0]:[U-Boot SPL 2018.09-00002-g0b54a51eee (Sep 10 2018 - 19:41:39 -0500)]:[location: dd MBR]
bootloader:[microSD-(push-button)]:[/dev/mmcblk0]:[U-Boot 2018.09-00002-g0b54a51eee]:[location: dd MBR]
bootloader:[eMMC-(default)]:[/dev/mmcblk1]:[U-Boot SPL 2018.03-00002-gac9cce7c6a (Apr 05 2018 - 13:07:46 -0500)]:[location: dd MBR]
bootloader:[eMMC-(default)]:[/dev/mmcblk1]:[U-Boot 2018.03-00002-gac9cce7c6a]:[location: dd MBR]
UBOOT: Booted Device-Tree:[am335x-boneblack-uboot-univ.dts]
/boot/uEnv.txt Settings:
pkg check: to individually upgrade run: [sudo apt install --only-upgrade ]
groups:[debian : debian adm kmem dialout cdrom floppy audio dip video plugdev users systemd-journal i2c bluetooth netdev cloud9ide gpio pwm eqep admin spi tisdk weston-launch xenomai]
cmdline:[console=ttyO0,115200n8 bone_capemgr.uboot_capemgr_enabled=1 root=/dev/mmcblk0p1 ro rootfstype=ext4 rootwait coherent_pool=1M net.ifnames=0 quiet]
dmesg | grep remote
[ 1.147260] remoteproc remoteproc0: wkup_m3 is available
[ 1.231303] remoteproc remoteproc0: powering up wkup_m3
[ 1.231426] remoteproc remoteproc0: Booting fw image am335x-pm-firmware.elf, size 217168
[ 1.233981] remoteproc remoteproc0: remote processor wkup_m3 is now up
[ 108.634522] remoteproc remoteproc1: is available
[ 108.656634] remoteproc remoteproc2: is available
dmesg | grep pru
[ 108.019424] pruss 4a300000.pruss: creating PRU cores and other child platform devices
[ 108.634522] remoteproc remoteproc1: is available
[ 108.634642] pru-rproc PRU rproc node /ocp/pruss_soc_bus@4a326004/pruss@0/pru@34000 probed successfully
[ 108.656634] remoteproc remoteproc2: is available
[ 108.656808] pru-rproc PRU rproc node /ocp/pruss_soc_bus@4a326004/pruss@0/pru@38000 probed successfully
dmesg | grep pinctrl-single
[ 0.783913] pinctrl-single 44e10800.pinmux: 142 pins at pa f9e10800 size 568
dmesg | grep gpio-of-helper
[ 0.796624] gpio-of-helper ocp:cape-universal: ready
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

Any ideas?

I suggest updating to a new version of the SD card. It looks like the PRUs are getting started at boot time, but the path isn’t setup right. I think we setup some links so the path /dev/remoteproc/pruss-core0/state points to the right place.

You could also try:
cd /var/lib/cloud9
git pull
to update cloud9 folders.



git pull on /var/lib/cloud9 fails with 'fatal: Not a git repository (or any of the parent directories): .git

I’m such a neophyte on git. What do I need to do?

And, what do you mean by updating to a new version of the SD card? The OS is booting from the SD card and the information posted earlier is based on that.

On newer versions of the SD card image /var/lib/cloud9 is a git repo which you can do a git pull to update. Your version is too old.

Follow the instructions at: Getting Started
to download and install an updated version of the SD card image.


So you are saying that this version is too old?

Linux beaglebone 4.14.108-ti-r137 #1stretch SMP PREEMPT Tue Aug 25 01:48:39 UTC 2020 armv7l GNU/Linux

I asked because the ones on the page @ the link are older than the one I have installed.

Good point, it should work… I’m running a newer test image[1], but I took my Beagle home so I can’t do a quick check on it until later.


I’ll get this one onto an SD card and give it a try. If I can just get this configured I think I can make quick work of this problem!

I fired up the Beagle at home it the PRU works out of the box.

What do you get running
ls /dev/remoteproc

I get:

ls -ls /dev/remoteproc
total 0
0 lrwxrwxrwx 1 root root 33 Feb 17 17:26 pruss-core0 → /sys/class/remoteproc/remoteproc1
0 lrwxrwxrwx 1 root root 33 Feb 17 17:26 pruss-core1 → /sys/class/remoteproc/remoteproc2

If you are missing pruss-core0 and pruss-core1 you could try adding the links by hand and see what happens.

cd /dev/remoteproc
sudo ln -s /sys/class/remoteproc/remoteproc1 pruss-core0

sudo ln -s /sys/class/remoteproc/remoteproc2 pruss-core1

  The worst you may have to handle is the wrap-around in a long-running


With the current OS there isn’t a /dev/remoteproc even.

I’m going to try the updated OS build this morning.


Mark ,

It is working with the updated OS. Thanks so much!

Now I will explore how to get the simple timing that I need using the PRU.

I’ve gone through the cookbook and it’s very helpful.

I’m still fuzzy on how to do what I need to do.

My main code for controlling the valves, getting user input, etc. is in C.

I need to call a procedure in C that reads sensors. I will pass this procedure the number of milliseconds it should read the sensors and then return to the main program and turn the valves off. The number of milliseconds can, and will likely, change depending on what we are processing with these valves. I get that input at the start of the main program.

My thought is that in the procedure that reads the sensors, it will grab a start time (doesn’t have to be actual time) value from the PRU, read the sensors, and loop until the current time-start time equals the amount of time it should read the sensors. Then it will return to the main program.

I just don’t know how to read the PRU’s clock to get the time values. I don’t think I saw an example in the cookbook for ‘branching’ out from a main program to use the PRUs for this type of processing. Just point me in the right direction, please.


It’s good to hear you have the PRUs working. I still think if all you need is millisecond timing the PRUs are over kill.

In C you can use usleep() and pass it the number of microseconds you want to pause.