First Experiences with Beaglebone Black, Hard Real Time and Parallax Ping))) Sensor
Parallax Ping))) is a distance sensor that requires accurate time measurement of response signal. The duration of this signal is the distance measured. However, as Linux is not a hard-real time operating system, getting a simple measurement from Parallax Ping)) presents a problem.
Parallax Ping))) has a simple protocol that requires only one connection for both request and response. The request is a pulse of 2-5 usecs, while the response pulse length is the distance measured.
On Linux, this is tricky.
First, in user space, it is difficult to get the scheduler predictability right. This might be minimized by running the application thread in one of the real time schedulers (SCHED_FIFO, SCHED_RR) and also augment this with rt-linux kernel patches or at least increasing the linux kernel preempt level. However, even in high spec machines these tricks do not guarantee latency below 10 usec. In other words, it's possible for the process to get swapped out in the middle of these measurements only to get scheduled back again after x usecs (or even msecs without rt-linux.)
Second, even in kernel space, the interrupt latency is too great to accurately measure these results. I think these issues could perhaps be overcome by approximations via multiple measurements, estimating interrupt latency, handling the interrupt in top-halves, or perhaps registering this interrupt at a higher priority then others. There are some opportunities to investigate and experiment in kernel space.
Beaglebone Black provides two PRU units at 200Mhz giving us 5 usec instructions. These processing units are specifically designed to provide predictable instruction latency. In other words, they are hard real time.
One important gotcha is the fact that Beaglebone Black digital pins use 3.3 volts while Parallax Ping)) operates higher at 5.0 volts. I've overcome this difficulty by using a cheap bi-directional level shifter. This is important since 5.0 volts can fry beaglebone black ports or if you are unlucky the beaglebone black itself. :-(
Also on Linux, it's not very quick to swap I/O mode (input to/from output) on GPIO. Especially on user-space, this requires expensive sysfs operations. On PRU, I have not investigated this. Instead, I've split the Ping)) I/O pin into two via resistor and used two I/O pins directly accessible from PRU.
As usual, first step is to get the device tree blob right. I've hacked one of the BB-BONE-PRU dts files and added my I/O pins there and enabled this on the cape manager.
For PRU coding, you have two basic options:
1) Use Texas Instruments IDE / compiler / tools and code it in C.
2) Use pruss compiler from TI, but code in Assembly.
Since my task at hand was simple, I chose Assembly. Also I did not want to use another IDE. I'm really happy with sublime text and if not, good old vi. The PRU instruction set is limited to about 40 instructions, so assembly coding was actually easier than I thought.
This whole process took some days to learn and experiment. But an incredibly rewarding experience. With its reasonable price tag, Beaglebone Black is hackers dream come true.
For sample code: https://github.com/skinowski/bb_pru_parallax_sonar











