Tool/software: TI C/C++ Compiler
I am compiling a test pru program. When I link it with the arm program, I get the wrong address for the shared memory. If I get the address from the compiler .map file and manually set it, it works.
This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Tool/software: TI C/C++ Compiler
I am compiling a test pru program. When I link it with the arm program, I get the wrong address for the shared memory. If I get the address from the compiler .map file and manually set it, it works.
You must be using hexpru as part of some larger procedure to get a program loaded and running on the PRU. Unfortunately, I am not familiar with this procedure. Please tell me more about it. In particular, I need to know exactly how hexpru is invoked, especially what output format is used.
Thanks and regards,
-George
I compile with: clpru -o3 test_pru.c -al -k -z lnk.cmd -o test_pru.out
and create host link file with:hexpru PRU_to_ARM.cmd test_pru.out -o test_pru.obj
Here is lnk.cmd:
-cr
-stack 0x100
-heap 0x100
-i /usr/local/ti-cgt-pru_2.1.5/lib
-m test_pru.map
-o test_pru.bin
MEMORY
{
PAGE 0:
PRUIMEM: o = 0x00000000 l = 0x00001000 /* 8kB PRU0 Instruction RAM */
PAGE 1:
PRUDMEM: o = 0x00000000 l = 0x00001000 /* 8kB PRU Data RAM 0 */
}
SECTIONS
{
.text > PRUIMEM, PAGE 0
.stack > PRUDMEM, PAGE 1
.bss > PRUDMEM, PAGE 1
.cio > PRUDMEM, PAGE 1
.const > PRUDMEM, PAGE 1
.data > PRUDMEM, PAGE 1
.switch > PRUDMEM, PAGE 1
.sysmem > PRUDMEM, PAGE 1
.cinit > PRUDMEM, PAGE 1
}
Here is PRU_to_ARM.cmd
--image
--host_image
--host_image:target=ARM
--host_image:endianness=little
--host_image:hidden_symbols
--host_image:show=shared_buf
ROMS
{
PAGE 0:
PRU0_IMEM: o=0x00000000 l=0x00001000
PAGE 1:
PRU0_DMEM: o=0x00000000 l=0x00001000
PRU0_EXT: o=0x80000000 l=0x00001000
}
I am including test_pru.c and test_arm.c here:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pruss/prussdrv.h>
#include <pruss/pruss_intc_mapping.h>
///#define USE_PASM
#define PRU_NUM 0
#ifdef USE_PASM
# define PRU_CODE "./test_pru.bin"
#else
# define PRU_CODE "./test_pru_code.bin"
#endif
//**********************************************************
// PRU Internal Registers
static char *Cycle; // PRU Cycle Counter
static char *PruCtl; // PRU Control Register
//**********************************************************
/*** pru_setup() -- initialize PRU and interrupt handler
Initializes the PRU specified by PRU_NUM and sets up PRU_EVTOUT_0 handler.
Returns 0 on success, non-0 on error.
***/
static int pru_setup(const char * const path) {
int rtn;
tpruss_intc_initdata intc = PRUSS_INTC_INITDATA;
if(!path) {
fprintf(stderr, "pru_setup(): path is NULL\n");
return -1;
}
// initialize the library, PRU and interrupt
if(access( PRU_CODE, F_OK ) == -1 ){
printf("%s does not exist\n", PRU_CODE);
return -1;
}
if((rtn = prussdrv_init()) != 0) {
fprintf(stderr, "prussdrv_init() failed\n");
return rtn;
}
/* open the interrupt */
if((rtn = prussdrv_open(PRU_EVTOUT_0)) != 0) {
fprintf(stderr, "prussdrv_open() failed\n");
return rtn;
}
/* initialize interrupt */
if((rtn = prussdrv_pruintc_init(&intc)) != 0) {
fprintf(stderr, "prussdrv_pruintc_init() failed\n");
return rtn;
}
return rtn;
}
/*** pru_cleanup() -- halt PRU and release driver
Performs all necessary de-initialization tasks for the prussdrv library.
Returns 0 on success, non-0 on error.
***/
static int pru_cleanup(void) {
int rtn = 0;
/* clear the event (if asserted) */
if(prussdrv_pru_clear_event(PRU_EVTOUT_0, PRU0_ARM_INTERRUPT)) {
fprintf(stderr, "prussdrv_pru_clear_event() failed\n");
rtn = -1;
}
/* halt and disable the PRU (if running) */
if((rtn = prussdrv_pru_disable(PRU_NUM)) != 0) {
fprintf(stderr, "prussdrv_pru_disable() failed\n");
rtn = -1;
}
/* release the PRU clocks and disable prussdrv module */
if((rtn = prussdrv_exit()) != 0) {
fprintf(stderr, "prussdrv_exit() failed\n");
rtn = -1;
}
printf("PRU Stopped\n");
return rtn;
}
//*****************************************************************************
void print_buf(const char *name, char *buf, int len){
printf("%s @%08X = ", name, buf);///
for(int i=0; i<len; i++){
printf("%02X ", (buf)[i]);
if(i && ((i % 16) == 15)){
printf("\n ");
for(int n=0; n<strlen(name); n++) printf(" ");
}
}
printf("\n");
}
//*****************************************************************************
int main(){
int i;
/* Invoke PRU */
if(pru_setup(PRU_CODE)){
printf("%s open failed\n", PRU_CODE);
pru_cleanup();
return -1;
}
/* Shared buffer between ARM and PRU0 */
# ifdef USE_PASM
static void *buffer;
int shared_size = 100;
prussdrv_map_prumem(PRU_NUM, &buffer);
# else
int shared_size = 200;
extern volatile char shared_buf[];
static void *share_mem = (void *)shared_buf;
prussdrv_map_prumem(PRUSS0_PRU0_DATARAM, &share_mem);
/// volatile void *buffer = (volatile void *)((long)share_mem + (long)shared_buf); // does not work!
volatile void *buffer = (volatile void *)((long)share_mem + (long)shared_buf - (long)0x222B0);
/// volatile void *buffer = (volatile void *)((long)share_mem + (long)0xE0);
printf("share_mem = %X shared_buf = %X\n", (int)share_mem, (int)shared_buf);///
# endif
// Clear the buffer
for(int i=0; i< shared_size; i++) ((char *)buffer)[i]=0;
print_buf("buffer", (char *)buffer, shared_size);
if(prussdrv_pru_reset(PRU_NUM) < 0){
printf("PRU%d: Reset failed\n", PRU_NUM);
pru_cleanup();
return -1;
}
usleep(100000);
if(prussdrv_exec_program(PRU_NUM, PRU_CODE) < 0){
printf("PRU%d: %s execute failed\n", PRU_NUM, PRU_CODE);
pru_cleanup();
return -1;
}
usleep(100000);
/* Perform a read from the shared buffer */
print_buf("buffer", (char *)buffer, shared_size);
pru_cleanup();
return(0);
}
#define CLOCK 200000000 // PRU is always clocked at 200MHz
volatile char shared_buf[100] __attribute__((cregister("PRUDMEM")));
volatile char shared_buf[100];
volatile register unsigned int __R30;
void uSleep(int uSecs){
int uSec;
for(uSec=0; uSec<uSecs; uSec++){
__delay_cycles(CLOCK / 1000000); // Delay 1 uSec
}
}
void sendBit(char val){
if(val & 1) { __R30 |= (1<<5); }
else { __R30 &= ~(1<<5); }
uSleep(833);
}
void sendByte(unsigned char b){
int i;
sendBit(0); // Start bit
for(i=0; i<8; i++){
sendBit(b & 1); // Data bits
b >>= 1;
}
sendBit(1); // Stop bits
sendBit(1);
}
int main()
{
int ix=0;
while(1){
for (ix=64; ix<96; ix++){
shared_buf[ix] = ix*3;
}
/// sendByte(0x0A);
/// sendByte(0x0D);
}
}
Hello Brent,
I am unfamiliar with the procedure you are using - George might be able to offer help there. For a template of how I typically compile PRU code in Linux, take a look at any of the Makefiles in the PRU Software Support Package (in the Linux SDK under sdk/example-applications/pru-icss.../examples/am335x/PRU_project or the git repo - example here).
Regards,
Nick
Hello Brent,
* Are you running Linux or RTOS on your ARM core that loads the PRU firmware into the PRU?
* What version of that OS are you running?
* How are you loading the PRU firmware?
* Please describe the error behavior you are seeing.
Regards,
Nick
As in the information I already sent you.
*Linux
*Debian 9.3
*prussdrv_exec_program()
When I link the pru code to the arm code, it produces the wrong address for the shared memory.
Hello Brent,
TI currently supports using RemoteProc to load PRU firmware - I would expect RemoteProc to work for you unless you are using UIO. TI does not currently support UIO, and you would want to go elsewhere for support in loading PRU firmware using UIO (perhaps the beaglebone forums).
Please note that TI does not support Debian distributions, so we are also unable to address any future Linux-specific questions.
Regards,
Nick