If you’re familiar with assembly code, the PRU’s instruction set should be fairly straightforward.
The instruction set is documented on the wiki and in the PRU reference manual (section 5).
The demonstration blink code uses register R1 to count the number of blinks (10) and register R0 to provide the delay between flashes.
The delay timing illustrates an important feature of the PRU: it is entirely deterministic.
Each instruction takes 5 nanoseconds (at 200 MHz).
There is no pipelining, branch delays, memory paging, interrupts, scheduling, or anything else that interferes with instruction execution.
This makes PRU execution predictable and suitable for real-time processing.
(In contrast, the main ARM processor has all the scheduling and timing issues of Linux, making it unsuitable for real-time processing.)
Since the delay loop is two instructions long and executes 0xa00000 times (an arbitrary value that gave a visible delay), we can compute that each delay is 104.858 milliseconds, regardless of what else the processor is doing.
(This is shown in the oscilloscope trace below.)
A similar loop on the ARM processor would have variable timing, depending on system load.
How do we know that pin P8_11 is controlled by bit 15 of R30?
We’re using one of the PRU output pins called “pr1_pru0_pru_r30_15”, which is a PRU 0 output pin controlled by R30 bit 15.
(Note that the PRU GPIO pins are separate from the “regular” GPIO pins.)
The BeagleBone header chart shows that this PRU I/O pin is connected to BeagleBone header pin P8_11.
To tell the BeagleBone we want to use this pin with the PRU, the device tree configuration is updated as discussed next.