BeagleBone Black programmable realtime unit (PRU) Hello World – Part 2

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, no Code Composer Studio (CCS) oder Eclipse needed, but you can use them, if you want to.

The Host-Application

As I described above, we will need two seperate applications for this example. The host application will be written in C, using libraries provided by ti. Other libraries for other 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)
{
	// Initialize 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 here 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.
Now compile the above code with:

gcc pwm.c -lprussdrv -lpthread -o pwm

This will create an executable output file called pwm.

The PRU Application

Now let’s look at 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 is an easy to use and light-weight tool for compiling, so I’ll stick to 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

// Here I define a macro for sleeping
// Because one instruction in the PRU takes 5ns
// we can wait very precisely, but you could
// adapt this DELAY_NS, if you need even more
// accuracy.
.macro DELAY_NS
.mparam	wait_number
    MOV r10, ((wait_number/10)-5)
    DELAY:
        SUB r10, r10, 1
        QBNE DELAY, r10, 0
.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 out one pulse,
// then subtracts 1 from the loop counter (r0)
// and repeats this until the loop counter is 0
// the program is ended 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
        // equals 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

This looks like a lot of code on the first sight, but I’ve tried my best commenting it properly, so the most of it are actually comments. 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 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 assembly 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!

Now you just have to compile the above code:

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 look at the results:

./pwm

You can make the output visible with an oscilloscope:

pru_wavegen_output

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!

Further steps

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)

comment-banner

Advertisements

19 thoughts on “BeagleBone Black programmable realtime unit (PRU) Hello World – Part 2

      1. I really like your articles. I created an account on wordpress just to follow you lol, so you better keep up the good work! 😀

        Liked by 2 people

      2. 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!

        Like

    1. 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

      Liked by 1 person

Leave your two cents, comment here!

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s