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.

ARM interrupt from PRU

Other Parts Discussed in Thread: AM3358

I have a TI-RTOS application that loads a PRU application using the PRUSS driver.  The APIs are not well documented and I'm unclear how to configure it. 

Here's the PRU code running on PRU 1

#define PRU1_ARM_INTERRUPT 19

#define HOST_NUM 2
#define CHAN_NUM 2

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

// 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 PRU1_ARM_INTERRUPT (event 19) to channel 2 */
CT_INTC.CMR4_bit.CH_MAP_19 = CHAN_NUM;

/* Ensure PRU1_ARM_INTERRUPT is cleared */
CT_INTC.SICR = PRU1_ARM_INTERRUPT;

The ARM code

PRUICSS_socGetInitCfg(&pruss_config);

/* Creates handle for PRUICSS instance */
handle = PRUICSS_create(pruss_config, PRUICCSS_PRU1);

/* Disable PRUICSS instance */
PRUICSS_pruDisable(handle,PRUICCSS_PRU1);

/* Register an Interrupt Handler for an event */
//PRUICSS_registerIrqHandler(handle,pruEvtoutNum,intrNum,eventNum,waitEnable,irqHandler);  <-- What should these parameter be?

/* Sets the buffer pointer for PRU */
PRUICSS_setPRUBuffer(handle, PRUICCSS_PRU1, pru_code, sizeof(pru_code));

/* API to do Interrupt-Channel-host mapping */
//PRUICSS_pruIntcInit(handle, &pruss_intc_initdata);

PRUICSS_enableOCPMasterAccess(handle);


/* Execute program on PRU */
PRUICSS_pruExecProgram(handle,PRUICCSS_PRU1);

/* Enable PRU */
PRUICSS_pruEnable(handle,PRUICCSS_PRU1);

  • Please post which processor you are using, and what SDK version?

  • I'm working on a beagle bone black.  So AM3358.

    sys/bios 6.75.2.00 and am335x PDK 1.0.14

  • Hi,

    Please refer to the API comment:

    /**
     * @brief  This function Registers an Interrupt Handler for an event.\n
     *
     * @param   pruEvtoutNum   The ARM side event number.\n
     *
     * @param   handle         Pruss's driver handle
     *
     * @param  intrNum        Interrupt number of MPU/C66x
     *
     * @param  eventNum       Event number of PRUICSS
     *
     * @param  waitEnable     Flag specifying whether application can wait on this interrupt
     *                using PRUICSSPruWaitEvent function
     *
     * @param   irqHandler     Pointer to a function which will be called on interrupt.\n
     *
     * \return  0 in case of successful registration, -1 otherwise. \n
     */
    int32_t PRUICSS_registerIrqHandler(PRUICSS_Handle handle,
                                       uint32_t pruEvtoutNum,
                                       int32_t intrNum,
                                       int32_t eventNum,
                                       uint8_t waitEnable,
                                       PRUICSSDRV_IRQ_HANDLER irqHandler
                                      )

    Also the interrupt mapping explained here may help:

    https://processors.wiki.ti.com/index.php/ICSS_EMAC_LLD_developers_guide#Interrupts_and_Tasks

    Regards,
    Garrett

  • Yes, I have seen that. And it's not helpful.

    When a developer is reading through the TRM and trying to map a PRU event to an ARM interrupt, depending on what section of the TRM you are reading, the terms change and vary from place to place to it's difficult to get a clear picture of how an interrupt is propagated through the system.  So I'll attempt to explain how I believe it works from my reading and hopefully my far more specific description will help focus things.

    The PRU-ICSS INTC support 64 system events (TRM 4.4.2.1).  Event numbers 16-31 are used for the PRU to signal the ARM core or the other PRU. 

    Event 16 corresponds to signal name pr1_pru_mst_init[0]_init_req.  , Event 17 corresponds to signal name pr1_pru_mst_init[1]_init_req.   .... Event 31 corresponds to signal name pr1_pru_mst_init[15]_init_req.

    These events can be mapped to any of the 10 channels.

    Each channel gets mapped to one of 10 host interrupts.

    So the following PRU code should set up systems event 19 to get mapped to channel 2, channel 2 is mapped to host 2

    #define PRU_ARM_INTERRUPT 19

    #define HOST_NUM 2
    #define CHAN_NUM 2

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

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

    //Enable the system event to be propagated through the INTC
    CT_INTC.EISR |= PRU_ARM_INTERRUPT;

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

    /* Map PRU0_ARM_INTERRUPT (event 19) to channel 2 */
    CT_INTC.CMR4_bit.CH_MAP_19 = CHAN_NUM;

    /* Ensure PRU_ARM_INTERRUPT is cleared */
    CT_INTC.SICR = PRU_ARM_INTERRUPT;

    To assert an interrupt you need to simultaneously write a 1 to __R31 bit 5, and a channel number to bits 3:0.

    The output channels 0-15 are connected to PRU-ICSS INTC system events 16-31 used to signal the ARM. We are using system event 19, which maps to signal pr1_pru_mst_intr[3]_intr_req. So to assert the interrupt we write '100011' to __R31 (see TRM 4.4.1.2.2)

    PRU Code:

    #define PRU_ARM_INTERRUPT_PULSE 0x23

    __R31 = PRU_ARM_INTERRUPT_PULSE;

    On the ARM side interrupts 20-27 are PRU_ICSS_EVTOUTn.  Source is pr1_host[n].  Per the footnote on Table 6.1 in the TRM,  pr1_host_intr[0:7] correspond to Host2-9 of the PRU INTC.

    So, PRU event 19 gets mapped to PRU INTC channel 2, then to PRU INTC host2.  PRU Host2 gets forwarded to AMR PRU_ICSS_EVTOUT0, interrupt 20.

    So given all that, and assuming it's correct.  I still find it difficult to figure out what is what in the API.  Let take each parameter at a time:

    pruEvtoutNum:  I assume this is PRU_ICSS_EVTOUT0, or 0.

    intrNum: I assume this is the ARM interrupt number, 20 in my case.  But seems redundant seeing as PRU_ICSS_EVTOUT0 refers to interrupt 20.

    eventNum: Event number of PRUICSS.  What is this?  Same as pruEvtoutNum?   The system event number from the PRU side (19 in my case)?

  • Hi,

    As the PRUSS driver is compatible across multiple processors (ARM a8/a9/a15.. and DSP c66x), some parameters are indeed a bit confusing.

    pruEvtoutNum: it is PRU_ICSS_EVTOUT0 which is defined as 

    #define PRU0 0
    #define PRU1 1
    #define PRU_EVTOUT0 2
    #define PRU_EVTOUT1 3

    intrNum: It is the ARM interrupt number, 20 in your case. For other processors, the interrupt number is not directly associated with PRU_ICSS_EVTOUT0, for example on A15 or DSP in AM572x.

    eventNum: this is mainly applicable to DSP c66x which contains an event combiner which allows user to combine up to 32 system events into a single combined event, and using the EventCombiner module along with the Hwi module, allows the user to route a combined event to any of the 12 maskable CPU interrupts available on GEM:

    #ifdef C66x
    PRUICSS_registerIrqHandler(handle,2,15,38,
    1,
    pruss_isr
    );

    Regards,
    Garrett

  • Hi Garrett,

    Thanks for your clarification.  That was a huge help and I now have it all working.  Thanks again.