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.

PRU-SWPKG: Sharing variables across PRUs

Part Number: PRU-SWPKG


Since the PRUSS 0 does not have an explicit PRU Shared memory available on AM437x I am trying to use PRU DMEM to share variables across the two PRU cores. I have added a pragma directive for DATA_SECTION in both the C files (PRU0 and PRU1 code) and also specified it in the linker file. Both '.map' files show the same address location and space for the variable but I don't see the variable being updated. The way i am checking this is that as soon as the PRU1 updates the variable, PRU0 flashes an led but that doesn't look like it is working.

Here are the relevant sections:

C file declaration in PRU0.c and PRU1.c (identical in both):

#pragma DATA_SECTION(max_count, ".max_count")
volatile far uint32_t max_count = 0;

The .map file:

*          1    00002fe0    00000004     UNINITIALIZED
                  00002fe0    00000004     PRU0.object (.max_count)
*          1    00002fe0    00000004     UNINITIALIZED
                  00002fe0    00000004     PRU_pidSendData.object (.max_count)

And I have also attached the linker file.

/*  AM437x_PRU_SS0.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 AM437x device.             */

-cr								/* Link using C conventions */

/* Specify the System Memory Map */
      PAGE 0:
	PRU_IMEM		: org = 0x00000000 len = 0x00001000  /* 4kB PRU-ICSS0 Instruction RAM */

      PAGE 1:

	/* RAM */

	PRU_DMEM_0_1	: org = 0x00000000 len = 0x00001000 CREGISTER=24 /* 4kB PRU Data RAM 0_1 */
	PRU_DMEM_1_0	: org = 0x00002000 len = 0x00000fe0	CREGISTER=25 /* 4kB PRU Data RAM 1_0 */
	SHAREDMEM		: org = 0x00002fe0 len = 0x00000004

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

	/* Peripherals */

	PRU_CFG			: org = 0x00026000 len = 0x00000120	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
	MMCSD0			: 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 */
	/* 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
	.max_count	>	SHAREDMEM, PAGE 1

Is there something else that needs to be declared?
  • The software team have been notified. They will respond here.
  • Puneeth,

    Please see the memory map for the PRU subsystems in the AM437x TRM ( in Table 30-5 in section

    You'll see that PRU-ICSS0's PRU0 accesses its own local memory (PRU0 DRAM) at address 0x0000 and it accesses PRU1's local memory (PRU1 DRAM) at 0x2000. What can be a bit confusing at first, is that PRU1 also sees its own local memory (PRU1 DRAM) at 0x0000 (from its perspective) and it sees PRU0's local memory (PRU0 DRAM) at 0x2000.


    PRU0 -> PRU0 DRAM -> 0x0000

    PRU0 -> PRU1 DRAM -> 0x2000

    PRU1 -> PRU0 DRAM -> 0x2000

    PRU1 -> PRU1 DRAM -> 0x0000

    What I think is happening in your case is that both PRUs are using the same address at 0x2FE0 which means that PRU0 is looking into PRU1's DRAM and PRU1 is looking into PRU0's DRAM. So, they aren't using the same memory location.

    You need to decide which DRAM (PRU0 DRAM or PRU1 DRAM) that you want the shared variable to reside and then you need to have asymmetric linker files where one PRU is looking at 0x0FE0 and the other PRU is looking at 0x2FE0.

    Jason Reeder

  • So this works perfectly fine for a single uint32_t variable but if I try to do declare another variable the pru stops abruptly.
    This is what I am doing:
    #pragma DATA_SECTION(count1, ".count1")
    #pragma RETAIN(count1)
    volatile far uint32_t count1;

    #pragma DATA_SECTION(count2, ".count2")
    #pragma RETAIN(count2)
    volatile far uint32_t count2;

    and in the cmd file
    SHAREDMEM1 : org = 0x00000fe0 len = 0x00000008
    SHAREDMEM2 : org = 0x00000fe8 len = 0x00000008
    SHAREDMEM1 : org = 0x00002fe0 len = 0x00000008
    SHAREDMEM2 : org = 0x00002fe8 len = 0x00000008
    .count1 > SHAREDMEM1, PAGE 1
    .count2 > SHAREDMEM2, PAGE 1

    The map file also looks okay, but unless I comment out the #DATA_SECTION in one of the PRU core's code the PRU stops abruptly.
    I have also tried other approaches, making a struct out of two variables, using an array of size 2, but none of them seem to work.

  • Actually, the problem was in some other part of my code. i\It was an uint8 overflow or an incorrect comparison I believe.
    However I just want to confirm whether the way I am currently doing the above is the best way to do it.
    Also, is there any way to debug the PRU code? Currently I rely on leds to see if things are reaching a particular point or not. Is there a more convenient way?
  • Yes, the above method is the correct way to share a variable between the two PRU cores.

    The most in depth method to debug your PRU code would be to use JTAG along with Code Composer Studio.

    A much lighter method that I often employ is to have the PRU write values into memory and then use the devmem2 utility in Linux running on the ARM core to check the values in the memories.

    On the PRU (the address below should be in PRU-ICSS0 PRU0's Data RAM... You could also use the local address if you'd like):
    #define DEBUG *(volatile unsigned int *) 0x54440FD0

    On the ARM terminal:
    devmem2 0x54440FD0

    Jason Reeder