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.

Compiler: hexpru produces wrong address for shared memory



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);
       }
    }
    

  • Here is the compile command for the ARM program:arm-linux-gnueabihf-g++ -g -Wno-deprecated -I ./ -c test_arm.c
    arm-linux-gnueabihf-g++ -g -Wno-deprecated test_arm.o test_pru.obj -lprussdrv -L ./pruss/ -o test_arm
  • 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

  • I am not having a problem compiling the pru code. The problem is getting shared memory address to the arm program.
  • 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,

    Are you using UIO with your PRU application?

    Regards,
    Nick
  • 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