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
Hi All, I'm running Arch Linux on my BBB, so no remoteproc for me :-( when working with the PRU.
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.
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();
}
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();
}
prussdrv_open(PRU_EVTOUT_0);
prussdrv_open(PRU_EVTOUT_0);
prussdrv_init returns: 0prussdrv_open returns: -1Segmentation fault (core dumped)
prussdrv_init returns: 0prussdrv_open returns: 0prussdrv_pruintc_init returns: 0prussdrv_exec_program returns: -1
su --command="export LD_LIBRARY_PATH=../lib && ldconfig && gdbserver localhost:8080 ./runTests
When I run the test as a normal user and output the return values to the cout it returns
prussdrv_init returns: 0prussdrv_open returns: -1Segmentation fault (core dumped)
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: 0prussdrv_open returns: 0prussdrv_pruintc_init returns: 0prussdrv_exec_program returns: -1
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
/****************************************************************************//* 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}
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