Problems in using PRU on BeagleBone

318 views
Skip to first unread message

phfbertoleti

unread,
Jan 16, 2021, 9:25:21 PM1/16/21
to BeagleBoard
Hi everyone.

My name is Pedro and I'm from Brazil. I'm trying to learn how to use PRUs in BeagleBone (I'm using BeagleBone Green Wireless now) and I'm facing a problem I cannot solve.

I'm reading Derek Molloy's book (Exploring BeagleBone) and one of the first examples / "hello world"-like is checking which firmware is loaded in PRU0 and start it. However, when I try to do this, I get "write error: Invalid argument" as error output:

debian@beaglebone:/sys/class/remoteproc/remoteproc1$ cat firmware 
am335x-pru1-fw
debian@beaglebone:/sys/class/remoteproc/remoteproc1$ echo 'start' > state
-bash: echo: write error: Invalid argument

What am I doing wrong? I would like to see "running" at state value, in order to be sure PRU0 is working.

Here follows some useful information:

Kernel version: 4.19.94-ti-r42
Dmesg output related to remoteproc:

---------------------
[   11.169923] remoteproc remoteproc0: 4a334000.pru is available
[   11.171927] remoteproc remoteproc1: 4a338000.pru is available
[   60.948771] remoteproc remoteproc2: wkup_m3 is available
[   60.956133] remoteproc remoteproc2: powering up wkup_m3
[   60.956160] remoteproc remoteproc2: Booting fw image am335x-pm-firmware.elf, size 217168
[   60.956412] remoteproc remoteproc2: remote processor wkup_m3 is now up
[  454.023370] remoteproc remoteproc1: powering up 4a338000.pru
[  454.027965] remoteproc remoteproc1: loading /lib/firmware/am335x-pru1-fw failed with error -22
[  454.027986] remoteproc remoteproc1: Direct firmware load for am335x-pru1-fw failed with error -22
[  454.028006] remoteproc remoteproc1: request_firmware failed: -22
[  454.043116] remoteproc remoteproc1: Boot failed: -22
---------------------

Thanks in advance.

Best Regards,
Pedro Bertoleti

Vinicius Juvinski

unread,
Jan 16, 2021, 10:05:07 PM1/16/21
to beagl...@googlegroups.com
Hi Pedro,

I recommend you take a look at 

Have you checked the dmesg to see what is happening at kernel level ?

--
For more options, visit http://beagleboard.org/discuss
---
You received this message because you are subscribed to the Google Groups "BeagleBoard" group.
To unsubscribe from this group and stop receiving emails from it, send an email to beagleboard...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/beagleboard/7c2be7bd-63f3-4798-85dd-e5be63d86831n%40googlegroups.com.

phfbertoleti

unread,
Jan 16, 2021, 10:59:07 PM1/16/21
to BeagleBoard
Hi vinicius. 

First of all, thanks for the reply and for indicating me PRU cook book. 
Regarding dmesg messages, yes, I've checked them (as shown below). It seems PRUs are available for use, am I right?
What do you recommend as a hello world test for PRU? 

---------------------
[   11.169923] remoteproc remoteproc0: 4a334000.pru is available
[   11.171927] remoteproc remoteproc1: 4a338000.pru is available
[   60.948771] remoteproc remoteproc2: wkup_m3 is available
[   60.956133] remoteproc remoteproc2: powering up wkup_m3
[   60.956160] remoteproc remoteproc2: Booting fw image am335x-pm-firmware.elf, size 217168
[   60.956412] remoteproc remoteproc2: remote processor wkup_m3 is now up
[  454.023370] remoteproc remoteproc1: powering up 4a338000.pru
[  454.027965] remoteproc remoteproc1: loading /lib/firmware/am335x-pru1-fw failed with error -22
[  454.027986] remoteproc remoteproc1: Direct firmware load for am335x-pru1-fw failed with error -22
[  454.028006] remoteproc remoteproc1: request_firmware failed: -22
[  454.043116] remoteproc remoteproc1: Boot failed: -22
---------------------


Best Regards,
Pedro Bertoleti

Vinicius Juvinski

unread,
Jan 16, 2021, 11:46:00 PM1/16/21
to beagl...@googlegroups.com
Hi Pedro,


You are having error 22 - I don’t remember right now the cause , the prucookbook has the explanation and how to fix :)

Pedro Henrique Fonseca Bertoleti

unread,
Jan 16, 2021, 11:56:00 PM1/16/21
to beagl...@googlegroups.com
Sorry, I couldn't find any information on this error 22 on PRU cook book. Please, anyone can help me on handling this error?

Vinicius Juvinski

unread,
Jan 17, 2021, 12:59:59 AM1/17/21
to beagl...@googlegroups.com
Yes ,the answer is there - 4.2

Pedro Henrique Fonseca Bertoleti

unread,
Jan 17, 2021, 1:08:01 AM1/17/21
to beagl...@googlegroups.com
Thanks!

In this reference, I can see a custom firmware has been developes and a header file was missing in its code. However, in my case, I'm using a firmware which is in /lib/firmware by default (am335x-pru1-fw). I assume this firmware works, once it comes with distro (I'm using official image provided in BeagleBone site).

Why am I getting this error with a firmware it's supposed to work? Please, would you shed some light on it? 


Best Regards.

Vinicius Juvinski

unread,
Jan 17, 2021, 1:11:21 AM1/17/21
to beagl...@googlegroups.com

Please send the result of version.sh under opt/scripts

phfbertoleti

unread,
Jan 17, 2021, 12:27:34 PM1/17/21
to BeagleBoard
Vinicius, here follows the output of version.sh:


-----------
debian@beaglebone:/opt/scripts/tools$ sudo ./version.sh 
[sudo] password for debian: 
git:/opt/scripts/:[b39ec679648a6be8f25f48bd1c9784c1fc5a0c46]
eeprom:[A335BNLTGW1ABBGW16054623]
model:[TI_AM335x_BeagleBone_Green_Wireless]
dogtag:[BeagleBoard.org Debian Buster IoT Image 2020-04-06]
bootloader:[eMMC-(default)]:[/dev/mmcblk1]:[U-Boot 2019.04-00002-g07d5700e21]:[location: dd MBR]
UBOOT: Booted Device-Tree:[am335x-bonegreen-wireless-uboot-univ.dts]
UBOOT: Loaded Overlay:[AM335X-PRU-RPROC-4-19-TI-00A0]
UBOOT: Loaded Overlay:[BB-ADC-00A0]
UBOOT: Loaded Overlay:[BB-BBGW-WL1835-00A0]
UBOOT: Loaded Overlay:[BB-BONE-eMMC1-01-00A0]
kernel:[4.19.94-ti-r42]
nodejs:[v10.15.2]
/boot/uEnv.txt Settings:
uboot_overlay_options:[enable_uboot_overlays=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]
pkg check: to individually upgrade run: [sudo apt install --only-upgrade <pkg>]
pkg:[bb-cape-overlays]:[4.14.20200814.0-0~buster+20200814]
pkg:[bb-wl18xx-firmware]:[1.20200813.1-0~buster+20200813]
pkg:[kmod]:[26-1]
pkg:[librobotcontrol]:[1.0.5-git20200715.0-0~buster+20200716]
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/mmcblk1p1 ro rootfstype=ext4 rootwait coherent_pool=1M net.ifnames=0 lpj=1990656 rng_core.default_quality=100 quiet]
dmesg | grep remote
[   11.585512] remoteproc remoteproc0: 4a334000.pru is available
[   11.605383] remoteproc remoteproc1: 4a338000.pru is available
[   60.745582] remoteproc remoteproc2: wkup_m3 is available
[   60.840333] remoteproc remoteproc2: powering up wkup_m3
[   60.840364] remoteproc remoteproc2: Booting fw image am335x-pm-firmware.elf, size 217168
[   60.840611] remoteproc remoteproc2: remote processor wkup_m3 is now up
dmesg | grep pru
[   11.585512] remoteproc remoteproc0: 4a334000.pru is available
[   11.585705] pru-rproc 4a334000.pru: PRU rproc node pru@4a334000 probed successfully
[   11.605383] remoteproc remoteproc1: 4a338000.pru is available
[   11.605571] pru-rproc 4a338000.pru: PRU rproc node pru@4a338000 probed successfully
dmesg | grep pinctrl-single
[    0.945761] pinctrl-single 44e10800.pinmux: 142 pins, size 568
dmesg | grep gpio-of-helper
[    0.958228] gpio-of-helper ocp:cape-universal: ready
lsusb
Bus 001 Device 002: ID 05e3:0610 Genesys Logic, Inc. 4-port hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
END
-----------

Vinicius Juvinski

unread,
Jan 17, 2021, 4:32:47 PM1/17/21
to beagl...@googlegroups.com
Hi Pedro,

I didn't find the source code for this firmware.
I recommend you install the TI's Code Composer Studio (https://www.ti.com/design-resources/embedded-development/ccs-development-tools.html)
And follow the PRU cookbook. The book from Derek's if is the first edition if I am not wrong, is focused on kernel 3.18, I bought the second edition and this is updated to 4.14 version.
So to start with PRU I really recommend the PRUCookbook + CCS.

Best regards.

Pedro Henrique Fonseca Bertoleti

unread,
Jan 17, 2021, 4:41:09 PM1/17/21
to beagl...@googlegroups.com
Hi Vinicius.

Some minutes ago I was able to make it work. I tried to compile a custom firmware, flash it to pru (through remoteproc) and start it, and I've got success innchange state value.

However, I'm not able to control (on/off) a LED in BeagleBone Green Wireless. I've set in config_pin the gpio P9_27 to pruout successfully, but I've got no lucky in controlling the LED I've wired to this gpio. I'll try to do it in BeagleBone Black, and I'll follow pru cook book as you recommended.

Thanks!

Vinicius Juvinski

unread,
Jan 17, 2021, 5:14:06 PM1/17/21
to beagl...@googlegroups.com
Could you please share your code ?

Have you checked with confit-pin or show-pins to confirm there are as pru out ?

Sent from my iPhone


Em 17 de jan. de 2021, à(s) 18:40, Pedro Henrique Fonseca Bertoleti <phfber...@gmail.com> escreveu:



Pedro Henrique Fonseca Bertoleti

unread,
Jan 17, 2021, 5:54:24 PM1/17/21
to beagl...@googlegroups.com
Hi Vinicius. The code I've used is the same as available here: https://github.com/derekmolloy/exploringBB/blob/version2/chp15/pru/blinkLED/blinkLED.c

And yes, I've confirmed and P9_27 (GPIO to wire the LED) was configured as pruout.


Best Regards,
Pedro Bertoleti



--
Atenciosamente,

Pedro Bertoleti
(http://pedrobertoleti.com.br/)

Vinicius Juvinski

unread,
Jan 17, 2021, 6:16:30 PM1/17/21
to beagl...@googlegroups.com
One question 

On what pru you are running your code? 0 or 1?
For p9_27 must be pru0

There was something on dmesg?

Sent from my iPhone


Em 17 de jan. de 2021, à(s) 19:54, Pedro Henrique Fonseca Bertoleti <phfber...@gmail.com> escreveu:



Pedro Henrique Fonseca Bertoleti

unread,
Jan 17, 2021, 6:23:07 PM1/17/21
to beagl...@googlegroups.com
I'm running on pru0. And I've seen no errors in dmesg related to pru.

phfbertoleti

unread,
Jan 17, 2021, 8:28:54 PM1/17/21
to BeagleBoard
Hi Vinicius.

I just tried the very same thing on a BeagleBone Black and worked like a charm!
Honestly, I don't know what gone wrong in BBGW. But it's ok, I can go further in my studies using BeagleBone Black.

Again, thanks for the help.


Best Regards,
Pedro Bertoleti

Vinicius Juvinski

unread,
Jan 17, 2021, 9:08:18 PM1/17/21
to beagl...@googlegroups.com
Are you using any dtb up in your bbgw?
Both are using the same kernel version ?


Pedro Henrique Fonseca Bertoleti

unread,
Jan 17, 2021, 9:14:14 PM1/17/21
to beagl...@googlegroups.com
Regarding changes in dtb or dtbo, this is a good question. After seeing your question, I remembered I've made some experiments in BBGW device tree some months ago. However, now I have absolutely no clue on what I've changed that time (my memory betrays me). Maybe I've made some mess there.

Regarding Kernel version, both veraiona are the same.

Vinicius Juvinski

unread,
Jan 17, 2021, 9:19:55 PM1/17/21
to beagl...@googlegroups.com

Please take a look on that because the compatibility between bbb,bbg and bbgw are really big - I have the same project running in all of them without any change - except on bbgw - the p8.15 is used by the Wi-Fi card and you can’t use it - and this is the ecap for the pru1, but with this exception the things should work


phfbertoleti

unread,
Jan 17, 2021, 10:03:22 PM1/17/21
to BeagleBoard
I'll write the newest iamge on my BBGW. I think after that everything will back to normal.

Regarding PRUs, I think you can answer me the following: I was able to write data succesfully to shared data segment using PRU0, to confirm I've checked memory using devmem2. However, I'm not so sure on how I can read it from host (Linux) side, once Linux side uses virtual memory (= no physical memory address are referred there, per my understanding).

How do you recommend me to read (or write) data to shared memory from host (Linux) side in C? Is there any special library for this? I assume this is the easiest (maybe the only, as I've understood so far) way to communicate Linux side and PRUs side.


Best Regards,
Pedro Bertoleti

Gerhard Hoffmann

unread,
Jan 18, 2021, 12:03:13 AM1/18/21
to beagl...@googlegroups.com

Am 18.01.21 um 04:03 schrieb phfbertoleti:
> I'll write the newest iamge on my BBGW. I think after that everything
> will back to normal.
>
> Regarding PRUs, I think you can answer me the following: I was able to
> write data succesfully to shared data segment using PRU0, to confirm
> I've checked memory using devmem2. However, I'm not so sure on how I
> can read it from host (Linux) side, once Linux side uses virtual
> memory (= no physical memory address are referred there, per my
> understanding).
>
> How do you recommend me to read (or write) data to shared memory from
> host (Linux) side in C? Is there any special library for this? I
> assume this is the easiest (maybe the only, as I've understood so far)
> way to communicate Linux side and PRUs side.

I have mostly made a FFT analyzer from a BBB. There are up to 3 LTC2500
ADCs sampling analog

data at 1MSPS, 32 Bits per sample. I got my Agilent 89441A back to work,
therefore this here is idle

for >> 1 year.  I started that with PRU0, but PRU1 has more usable pins.


PRU 1 was reading the data with the help of an external CPLD that
converted SPI to Bytes since even

the PRU could not read SPI at 3*100 MBit. There is a 12 KB dual port
buffer somewhere accessible to

both the ARM and the PRU. The lowest words of the buffer make a
command/status interface between

ARM and PRU (command, status, 3 parameters, 3 test results, etc). The
rest of the buffer is used to

transfer long  time series to the ARM in a ping-pong way. (The way I
used it.)


The shared buffer has a fixed address on the PRU side, and also on the
ARM side. You cannot use

this address in your ARM program but you can mmap() it into the virtual
memory space of the ARM.

That is a standard system call.


The following source code was not meant for publication, it is
half-done. Don't hit me too hard.

But the access to the shared ram works from both sides, this here is the
ARM side.

It seems you have the PRU side already. What you need is probably openpru().

Sorry for the semi-German in the source.


regards, Gerhard






-----------------------------------------------

// pru_if.h
//
// extern int         init_spi_pins(void);

extern int         open_pru(void);
extern int         close_pru(void);
extern void     run_pru_cmnd( int pru_argc, char **pru_argv);
extern int         do_aquisition_cmnd( int n_samples);

#define ADC_BUFFER_SIZE (32*1024)
extern int         adc_buffer[ADC_BUFFER_SIZE];

-----------------------------------------------

pru_if.c


#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 <sys/time.h>        /* setitimer(2)  and getitimer(2)  */
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>

#include <unistd.h>            /* for nice system call */

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

#include "cmnd_stat_codes.h"


int adc_buffer[ADC_BUFFER_SIZE];


int                dev_mem_fd;
volatile int    *shared_ram;
volatile int    *pru_ram;            // the 8 KB local data = 2 KWORDS

int                cmnd_to_send;


int init_BBB_pins(){

    // printf("initializing pins for SPI and PRU\n");
    // 2> stderr umleiten   &> stdout und stderr umleiten
    system("/bin/rm -f spitest.log");

    // this here worked from bash, never change a winning team.
    if (system("/usr/bin/config-pin  p8.45 pruin  2> spitest.log"))
return 1;    // PRU1.0      q0
    if (system("/usr/bin/config-pin  p8.46 pruin  2> spitest.log"))
return 1;    // PRU1.1      q1
    if (system("/usr/bin/config-pin  p8.43 pruin  2> spitest.log"))
return 1;    // PRU1.2      q2
    if (system("/usr/bin/config-pin  p8.44 pruin  2> spitest.log"))
return 1;    // PRU1.3      q3
    if (system("/usr/bin/config-pin  p8.41 pruin  2> spitest.log"))
return 1;    // PRU1.4      q4
    if (system("/usr/bin/config-pin  p8.42 pruin  2> spitest.log"))
return 1;    // PRU1.5      q5
    if (system("/usr/bin/config-pin  p8.39 pruin  2> spitest.log"))
return 1;    // PRU1.6      q6
    if (system("/usr/bin/config-pin  p8.40 pruin  2> spitest.log"))
return 1;    // PRU1.7      q7

    if (system("/usr/bin/config-pin  p8.27 pruout 2> spitest.log"))
return 1;    // PRU1.8      qsel0       cpld.19 könnte auch zusätzlich
SDI sein
    if (system("/usr/bin/config-pin  p8.29 pruout 2> spitest.log"))
return 1;    // PRU1.9      qsel1       cpld.16
    if (system("/usr/bin/config-pin  p8.28 pruout 2> spitest.log"))
return 1;    // PRU1.10     prog_clk    cpld.36
    if (system("/usr/bin/config-pin  p8.30 pruout 2> spitest.log"))
return 1;    // PRU1.11     prog_data / sdi

    if (system("/usr/bin/config-pin  p9.26 pruin  2> spitest.log"))
return 1;    // PRU1.16_in  data available from CPLD.12 ( Busy or DRL,
depending chan B/A)
    if (system("/usr/bin/config-pin  p9.22 out    2> spitest.log"))
return 1;    // GPIO0.2     prog_ena    cpld.39
    if (system("/usr/bin/config-pin  p9.18 out    2> spitest.log"))
return 1;    // GPIO0.4     use_chan_b  cpld.8
    // printf("done with initializing pins.\n");
    return 0;
}



void copy_shared_ram_to_file(char *fn){

    FILE * phyle;
    int i, j;

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

}


void copy_pru_ram_to_file(char *fn){
    FILE * phyle;
    int i, j;
    phyle = fopen(fn, "w");        // FIXME return value
    fprintf(phyle, "%s\n", fn);
    fprintf(phyle, "byte index  word index  content   all hex\n\n");
    fprintf(phyle, "stack lowest and data nil pointer\n");
    for (i=0; i< 4*1024; i++){   // 2 * 8 KB are 4 Kwords
        if      (0x100/4 == i)    { fprintf(phyle, "\nstack highest -
heap lowest\n"); }
        else if (0x200/4 == i)    { fprintf(phyle, "\nheap highest\n"); }
        fprintf(phyle, "%8x   %8x = %8x\n", 4*i, i, pru_ram[i]);
    }
    fclose(phyle);      // FIXME return value
}



void display_cmnd( int cmnd){
    printf(" <%c> %d = ", cmnd, cmnd);
    switch (cmnd){
        case CMND_NONE:                printf("none\n"); break;
        case CMND_HALT:                printf("halt\n"); break;
        case CMND_BLINK_FAST:        printf("blink fast\n"); break;
        case CMND_BLINK_SLOWLY:        printf("blink slowly\n"); break;
        case CMND_CHAN:                printf("Channel select 1=B\n");
break;
        case CMND_INIT_ADC:            printf("init ADC\n"); break;
        case CMND_START_AQUISITION: printf("start_aquisition\n"); break;
        case CMND_CLEAR_RAM:        printf("wipe out the rams\n"); break;
        case CMND_XMIT_WORD:        printf("xmit word via spi\n"); break;
        case CMND_TEST:                printf("test\n"); break;
        case CMND_WRITE_ADDRESS:    printf("write address\n"); break;
        case CMND_READ_ADDRESS:        printf("read address\n"); break;
        case CMND_UIUIUI:            printf("uiuiui\n"); break;
        case CMND_READ_ADC:            printf("read ADC\n"); break;
        default:                    printf("????\n");
    }
}  // display_cmnd()


// %i matches 0XABC 0xabc as hex , 0777 as oct, the rest in decimal
// octal may come as a surprise! I still love the PDP-11.
// %i funktioniert irgendwie nicht mit großen Zahlen wie 0xDEADBEEF, da
kommt 7fff ffff raus.
// so we do it without %i  and without octal.

int num_to_int(const char *s){

    int result;
    if ((*s == '0') && (*(s+1) == 'x')){ // *s+1 kann das Null-byte sein!
        sscanf(s, "%x", &result);
    } else {
        sscanf(s, "%d", &result);
    }
//    sscanf(s, "%i", &result);
    return result;
}


// display status cannot have the state as param since it must do busy
waiting.

void display_status(){

    if (shared_ram[STATUS] == STAT_BUSY){
        printf("PRU program is Busy. Waiting...\n");
        while (shared_ram[STATUS] == STAT_BUSY){};
    }

    printf("status = %08x = ", shared_ram[STATUS]);
    switch (shared_ram[STATUS]){
        case STAT_CLEARED:        printf("cleared"); break;
        case STAT_RDY_FOR_CMND:    printf("ready for command"); break;
        case STAT_INITIALIZING:    printf("initializing"); break;
        case STAT_BUSY:            printf("busy"); break;
        default:                printf("stat_unknown");
    }

    printf("error = %08x = ", shared_ram[ERRCODE]);
    switch (shared_ram[ERRCODE]){
        case ERR_NONE:                printf("none\n"); break;
        case ERR_HALTED:            printf("halted\n"); break;
        case ERR_BAD_CMND:            printf("bad command\n"); break;
        case ERR_BAD_PARAM:            printf("bad parameter\n"); break;
        case ERR_PIPO_OVERRUN:        printf("ping pong buffer
overflow\n"); break;
        case ERR_SPI_OVERRUN:        printf("SPI overrun\n"); break;
//        case ERR_UNEXPECTED_BUSY:    printf("unexpected busy\n"); break;
        default:                    printf("error_unknown\n");
    }

}  // display_status()


// this is now the aquisition command for the client command interpreter.
// Nevertheless it can return PRU error codes.
// TODO analoge Vcc überwachen, Timeout einbauen

int do_aquisition_cmnd( int n_samples){

    // FILE * phyle;
    int i;
    int *adc_buf_p;                // pointer into adc buffer for data
collection
    volatile int * ppp;            // ping pong pointer
    int words_transferred;

    printf("do aqu - on entry %d n_samples\n", n_samples);


    adc_buf_p             = adc_buffer;    // destination in ARM RAM
    words_transferred    = 0;
    // should not be busy when we start aquisition. cannot happen, really.
    if (shared_ram[STATUS] != STAT_RDY_FOR_CMND){
        return shared_ram[ERRCODE];
    }

    // That can be timelimited by setitimer(2) and getitimer(2),
    // avoid checking faster for done than PRU notes that it has work to do
    // den Sinn sehe ich gerade nicht ein  FIXME
?????????????????????????????????????????????????
    shared_ram[STATUS]  = STAT_CLEARED;


    shared_ram[PARAM1]  = compose_adc_ctl();    // 1 word from SCPI options
    shared_ram[COMMAND] = CMND_INIT_ADC;
    // Wait util PRU is done with initializing the ADC.
    // FIXME  can take forever if ADC has no power or clock
    while (shared_ram[STATUS] != STAT_RDY_FOR_CMND){};


    shared_ram[PARAM1]  = use_chan_b;            // Set 1 MSPS or
decimated output
    shared_ram[COMMAND] = CMND_CHAN;
    while (shared_ram[STATUS] != STAT_RDY_FOR_CMND){};

    printf("\nentering nice mode - starting aquisition n_samples =
%d\n, n_samples");
    nice (-19);

    shared_ram[STATUS]  = STAT_CLEARED;
    shared_ram[PARAM1]    = n_samples;
    shared_ram[COMMAND] = CMND_START_AQUISITION;

    while (    words_transferred <= n_samples) {

        if (shared_ram[PING_FULL] = 1){
            printf("i");
            ppp = & shared_ram[PING];        // + 0x400
            i = 1024;
            while (i--){
                *adc_buf_p++ = *ppp++;
            }
            shared_ram[PING_FULL] = 0;    // we got the contents, can
now be re-used
            words_transferred += 1024;

        } // ping buffer full

        if (shared_ram[PONG_FULL] = 1){
            printf("o");
            ppp = & shared_ram[PONG];        // + 0x800
            i = 1024;
            while (i--){
                *adc_buf_p++ = 48;    //  FIXME *ppp++;
            }
            shared_ram[PONG_FULL] = 0;    // we got the contents, can
now be re-used
            words_transferred += 1024;

        } // pong buffer full

    } // while()

    nice(0);
    printf ("     transferred %d words\n", words_transferred );
    if ( ERR_PIPO_OVERRUN == shared_ram[STATUS]) return ERR_PIPO_OVERRUN;
    if ( ERR_SPI_OVERRUN  == shared_ram[STATUS]) return
ERR_SPI_OVERRUN;    // cannot happen now.



    phyle = fopen("adc_result.txt", "w");        // FIXME return value
    fprintf(phyle, "word index  content\n\n");
    for (i=0; i< words_transferred; i++){   // 12 KB are 3 Kwords
        fprintf(phyle, "%12d  0x%8x = %8x  %12d\n", i, i,
adc_buffer[i], adc_buffer[i]);
    }
    fclose(phyle);      // FIXME return value

    return 0;
}  // do_aquisition_cmnd()



int pr_val(unsigned u, unsigned bit){
    return (u & (1<<bit) ? '1' : '0');
}


// some commands may need some postprocessing to display meaningful
results etc

void command_postprocessing(){

    // int t1, t2, t3;

    if (cmnd_to_send == CMND_START_AQUISITION) {    // that must go
fast now. No inspection by hand.
        printf("\npostprocessing aquisition command\n");
        do_aquisition_cmnd(32000);

    } else if ( cmnd_to_send == CMND_WRITE_ADDRESS){
        printf("\nPRU data space at 0x%08x written with 0x%08x check
read = 0x%08x\n",
                    shared_ram[PARAM1], shared_ram[PARAM2],
shared_ram[PARAM3]);

    } else if ( cmnd_to_send == CMND_READ_ADDRESS) {
        printf("\nPRU data space 0x%08x reads  0x%08x    dec %d\n",
                    shared_ram[PARAM1], shared_ram[PARAM3],
shared_ram[PARAM3]);
        //decode_some_registers(shared_ram[PARAM1], shared_ram[PARAM3]);
    }
}


void disp_shared_ram_state(){
    //printf("share0 = %10d 0x%08x\n",    shared_ram[0     ],
shared_ram[0     ] );
    printf("param1 = %12d 0x%08x",    shared_ram[PARAM1],
shared_ram[PARAM1] );
    printf("      test1  = %12d 0x%08x\n", shared_ram[TEST1],
shared_ram[TEST1] );
    printf("param2 = %12d 0x%08x",    shared_ram[PARAM2],
shared_ram[PARAM2] );
    printf("      test2  = %12d 0x%08x\n", shared_ram[TEST2],
shared_ram[TEST2] );
    printf("param3 = %12d 0x%08x",    shared_ram[PARAM3],
shared_ram[PARAM3] );
    printf("      test3  = %12d 0x%08x\n", shared_ram[TEST3],
shared_ram[TEST3] );
}


// when there are arguments given to the ltcsrv, they are commands for
the pru and up to 3 parameters
// Just numbers. pass them on to the PRU and display the results.

void run_pru_cmnd( int argc, char *argv[]){

    int i;
    // printf("entered run_pru_cmnd()\n");
    // printf("\nStatus before running PRU command: "); // Cannot be
done later b/c we might change params for
                                                    // a prog that
still might run.
    // display_status();                            // this will wait
until PRU program is no longer busy.
    if (shared_ram[STATUS] == STAT_BUSY){
        printf("PRU program is already busy. Try to abort? (y/ any
key)\n");
        if (getchar() == 'y'){
            shared_ram[COMMAND] = CMND_ABORT;
            printf("trying to abort it and exit\n");
            exit (-1);
        } else {
            printf("waiting...\n");
            while (shared_ram[STATUS] == STAT_BUSY) {};
        }
    }
    //printf("Leftover command word before launching new command: ");
    //display_cmnd(shared_ram[COMMAND]);

    cmnd_to_send = argv[1][0];                            // atoi(argv[1]);
    printf("\ncommand to send: ");
    display_cmnd(cmnd_to_send);


     if (cmnd_to_send == CMND_CLEAR_RAM){
        // this works locally just to fill it with FFFF.
        // The PRU will need a restart after that.
        for (i=0; i < 3*1024; i++) shared_ram[i] = 0xffffffff;
        for (i=0; i < 4*1024; i++) pru_ram[i]    = 0xfffffff0;
        printf("\nthat was no real command, just wiped out PRU data and
shared RAM\n");
        printf("to make a nice background for the memory dumps. restart
the PRU.\n");
        printf("exiting.\n");
        exit (0);
    }
    // printf("\nnach command2send\n");
    if (argc == 3){

        shared_ram[PARAM1]  = num_to_int(argv[2]);

    } else if (argc == 4){

        shared_ram[PARAM1]  = num_to_int(argv[2]);
        shared_ram[PARAM2]  = num_to_int(argv[3]);

    } else if (argc == 5){

        shared_ram[PARAM1]  = num_to_int(argv[2]);
        shared_ram[PARAM2]  = num_to_int(argv[3]);
        shared_ram[PARAM3]  = num_to_int(argv[4]);

    } else if (argc >= 6){
        printf("argc too large: %d, giving up\n", argc);
        exit(-1);
    }
    shared_ram[TEST1] = -1;
    shared_ram[TEST2] = -2;
    shared_ram[TEST3] = -3;
    // printf("huhuh\n");
    // nicht existierende argv anzufassen führt zu segfault.
    // printf("%d    %d    %d \n", atoi(argv[1]), atoi(argv[2]),
atoi(argv[3]));
    // for (int k= 0; k<8; k++) printf("\nshared ram[%d] = 0x%x  %d",
k, shared_ram[k], shared_ram[k]);
    // printf("\n");
    // now display & safe the pre-conditions.
    disp_shared_ram_state();
//    copy_pru_ram_to_file("pre_pru.txt");
//    copy_shared_ram_to_file("pre_shared.txt");

//-------------------------------------------------------------------------------

    //printf("\nKicking it off\n");
    shared_ram[COMMAND] = cmnd_to_send; // Now trigger the action.

    command_postprocessing();

    printf("\nStatus after running PRU command: ");
    display_status();   // this will wait until PRU program is no
longer busy.
    //printf("Hopefully cleared command word after execution: ");
    //display_cmnd(shared_ram[COMMAND]);

    disp_shared_ram_state();
    // printf("copying shared ram to file\n");
    copy_pru_ram_to_file("post_pru.txt");
    copy_shared_ram_to_file("post_shared.txt");

    exit(0);
}  // run_pru_cmnd()




int open_pru(){

    int i;

    //if (verbose) printf("enter open_pru()\n");
    if (init_BBB_pins()) return 1;

    // map the shared ram into our virtual memory
    dev_mem_fd = open("/dev/mem",O_RDWR | O_SYNC);

    // mmap params:
    // address 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("could not mmap() shared PRU ram");

    // 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("could not mmap() local PRU rams");
    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;
}






phfbertoleti

unread,
Jan 18, 2021, 7:26:30 AM1/18/21
to BeagleBoard
Gehard, thank you very much!

Considering the code you've provided, I understand that:
  •  I need these header files:

#include <sys/types.h>      
#include <stdio.h>           
#include <stdlib.h>          
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include "ltcsrv.h"
#include "pru_if.h"

  • A file descriptor must be used for /dev/mem:

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

  • Shared RAM is mapped (prepared for use) by this line:

 shared_ram = (int *) mmap(NULL, 12*1024, PROT_READ | PROT_WRITE, MAP_SHARED, dev_mem_fd, 0x4A300000 + 0x10000);

  • Here follows examples of usage (in this case, writing to shared ram memory): 

 shared_ram[0] = ...   ; //write to 0x4A310000
 shared_ram[1] = ...   ; //write to 0x4A310004
 shared_ram[1] = ...   ; //write to 0x4A310008

Am I right?

Regarding header files, I noticed the pru related headerfile has been included as #include "pru_if.h". Is it a local file from your project or a header file referred to a lib? In case of being referred to a lib, it could be included as #include <pru_if.h>, right?


Best Regards,
Pedro Bertoleti

Gerhard Hoffmann

unread,
Jan 18, 2021, 8:14:48 AM1/18/21
to beagl...@googlegroups.com

Hi,

just for the mapping, you won't need most of the include files.

I often include xyz.h in xyz.c so that I get at least a warning when I change

sth. so that the public promises in .h no longer hold.

pru_if.h is in the post but not needed.

Remove the includes and the compiler will tell you what is missing.

You definitely don't need ltcsrv.h and the stuff for nice(). 


  • A file descriptor must be used for /dev/mem:

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

  • Shared RAM is mapped (prepared for use) by this line:

 shared_ram = (int *) mmap(NULL, 12*1024, PROT_READ | PROT_WRITE, MAP_SHARED, dev_mem_fd, 0x4A300000 + 0x10000);

  • Here follows examples of usage (in this case, writing to shared ram memory): 

 shared_ram[0] = ...   ; //write to 0x4A310000
 shared_ram[1] = ...   ; //write to 0x4A310004
 shared_ram[1] = ...   ; //write to 0x4A310008
                       ^!!

Am I right?

Yes.

I should have snipped a lot of text, but was only half awake.

Cheers, Gerhard



Vinicius Juvinski

unread,
Jan 18, 2021, 9:50:10 AM1/18/21
to beagl...@googlegroups.com
One detail,

If I not wrong, the first 100 bytes of the dram is used by pru for some configs, register and other stuffs I don't remember right now, so you should use BASE Address +1000 at least 



https://www.ti.com/lit/ug/spruh73q/spruh73q.pdf?ts=1610923856664 - section 4.3 details the memory usage from PRU.




--
For more options, visit http://beagleboard.org/discuss
---
You received this message because you are subscribed to the Google Groups "BeagleBoard" group.
To unsubscribe from this group and stop receiving emails from it, send an email to beagleboard...@googlegroups.com.

Pedro Henrique Fonseca Bertoleti

unread,
Jan 18, 2021, 10:06:34 AM1/18/21
to beagl...@googlegroups.com
Vinicius, have you meant 0x4A300000 + 0x1000 as the frist shared mem address to be used?

Gerhard Hoffmann

unread,
Jan 18, 2021, 10:25:09 AM1/18/21
to beagl...@googlegroups.com

Am 18.01.21 um 15:49 schrieb Vinicius Juvinski:
> One detail,
>
> If I not wrong, the first 100 bytes of the dram is used by pru for
> some configs, register and other stuffs I don't remember right now, so
> you should use BASE Address +1000 at least
>
>
>
> https://www.ti.com/lit/ug/spruh73q/spruh73q.pdf?ts=1610923856664 -
> section 4.3 details the memory usage from PRU.
>
>
Probably PRU-owned SRAM, not the global DRAM.

The 12 KB shared ram is free to use, the ARM and the PRU program just
must agree.

Each PRU has 2 KB static ram intended for itself, it can also be seen by
the other PRU

and by the ARM. The C compiler uses that for variables, stack and heap.

When you use the functions copy_pru_ram_to_file() and
copy_shared_ram_to_file()

you can open the file with vi or whatever and see the RAM contents in a
slightly

annotated form. It's not a symbolic debugger but better than nothing.


Gerhard



Vinicius Juvinski

unread,
Jan 18, 2021, 10:47:03 AM1/18/21
to beagl...@googlegroups.com
Hi Pedro,

Yes 

Sent from my iPhone


Em 18 de jan. de 2021, à(s) 12:06, Pedro Henrique Fonseca Bertoleti <phfber...@gmail.com> escreveu:



Pedro Henrique Fonseca Bertoleti

unread,
Jan 18, 2021, 10:29:37 PM1/18/21
to beagl...@googlegroups.com
Vinicius and Gehard, thank you very much for your help!

I'm able to communicate (through shared memory) PRU0 and host (Linux) side. It worked really well!



Vinicius Juvinski

unread,
Jan 18, 2021, 11:01:11 PM1/18/21
to beagl...@googlegroups.com
Reply all
Reply to author
Forward
0 new messages