I finally got my Beaglebone Black PRU C code project up and going.
It took a lot of googling and posting, but I thought it would be nice to post a condensed version of the notes needed to get C code running on the BBB PRU.
This is targeting Debian 3.8 kernel versions.
------------------------------------------------------------------------------
Possible PRU pin mappings + values for device tree building + BBB conflict pins
------------------------------------------------------------------------------
Bit pr1_pru0_pru_r30_? (out)
0 P9_31, gpio3[14], 0x190 , Mode 6
1 P9-29, gpio3[15], 0x194, Mode 6
2 P9-30, gpio3[16], 0x198, Mode 6 (HDMI, LCD)
3 P9-28, gpio3[17], 0x19c, Mode 6
4 P9-42, gpio3[14], 0x1a0, Mode 6
5 P9-27, gpio3[19], 0x1a4, Mode 6 (HDMI, LCD)
6 P9-41, gpio3[20], 0x1a8, Mode 6
7 P9-25, gpio3[21], 0x1ac, Mode 6
8
9
10
11
12
13
14 P8-12, gpio1[12], 0x030, Mode 6
15 P8-11, gpio1[13], 0x034, Mode 6
Bit pr1_pru0_pru_r31_? (in)
0 P9-31, gpio3[14], 0x190, Mode 5
1 P9-29, gpio3[15], 0x194, Mode 5
2 P9-30, gpio3[16], 0x198, Mode 5 (HDMI, LCD)
3 P9-28, gpio3[17], 0x19c, Mode 5
4 P9-42, gpio3[14], 0x1a0, Mode 5
5 P9-27, gpio3[19], 0x1a4, Mode 5
6 P9-41, gpio3[20], 0x1a8, Mode 5
7 P9-25, gpio3[21], 0x1ac, Mode 5
8
9
10
11
12
13
14 P8-16, gpio1[14], 0x038, Mode 6
15 P8-15, gpio1[15], 0x03c, Mode 6
16 P9-24, gpio0[15], 0x0184, Mode 6 (HDMI, LCD)
16 P9-41, gpio3[20], 0x164, Mode 5
Bit pr1_pru1_pru_r30_? (out)
0 P8-45, gpio2[6], 0x0a0, Mode 5 (HDMI, LCD)
1 P8-46, gpio2[7], 0x0a0, Mode 5 (HDMI, LCD)
2 P8-43, gpio2[8], 0x0a8, Mode 5 (HDMI, LCD)
3 P8-44, gpio2[9], 0x0ac, Mode 5 (HDMI, LCD)
4 P8-41, gpio2[10], 0x0b0, Mode 5 (HDMI, LCD)
5 P8-42, gpio2[11], 0x0b4, Mode 5 (HDMI, LCD)
6 P8-39, gpio2[12], 0x0b8, Mode 5 (HDMI, LCD)
7 P8-40, gpio2[13], 0x0bc, Mode 5 (HDMI, LCD)
8 P8-27, gpio2[22], 0x0e0, Mode 5 (HDMI, LCD)
9 P8-29, gpio2[23], 0x0e4, Mode 5 (HDMI, LCD)
10 P8-28, gpio2[24], 0x0e8, Mode 5 (HDMI, LCD)
11
12 P8-21, gpio1[30], 0x080, Mode 5 (HDMI, LCD)
13 P8-20, gpio1[31], 0x084, Mode 5 (HDMI, LCD)
14
15
16
Bit pr1_pru1_pru_r31_? (in)
0 P8-45, gpio2[6], 0x0a0, Mode 6 (HDMI, LCD)
1 P8-46, gpio2[7], 0x0a0, Mode 6 (HDMI, LCD)
2 P8-43, gpio2[8], 0x0a8, Mode 6 (HDMI, LCD)
3 P8-44, gpio2[9], 0x0ac, Mode 6 (HDMI, LCD)
4 P8-41, gpio2[10], 0x0b0, Mode 6 (HDMI, LCD)
5 P8-42, gpio2[11], 0x0b4, Mode 6 (HDMI, LCD)
6 P8-39, gpio2[12], 0x0b8, Mode 6 (HDMI, LCD)
7 P8-40, gpio2[13], 0x0bc, Mode 6 (HDMI, LCD)
8 P8-27, gpio2[22], 0x0e0, Mode 6 (HDMI, LCD)
9 P8-29, gpio2[23], 0x0e4, Mode 6 (HDMI, LCD)
10 P8-28, gpio2[24], 0x0e8, Mode 6 (HDMI, LCD)
11
12 P8-21, gpio1[30], 0x080, Mode 6 (HDMI, LCD)
13 P8-20, gpio1[31], 0x084, Mode 6 (HDMI, LCD)
14
15
16 P9-26, gpio1[29], 0x180, Mode 6
------------------------------------------------------------------------------
Beaglebone Black Kernel 3.8 Device Tree Overlay - map GPIO pins directly to PRU R30 or R31
Create overlay file /lib/kernel/myoverlay-00A0.dts using contents below.
Compile using device tree compiler (dtc):
#sudo apt-get install device-tree-compiler
#sudo dtc -O dtb -o /lib/firmware/myoverlay-00A0.dtbo -b 0 -@ /lib/firmware/myoverlay-00A0.dts
Modify cape manager file in /etc/default/capemgr to load overlay during boot:
#sudo nano /etc/default/capemgr
CAPE=myoverlay
Edit /etc/modules and append text
#sudo nano /etc/modules
uio_pruss
------------------------------------------------------------------------------
/dts-v1/;
/plugin/;
/ {
compatible = "ti,beaglebone", "ti,beaglebone-black";
/* identification */
part-number = "MYOVERLAY";
version = "00A0";
/* state the resources this cape uses */
exclusive-use =
// PRU resources used
"pruss",
"pru0",
// PRU Input pins
"P8.16","pr1_pru0_pru_r31_14", // PIN Name and the PRU port it maps to (see table above)
// PRU Output pins
"P9.31","pr1_pru0_pru_r30_0";
// MUX Bit Maps:
// 0x40 = slow slew (0 = fast slew)
// 0x20 = input (0 = output)
// 0x10 = pullup, 0x08 = disabled (0 = pulldown)
// 0x01 to 0x07 = mode 1 to 7
fragment@8 {
target = <&am33xx_pinmux>;
__overlay__ {
pruss_pins: pruss_pins {
pinctrl-single,pins = <
0x038 0x36 // P8_16, gpio3[14] mode 6, input pull-up
0x190 0x15 // P9_31 gpio1[19] mode 5, output, pull-down
>;
};
};
};
fragment@10 {
target = <&pruss>;
__overlay__ {
status = "okay"; // This enables the PRU
pinctrl-names = "default";
pinctrl-0 = <&pruss_pins>; // This uses our custom mapping (see above definition)
// This is for documentation only. You can see the pin mappings by:
// sudo cat /sys/kernel/debug/gpio
any_name1 { // Grouping of pins under this name
pin-names = "Input pin description"; // one name per pin defined in gpios. Multiple entries are comma seperated;
gpios = <&gpio4 14 1>; // &gpio? (One based: 1-4 instead of 0-3) bit(0-31) input(1)/output(0). Multiple entries seperated by a space
};
any_name2 {
pin-names = "Output pin description";
gpios = <&gpio2 19 0>;
};
};
};
};
------------------------------------------------------------------------------
PRU C Code – compile using clpru & hexpru
------------------------------------------------------------------------------
// C library Installed by: apt-get install am335x-pru-package ti-pru-cgt-installer
#include <stdint.h>
// PRU support libraries Installed from home directory with: git clone git://
git.ti.com/pru-software-support-package/pru-software-support-package.git pru_support
#include <pru_cfg.h>
#define PRU0_ARM_INTERRUPT 19 // Interrupt used to signal to host we have halted
volatile register uint32_t __R30; // Output pins
volatile register uint32_t __R31; // Input pins
// Mapping Constant table register to variable
volatile pruCfg CT_CFG __attribute__((cregister("CFG", near), peripheral)); // PRU CFG register pointer loaded from constants table (see lnk.cmd)
int main(void) {
// Enable OCP master ports - this enables pinmux pins to R30 & R31 & host ram access (all the BBB GPIO ports & such)
CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;
// Do work - write your code here
// Signal the process has completed (this will wake up the loader to tell it work is done)
__R31 = (__R31 & ~0xff) | (PRU0_ARM_INTERRUPT+16);
return 0;
}
------------------------------------------------------------------------------
lnk.cmd – linker command file defines physical address mappings
------------------------------------------------------------------------------
-cr
-stack 0x100
-heap 0x100
MEMORY
{
PAGE 0:
PRUIMEM : org = 0x00000000 len = 0x00002000 /* 8kB PRU0 Instruction RAM */
PAGE 1:
PRUDMEM : org = 0x00000000 len = 0x00002000 /* 8kB PRU Data RAM 0 */
SHAREDMEM : org = 0x00010000 len = 0x00003000 /* 12kB Shared RAM */
PRU0_CTRL : org = 0x00022000 len = 0x00000030
PRU1_CTRL : org = 0x00024000 len = 0x00000030
/* Constant Table Memory directives. */
INTC : org = 0x00020000 len = 0x00001504 CREGISTER=0
DMTIMER2 : org = 0x48040000 len = 0x00000100 CREGISTER=1
I2C1 : org = 0x4802A000 len = 0x00000100 CREGISTER=2
ECAP : org = 0x00030000 len = 0x00000100 CREGISTER=3
CFG : org = 0x00026000 len = 0x00000100 CREGISTER=4
MMCHS0 : org = 0x48060000 len = 0x00000100 CREGISTER=5
MCSPI0 : org = 0x48030000 len = 0x00000100 CREGISTER=6
UART0 : org = 0x00028000 len = 0x00000100 CREGISTER=7
MCASP0_DMA : org = 0x46000000 len = 0x00000100 CREGISTER=8
GEMAC : org = 0x4A100000 len = 0x00000100 CREGISTER=9
RSVD10 : org = 0x48318000 len = 0x00000100 CREGISTER=10
UART1 : org = 0x48022000 len = 0x00000100 CREGISTER=11
UART2 : org = 0x48024000 len = 0x00000100 CREGISTER=12
RSVD13 : org = 0x48310000 len = 0x00000100 CREGISTER=13
DCAN0 : org = 0x481CC000 len = 0x00000100 CREGISTER=14
DCAN1 : org = 0x481D0000 len = 0x00000100 CREGISTER=15
MCSPI1 : org = 0x481A0000 len = 0x00000100 CREGISTER=16
I2C2 : org = 0x4819C000 len = 0x00000100 CREGISTER=17
EHRPWM1 : org = 0x48300000 len = 0x00000100 CREGISTER=18
EHRPWM2 : org = 0x48302000 len = 0x00000100 CREGISTER=19
EHRPWM3 : org = 0x48304000 len = 0x00000100 CREGISTER=20
MDIO : org = 0x00032400 len = 0x00000100 CREGISTER=21
MBX0 : org = 0x480C8000 len = 0x00000100 CREGISTER=22
SPINLOCK : org = 0x480CA000 len = 0x00000100 CREGISTER=23
/* PRU0_1 : org = 0x00000000 len = 0x00000100 CREGISTER=24
PRU1_0 : org = 0x00000000 len = 0x00000100 CREGISTER=25 */
IEP : org = 0x0002E000 len = 0x0000031C CREGISTER=26
/* MII_RT : org = 0x00032000 len = 0x00000100 CREGISTER=27
SHARED_RAM : org = 0x00000000 len = 0x00000100 CREGISTER=28 */
TPCC : org = 0x49000000 len = 0x000010A0 CREGISTER=29
L3OCMC : org = 0x40000000 len = 0x00010000 CREGISTER=30
DDR : org = 0x80000000 len = 0x00000100 CREGISTER=31
}
SECTIONS {
/* Forces _c_int00 to the start of PRU IRAM. Not necessary when loading
an ELF file, but useful when loading a binary */
.text:_c_int00* > 0x0, PAGE 0
.text > PRUIMEM, PAGE 0
.stack > PRUDMEM, PAGE 1
.bss > PRUDMEM, PAGE 1
.cio > PRUDMEM, PAGE 1
.data > PRUDMEM, PAGE 1
.switch > PRUDMEM, PAGE 1
.sysmem > PRUDMEM, PAGE 1
.cinit > PRUDMEM, PAGE 1
.rodata > PRUDMEM, PAGE 1
.rofardata > PRUDMEM, PAGE 1
.farbss > PRUDMEM, PAGE 1
.fardata > PRUDMEM, PAGE 1
.PRU0_CTRL > PRU0_CTRL, PAGE 1
.resource_table > PRUDMEM, PAGE 1
}
------------------------------------------------------------------------------
bin.cmd – used by hexpru to generate text.bin and data.bin
------------------------------------------------------------------------------
-b
-image
ROMS {
PAGE 0:
text: o = 0x0, l = 0x1000, files={text.bin}
PAGE 1:
data: o = 0x0, l = 0x1000, files={data.bin}
}
------------------------------------------------------------------------------
Compile command:
------------------------------------------------------------------------------
clpru -i /usr/share/ti/cgt-pru/lib -i ~/pru_support/include -i . --endian=little --define am3359 --define pru0 --silicon_version=3 -o1 source.c -z lnk.cmd -o source.out -m source.map
hexpru bin.cmd pru_cblink.out
------------------------------------------------------------------------------
pru_loader.c – host side code to load the text.bin image to pru 0. Compile with: gcc -o pru_loader pru_loader.c -lprussdrv
Run from linux command prompt to deploy text.bin to PRU 0 and run it (text.bin must be in the current directory)
------------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <prussdrv.h>
#include <pruss_intc_mapping.h>
#define PRU_NUM 0
#define AM33XX
int main (int argc, char **argv)
{
unsigned int ret;
tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA;
/* Initialize the PRU */
prussdrv_init ();
/* Open PRU Interrupt */
ret = prussdrv_open(PRU_EVTOUT_0);
if (ret) {
printf("prussdrv_open open failed\n");
return (ret);
}
/* Get the interrupt initialized */
prussdrv_pruintc_init(&pruss_intc_initdata);
/* Execute example on PRU */
prussdrv_exec_program (PRU_NUM, "./text.bin");
/* Wait until PRU0 has finished execution */
prussdrv_pru_wait_event (PRU_EVTOUT_0);
prussdrv_pru_clear_event (PRU_EVTOUT_0, PRU0_ARM_INTERRUPT);
/* Disable PRU and close memory mapping*/
prussdrv_pru_disable (PRU_NUM);
prussdrv_exit ();
return(0);
}