PRUSSV2 timer interrupt handling example for AM335x

I am busy developing program containing both local eCAP and IEP timers. The main loop is becoming relative 'slow' because of the need of polling both timer timeouts.

I am trying to replace the tedious polling instructions and to use R31 bits 30 and 31 as PRU interrupt 0 and 1 from IEP and eCAP, but so far without success.I try to use interrupt 7 (pr1_iep_tim_cap_cmp_pend) and interrupt 15 (pr1_ecap_intr_req).

I have followed the steps as mentioned in PRU Interrupt Controller wiki  and PRUSSV2 handling

Note that the first document is not intended for the AM335x.

Question 1:

Has anybody a PRUSSV2 interrupt example for me to check what i do wrong or have missed?

Question 2::

The description of the HIEISR register  (AM335x PRU-ICSS Reference Guide chapter 6.4.9) is a bit unclear for me:

The Host Interrupt Enable Indexed Set Register allows enabling a host interrupt output. The host interrupt
to enable is the index value written. This enables the host interrupt output or triggers the output again if
already enabled.

Does that mean that if I want to enable host interrupts 0 and 1, that I have to perform two write actions;  0x00, followed by 0x01?

Part of my code is listed below:

   // Disable MII_RT (EthercaT) Events to the INTC
   LBCO     r0, PRU_CTAB_PRUSS_CFG, CFG_MII_RT, 4
   CLR      r0, r0, 0                        // Use external events (not ethercat events)
   SBCO     r0, PRU_CTAB_PRUSS_CFG, CFG_MII_RT, 4

   //
   // route pr1_iep_tim_cap_cmp_pend (int number 7) to PRU interrupt 1 (R31 bit 31)
   // route pr1_ecap_intr_req       (int number 15) to PRU interrupt 0 (R31 bit 30)
   //

   // Clear global interrupt
   LBCO     r0, PRU_CTAB_LOC_INTC, INTC_GER, 4
   clr      r0, r0, 0
   SBCO     r0, PRU_CTAB_LOC_INTC, INTC_GER, 4

   // Follow these steps to configure the interrupt controller.
   // 1. Set polarity and type of system event through the System Interrupt Polarity Registers (SIPR1 and
   //    SPIR2) and the System Interrupt Type Registers (SITR1 and SITR2). Polarity of all system interrupts is
   //    always high. Type of all system interrupts is always pulse.
   // active high, level interrupt
   mov      r1, INTC_SIPR0
   LBCO     r0, PRU_CTAB_LOC_INTC, r1, 4
   set      r0, r0, 7                        // IEP cmp status active high
   set      r0, r0, 15                        // eCAP interrupt status active high
   SBCO     r0, PRU_CTAB_LOC_INTC, r1, 4

   mov      r1, INTC_SITR0
   LBCO     r0, PRU_CTAB_LOC_INTC, r1, 4
   clr      r0, r0, 7
   clr      r0, r0, 15
   SBCO     r0, PRU_CTAB_LOC_INTC, r1, 4

   // 2. Map system event to INTC channel through CHANMAP registers.
   // Map system interrupt 7 to channel 0
   mov      r1, INTC_CMR1
   LBCO     r0, PRU_CTAB_LOC_INTC, r1, 4
   M_MOV32  r2, 0xF0FFFFFF
   and      r0, r0, r2
   SBCO     r0, PRU_CTAB_LOC_INTC, r1, 4

   // Map system interrupt 15 to channel 1
   mov      r1, INTC_CMR3
   LBCO     r0, PRU_CTAB_LOC_INTC, r1, 4
   M_MOV32  r2, 0xF0FFFFFF
   and      r0, r0, r2
   M_MOV32  r2, 0x01000000
   or       r0, r0, r2
   SBCO     r0, PRU_CTAB_LOC_INTC, r1, 4


   // 3. Map channel to host interrupt through HOSTMAP registers. Recommend channel “x” be mapped to
   //    host interrupt “x”.
   // Map channel 0 to host interrupt 0, 1 to 1, ...
   mov      r1, INTC_HMR0
   M_MOV32  r0, 0x03020100
   SBCO     r0, PRU_CTAB_LOC_INTC, r1, 4
   mov      r1, INTC_HMR1
   M_MOV32  r0, 0x07060504
   SBCO     r0, PRU_CTAB_LOC_INTC, r1, 4
   mov      r1, INTC_HMR2
   M_MOV32  r0, 0x00000908
   SBCO     r0, PRU_CTAB_LOC_INTC, r1, 4

   // 4. Clear system interrupt by writing 1s to SECR registers.
   M_MOV32  r0, 0xFFFFFFFF
   mov      r1, INTC_SECR0
   SBCO     r0, PRU_CTAB_LOC_INTC, r1, 4
   mov      r1, INTC_SECR1
   SBCO     r0, PRU_CTAB_LOC_INTC, r1, 4

   // 5. Enable host interrupt by writing index value to HOSTINTENIDX register.
   mov      r1, INTC_HIEISR
   M_MOV32  r0, 0x01                        // enable host interrupt 01
   SBCO     r0, PRU_CTAB_LOC_INTC, r1, 4
M_MOV32  r0, 0x00                        // enable host interrupt 00
SBCO     r0, PRU_CTAB_LOC_INTC, r1, 4

   // 6. Enable interrupt nesting if desired.
   LBCO     r0, PRU_CTAB_LOC_INTC, INTC_CR, 4
   clr      r0, r0, 2
   clr      r0, r0, 3
   SBCO     r0, PRU_CTAB_LOC_INTC, INTC_CR, 4

   // 7. Globally enable all interrupts through GLBLEN register.
   LBCO     r0, PRU_CTAB_LOC_INTC, INTC_GER, 4
   set      r0, r0, 0
   SBCO     r0, PRU_CTAB_LOC_INTC, INTC_GER, 4

The eCAP interrupt is enabled via:

   // Set Counter Equal Period Interrupt Enable
   mov      r2, 0x40
   sbco     r2, PRU_CTAB_ECAP, ECAP_OFFS_ECEINT, 2    // Counter Equal Period Interrupt Enable

As far as I can see is there no interrupt enable bit present in the IEP.

In 10.2.2.1 is stated:

– One global event output for interrupt generation triggered by any compare event.

  • Hi Rob,

    The AM335x PRU package intended for do-it-yourself users contains several AM335x PRU example code: https://github.com/beagleboard/am335x_pru_package.  You may find the PRU_PRUtoPRU_Interrupt example to be a useful model.

    Please note that there are some small differences between the AM18x and AM335x PRU INTC event mapping.  For example, internal and external event numbers are swapped (on AM18x external events generated by peripherals are mapped to system events 0-31, while AM335x maps these events to 32-63).  See the "AM18x PRUSS to AM335x PRU-ICSS Software Migration Guide" within the AM335x PRU package for more details.  

    Regards,

    Melissa

  • In reply to melissaw:

    Thank you for your reply. However, in the programming example I could not find any clues for my timer problem.

    I've got both the IEP and eCAP timers running and like to receive interrupts of these timers. Probably I forget to program something, but I just can't figure out my error.

    Can you confirm that the PRUSS eCAP interrupt output is connected to Int number 15 (pr1_ecap_intr_req) and that the IEP, which has "One global event output for interrupt generation triggered by any compare event" is connected to Int number 7 (pr1_iep_tim_cap_cmp_pend)

    It would help me enormously to get hold of an example where the INTC module is programmed and some interrupt is used.

  • In reply to Rob van de Schepop:

    Hi Rob,

    You might reference the some of the AM18x PRU examples, such as PRU_timer2Interrupt.p. The PRU configures the INTC in this example.  The basic structure of configuring the PRU INTC on AM335x will be the same as on AM18x.  (The ARM core configures the INTC in the AM335x examples.)

    Another debug technique might be to replace the eCAP and IEP events with one of the PRU-generated events.  This may help you isolate if the issue is that the INTC is not configured correctly or the IEP / eCAP is not generating an event.  

    Also, are you enabling the IEP compare event in the CMP_CFG register?  (Note the descriptions for CMP_EN and CMP0_RST_CNT_EN are swapped in the am335xPruReferenceGuide.pdf.  CMP_EN (bits 1-8) are the enable bits for each compare register.)

    Regards,
    Melissa

  • In reply to melissaw:

    Hi,

    after some searching and debugging I managed to enable interrupt handling. It turned out that I had forgotten to enable system interrupts as well. So now I have both IEP and eCAP timers working with interrupt handling.

    part of my code that enables system interrupts 7 (IEP) and 15 (eCAP):

       // Disable MII_RT (EthercaT) Events to the INTC
       LBCO     r0, PRU_CTAB_PRUSS_CFG, CFG_MII_RT, 4
       clr      r0, r0, 0                        // Use external events (not ethercat events)
       SBCO     r0, PRU_CTAB_PRUSS_CFG, CFG_MII_RT, 4

       //
       // route pr1_iep_tim_cap_cmp_pend (int number 7) to PRU interrupt 1 (R31 bit 31)
       // route pr1_ecap_intr_req       (int number 15) to PRU interrupt 0 (R31 bit 30)
       //

       // Clear global interrupt
       LBCO     r0, PRU_CTAB_LOC_INTC, INTC_GER, 4
       clr      r0, r0, 0
       SBCO     r0, PRU_CTAB_LOC_INTC, INTC_GER, 4

       // Preset all interrupts to channel 9
       M_MOV32  r0, 0x09090909
       mov      r1, INTC_CMR0
       mov      r2, INTC_CMR15
    L_CMRX_CLR:
       SBCO     r0, PRU_CTAB_LOC_INTC, r1, 4    // preset INTC_CMR0 to INTC_CMR15
       add      r1, r1, 4
       qbge     L_CMRX_CLR, r1, r2            // jump if r2 greater than or equal to r1

       // Disable all host interrupts
       mov      r1, INTC_HIDISR
       mov      r0, 0x00
    L_HIDISR_CLR:
       SBCO     r0, PRU_CTAB_LOC_INTC, r1, 4
       add      r0, r0, 1
       qbge     L_HIDISR_CLR, r0, 9            // jump if 9 greater than or equal to r0

       // 1. Set polarity and type of system event through the System Interrupt Polarity Registers (SIPR1 and
       //    SPIR2) and the System Interrupt Type Registers (SITR1 and SITR2). Polarity of all system interrupts is
       //    always high. Type of all system interrupts is always pulse.
       // active high, level interrupt
       M_MOV32  r0, 0xFFFFFFFF
       mov      r1, INTC_SIPR0
       SBCO     r0, PRU_CTAB_LOC_INTC, r1, 4
       mov      r1, INTC_SIPR1
       SBCO     r0, PRU_CTAB_LOC_INTC, r1, 4

       mov      r0, 0
       mov      r1, INTC_SITR0
       SBCO     r0, PRU_CTAB_LOC_INTC, r1, 4
       mov      r1, INTC_SITR1
       SBCO     r0, PRU_CTAB_LOC_INTC, r1, 4

       // 2. Map system event to INTC channel through CHANMAP registers.
       // Map system interrupt 7 to channel 0
       mov      r1, INTC_CMR1
       LBCO     r0, PRU_CTAB_LOC_INTC, r1, 4
       M_MOV32  r2, 0xF0FFFFFF
       and      r0, r0, r2
       SBCO     r0, PRU_CTAB_LOC_INTC, r1, 4

       // Map system interrupt 15 to channel 1
       mov      r1, INTC_CMR3
       LBCO     r0, PRU_CTAB_LOC_INTC, r1, 4
       M_MOV32  r2, 0xF0FFFFFF
       and      r0, r0, r2
       M_MOV32  r2, 0x01000000
       or       r0, r0, r2
       SBCO     r0, PRU_CTAB_LOC_INTC, r1, 4


       // 3. Map channel to host interrupt through HOSTMAP registers.
       //    Recommend channel “x” be mapped to host interrupt “x”.
       // Map all channels to host interrupt 9 except 0 and 1
       mov      r1, INTC_HMR0
       M_MOV32  r0, 0x03020100
       SBCO     r0, PRU_CTAB_LOC_INTC, r1, 4
       mov      r1, INTC_HMR1
       M_MOV32  r0, 0x07060504
       SBCO     r0, PRU_CTAB_LOC_INTC, r1, 4
       mov      r1, INTC_HMR2
       M_MOV32  r0, 0x00000908
       SBCO     r0, PRU_CTAB_LOC_INTC, r1, 4

       // 4. Clear system interrupt by writing 1s to SECR registers.
       M_MOV32  r0, 0xFFFFFFFF
       mov      r1, INTC_SECR0
       SBCO     r0, PRU_CTAB_LOC_INTC, r1, 4
       mov      r1, INTC_SECR1
       SBCO     r0, PRU_CTAB_LOC_INTC, r1, 4

       // 5. Enable host interrupt by writing index value to HOSTINTENIDX register.
       mov      r1, INTC_HIEISR
       M_MOV32  r0, 0x00                        // enable host interrupt 00
       SBCO     r0, PRU_CTAB_LOC_INTC, r1, 4
       M_MOV32  r0, 0x01                        // enable host interrupt 01
       SBCO     r0, PRU_CTAB_LOC_INTC, r1, 4

       // 5a. Enable System interrupts 15 and 7
       M_MOV32  r0, 0xFFFFFFFF                    // First clear all system interrupts
       mov      r1, INTC_ECR0
       SBCO     r0, PRU_CTAB_LOC_INTC, r1, 4
       mov      r1, INTC_ECR1
       SBCO     r0, PRU_CTAB_LOC_INTC, r1, 4

       mov      r1, INTC_ESR0
       M_MOV32  r0, 0x00008080                    // enable system interrupts 15 and 7
       SBCO     r0, PRU_CTAB_LOC_INTC, r1, 4

       // 6. Enable interrupt nesting if desired.
       LBCO     r0, PRU_CTAB_LOC_INTC, INTC_CR, 4
       clr      r0, r0, 2
       clr      r0, r0, 3
       SBCO     r0, PRU_CTAB_LOC_INTC, INTC_CR, 4

       // 7. Globally enable all interrupts through GLBLEN register.
       LBCO     r0, PRU_CTAB_LOC_INTC, INTC_GER, 4
       set      r0, r0, 0
       SBCO     r0, PRU_CTAB_LOC_INTC, INTC_GER, 4