Beaglebone Black [BBB] Read Shared memory from PRU

i wrote a PRU Programm where i read some Sensors and calculate something. Then i save the Data in the shared RAM.

But how can i read the memory from the ARM? is it possible to read it from an c programm or shell? edit: i programm the PRU with this method: https://markayoder.github.io/PRUCookbook/index.html

Greetings Marcus

That is experimental code I have not seen for some months (must first do the hardware)

It shows how to mmap the PRU / shared ram into the ARM memory space and dump the contents to files.

The dumps are somewhat annotated with the data structures I use.

This is ad hoc ripped from the source files, not intended to be compiled as it is.

#include <sys/types.h> /* type definitions used by many programs */
#include <stdio.h> /* standard IO functions */
#include <stdlib.h> /* commonly used functions, EXIT_SUCCESS and EXIT_FAILURE */
#include <errno.h>
#include <string.h>
#include <math.h>

#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>

#include "ltcsrv.h" /* for panic() */
#include "pru_if.h" /* to enforce consistency with .c */

#include "cmnd_stat_codes.h"

#define ADC_BUFFER_SIZE (16*1024)

int dev_mem_fd;
volatile int *shared_ram;
volatile int *pru_ram; // the 8 KB local data = 2 KWORDS
int adc_buffer[ADC_BUFFER_SIZE];
int cmnd_to_send;

int open_pru(){

 int i;

 //if \(verbose\) printf\(&quot;enter open\_pru\(\)\\n&quot;\);
 if \(init\_cpld\_pins\(\)\) return 1;

 //if\(verbose\) printf\(&quot;starting pru 0\\n&quot;\);

// if (!start_pru()) return 1;
// printf("sleeping 1 s\n");
// sleep(1);

 // map the shared ram into our virtual memory
 //printf\(&quot;mapping\.\.\.\\n&quot;\);
 dev\_mem\_fd = open\(&quot;/dev/mem&quot;,O\_RDWR | O\_SYNC\);

 // mmap params:
 // addres where the kernel creates the mapping\. NULL= do as you like
 // size of the mapped region  12288 = 12 KBytes
 // protection
 // flags
 // file descriptor von /dev/mem
 // pru\-base  = 0x4A30\_0000, shared ram starts at \+0x10000
 shared\_ram = \(int \*\) mmap\(NULL, 12\*1024, PROT\_READ | PROT\_WRITE, MAP\_SHARED,
             dev\_mem\_fd, 0x4A300000 \+ 0x10000\);
 if \(\-1 == \(int\)shared\_ram\) panic\(&quot;could not mmap\(\) shared PRU ram&quot;\);

 // both PRU local data rams together
 pru\_ram = \(int \*\) mmap\(NULL, 2\*8\*1024, PROT\_READ | PROT\_WRITE, MAP\_SHARED,
             dev\_mem\_fd, 0x4A300000 \+ 0x00000\);
 if \(\-1 == \(int\)pru\_ram\) panic\(&quot;could not mmap\(\) local PRU rams&quot;\);

 for \(i=0; i&lt; ADC\_BUFFER\_SIZE; i\+\+\)\{   // 12 KB are 3 Kwords
     adc\_buffer\[i\] = 0;
 \}

 return 0;

}

int close_pru(void){
// FIXME: shared RAM must be un-mapped and file descriptors should be closed
if (verbose) printf("enter close_pru()\n");
// if (!stop_pru()) return 1;
if (verbose) printf("leaving close_pru()\n");
return 0;
}

void copy_shared_ram_to_file(char *fn){

 FILE \* phyle;
 int i, j;

 phyle = fopen\(fn, &quot;w&quot;\);        // FIXME return value
 fprintf\(phyle, &quot;%s\\n&quot;, fn\);
 fprintf\(phyle, &quot;byte index dec byte index hex  word index content\\n\\n&quot;\);
 for \(i=0; i&lt; 3\*1024; i\+\+\)\{   // 12 KB are 3 Kwords
     fprintf\(phyle, &quot;\\n%12d   %8x   %8x  = 0x%8x    %12d&quot;, 4\*i, 4\*i, i, shared\_ram\[i\], shared\_ram\[i\]\);
     switch\(i\)\{
         case 0:                fprintf\(phyle, &quot;  unused&quot;\); break;
         case COMMAND:        fprintf\(phyle, &quot;  command&quot;\); break;
         case STATUS:        fprintf\(phyle, &quot;  status&quot;\); break;
         case PARAM1:        fprintf\(phyle, &quot;  param1&quot;\); break;
         case PARAM2:        fprintf\(phyle, &quot;  param2&quot;\); break;
         case PARAM3:        fprintf\(phyle, &quot;  param3&quot;\); break;
         case TEST1:            fprintf\(phyle, &quot;  test1&quot;\); break;
         case TEST2:            fprintf\(phyle, &quot;  test2&quot;\); break;
         case TEST3:            fprintf\(phyle, &quot;  test3&quot;\); break;
         case PING\_FULL:        fprintf\(phyle, &quot;  ping\_full&quot;\); break;
         case PONG\_FULL:        fprintf\(phyle, &quot;  pong\_full&quot;\); break;
         case PING:            fprintf\(phyle, &quot;  ping buffer start&quot;\); break;
         case PONG:            fprintf\(phyle, &quot;  pong buffer start&quot;\); break;
     \}
 \}
 fclose\(phyle\);      // FIXME return value

}

// thats for all the 2*8 KBytes
void copy_pru_ram_to_file(char *fn){

 FILE \* phyle;
 int i, j;

 phyle = fopen\(fn, &quot;w&quot;\);        // FIXME return value
 fprintf\(phyle, &quot;%s\\n&quot;, fn\);
 fprintf\(phyle, &quot;byte index  word index  content   all hex\\n\\n&quot;\);
 fprintf\(phyle, &quot;stack lowest and data nil pointer\\n&quot;\);

 for \(i=0; i&lt; 4\*1024; i\+\+\)\{   // 2 \* 8 KB are 4 Kwords

     if      \(0x100/4 == i\)    \{ fprintf\(phyle, &quot;\\nstack highest \- heap lowest\\n&quot;\); \}
     else if \(0x200/4 == i\)    \{ fprintf\(phyle, &quot;\\nheap highest\\n&quot;\); \}

     fprintf\(phyle, &quot;%8x   %8x = %8x\\n&quot;, 4\*i, i, pru\_ram\[i\]\);

 \}
 fclose\(phyle\);      // FIXME return value

}

hope it helps somewhat.

regards,

Gerhard

The PRU Cookbook has an exampled of writing shared memory with the ARM.

https://markayoder.github.io/PRUCookbook/05blocks/blocks.html#_controlling_the_pwm_frequency

–Mark

Mark - I’m integrating the concepts from the PRUCookbook so I can send some control parameters entered by the user in the host side program and pass them over to the PRU0 firmware.

I’m getting this error when I try to compile the code.

Setting up pru0 memory access.
ERROR: could not open /dev/mem.

Any ideas?

I’m running a BBB Wireless with video and audio disabled.

Here’s the output of version.sh

debian@beaglebone:/var/lib/cloud9$ sudo /opt/scripts/tools/version.sh
[sudo] password for debian:
git:/opt/scripts/:[b39ec679648a6be8f25f48bd1c9784c1fc5a0c46]
eeprom:[A335BNLTBWA52027BBWG0227]
model:[TI_AM335x_BeagleBone_Black_Wireless]
dogtag:[BeagleBoard.org Debian Buster IoT Image 2020-04-06]
bootloader:[microSD-(push-button)]:[/dev/mmcblk0]:[U-Boot 2019.04-00002-g07d5700e21]:[location: dd MBR]
bootloader:[eMMC-(default)]:[/dev/mmcblk1]:[U-Boot 2018.03-00002-gac9cce7c6a]:[location: dd MBR]
UBOOT: Booted Device-Tree:[am335x-boneblack-uboot-univ.dts]
UBOOT: Loaded Overlay:[AM335X-PRU-RPROC-4-19-TI-00A0]
UBOOT: Loaded Overlay:[BB-ADC-00A0]
UBOOT: Loaded Overlay:[BB-BBBW-WL1835-00A0]
UBOOT: Loaded Overlay:[BB-BONE-eMMC1-01-00A0]
UBOOT: Loaded Overlay:[BB-I2C2-RTC-DS3231]
UBOOT: Loaded Overlay:[BB-W1-P9.12-00A2]
kernel:[4.19.94-ti-r61]
nodejs:[v10.15.2]
/boot/uEnv.txt Settings:
uboot_overlay_options:[enable_uboot_overlays=1]
uboot_overlay_options:[uboot_overlay_addr4=/lib/firmware/BB-W1-P9.12-00A0.dtbo]
uboot_overlay_options:[disable_uboot_overlay_video=1]
uboot_overlay_options:[disable_uboot_overlay_audio=1]
uboot_overlay_options:[uboot_overlay_pru=/lib/firmware/AM335X-PRU-RPROC-4-19-TI-00A0.dtbo]
uboot_overlay_options:[enable_uboot_cape_universal=1]
uboot_overlay_options:[dtb_overlay=/lib/firmware/BB-I2C2-RTC-DS3231.dtbo]
pkg check: to individually upgrade run: [sudo apt install --only-upgrade ]
pkg:[bb-cape-overlays]:[4.14.20210401.0-0~buster+20210401]
pkg:[bb-wl18xx-firmware]:[1.20200322.0-0rcnee0~buster+20200322]
pkg:[kmod]:[26-1]
pkg:[librobotcontrol]:[1.0.4-git20190227.1-0rcnee0~buster+20190327]
pkg:[firmware-ti-connectivity]:[20190717-2rcnee1~buster+20200305]
groups:[debian : debian adm kmem dialout cdrom floppy audio dip video plugdev users systemd-journal bluetooth netdev i2c gpio pwm eqep remoteproc admin spi iio docker tisdk weston-launch xenomai cloud9ide]
cmdline:[console=ttyO0,115200n8 bone_capemgr.uboot_capemgr_enabled=1 root=/dev/mmcblk0p1 ro rootfstype=ext4 rootwait coherent_pool=1M net.ifnames=0 lpj=1990656 rng_core.default_quality=100 quiet]
dmesg | grep remote
[ 69.927418] remoteproc remoteproc0: wkup_m3 is available
[ 70.105672] remoteproc remoteproc0: powering up wkup_m3
[ 70.105706] remoteproc remoteproc0: Booting fw image am335x-pm-firmware.elf, size 217148
[ 70.106000] remoteproc remoteproc0: remote processor wkup_m3 is now up
[ 72.319951] remoteproc remoteproc1: 4a334000.pru is available
[ 72.335870] remoteproc remoteproc2: 4a338000.pru is available
[ 564.302719] remoteproc remoteproc1: powering up 4a334000.pru
[ 564.303391] remoteproc remoteproc1: Booting fw image am335x-pru0-fw, size 118908
[ 564.316303] remoteproc remoteproc1: registered virtio0 (type 7)
[ 564.316324] remoteproc remoteproc1: remote processor 4a334000.pru is now up
[ 590.322924] remoteproc remoteproc1: stopped remote processor 4a334000.pru
[ 594.762821] remoteproc remoteproc1: powering up 4a334000.pru
[ 594.763533] remoteproc remoteproc1: Booting fw image am335x-pru0-fw, size 118888
[ 594.777049] remoteproc remoteproc1: registered virtio0 (type 7)
[ 594.777060] remoteproc remoteproc1: remote processor 4a334000.pru is now up
dmesg | grep pru
[ 72.319951] remoteproc remoteproc1: 4a334000.pru is available
[ 72.320135] pru-rproc 4a334000.pru: PRU rproc node pru@4a334000 probed successfully
[ 72.335870] remoteproc remoteproc2: 4a338000.pru is available
[ 72.336020] pru-rproc 4a338000.pru: PRU rproc node pru@4a338000 probed successfully
[ 564.302719] remoteproc remoteproc1: powering up 4a334000.pru
[ 564.303391] remoteproc remoteproc1: Booting fw image am335x-pru0-fw, size 118908
[ 564.304236] pruss 4a300000.pruss: configured system_events[63-0] = 00000000,00030000
[ 564.304251] pruss 4a300000.pruss: configured intr_channels = 0x00000005 host_intr = 0x00000005
[ 564.316324] remoteproc remoteproc1: remote processor 4a334000.pru is now up
[ 564.391508] virtio_rpmsg_bus virtio0: creating channel rpmsg-pru addr 0x1e
[ 564.467856] rpmsg_pru virtio0.rpmsg-pru.-1.30: new rpmsg_pru device: /dev/rpmsg_pru30
[ 590.322860] pruss 4a300000.pruss: unconfigured system_events[63-0] = 00000000,00030000
[ 590.322880] pruss 4a300000.pruss: unconfigured host_intr = 0x00000005
[ 590.322924] remoteproc remoteproc1: stopped remote processor 4a334000.pru
[ 594.762821] remoteproc remoteproc1: powering up 4a334000.pru
[ 594.763533] remoteproc remoteproc1: Booting fw image am335x-pru0-fw, size 118888
[ 594.764695] pruss 4a300000.pruss: configured system_events[63-0] = 00000000,00030000
[ 594.764710] pruss 4a300000.pruss: configured intr_channels = 0x00000005 host_intr = 0x00000005
[ 594.775769] virtio_rpmsg_bus virtio0: creating channel rpmsg-pru addr 0x1e
[ 594.776757] rpmsg_pru virtio0.rpmsg-pru.-1.30: new rpmsg_pru device: /dev/rpmsg_pru30
[ 594.777060] remoteproc remoteproc1: remote processor 4a334000.pru is now up
dmesg | grep pinctrl-single
[ 0.952360] pinctrl-single 44e10800.pinmux: 142 pins, size 568
dmesg | grep gpio-of-helper
[ 0.965863] gpio-of-helper ocp:cape-universal: ready
lsusb
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
END

Here’s the code too. Sorry, should have included it.

int fd;
printf(“Setting up pru0 memory access.\n”);

fd = open ("/dev/mem", O_RDWR | O_SYNC);
if (fd == -1) {
printf (“ERROR: could not open /dev/mem.\n\n”);
return 1;
}

When I look for /dev/mem it doesn’t exist whether logged in as debian or root

Are you sure /dev/mem isn’t there? I think it’s required.

bone$ ls -ls /dev/mem
0 crw-r----- 1 root kmem 1, 1 Apr 14 09:11 /dev/mem
bone$ groups
debian adm kmem dialout cdrom floppy audio dip video plugdev users systemd-journal input bluetooth netdev i2c remoteproc eqep pwm cloud9ide xenomai weston-launch tisdk docker iio spi admin gpio

You should be in the kmem group by default so sudo isn’t needed.

–Mark

Well, yes indeed, it is there this morning. I’ll retry the code later and get back to you.

Mark ,

pwm4.pru0.c compiles fine from a command line in PUTTY using make TARGET=pwm4.pru0

When I try to run pwm_test.c within the cloud9 IDE I get this message from the program.

Compiling /var/lib/cloud9/PRUCookbook/docs/05blocks/code/pwm-test.c …
/var/lib/cloud9/common/Makefile:28: MODEL=TI_AM335x_BeagleBone_Black_Wireless,TARGET=,COMMON=/var/lib/cloud9/common
make: ‘pwm-test’ is up to date.
Servo tester
ERROR: could not open /dev/mem.

I checked with ls -ls /dev/mem logged in as debian and it’s there.

Any ideas?

I checked with ls -ls /dev/mem logged in as debian and it's there.

debian@beaglebone:~$ ls -ls /dev/mem
0 crw-r----- 1 root kmem 1, 1 Apr 30 12:06 /dev/mem
debian@beaglebone:~$
debian@beaglebone:~$ groups
debian adm kmem dialout cdrom floppy audio dip video plugdev users
systemd-journal input bluetooth netdev i2c remoteproc eqep pwm cloud9ide
xenomai weston-launch tisdk docker iio spi admin gpio
debian@beaglebone:~$

  That is what my BBB shows.

    Owner (root) has R/W permission
    Group (kmem) has Read-Only permission.

  The debian account has kmem group access.

  From your earlier post...

   fd = open ("/dev/mem", O_RDWR | O_SYNC);

... you are asking for R/W access -- which is not set for members of the
kmem group. What happens if you attempt to open /dev/mem for read-only
access?

I changed the code to this and get the same error.

fd = open ("/dev/mem", O_RDONLY | O_SYNC); // not sure O_SYNC is necessary since this is a read-only open situation

Servo tester!!!
ERROR: could not open /dev/mem.

make: *** [/var/lib/cloud9/common/Makefile:173: start] Error 1
rm /tmp/cloud9-examples/pwm-test.o

Here’s some info about my specific owner/group & permissions.

debian@beaglebone:/var/lib/cloud9$ ls -ls /dev/mem
0 crw-r----- 1 root kmem 1, 1 Apr 30 20:30 /dev/mem
debian@beaglebone:/var/lib/cloud9$ groups
debian adm kmem dialout cdrom floppy audio dip video plugdev users systemd-journal bluetooth netdev i2c cloud9ide xenomai weston-launch tisdk docker iio spi admin remoteproc eqep pwm gpio
debian@beaglebone:/var/lib/cloud9$ whoami
debian
debian@beaglebone:/var/lib/cloud9$