Introduction
In this part of the series I’m going to show you how to write a very basic C Host-Application that will run a program on the PRU of the BBB. This part of the series assumes that you have basic C skills. I’ll also include some useful links to the official ti API. Everything can be done with the tools that come with the BBB. Code Composer Studio (CCS) oder Eclipse are not needed needed but you can use them, if you want to.
New kernel versions
Newer versions of the Linux kernel that runs on the BBB seem to use a different driver for accessing the PRU and the memory. If you are running into issues, for example when you can’t compile or run PRU applications, consider downgrading to an older version (3.8 seems to work fine) or take a look at this great guide which will show you, how to disable the newer drivers and use the older, simpler ones, instead.
The Host-Application
As I described above, we will need two seperate applications for this example. The host application will be written in C and it uses libraries provided by ti. Other ones for different languages are available (like PyPRUSS for python).
In this hello world example the host-application does just the minimum that is needed to load a program on the PRU and execute it:
#include <stdio.h>
#include <prussdrv.h>
#include <pruss_intc_mapping.h>
static int cleanUp(void)
{
// Disable PRU 0
prussdrv_pru_disable(0);
prussdrv_exit ();
return 0;
}
int main (void)
{
// Initialition structure used by prussdrv_pruintc_intc
// PRUSS_INTC_INITDATA is found in pruss_intc_mapping.h
tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA;
// Initialize the PRU Interrupt System prussdrv_init ();
prussdrv_open (PRU_EVTOUT_0);
prussdrv_pruintc_init(&pruss_intc_initdata);
// Load and execute the PRU program on the PRU (PRU 0)
// For PRU 1 write a 1 instead of the 0 as the first
// parameter
prussdrv_exec_program (0, "./pwm.bin");
// Now wait until the PRU messages the host
// That it finished executing the program
int n = prussdrv_pru_wait_event (PRU_EVTOUT_0);
printf("Pru ended. Event: %i\n", n);
// Disable PRU
return cleanUp();
}
The code is pretty simple and can also be found in ti’s API. Compile the code with:
gcc pwm.c -lprussdrv -lpthread -o pwm
This will create an executable output file called pwm.
The PRU Application
Now let’s discuss the program, that will run on the PRU. It is written in ARM assembler and I will compile it with pasm. I know that pasm will not longer be maintained by ti but it works and it’s an easy to use and light-weight tool for compiling, so I’ll use it as long as possible.
// Origin 0 defines the start of the program in the
// PRU's instruction RAM, entrypoint is for debugging
.origin 0
.entrypoint START
// The following macro defines a very simple delay function
// Because most (but not all!) instructions in the PRU take 5ns,
// we can wait quite precisely, but you could
// adapt this DELAY_NS function, if you needed even more accuracy. .macro DELAY_NS
.mparam wait_number
MOV r10, ((wait_number/10)-5)
DELAY:
SUB r10, r10, 1
QBNE DELAY, r10, 0
// This is obviously not the nice way,
// because you can easily miss r10 reaching 0,
// but it will work for this simple example.
.endm
// This macro sets an output pin low
// then waits for the LOWTIME (in ns)
// and then sets the pin high and waits
// again for HIGHTIME nanoseconds.
.macro SEND_R30_5_PULSE
.mparam LOWTIME, HIGHTIME
CLR R30.t5
DELAY_NS LOWTIME
SET R30.t5
DELAY_NS HIGHTIME
.endm
// Define constants for host notification
#define PRU0_R31_VEC_VALID 32
#define PRU_EVTOUT_0 3
// Entrypoint
START:
// Store 100000 to register 0
// This value will be used for a loop
MOV r0, 100000
// Jump to the label called 'RUN'
QBA RUN
// This section sends one pulse
// then subtracts 1 from the loop counter (r0)
// and repeats this until the loop counter is 0
// the program terminates afterwards
RUN:
// Send out one pulse
SEND_R30_5_PULSE 18450, 26540
// Subtract 1 from the loop counter
SUB r0, r0, 1
// Jump to 'RUN' if the loop counter is not
// equal to 0
QBNE RUN, r0, 0
// Jump to 'END' if the loop counter is 0
QBEQ END, r0, 0
// Notifies the Host-Program that the PRU-Application
// has finished and halts the PRU (Don't forget to
// halt the PRU at the end of your code, otherwise
// it could stall and you'll need to restart your BBB
// to use it again!)
END:
MOV R31.b0, PRU0_R31_VEC_VALID | PRU_EVTOUT_0 HALT
At first, this looks like a lot of code but I tried my best commenting it properly. Just one thing: By setting the bit 5 of register 30 high or low (CLR R30.t5 and SET R30.t5), the output pin (P9_27), we defined in the device tree overlay gets set high or low. This is possible because of the PRU’s so called magic registers, where R30 is for outputs and R31 is for inputs (Take a look at the pinmux table I showed you in the last part. What name does the pin have in mode5?). You can get more information about these in the TRM.
If you are completely new to assembler programming, the instructions might be new for you. But don’t worry, the PRU has a rather small instruction set. You can find a link with all available instructions at the end of this article!
Unfortunately, the default instruction set doesn’t include a NOP, which could be used to wait 5ns. However you can easily create a macro yourself:
.macro NOP
ADD r21, r21, 1
.endm
However, the NOP is not really needed for this example.
Now you just have to compile the code from above:
pasm -b pwm.p
This will create a little endian encoded file, that the host-program can send to the PRU and execute it.
The output
So let’s run the program and take a look at the results:
./pwm
You can make the output visible with an oscilloscope:

Or by using an LED on a breadboard, or by adapting the above example, so that the output goes to one of the USR-LEDs on the BBB, instead of a GPIO-Pin!
Where to go from here?
You could change the above code to output the signal directly to one of the BBB User-LEDs. You could also build your own wave-form generator with variable frequencies by using the BBB analog inputs. Be creative!
Hopefully I got you up and running with the PRU so you can start using it in your own projects! Post your PRU project idea in the comment section and share it with other readers!
Further readings
ti Linux Application Loader API
ti PRU-Assembler instructions (API)
A good article about ARM-Assembler
Official ARM assembly instructions page (API)
Another PRU tutorial
Table of contents
Part 0 – Introduction
Part 1 – About device trees and overlays
Part 2 – Programming (You are here)

Nice. Thanks!
LikeLiked by 2 people
It’s a bit late but you’re welcome! 🙂
LikeLike
Really nice article! You earned a new follower. Really looking forward to seeing more great tutorials and especially projects/builds!
LikeLiked by 3 people
I’m glad you like my articles! There are several projects I’m working on right now and I plan to release a new article this week.
LikeLike
I really like your articles. I created an account on wordpress just to follow you lol, so you better keep up the good work! 😀
LikeLiked by 2 people
Wow that’s very kind! You can also follow us just by entering your email address, you’ll then get email updates without having a wp account. Cheers!
LikeLike
Are macros are like methods in this assembly language? Because you call them in the code?
LikeLiked by 2 people
A macro is a series of instructions you can easily place in different lines of your code. They help you to organize your code. So they are sort of like methods (the can have methods too, but no return values), but as far as I know when you invoke the macro, the macro’s code is simply substituted to the position you called it at. However they help keeping your code organized.
Read more about macros here:
http://processors.wiki.ti.com/index.php/PRU_Assembly_Advanced_Topics#Using_Macros
LikeLiked by 1 person
Hello dear Sir!
Thanks so much for giving these informations to me. It really helped me in my project. Have a good day.
LikeLiked by 1 person
Wow man thanks a lot!! Finally a working example and a good written article!
LikeLiked by 1 person
You are welcome! Don’t forget to tell your friends about it and to subscribe to my blog, so you don’t miss any articles.
LikeLike
Nice series. Evrything works perfect for me
LikeLiked by 2 people
I’m glad you liked it! 🙂
LikeLike