Using the second PRU for your own code
The Bela environment uses one of the Programmable Real-time Units (PRUs) on the BeagleBone Black to handle the data transfer to and from the analog, digital and audio pins. The BeagleBone Black has two PRUs, leaving the second one free for your use!
This example shows a simple GPIO sketch running on the second PRU, with communication back to the main CPU. Because the 16 GPIOs used for the Bela digital pins are already in use by the first PRU, we need to choose a different pin for this example. In this case, GPIO 30 is used as an output to drive an LED.
To run this example, attach a resistor and LED in series between GPIO 30 and ground. You should see the LED blink progressively faster, and when it becomes fast enough that it cannot be seen blinking anymore, it resets to its original speed.
The PRU code for this exmaple can be found in pru_gpio.p. You need the program "pasm" (PRU assembler) from the TI prussdrv library to compile it. The compiled version is found in pru_gpio_bin.h. Which PRU this code runs on depends on which PRU is used by Bela. This can be selected by passing the –pru-number flag to Bela; e.g. –pru-number=1 makes Bela use PRU 1 for its core code, leaving PRU 0 for the user code.
#include <GPIOcontrol.h>
#include <cmath>
#include "prussdrv.h"
#include "pruss_intc_mapping.h"
#include "pru_gpio_bin.h"
#define PRU_COMM_USER_DELAY 0
uint32_t *gPRUCommunicationMem = 0;
int gpioNumber0 = 30;
float gFrequency = 440.0;
float gPhase;
float gInverseSampleRate;
int gUpdateCount = 0;
int64_t gPeriodNS = 500000000LL;
bool load_pru(int pru_number);
bool start_pru(int pru_number);
void set_period(uint64_t period_ns);
int gPruNumber;
{
gPruNumber = 1;
else
gPruNumber = 0;
}
{
if(gpio_export(gpioNumber0)) {
printf("Warning: couldn't export GPIO pin %d\n", gpioNumber0);
}
if(gpio_set_dir(gpioNumber0, OUTPUT_PIN)) {
printf("Warning: couldn't set direction on GPIO pin\n");
}
if(!load_pru(gPruNumber)) {
printf("Error: could not initialise user PRU code.\n");
return false;
}
set_period(gPeriodNS);
if(!start_pru(gPruNumber)) {
printf("Error: could not start user PRU code.\n");
return false;
}
gPhase = 0.0;
return true;
}
{
for(
unsigned int n = 0; n < context->
audioFrames; n++) {
float out = 0.8 * sinf(gPhase);
gPhase += 2.0f * (float)M_PI * gFrequency * gInverseSampleRate;
if(gPhase > M_PI)
gPhase -= 2.0f * (float)M_PI;
}
if(++gUpdateCount >= 1024) {
gUpdateCount = 0;
gPeriodNS -= 1000000LL;
if(gPeriodNS <= 0)
gPeriodNS = 500000000ULL;
set_period(gPeriodNS);
}
}
}
{
if(gpio_unexport(gpioNumber0)) {
printf("Warning: couldn't unexport GPIO pin %d\n", gpioNumber0);
}
prussdrv_pru_disable(gPruNumber);
}
bool load_pru(int pru_number)
{
void *pruMemRaw;
uint32_t *pruMemInt;
if(prussdrv_open(PRU_EVTOUT_1)) {
rt_printf("Failed to open user-side PRU driver\n");
return false;
}
prussdrv_map_prumem(PRUSS0_SHARED_DATARAM, (void **)&pruMemRaw);
pruMemInt = (uint32_t *)pruMemRaw;
gPRUCommunicationMem = &pruMemInt[0x800/sizeof(uint32_t)];
return true;
}
bool start_pru(int pru_number)
{
if(prussdrv_exec_code(pru_number, PRUcode, sizeof(PRUcode))) {
rt_printf("Failed to execute user-side PRU code\n");
return false;
}
return true;
}
void set_period(uint64_t period_ns)
{
uint64_t delay = period_ns / 20ULL - 20;
gPRUCommunicationMem[PRU_COMM_USER_DELAY] = (uint32_t)delay;
}