gdbserver shared library PRU loader

89 views
Skip to first unread message

Jelle Spijker

unread,
Oct 12, 2016, 9:05:12 AM10/12/16
to BeagleBoard
Hi All,

I'm running Arch Linux on my BBB, so no remoteproc for me :-( when working with the PRU.

In my setup I'm developing a shared library that loads a simple PRU program via a unittest to verify if it works. Because I work with prussdrv the program should be run with sudo. If that it is the case the shared library can't be found, so I have to export LD_LIBRARY=../lib/ for my super user. Now debugging works for unit test, but as soon as I have to step into the code of the shared library, it doesn't show the code, so I can't figure out where my program hangs.

If anybody knows how to load a PRU firmware with out being root it is much preferred.

I'm currently executing gdbserver with the following command:
su --command="export LD_LIBRARY_PATH=../lib && gdbserver localhost:8080 ./runTests"

My current code is one of the most basic pieces just to load a PRU program, which toggles a pin, to drive a steppermotor, but I can't see any a pattern on my scope, so I assume it doesn't get load, which I can't verify.

Fragment of the devicetree:
/ {
   compatible =
"ti,beaglebone", "ti,beaglebone-black", "ti,beaglebone-green";

   
// identification
   part-number = "MTI-CATAMARAN";
   version
= "00A0";

   
// resources this cape uses
   exclusive-use =
     
"P9.39",      // AIN0
      "P9.40",      // AIN1
      "P9.37",      // AIN2
      "P9.38",      // AIN3
      "P9.33",      // AIN4
      "P9.36",      // AIN5
      "P9.35",      // AIN6
    "P8.44",  /* Sonar front */
    "P8.45",  /* Sonar SB */
    "P8.46",  /* Sonar PS */
    "P8.41",  /* Sonar front Step */
    "P8.42",  /* Sonar front Dir */
    "P9.13",   /* uart4_txd IMU */
    "P9.11",   /* uart4_rxd IMU */

      "tscadc",  // hardware ip used
    "pruss";


   fragment@
0 {
      target
= <&tscadc>;
      __overlay__
{

         status
= "okay";
         adc
{
            ti
,adc-channels = <0 1 2 3 4 5 6>;
            ti
,chan-step-avg = <0x16 0x16 0x16 0x16 0x16 0x16 0x16>;
            ti
,chan-step-opendelay = <0x98 0x98 0x98 0x98 0x98 0x98 0x98>;
            ti
,chan-step-sampledelay = <0x0 0x0 0x0 0x0 0x0 0x0 0x0>;
         
};
     
};
 
};

  fragment@
1 {
    target
= <&pruss>;
    __overlay__
{

      status
= "okay";
   
};
 
};

  fragment@
2 {
    target
= <&am33xx_pinmux>;
    __overlay__
{

    pru_pru_pins
: pinmux_pru_pru_pins {
        pinctrl
-single,pins = <
            BONE_P8_41
(PIN_OUTPUT_PULLDOWN | MUX_MODE5) /* lcd_data5.pr1_pru1_pru_r30_4, MODE5 | OUTPUT | PRU, Sonar front Dir */
            BONE_P8_42 (PIN_OUTPUT_PULLDOWN | MUX_MODE5) /* lcd_data4.pr1_pru1_pru_r30_5, MODE5 | OUTPUT | PRU, Sonar front Step */
            BONE_P8_44 (PIN_INPUT_PULLDOWN | MUX_MODE6)     /* lcd_data3.pr1_pru1_pru_r31_3, MODE6 | INPUT | PRU, Sonar front */
            BONE_P8_45 (PIN_INPUT_PULLDOWN | MUX_MODE6)     /* lcd_data1.pr1_pru1_pru_r31_0, MODE6 | INPUT | PRU, Sonar PS */
            BONE_P8_46 (PIN_INPUT_PULLDOWN | MUX_MODE6)     /* lcd_data0.pr1_pru1_pru_r31_1, MODE6 | INPUT | PRU, Sonar SB */
        >;
   
};

    bb_uart4_pins
: pinmux_bb_uart4_pins {
        pinctrl
-single,pins = <
          BONE_P9_13
(PIN_OUTPUT | MUX_MODE6)  // gpmc_wpn.uart4_txd_mux2
          BONE_P9_11 (PIN_INPUT  | MUX_MODE6)  // gpmc_wait0.uart4_rxd_mux2
        >;
     
};
   
};
 
};

  fragment@
3 {
    target
= <&uart4>;
    __overlay__
{
      status
= "okay";
      pinctrl
-names = "default";
      pinctrl
-0 = <&bb_uart4_pins>;
   
};
 
};

};

The PRU firmware:
#include <stdint.h>
#include "resource_table_empty.h"

volatile register unsigned int __R31, __R30;

int main(void)
{
       
unsigned int i;

       
for (i = 0; i < 200; i++) {
                __R30
= __R30 | (1 << 5); // HIGH
                __delay_cycles
(60000000);
                __R30
= __R30 & ~(1 << 5); // LOW
                __delay_cycles
(60000000);
       
}

        __R31
= 32 | 3; // send interrupt to host
        __halt
();
       
       
/* Should never return */
       
return 0;
}



Fragment of the UnitTest (Google test) (This code I can step through with my IDE):
TEST(Controller, PRU_Toggle) {
   
using namespace oCpt::components::controller;
   
using namespace oCpt;
   
World::ptr world = World::ptr(new World());
   
BBB::ptr controller = BBB::ptr(new BBB(world));
   
BBB *bbb = static_cast<BBB*>(controller.get());
    bbb
->loadPRUfirmware(1,"./SonarArray.out");
}

Fragment of the Shared library:
void BBB::loadPRUfirmware(const unsigned int &number, const std::string &firmwareLocation) {
   
//Initialize structure used by prussdrv_pruintc_intc
    tpruss_intc_initdata pruss__intc_initdata = PRUSS_INTC_INITDATA;
   
//Allocate and initialize memory
    prussdrv_init();
    prussdrv_open
(PRU_EVTOUT0);
   
//Map PRU's interrupts
    prussdrv_pruintc_init(&pruss__intc_initdata);
   
//Load and execute the PRU program on the PRU
    prussdrv_exec_program(number, firmwareLocation.c_str());
   
// Wait for event completion from PRU, returns PRU_EVTOUT_0 number
    //int n = prussdrv_pru_wait_event(PRU_EVTOUT0);
    //prussdrv_pru_disable(number);
    //prussdrv_exit();
}

Any help is much appreciated

best regards,
Jelle

TJF

unread,
Oct 12, 2016, 11:53:36 AM10/12/16
to BeagleBoard
Hi!


Am Mittwoch, 12. Oktober 2016 15:05:12 UTC+2 schrieb Jelle Spijker:
Hi All,

I'm running Arch Linux on my BBB, so no remoteproc for me :-( when working with the PRU.

You're lucky, you didn't waste time for testing remoteproc.
 
Because I work with prussdrv the program should be run with sudo. If that it is the case the shared library can't be found, so I have to export LD_LIBRARY=../lib/ for my super user.

prussdrv doesn't need root privileges, but the user needs at least read access to the interrupt handlers (/dev/uio[0-7]).

Regarding the linker issue: did you update the cache for the run-time linker (sudo ldconfig).

Fragment of the Shared library:
void BBB::loadPRUfirmware(const unsigned int &number, const std::string &firmwareLocation) {
   
//Initialize structure used by prussdrv_pruintc_intc
    tpruss_intc_initdata pruss__intc_initdata = PRUSS_INTC_INITDATA;
   
//Allocate and initialize memory
    prussdrv_init();
    prussdrv_open
(PRU_EVTOUT0);
   
//Map PRU's interrupts
    prussdrv_pruintc_init(&pruss__intc_initdata);
   
//Load and execute the PRU program on the PRU
    prussdrv_exec_program(number, firmwareLocation.c_str());
   
// Wait for event completion from PRU, returns PRU_EVTOUT_0 number
    //int n = prussdrv_pru_wait_event(PRU_EVTOUT0);
    //prussdrv_pru_disable(number);
    //prussdrv_exit();
}

All prussdrv functions return a value (zero in case of success). What return values do you get?
 
Regards

TJF

unread,
Oct 12, 2016, 11:57:49 AM10/12/16
to BeagleBoard
Just found another issue:


Am Mittwoch, 12. Oktober 2016 15:05:12 UTC+2 schrieb Jelle Spijker:
Fragment of the Shared library:
void BBB::loadPRUfirmware(const unsigned int &number, const std::string &firmwareLocation) {
   
//Initialize structure used by prussdrv_pruintc_intc
    tpruss_intc_initdata pruss__intc_initdata = PRUSS_INTC_INITDATA;
   
//Allocate and initialize memory
    prussdrv_init();
    prussdrv_open
(PRU_EVTOUT0);
   
//Map PRU's interrupts
    prussdrv_pruintc_init(&pruss__intc_initdata);
   
//Load and execute the PRU program on the PRU
    prussdrv_exec_program(number, firmwareLocation.c_str());
   
// Wait for event completion from PRU, returns PRU_EVTOUT_0 number
    //int n = prussdrv_pru_wait_event(PRU_EVTOUT0);
    //prussdrv_pru_disable(number);
    //prussdrv_exit();
}

It should read (underscore before 0):

prussdrv_open(PRU_EVTOUT_0);

 

Jelle Spijker

unread,
Oct 13, 2016, 3:16:31 AM10/13/16
to BeagleBoard
Hi TJF,

Thnx for your reply. I tried the following steps:

I added the /dev/uio[0..7] to the group bbb (of which my user is a member) and gave them read right for a group.
I changed the typo
prussdrv_open(PRU_EVTOUT_0);

When I run the test as a normal user and output the return values to the cout it returns
prussdrv_init returns: 0
prussdrv_open returns: -1
Segmentation fault (core dumped)


When I execute as sudo it gives the following output:
prussdrv_init returns: 0
prussdrv_open returns: 0
prussdrv_pruintc_init returns: 0
prussdrv_exec_program returns: -1

When I try to remote debug as sudo by running gdbserver as follows:
su --command="export LD_LIBRARY_PATH=../lib && ldconfig && gdbserver localhost:8080 ./runTests

I still can't step through my shared library code

Op woensdag 12 oktober 2016 17:57:49 UTC+2 schreef TJF:

TJF

unread,
Oct 13, 2016, 3:45:27 AM10/13/16
to BeagleBoard


Am Donnerstag, 13. Oktober 2016 09:16:31 UTC+2 schrieb Jelle Spijker:
When I run the test as a normal user and output the return values to the cout it returns
prussdrv_init returns: 0
prussdrv_open returns: -1
Segmentation fault (core dumped)


I'm not sure ATM. It may also need write access for the interrupt specified in function call prussdrv_open(). That's /dev/uio0 in your case. Just make them all writeable for the group, to be on the save side.

When I execute as sudo it gives the following output:
prussdrv_init returns: 0
prussdrv_open returns: 0
prussdrv_pruintc_init returns: 0
prussdrv_exec_program returns: -1

How did you generate the binary? Function prussdrv_exec_program()doesn't handle ELF format (generated by C compilers). It only loads raw code (as generated by pasm assembler).
 
When I try to remote debug as sudo by running gdbserver as follows:
su --command="export LD_LIBRARY_PATH=../lib && ldconfig && gdbserver localhost:8080 ./runTests

I still can't step through my shared library code

Sorry, can't help. I never used a debugger.

It seems that you installed libprussdrv local, so you don't need ldconfig command here. (It's used once in case of system wide installation.)

Regards

Jelle Spijker

unread,
Oct 13, 2016, 4:42:13 AM10/13/16
to BeagleBoard
The PRU program is genereted in C with the CCS IDE, the compiler is TI V2.1.2 en the linker command file is AM335x_PRU.cmd
/****************************************************************************/
/*  AM335x_PRU.cmd                                                          */
/*  Copyright (c) 2015  Texas Instruments Incorporated                      */
/*                                                                          */
/*    Description: This file is a linker command file that can be used for  */
/*                 linking PRU programs built with the C compiler and       */
/*                 the resulting .out file on an AM335x device.             */
/****************************************************************************/

-cr    /* Link using C conventions */

/* Specify the System Memory Map */
MEMORY
{
    PAGE 0:
    PRU_IMEM        : org = 0x00000000 len = 0x00002000  /* 8kB PRU0 Instruction RAM */

    PAGE 1:

    /* RAM */

    PRU_DMEM_0_1    : org = 0x00000000 len = 0x00002000  CREGISTER=24  /* 8kB PRU Data RAM 0_1 */
    PRU_DMEM_1_0    : org = 0x00002000 len = 0x00002000  CREGISTER=25  /* 8kB PRU Data RAM 1_0 */
    
    PAGE 2:
    PRU_SHAREDMEM   : org = 0x00010000 len = 0x00003000  CREGISTER=28  /* 12kB Shared RAM */

    DDR             : org = 0x80000000 len = 0x00000100  CREGISTER=31
    L3OCMC          : org = 0x40000000 len = 0x00010000  CREGISTER=30


    /* Peripherals */

    PRU_CFG         : org = 0x00026000 len = 0x00000044  CREGISTER=4
    PRU_ECAP        : org = 0x00030000 len = 0x00000060  CREGISTER=3
    PRU_IEP         : org = 0x0002E000 len = 0x0000031C  CREGISTER=26
    PRU_INTC        : org = 0x00020000 len = 0x00001504  CREGISTER=0
    PRU_UART        : org = 0x00028000 len = 0x00000038  CREGISTER=7

    DCAN0           : org = 0x481CC000 len = 0x000001E8  CREGISTER=14
    DCAN1           : org = 0x481D0000 len = 0x000001E8  CREGISTER=15
    DMTIMER2        : org = 0x48040000 len = 0x0000005C  CREGISTER=1
    PWMSS0          : org = 0x48300000 len = 0x000002C4  CREGISTER=18
    PWMSS1          : org = 0x48302000 len = 0x000002C4  CREGISTER=19
    PWMSS2          : org = 0x48304000 len = 0x000002C4  CREGISTER=20
    GEMAC           : org = 0x4A100000 len = 0x0000128C  CREGISTER=9
    I2C1            : org = 0x4802A000 len = 0x000000D8  CREGISTER=2
    I2C2            : org = 0x4819C000 len = 0x000000D8  CREGISTER=17
    MBX0            : org = 0x480C8000 len = 0x00000140  CREGISTER=22
    MCASP0_DMA      : org = 0x46000000 len = 0x00000100  CREGISTER=8
    MCSPI0          : org = 0x48030000 len = 0x000001A4  CREGISTER=6
    MCSPI1          : org = 0x481A0000 len = 0x000001A4  CREGISTER=16
    MMCHS0          : org = 0x48060000 len = 0x00000300  CREGISTER=5
    SPINLOCK        : org = 0x480CA000 len = 0x00000880  CREGISTER=23
    TPCC            : org = 0x49000000 len = 0x00001098  CREGISTER=29
    UART1           : org = 0x48022000 len = 0x00000088  CREGISTER=11
    UART2           : org = 0x48024000 len = 0x00000088  CREGISTER=12

    RSVD10          : org = 0x48318000 len = 0x00000100  CREGISTER=10
    RSVD13          : org = 0x48310000 len = 0x00000100  CREGISTER=13
    RSVD21          : org = 0x00032400 len = 0x00000100  CREGISTER=21
    RSVD27          : org = 0x00032000 len = 0x00000100  CREGISTER=27

}

/* Specify the sections allocation into memory */
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              >  PRU_IMEM, PAGE 0
    .stack             >  PRU_DMEM_0_1, PAGE 1
    .bss               >  PRU_DMEM_0_1, PAGE 1
    .cio               >  PRU_DMEM_0_1, PAGE 1
    .data              >  PRU_DMEM_0_1, PAGE 1
    .switch            >  PRU_DMEM_0_1, PAGE 1
    .sysmem            >  PRU_DMEM_0_1, PAGE 1
    .cinit             >  PRU_DMEM_0_1, PAGE 1
    .rodata            >  PRU_DMEM_0_1, PAGE 1
    .rofardata         >  PRU_DMEM_0_1, PAGE 1
    .farbss            >  PRU_DMEM_0_1, PAGE 1
    .fardata           >  PRU_DMEM_0_1, PAGE 1
    .resource_table    >  PRU_DMEM_0_1, PAGE 1
}


 It generates an SonarArray.out see attachment. 

Op donderdag 13 oktober 2016 09:45:27 UTC+2 schreef TJF:
SonarArray.out

TJF

unread,
Oct 14, 2016, 1:25:51 AM10/14/16
to BeagleBoard

Am Donnerstag, 13. Oktober 2016 10:42:13 UTC+2 schrieb Jelle Spijker:
The PRU program is genereted in C with the CCS IDE, the compiler is TI V2.1.2 en the linker command file is AM335x_PRU.cmd

That doesn't work. You'd have to extract the .text section from that file and load only that data with function prussdrv_exec_program().

Better use pasm assembler. You won't have to deal with all that overhead.

Regards
Reply all
Reply to author
Forward
0 new messages