PRU shared Ram

Many thanks to Jason and others for publishing some interesting PRU examples.

I’ve tried a number of the examples, but its been painful to follow the evolution and very little has worked LXQT 4.9.78-ti-r94 .

Jason has an interesting example bitflip.c/.pru0c that uses AM33XX_PRUSS_SHAREDRAM_BASE 0x4a310000.

I’m wondering if anybody has any comments on this approach?

I have built a proto that I have got working, I only need to get 8 int16 from A8 to the PRU. These represent a frequency for 8 toggling GPIOs

(For PRU0 I’m using P9_25 27 28 29 30 31 P8_11 12)

This method has intially worked for me using

LXQT 4.9.78-ti-r94 #1 4.9.78-ti-r94 #1 SMP PREEMPT Fri Jan 26 21:26:24 UTC 2018

with 8*int16 (or 32bytes).

Initially I tried 8int32 (64bytes) but could only sucessfully use the first 5int32(40bytes

However switching to LXQT 4.14.49-ti-r54 #1 SMP PREEMPT Fri Jun 15 22:14:13 UTC 2018

I seem to be running into problems with the one way comms through the SHARED RAM being limited to 2*int16 or 4bytes.

The actual code example is at

Any observations on initializing and using AM33XX_PRUSS_SHAREDRAM_BASE in this way much appreciated.

Details are

sudo /opt/scripts/tools/
dogtag:[ Debian Image 2018-06-17]
bootloader:[eMMC-(default)]:[/dev/mmcblk1]:[U-Boot 2018.03-00002-gac9cce7c6a]:[location: dd MBR]
pkg check: to individually upgrade run: [sudo apt install --only-upgrade ]
groups:[debian : debian adm kmem dialout cdrom floppy audio dip video plugdev users systemd-journal i2c bluetooth netdev cloud9ide gpio pwm eqep admin spi tisdk weston-launch xenomai]
cmdline:[console=ttyO0,115200n8 bone_capemgr.uboot_capemgr_enabled=1 root=/dev/mmcblk1p1 ro rootfstype=ext4 rootwait coherent_pool=1M net.ifnames=0 quiet cape_universaln=enable]
dmesg | grep pinctrl-single
[ 1.108053] pinctrl-single 44e10800.pinmux: 142 pins at pa f9e10800 size 568
dmesg | grep gpio-of-helper
[ 1.115448] gpio-of-helper ocp:cape-universal: ready

On Wed, 27 Jun 2018 12:18:27 -0700, Neil Hancock
<> declaimed the

with 8*int16 (or 32bytes).


  int16 is 2-bytes, 8*2 => 16 bytes

Initially I tried 8*int32 (64bytes) but could only sucessfully use the
first 5*int32(40bytes

  Similarly, int32 is 4-bytes, 8*4 => 32; 5*4 => 20

Oops - you are right, I’ll update my comments

Here is the code that is allocating the SHAREDRAM - though I’m still hazy as to how mmap() works in BBB mapping the SHAREDRAM

#define AM33XX_DATARAM0_PHYS_BASE 0x4a300000
#define AM33XX_DATARAM1_PHYS_BASE 0x4a302000
#define AM33XX_PRUSS_SHAREDRAM_BASE 0x4a310000
#define SHARED_RAM_SZ 16 /* grab 8*4 bytes or 8 words */

volatile uint16_t *shared_dataram;

/* Define an API to be calleable from JS -still needs work */

void bbbio_ppm_api(struct channels_s *channels){
memcpy((void *)shared_dataram,(void *)channels,sizeof(channels));

void bbbio_ppm_init() {
/* Allocate shared memory pointer to PRU0 DATARAM */
int mem_dev = open("/dev/mem", O_RDWR | O_SYNC);
volatile void *shared_dataram_init = mmap(NULL,

shared_dataram = (uint16_t *) shared_dataram_init;

void bbbio_ppm_cleanup() {
munmap((void *)shared_dataram,SHARED_RAM_SZ); //njh guess at releasing it.

void main() {
unsigned int sec_i, chnl_j;
unsigned int offset;
struct channels_s channels;
volatile uint16_t *shared_dataram2;


uint16_t ppm =60;//actually

offset = 0;
channels.chn[offset].sr =ppm;
printf(“shared_datara2 = %p, offset=%d At init Read:”, shared_dataram,offset);
shared_dataram2 = (uint16_t *) shared_dataram;
for(chnl_j=0; chnl_j<8; chnl_j++) {
printf(" %04d", *shared_dataram2);
if (0x3 ==(chnl_j & 0x3)){printf(" “);}

ppm =0;
for(chnl_j=0; chnl_j<8; chnl_j++) {
ppm += 60;
//Fut - wait for ack from PRU and then init shared ram

//while (1)
for(sec_i=0; sec_i<8; sec_i++) {
channels.chn[offset].sr +=ppm;
//memcpy((void *)shared_dataram,(void *)&channels,sizeof(channels));
printf(“Writing %04d Read:”, ppm);
shared_dataram2 = (uint16_t *) shared_dataram;
for(chnl_j=0; chnl_j<8; chnl_j++) {
printf(" %04d", *shared_dataram2);
if (0x3 ==(chnl_j & 0x3)){printf(" “);}

#endif //MAIN_LOCAL

Oops I got it - it was sizing a pointer and not the struct.

I’d be interested in anybody’s comments on the use of the SHAREDRAM approach as it makes for a very simple one way api. I’m partly publishing this as a tutorial for anybody else - but its my first try at the PRU.

Here is the logic anlayzer output from the Saleae 8 Channels mapping of PRU0 to GPIO P9_25 …P8_12
There is an increasing pulse count chn0, and then fixed 1hz, 2hz… on subsequent channels


I’ve worked up some examples[1] for a PRU Cookbook that might help. I’m taking a similar approach to what you did, but I’m using DRAM0. It shouldn’t be hard
to switch to shared RAM.


[1] Building Blocks - Applications

Ok thanks. I see I was think SHARED_RAM between the ARM-A8 and PRU0 and its actually shared between ARM PRU0 and PRU1. Ahhhh-lightbulb—hhhhh
Many thanks for the evolving cookbook and detailed explanation- I have got a little lost at times digging through the manual - gosh I want to read all the PRU sections - I’d have paid gold 4weeks ago when I started using the PRUst!.
If it becomes a book I’ll be first in line to buy it :).
The PRUs are a cool part of the BBB - and now I’ve got it working appears pretty simple.

The PRU cookbook is nearing completion (more accurately, I’m running out of summer).

Here’s a link PRU Cookbook

I’m happy for any feedback you can give me.


Wow. This is great. I like the problem/solution format. It really makes it easy to see which sections you might be interested in reading.

There is a typo on the first line of the Case Studies - Introduction that jumps out though: "It’s an excisting time"

And I wouldn't mind seeing a bit more of an explanation about how rpmsg works, for example a listing of resource_table_0.h with an explanation.

Just reading this now. Looks great. Trying to read through the examples - the format is really nice - how would you like feedback? Any deadlines for you on this?. I’m away on vacation on Tue, and then might be able to try the examples Sept 12 onwards.

I have an image that works fine on the older bones that fails to
function on a new batch from mouser.

What is failing is the hdmi output. the framer is the same part number
but a much different date code

I searched and saw no errata on the part from NXP

I just use a flasher SD card which should overwrite everything on the
emmc ( i hope )
or am i being bitten by something i cant think of.

Feedback via this topic is fine. Once the cookbook is closer to ready I’ll announce it in it’s own topic.