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.

AM5708: PRU access to OCMC

Part Number: AM5708

From my customer:

I tried to access OCMC memory location to share data between PRU & DSP core. Am able to read, write in the OCMC RAM1 location using DSP core, but not able to do same on PRU core.

 As per my observation under AM57xx_PRU.cmd only L3_OCMC with address 0x40000000 & size = 0x00010000 is defined .

So I add OCMC_RAM1 with following data: org = 0x40300000 len = 0x00080000 CREGISTER=32,  but am not getting clarity on CREGISTER, why this is defined & its use.

 To access this location I used the same approach as PRU used to share data with ARM using DDR memory location. But this approach doesn't work for me.

 Is there any link which describes how to use OCMC memory for shared data between cores like DSP-PRU.

 Along with this, Is there any way to connect DSP & PRU core while my AM572x-EVM is running under Linux. As right now am only able to connect single core when I stop my board under u-boot. As this will be helpful to debug multiple cores to see communication between them.

Thank you

  • Hello Lenio,

    Constant table question:
    AM57xx_PRU.cmd contains constant table (if searching the Technical Reference Manual or TRM, search both "constant table" and "constants table" since both names are used) values that can be found in the AM57xx TRM PRU chapter. The values are set, so you cannot add a new cregister entry 32. However, the OCMC_RAM entry is partially programmable. Check your TRM for how to set OCMC_RAM value 0x40nn_nn00 using c30_pointer.

    Second question:
    I am not clear on what you are asking. Please give more detail about what you are trying to do.

    Regards,
    Nick

  • Hi Nick,

    Lenio post this on behalf of me. Basically am trying to use shared memory between PRU & DSP core. Using DSP core am able to write in OCMC
    RAM, but not able to write in the OCMC memory location using PRU.

    I go through with AM57xx_PRU. cmd & gel script for PRU. But in both cases, no OCMC region is defined.

    The second query is regarding debugging on multiple cores simultaneously on AM572x-EVM.
    Currently to debug any core I need to halt my board under u-boot, then I able to use XDS200 USB emulator for debug purpose. Is there any approach which allow me to debug multiple cores while my board boot-up Linux kernel.

    Regards
    Akash
  • Hi Nick,

    I am trying to share data between DSP and PRU using shared memory i.e PRU_SHAREDMEM. The work flow is as:

    • I am taking a clock ( frequency 10MHz ) on pin 1 of GPI. On receiving rising edge on this pin I am writing the 32 bit data on the shared memory.
    • In DSP code, I am continuously reading the memory and on receiving the data I process the data and clear the data on the shared memory.

     

    The issue I am facing is that the data sharing is happening only single time. Once the PRU gets rising edge it writes to the memory and after that it never reads rising edge on  __R31 register. The value of __R31 register always reads 0x00.

     

    Th DSP code runs fine. It is able to read the shared memory and write to it.

     

    I have not implemented interrupt to handle data exchange between DSP and PRU. Is the current workflow fine or interrupt handling is required.

     

    In case of interrupt handling what will be the expected interrupt latency on DSP side.

     

    Is it required to put PRU in halt state or it can run continuously?

     

    Is there any signaling from host( DSP ) to bring out PRU from halt state to begin processing  for next clock cycle?

    Regards 

    Akash

  • Hello Akash,

    1) I am assuming you can write to the OCMC memory from PRU after using the c30_pointer as described in my previous response. Let me know if that information is insufficient.

    2) I think there is a way to debug the PRU in CCS while Linux is running, but I have not tried it myself. Let me know if you want me to dig around for documentation on how to do that, or general PRU debug information. I cannot comment on whether you can also debug a DSP core at the same time.

    3) On interrupts: If your DSP is able to constantly poll for refreshed data, I do not see a need for an interrupt between the PRU and the DSP in your design.

    4) On halt: I would avoid putting the PRU in halt. It seems like your design intends for the PRU code to run in a while loop that waits for R31 to be updated.

    5) On R31: have you verified your setup as per the TRM section "General-Purpose Inputs (R31): Enhanced PRU GP Module", pinmux settings, etc? Keep in mind the PRU will need to poll the register to check if the GPI value has changed.

    Regards,
    Nick
  • Hello Nick,

    1) I am assuming you can write to the OCMC memory from PRU after using the c30_pointer as described in my previous response. Let me know if that information is insufficient.
    => For PRU-ICSS1 (PRU0), the shared data RAM start address is 0x4B210000 (0x4B200000 + 0x00010000). The range is from 0x4B210000 to 0x4B21FFFF.
    I use this memory area to share data between PRU & DSP core. And am able to see data at DSP end, whatever I write from PRU.


    2) I think there is a way to debug the PRU in CCS while Linux is running, but I have not tried it myself. Let me know if you want me to dig around for documentation on how to do that, or general PRU debug information. I cannot comment on whether you can also debug a DSP core at the same time.

    => Am not able to debug PRU while Linux is running, but able to debug both DSP & PRU by using a XDS200 USB emulator. By doing that I confirmed that data sharing is happening successfully.


    3) On interrupts: If your DSP is able to constantly poll for refreshed data, I do not see a need for an interrupt between the PRU and the DSP in your design.

    => That exactly am doing right now, but the problem is while polling at both the end. In a ground loop of PRU am checking _R31 for input pulse at desired pin but, that pulse detect only a single time.
    And when that pulse is detected at that moment only I need to write on shared memory location, but that's not happening.
    But if debug my PRU core independently without running DSP core, that pulse is detected while poll in PRU with check of __R31 register.
    Otherwise polling is working perfectly at both the cores, just PRU able to detect input only single time while running both PRU & DSP core.

    4) On halt: I would avoid putting the PRU in halt. It seems like your design intends for the PRU code to run in a while loop that waits for R31 to be updated
    Yeah right there is no requirement of interrupt but why R31 is not getting any update only when both cores (PRU & DSP ) working together.

    5) On R31: have you verified your setup as per the TRM section "General-Purpose Inputs (R31): Enhanced PRU GP Module", pinmux settings, etc? Keep in mind the PRU will need to poll the register to check if the GPI value has changed.

    =>Yeah, everything is correct, as am able to capture input on desired pin using R31, whenever edge of pulse is deteched . But only if i run PRU core only.






    Regards
    Akash
  • Hello Akash,

    Ok, let us try to isolate what is going on with the PRU. I would not normally expect the PRU firmware to be affected by code running on the DSP or the ARM.

    1) Could you use an oscilloscope/digital logic analyzer to verify that the PRU input signal continues toggling in the use cases where PRU is not detecting an edge?

    2) Could another core be messing with the PRU? E.g., if the PRU is using variables in the shared memory region, and then those variables are accidentally modified by the DSP?

    3) Could you post the PRU pseudocode? I am curious to see if there are any dependencies on non-PRU things, or if you could accidentally be going into an infinite loop somewhere.

    4) It is possible that the debug environment is messing with the system behavior.

    Regards,
    Nick
  • Hi Nick,

    Below you can find my test code which am trying to execute now, i have not used any shared memory location variable right now, Then also when I run PRU core independently, then my input checking using R31 is working perfectly but once I run my DSP core, PRU R31 condition checking stops working.

    Main file: 

    /**
    * main.c
    */
    #include <stdint.h>
    #include <pru_cfg.h>
    #include <pru_intc.h>
    #include <pru_ctrl.h>

    volatile register uint32_t __R30;
    volatile register uint32_t __R31;

    #if 1

    /* PRU-to-DSP interrupt */
    #define PRU0_DSP_INTERRUPT (16 )

    #define HOST_NUM 2 /* For DSP */
    #define CHAN_NUM 2
    #endif

    #define Clk ( 1 << 1 ) /* GPIO3_8 pin 45 of P19 */
    #define Toggle ( 1 << 0 ) /* GPIO3_7 pin 52 of P19 */
    #define Input1 ( 1 << 2 ) /* GPIO3_9 pin of P19 */
    #define Input2 ( 1 << 3 ) /* GPIO3_10 pin of P19 */
    #define Input3 ( 1 << 4 ) /* GPIO3_11 pin of P19 */
    #define Input4 ( 1 << 5 ) /* GPIO3_12 pin of P19 */
    #define Input5 ( 1 << 7 ) /* GPIO3_14 pin of P19 */
    #define Input6 ( 1 << 8 ) /* GPIO3_15 pin of P19 */
    #define Input7 ( 1 << 9 ) /* GPIO3_16 pin of P19 */
    #define Input8 ( 1 << 11 ) /* GPIO3_18 pin of P19 */
    #define Input9 ( 1 << 13 ) /* GPIO3_20 pin of P19 */
    #define Input10 ( 1 << 16 ) /* GPIO3_23 pin of P19 */
    #define Input11 ( 1 << 17 ) /* GPIO3_24 pin of P19 */
    #define Input12 ( 1 << 19 ) /* GPIO3_26 pin of P19 */

    #define PRU_SHARED_MEM_ADDR 0x4B210000

    int16_t ADC_pinsread();

    int main(void)
    {
    volatile uint32_t gpo;
    volatile uint32_t gpi;
    volatile uint16_t adc_read = 0;

    /* direct pointer to memory address */
    //volatile int* shared_mem = (volatile int *) PRU_SHARED_MEM_ADDR;

    /* Clear SYSCFG[STANDBY_INIT] to enable OCP master port */
    CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;

    #if 0
    /********************Interrupt***************************/

    // Globally enable host interrupts
    CT_INTC.GER = 0x1;

    /* Clear any pending PRU-generated events */
    __R31 = 0x00000000;

    /* Enable Host interrupt 2 */
    CT_INTC.HIEISR |= HOST_NUM;

    /* Map channel 2 to host 2 */
    CT_INTC.HMR0_bit.HINT_MAP_2 = HOST_NUM;

    /* Map PRU0_DSP_INTERRUPT (event 16) to channel 2 */
    CT_INTC.CMR4_bit.CH_MAP_16 = CHAN_NUM;

    /* Write dummy data in shared memory */

    //shared_mem[1]=0xAAFFAAFF;
    /* Ensure PRU0_ARM_INTERRUPT is cleared */
    CT_INTC.SICR = (PRU0_DSP_INTERRUPT );

    /* Enable PRU0_ARM_INTERRUPT */
    CT_INTC.EISR = (PRU0_DSP_INTERRUPT );

    /* Ensure CT_DDR (C31) is pointing to start of DDR memory (0x80000000) */
    //PRU0_CTRL.CTPPR1_bit.C31_BLK_POINTER = 0x0;

    #endif
    CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;
    /********************Interrupt***************************/
    /* GPI Mode 0, GPO Mode 0 */
    CT_CFG.GPCFG0 = 0;

    /* Clear GPO pins */
    __R30 = 0x00000000;
    __R31 = 0x00000000;
    //__R31 |= 0x00000021; /* To trigger interrupt from PRU towards HOST */

    while(1){
    CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;
    CT_CFG.SYSCFG_bit.STANDBY_MODE = 0x01;
    CT_CFG.SYSCFG_bit.IDLE_MODE = 0x01;
    //__R31 |= 0x00000021;
    if( ( __R31 & Clk ) == Clk )
    {
    adc_read = 0;
    //gpo = __R30;
    //gpo ^= Toggle;
    //__R30 = gpo;
    //adc_read = ADC_pinsread();
    //shared_mem[1]=0xAAFFAAFF;
    //__halt();
    //__delay_cycles(100000000); // half-second delay /* 500ms @ 200MHz */
    }
    }
    return 0;
    }


    int16_t ADC_pinsread()
    {
    volatile int16_t adc_read; //shared_mem[1]=0xAAFFAAFF;
    adc_read = 0x0000;
    adc_read = (( __R31 & Input12 ) << 11 ) |
    (( __R31 & Input11 ) << 10 ) |
    (( __R31 & Input10 ) << 9 ) |
    (( __R31 & Input9 ) << 8 ) |
    (( __R31 & Input8 ) << 7 ) |
    (( __R31 & Input7 ) << 6 ) |
    (( __R31 & Input6 ) << 5 ) |
    (( __R31 & Input5 ) << 4 ) |
    (( __R31 & Input4 ) << 3 ) |
    (( __R31 & Input3 ) << 2 ) |
    (( __R31 & Input2 ) << 1 ) |
    (( __R31 & Input1 ) << 0 );
    return adc_read;
    }

    ==============================

    AM57xx_PRU.cmd

    /****************************************************************************/
    /* AM57xx_PRU.cmd */
    /* Copyright (c) 2015-2018 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 AM57xx device. */
    /****************************************************************************/

    -cr /* Link using C conventions */

    /* Specify the System Memory Map */
    MEMORY
    {
    PAGE 0:
    PRU_IMEM : org = 0x00000000 len = 0x00003000 /* 12kB PRU-ICSS1 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 = 0x00008000 CREGISTER=28 /* 32kB Shared RAM */

    DDR : org = 0x80000000 len = 0x00010000 CREGISTER=31
    L3OCMC : org = 0x40000000 len = 0x00010000 CREGISTER=30
    /* OCMC_RAM1 : org = 0x40300000 len = 0x00080000 CREGISTER=32 *//* 512kB L3 OCMC SRAM1 */
    /* OCMC_RAM2 : org = 0x40400000 len = 0x00100000 CREGISTER=33 *//* 1MB L3 OCMC SRAM2 */
    /* OCMC_RAM3 : org = 0x40500000 len = 0x00100000 CREGISTER=34 */ /* 1MB L3 OCMC SRAM3 */

    /* 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

    MCASP3_DMA : org = 0x46000000 len = 0x00000100 CREGISTER=8
    I2C3 : org = 0x48060000 len = 0x00000300 CREGISTER=5

    RSVD1 : org = 0x48040000 len = 0x0000005C CREGISTER=1
    RSVD2 : org = 0x4802A000 len = 0x000000D8 CREGISTER=2
    RSVD6 : org = 0x48030000 len = 0x000001A4 CREGISTER=6
    RSVD9 : org = 0x4A100000 len = 0x0000128C CREGISTER=9
    RSVD10 : org = 0x48318000 len = 0x00000100 CREGISTER=10
    RSVD11 : org = 0x48022000 len = 0x00000088 CREGISTER=11
    RSVD12 : org = 0x48024000 len = 0x00000088 CREGISTER=12
    RSVD13 : org = 0x48310000 len = 0x00000100 CREGISTER=13
    RSVD14 : org = 0x481CC000 len = 0x000001E8 CREGISTER=14
    RSVD15 : org = 0x481D0000 len = 0x000001E8 CREGISTER=15
    RSVD16 : org = 0x481A0000 len = 0x000001A4 CREGISTER=16
    RSVD17 : org = 0x4819C000 len = 0x000000D8 CREGISTER=17
    RSVD18 : org = 0x48300000 len = 0x000002C4 CREGISTER=18
    RSVD19 : org = 0x48302000 len = 0x000002C4 CREGISTER=19
    RSVD20 : org = 0x48304000 len = 0x000002C4 CREGISTER=20
    RSVD21 : org = 0x00032400 len = 0x00000100 CREGISTER=21
    RSVD22 : org = 0x480C8000 len = 0x00000140 CREGISTER=22
    RSVD23 : org = 0x480CA000 len = 0x00000880 CREGISTER=23
    RSVD27 : org = 0x00032000 len = 0x00000100 CREGISTER=27
    RSVD29 : org = 0x49000000 len = 0x00001098 CREGISTER=29
    }

    /* 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
    }

    ===========================================

    Having doubt on gel file. Is there any conflict create by gel file as gel file for both the cores are different.,as am running this code using XDS200 USB emulator.

    Is there any way to run both codes independently & board is under LINUX.  

    Like in case of DSP am able to run DSP application using remoteproc..

  • Take a look at 1) and 2) of my previous post. I'll have two posts after this. 

  • Code notes:

    I skimmed through your code and do not see anything that would cause an obvious infinite loop.

    Other notes:

    *writing to R31 generates INTC events rather than clearing GPI values.
    * You probably want to set CT_CFG.SYSCFG_bit values outside of your while loop
    * Your code is level sensitive, not edge sensitive. So it will enter the IF statement every time it samples the input level as high, rather than only when you see a rising edge. Something like the below might be more elegant. (Not tested, so there may be bugs in pseudocode)

    int high = 0;
    while(1){
    if( ( __R31 & Clk ) != high ) { // only enter IF statement on rising or falling edge
    if (high = 0) { // this only happens on rising edge detect
    // read / write value
    }
    high = (high ^ Clk) & Clk; // flip the high bit
    }
    }
  • Running with ARM -> Linux, DSP -> DSP code, PRU -> PRU code:

    You can run the PRU code while the ARM is running Linux. Please take a look at our RemoteProc and RPMsg documentation for how to load and run PRU firmware from Linux. See the post UART pins don't work with PRU for an example of test code that could be used to debug the PRU from the Linux command line (to make sure those gel files, etc are not causing problems).

  • Nick,

    I spoke with the customer on the phone and we discovered the DSP example code was making a call to Board_init() which reprogrammed the pinmux which in turn changed the muxing of the PRU IO pin. This is the reason the PRU loop got stuck, it was no longer receiving the input. Just wanted to let you know.

    Thanks

  • Fantastic, thanks Brad!

    Regards,
    Nick