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.

AM5728: DSP ISR latency

Part Number: AM5728
Other Parts Discussed in Thread: SYSCONFIG, SYSBIOS

Hi,

I run a baremetal DSP software that manage two ISR. The ARM is empty. The first one is an interrupt generated by the rising edge of the input capture ECAP1, and the second is generated by the comparaison event of the EPWM module. The ECAP ISR allows to force the synchronization of the EPWM and to measure in the same time the frequency of the input signal.

I measured the time between the rising edge and the effective input into the ISR (by toggling a GPIO), which is around 3µs. I don't understand why...

Could you help me to figure out how to minimize this delay, that should be close to zero?

Thanks,

Sylvain.

  • Have you looked at the power management?  In particular, there's a lot of automatic clock gating of the interface clocks.  I suspect that might be related to your delay.  I suggest looking at the PRCM configuration for the related peripherals and make sure the interface clocks are kept on.

  • Hi Brad,

    The clock of the PMWSS1 module is initialized in the Board_init() and I'm quite sure that it's correctly configured because the everything (ecap, counters..) run as expected.

    What do you mean by "... make sure the interface clocks are kept on" ?

    Regards,

    Sylvain

  • What's the value of CM_L4PER2_CLKSTCTRL at address 0x4A00 98FC?

  • Also, what's the value of PWMSS_SYSCONFIG?  For PWMSS1 it is address 0x4843 E004.

  • Hi Brad,

    The value of the registers are:

    - CM_L4PER2_CLKSTCTRL = 0x0001 7902

    - PWMSS_SYSCONFIG = 0x0000 0008

    That seems to be correct

  • Sylvain PALMERI said:
    - CM_L4PER2_CLKSTCTRL = 0x0001 7902

    That has CLKTRCTRL = 2, SW_WKUP.  Good.

    Sylvain PALMERI said:
    - PWMSS_SYSCONFIG = 0x0000 0008

    That has IDLEMODE = 2, Smart Idle.  Please try IDLEMODE = 1, No Idle.  In other words, please configure PWMSS_SYSCONFIG = 4.

  • Hi Brad,

    I modified the IDLEMODE value but that has no effect.

    Regards,

    Sylvain.

  • Sylvain PALMERI said:
    I measured the time between the rising edge and the effective input into the ISR (by toggling a GPIO), which is around 3µs. I don't understand why...

    As I'm re-reading your issue, I wonder if this might actually be the issue.  Can you share a snippet of your GPIO toggling code?  Have you measured the amount of time it takes you to toggle twice in a row as fast as you can?  There's latency in writing to the GPIO register, so that might be the real problem here.  The issue is much worse if you're doing a read-modify-write rather than using the "toggle" register to perform a straight write.  That's why I wanted to see your code.

  • Hi Brad,

    Here is he code of the ISR:

    /* ======================================================================== */
    /*  AppEcapIntrISR --                                                       */
    /* ======================================================================== */
    static void AppEcapIntrISR(void *handle)
    {
        uint32_t uEcap1_Value = 0U;

        GPIO_write(GPIO_LED_RED, GPIO_PIN_VAL_HIGH);

        /* Resetting the EPWM counter */
        CSL_epwmTbTriggerSwSync(PWMSS1_BASE_ADDRESS);

        /* Diagnostic tools update */
        uEcap1_Value = ECAPTimeStampRead(ECAP_BASE_ADDRESS, ECAP_CAPTURE_EVENT_1);
        DSP1DiagParam.Synchro_Period = (float)uEcap1_Value * (1/(float)SYSCLKOUT);
        DSP1DiagParam.Synchro_Freq     = 1 / DSP1DiagParam.Synchro_Period;

        /* Clear global interrupt flag and reset the Mod4 counter to zero*/
        ECAPGlobalIntEnable(ECAP_BASE_ADDRESS);
        ECAPIntStatusClear(ECAP_BASE_ADDRESS, ECAP_CEVT1_INT);
        ECAPOneShotREARM(ECAP_BASE_ADDRESS);

    }

    I thought also that the delay was comming from the GPIO_Write() macro, and I measure by toggling LED before and after the macro and I measured around 400ns. 

  • Sylvain PALMERI said:
    I thought also that the delay was comming from the GPIO_Write() macro, and I measure by toggling LED before and after the macro and I measured around 400ns.

    Did you do something like this and measure on a scope?

    GPIO_write(GPIO_LED_RED, GPIO_PIN_VAL_HIGH);

    GPIO_write(GPIO_LED_RED, GPIO_PIN_VAL_LOW);

    GPIO_write(GPIO_LED_RED, GPIO_PIN_VAL_HIGH);

    Can you tell me what you measure when doing that?

  • Hi Brad,

    I attached the capture of the signals after having implemented what you suggest.

    The LED write() macro is around 200ns.

    Regards,

    Sylvain.

  • Sylvain,

    Sorry, I'm traveling this week, so my responses are very delayed.  I'm trying to understand what's happening precisely.  The GPIO toggling is reasonably fast in your screenshot.  I'm wondering if you can add one more element to this test.  Can you toggle a different GPIO repeatedly as part of a background loop and display that signal on the scope along with the other two?  In particular I'm trying to understand whether the delay is in recognizing the interrupt or in actually executing your specific code.

    Along similar lines, how is your interrupt configured?  Which HWI is it mapped to?  Is it mapped directly, or are you leveraging the interrupt combiner?

    Best regards,
    Brad

  • Hi Brad,

    Your suggestion is very interresting. I implemented a fast GPIO toggle in the background task (purple curve) and we see in the draw that the background task is stopped quickly after the "yellow" rising edge. That means that the interrupt is reached but take a while to execute the code in the ISR.

    Here is my crossbar configuration:

    #define APP_ECAP1_INT                    ((uint32_t) (32U))

    #define APP_EPWM0_INT                   ((uint32_t) (33U))

    /* ======================================================================== */
    /*  BoardIntConfig --                                                        */
    /* ======================================================================== */
    static void BoardIntConfig(void)
    {
        /* XBar configuration */
        CSL_xbarIrqConfigure (CSL_XBAR_IRQ_CPU_ID_DSP1, CSL_XBAR_INST_DSP1_IRQ_32, CSL_XBAR_PWMSS1_IRQ_eCAP0INT);
        CSL_xbarIrqConfigure (CSL_XBAR_IRQ_CPU_ID_DSP1, CSL_XBAR_INST_DSP1_IRQ_33, CSL_XBAR_PWMSS1_IRQ_ePWM0INT);

        Intc_Init();
        Intc_IntEnable(0);

        /* Register ISR */
        Intc_IntRegister(APP_ECAP1_INT, (IntrFuncPtr) AppEcapIntrISR, 0);
        Intc_IntRegister(APP_EPWM0_INT, (IntrFuncPtr) AppEpwmIntrISR, 0);

        Intc_SystemEnable(APP_ECAP1_INT);
        Intc_SystemEnable(APP_EPWM0_INT);
    }

    Regards,

    Sylvain

  • Hi Brad,

    did you have time to take a look?

    Regards,

    Sylvain

  • Sylvain,

    Thanks for the friendly reminder.  Sorry for the delay.

    I had a look at the code (pdk_am57xx_1_0_15/packages/ti/csl/arch/c66x/src/interrupt.c).  I can see that it is using the Event Combiner hardware, which means there's multiple layers of software before your ISR actually runs.

    Before I propose any solutions, I have another question for you... What happens inside your ISR, e.g. do you call any RTOS functions like Semaphore_post(), etc.?  In short, there are a couple different options.  The lowest latency option would be to directly plug your interrupt handler into the vector table such that it gets called directly.  The downside of this approach is that you are not allowed to call any RTOS functions (no posting of SWIs, semaphores, events, etc.).  If you're doing something very hardware-centric in your ISR, however, this might be ideal.

    Best regards,
    Brad

  • Hi Brad,

    Thanks for your feedback. The DSP is runing as a baremetal software, so I don't call any RTOS functions. What I have shared is exaclty what I have coded for the moment. In short, I just managed GPIO to validate IRQ mechanism.

    Regards,

    Sylvain

  • Ok, I think the "direct plug" method will be best.  Normally I would do this using sysbios APIs, so that's going to be more difficult since you're running bare metal.  I think the easiest path forward will be to customize and rebuild the CSL libraries in order to do this.  I recommend putting that file under revision control.  Assuming you have some issues getting this working, I'm going to need to see a precise delta of what you've changed...

    The Intc_Init() function in pdk_am57xx_1_0_15/packages/ti/csl/arch/c66x/src/interrupt.c can be updated to plug your own handler.  Here's a snippet from that function:

         Intc_IntInstallRstIrqHandler(&(__ISR_Table[0]),  &init_regs);
        Intc_IntInstallIrqHandler(&(__ISR_Table[ISR_HANDLER_SIZE*(4U)]),
                                   &INTH_L1IRQ4Handler);
        Intc_IntInstallIrqHandler(&(__ISR_Table[ISR_HANDLER_SIZE*(5U)]),
                                   &INTH_L1IRQ5Handler);
        Intc_IntInstallIrqHandler(&(__ISR_Table[ISR_HANDLER_SIZE*(6U)]),
                                   &INTH_L1IRQ6Handler);
        Intc_IntInstallIrqHandler(&(__ISR_Table[ISR_HANDLER_SIZE*(7U)]),
                                   &INTH_L1IRQ7Handler);
        Intc_IntInstallIrqHandler(&(__ISR_Table[ISR_HANDLER_SIZE*(8U)]),
                                   &INTH_L1IRQ8Handler);
        Intc_IntInstallIrqHandler(&(__ISR_Table[ISR_HANDLER_SIZE*(9U)]),
                                   &INTH_L1IRQ9Handler);
        Intc_IntInstallIrqHandler(&(__ISR_Table[ISR_HANDLER_SIZE*(10U)]),
                                   &INTH_L1IRQ10Handler);
        Intc_IntInstallIrqHandler(&(__ISR_Table[ISR_HANDLER_SIZE*(11U)]),
                                   &INTH_L1IRQ11Handler);
        Intc_IntInstallIrqHandler(&(__ISR_Table[ISR_HANDLER_SIZE*(12U)]),
                                   &INTH_L1IRQ12Handler);
        Intc_IntInstallIrqHandler(&(__ISR_Table[ISR_HANDLER_SIZE*(13U)]),
                                   &INTH_L1IRQ13Handler);
        Intc_IntInstallIrqHandler(&(__ISR_Table[ISR_HANDLER_SIZE*(14U)]),
                                   &INTH_L1IRQ14Handler);
        Intc_IntInstallIrqHandler(&(__ISR_Table[ISR_HANDLER_SIZE*(15U)]),
                                   &INTH_L1IRQ15Handler);
    
        mask = 0x000000f2U;
        IER |= mask;
    

    Those first 4 calls to Intc_IntInstallIrqHandler() are the ones that are setting up the Event Combiner (i.e. there are 4 different subevents that make up the event combiner).  What I would recommend is:

    1. I think it would be preferable to have the event combiner interrupts at a lower priority.  They're currently the 4 highest priority interrupts.  Instead of occupying slots 4--7 I would suggest bumping them to occupy 8-11, or possibly even 12-15.  Besides changing the location in the table, that will also impact the mask being used.  I haven't tried it out, but I think changing just those two things should be sufficient.  In other words, event though I see a lot of code with switch statements related to the numbers 4-7, it doesn't look to me like that has any connection to the hardware and can just remain as is.  For example, if you move these handlers to interrupts 8-11 the mast will change from 0xF2 to 0xF02.  (Bit 1 corresponds to NMI which must be set.)

    Please verify that you get the step above working before moving forward.  The behavior should remain exactly the same as it is now.  However, it will give confidence that you can rebuild the CSL libraries and it will make it easy for the next step.

    2. For the "direct plug" method you will need to add the interrupt keyword to your ISR definition, i.e. instead of "void my_isr" it will become "interrupt void my_isr".  You will correspondingly update one of the Intc_IntInstallIrqHandler() calls in Intc_Init() to plug your function into the table (i.e. you'll need a corresponding "extern" there too).  You would also update the mask.  So if you plugged into INT4 then you would update the mask from 0xF02 to 0xF12.

  • Hi Brad,

    Sorry but I didn't cought exaclty what you mean^^. In the (1) could you please explain a bit more how to modify the code to fit with what you said? In (2) where in the code can I see that I'm connected to the INT4 or whatever? In my code, the crossbar definition link the ecap interrupt to the IRQ_32. 

    CSL_xbarIrqConfigure (CSL_XBAR_IRQ_CPU_ID_DSP1, CSL_XBAR_INST_DSP1_IRQ_32, CSL_XBAR_PWMSS1_IRQ_eCAP0INT);

    It's a bit confusing...

    Regards,

    Sylvain

  • Sylvain,

    If you'd like to understand the interrupt architecture better, please refer to the following:

    TMS320C66x DSP CPU and Instruction Set Reference Guide
    Chapter 6: Interrupts
    http://www.ti.com/lit/sprugh7

    TMS320C66x DSP CorePac User Guide
    Chapter 9: Interrupt Controller
    http://www.ti.com/lit/sprugw0

    In short, the interrupt controller has 124 inputs that come from all the peripherals in the chip and 12 outputs that connect to the CPU's 12 maskable interrupts.  But what if you need more than 12 interrupts?  That's where the event combiner comes into play.  It gives a second level of interrupt processing, and is being leveraged by the source code you're using now.

    I recommend switching to sysbios.  We can support you better there.  In short, the code you're leveraging right now is setup to use the "Event Combiner" hardware, and it was not designed for direct access to the 12 direct CPU interrupts.  If you switch to sysbios, it can handle the direct interrupts such that you can map IRQ_32 to one of the 12 direct interrupts (INT4-INT15).  This will reduce your interrupt latency, especially if you locate the associated handler in L2 SRAM so as to reduce cache miss penalty.

    Best regards,
    Brad

  • Brad,

    The ARM will use a Linux RT OS. Historically, we never used any OS in DSP developpement (F2812 or F28335) that's why we plan to run both DSP as bare metal. However, the strategy is not set in stone. In my point of view, that makes sense that the ARM works under OS, but for DSPs I do not see any benefit. Maybe I'm wrong...

    Concerning the interrupts architecture, I will re-read the documentation first, and try to apply why you suggest above.

    Regards,

    Sylvain.

  • Hi Brad,

    I modified the CSL to route the combined output to IRQ12 to 15. I mapped DSP_IRQ_32 to IRQ4 et DSP_IRQ_33 to IRQ5:

        /* Route combined inputs */
        /*INTH_intRouting[4] = ((uint32_t) INTH_INT_ID_EVT0);
        INTH_intRouting[5] = ((uint32_t) INTH_INT_ID_EVT1);
        INTH_intRouting[6] = ((uint32_t) INTH_INT_ID_EVT2);
        INTH_intRouting[7] = ((uint32_t) INTH_INT_ID_EVT3);*/
    	INTH_intRouting[12] = ((uint32_t) INTH_INT_ID_EVT0);
        INTH_intRouting[13] = ((uint32_t) INTH_INT_ID_EVT1);
        INTH_intRouting[14] = ((uint32_t) INTH_INT_ID_EVT2);
        INTH_intRouting[15] = ((uint32_t) INTH_INT_ID_EVT3);
    
        /* Configure IC */
        /* Remove all inputs from combiner */
        for (count = 0U; count < 4U; count++)
        {
            clr_int_evt(count, 0xFFFFFFFFU);
            set_int_evtmask(count, 0xFFFFFFFFU);
        }
    
        /*Mask dropped interrupts*/
        HW_WR_REG32((SOC_DSP_ICFG_BASE + DSP_INTDMASK), (uint32_t) 0xFFF0U);
    
        /*
         * Program the interrupt selector here,
         * the first 4 interrupt output of the interrupt selector is
         * routed from the interrupt combiner
         * Each of these interrupt line cater to 32 event input lines
         *
         * Below is the mapping -
         * 0 bit -> 0-31 event lines
         * 1 bit -> 32-63 event lines
         * 2 bit -> 64-95 event lines
         * 3 bit -> 96-127 event lines
         *
         */
        /*HW_WR_REG32((SOC_DSP_ICFG_BASE + DSP_INTMUX1), 0x03020100U);*/
    	/* route DSP_IRQ_32 on IRQ4 and DSP_IRQ_33 on IRQ5 */
    	HW_WR_REG32((SOC_DSP_ICFG_BASE + DSP_INTMUX1), 0x77772120U);		
    
        /* Route unused EVT 119 to other interrupt inputs */
        HW_WR_REG32((SOC_DSP_ICFG_BASE + DSP_INTMUX2), 0x77777777U);
        /*HW_WR_REG32((SOC_DSP_ICFG_BASE + DSP_INTMUX3), 0x77777777U);*/
    	/* Route combined output to IRQ[12-15] */
    	HW_WR_REG32((SOC_DSP_ICFG_BASE + DSP_INTMUX3), 0x03020100U);

    I didn't touch to the calls of Intc_IntInstallIrqHandler() functions

    Are these modifications corresponds to your suggestions?

    Another question.. what is the meaning of the following lines:

    INTH_intRouting[12] = ((uint32_t) INTH_INT_ID_EVT0);
        INTH_intRouting[13] = ((uint32_t) INTH_INT_ID_EVT1);
        INTH_intRouting[14] = ((uint32_t) INTH_INT_ID_EVT2);
        INTH_intRouting[15] = ((uint32_t) INTH_INT_ID_EVT3);

    Modifying the INTMUX is not sufficient?

    Regards,

    Sylvain.

  • Sylvain PALMERI said:

    Another question.. what is the meaning of the following lines:

    INTH_intRouting[12] = ((uint32_t) INTH_INT_ID_EVT0);
        INTH_intRouting[13] = ((uint32_t) INTH_INT_ID_EVT1);
        INTH_intRouting[14] = ((uint32_t) INTH_INT_ID_EVT2);
        INTH_intRouting[15] = ((uint32_t) INTH_INT_ID_EVT3);

    Modifying the INTMUX is not sufficient?

    It looks to me like this is just to remember which interrupts were registered in order to later unregister.  

    Your programming of the INTMUX registers looks correct for what you're trying to achieve.  You still need to update these two lines:

    Intc_IntInstallIrqHandler(&(__ISR_Table[ISR_HANDLER_SIZE*(4U)]),
    &INTH_L1IRQ4Handler);
    Intc_IntInstallIrqHandler(&(__ISR_Table[ISR_HANDLER_SIZE*(5U)]),
    &INTH_L1IRQ5Handler);

    You want to reference your own ISR instead of the default handlers.

    Also, you need a minor change in void INTH_IRQHandler(uint8_t l1intNumber).  Those case numbers should be 12-15 instead of 4-7.  That's the only change there, i.e. don't change the code inside the case statements as that is still correct.  The event combiner interrupts are 0, 1, 2, 3 so that doesn't change.

  • After compiling the CSL, the result is very bad. I still jump to the ISR but completely asynchronously with the ecap input which is the source of the interrupt.

    In the attached file, I removed the events 32 and 33 to respect the steps (1) that you said. This time, I only modify where the combined output are routed (I modifiied the mask accordingly), and normally I should find my 3us dealy that I had initially. But this time, I don't jump into ISR anymore.

    Could you please take a look to the attached file?

    /*
     *  Copyright (C) 2013-2018 Texas Instruments Incorporated - http://www.ti.com/
     *
     *  Redistribution and use in source and binary forms, with or without
     *  modification, are permitted provided that the following conditions
     *  are met:
     *
     *    Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     *    Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the
     *    distribution.
     *
     *    Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
     */
    
    /**
     *  \file   interrupt.c
     *
     *  \brief  Interrupt related APIs.
     **/
    
    /* ========================================================================== */
    /*                             Include Files                                  */
    /* ========================================================================== */
    #include <stdint.h>
    #include <stddef.h>
    #include <c6x.h>
    #include <ti/csl/soc.h>
    #include <interrupt.h>
    #include <ti/csl/hw_types.h>
    #include <ti/csl/csl_types.h>
    #if defined (TI814X_BUILD) || defined (TI8149_BUILD) || defined (TI811X_BUILD)
    /* not required */
    #else
    #include <ti/csl/arch/csl_arch.h>
    #endif
    
    /* ========================================================================== */
    /*                                 Macros & typedefs                          */
    /* ========================================================================== */
    /* number of DSP interrupt handlers 0..127*/
    #define INTH_INT_TABLE_SIZE     128U
    
    /* Max interrupt number*/
    #define INTH_INT_NUM_MAX     (INTH_INT_TABLE_SIZE - 1U)
    
    /* ISR table Handler size*/
    #define ISR_HANDLER_SIZE       (8U)
    
    typedef void (*InterIsrFuncPtr)(void);
    
    typedef struct NmiIrqPrams
    {
        IntrFuncPtr fPtr;
        void *args;
    }NmiIrqPrams_t;
    
    /* ========================================================================== */
    /*                      External Function Declarations                        */
    /* ========================================================================== */
    extern void init_regs(void);
    
    /* ========================================================================== */
    /*                 Internal Function Declarations                             */
    /* ========================================================================== */
    /* static __inline uint32_t get_int_evtflag(uint32_t i); */
    /* static __inline void set_int_evt(uint32_t i, uint32_t val); */
    static __inline uint32_t get_int_mevtflag(uint32_t i);
    static __inline void clr_int_evt(uint32_t i, uint32_t val);
    static __inline uint32_t get_int_evtmask(uint32_t i);
    static __inline void set_int_evtmask(uint32_t i, uint32_t val);
    
    #if 0 /* Unused Functions */
    /*
     * \brief Macro to get the status of the events
     * \Param i  = register index for the register index passed
     *       i = 0 Get status of register DSP_EVTFLAG0
     *       i = 1 Get status of register DSP_EVTFLAG1
     *       i = 2 Get status of register DSP_EVTFLAG2
     *       i = 3 Get status of register DSP_EVTFLAG3
     */
    static __inline uint32_t get_int_evtflag(uint32_t i)
    {
        uint32_t retval;
    
        retval = HW_RD_REG32(SOC_DSP_ICFG_BASE + DSP_EVTFLAG0 + \
                             ((i) << 2U));
        return retval;
    }
    
    /*
     * \brief Macro to set the event for the register index passed
     * \Param i  = register index
     *       i = 0 Set event in register DSP_EVTSET0
     *       i = 1 Set event in register DSP_EVTSET1
     *       i = 2 Set event in register DSP_EVTSET2
     *       i = 3 Set event in register DSP_EVTSET3
     *
     *       val = value to be written to register
     */
    
    static __inline void set_int_evt(uint32_t i, uint32_t val)
    {
        HW_WR_REG32((SOC_DSP_ICFG_BASE + DSP_EVTSET0 + \
                     ((i) << 2U)), (val));
    }
    
    #endif
    
    static __inline uint32_t get_int_mevtflag(uint32_t i)
    {
        uint32_t retval;
    
        retval = HW_RD_REG32(SOC_DSP_ICFG_BASE + \
                             DSP_MEVTFLAG0 +     \
                             ((i) << 2U));
        return retval;
    }
    
    /*
     * \brief Macro to clear the event for the register index passed
     * \Param i  = register index
     *       i = 0 clear event by writting to register DSP_EVTCLR0
     *       i = 1 clear event by writting to register DSP_EVTCLR1
     *       i = 2 clear event by writting to register DSP_EVTCLR2
     *       i = 3 clear event by writting to register DSP_EVTCLR3
     *
     *       val = value to be written to register
     */
    
    static __inline void clr_int_evt(uint32_t i, uint32_t val)
    {
        HW_WR_REG32((SOC_DSP_ICFG_BASE + DSP_EVTCLR0 + \
                     ((i) << 2U)), (val));
    }
    
    /*
     * \brief Get Masked event status for the register index passed
     * \Param i  = register index
     *       i = 0 Get event mask for register DSP_EVTMASK0
     *       i = 1 Get event mask for register DSP_EVTMASK1
     *       i = 2 Get event mask for register DSP_EVTMASK2
     *       i = 3 Get event mask for register DSP_EVTMASK3
     *
     */
    static __inline uint32_t get_int_evtmask(uint32_t i)
    {
        uint32_t retval;
    
        retval = HW_RD_REG32(SOC_DSP_ICFG_BASE + DSP_EVTMASK0 + \
                             ((i) << 2U));
        return retval;
    }
    
    /*
     * \brief Mask the events for the register index passed with mask val
     * \Param i  = register index
     *       i = 0 Set event mask for register DSP_EVTMASK0
     *       i = 1 Set event mask for register DSP_EVTMASK1
     *       i = 2 Set event mask for register DSP_EVTMASK2
     *       i = 3 Set event mask for register DSP_EVTMASK3
     *
     */
    static __inline void set_int_evtmask(uint32_t i, uint32_t val)
    {
        HW_WR_REG32((SOC_DSP_ICFG_BASE + DSP_EVTMASK0 + \
                     ((i) << 2U)), (val));
    }
    
    /* ========================================================================== */
    /*                            Global Variables                                */
    /* ========================================================================== */
    /* L2 Interrupt Vector Table */
    #ifdef __cplusplus
    #pragma DATA_SECTION(".l2_int")
    #else
    #pragma DATA_SECTION(inth_IrqHandler, ".l2_int")
    #endif  /* #ifdef __cplusplus */
    IntrFuncPtr     inth_IrqHandler[INTH_INT_TABLE_SIZE];
    
    void           *argArray[INTH_INT_TABLE_SIZE] = {0};
    uint32_t        INTH_intRouting[16];
    
    #ifdef __cplusplus
    #pragma DATA_SECTION(".vects")
    #else
    #pragma DATA_SECTION(__ISR_Table, ".vects")
    #pragma DATA_ALIGN(__ISR_Table, 1024)
    #endif  /* #ifdef __cplusplus */
    uint32_t        __ISR_Table[(16U)*ISR_HANDLER_SIZE];
    
    /* array of interrupt counter */
    static uint32_t inth_IrqCount[INTH_INT_TABLE_SIZE];
    
    NmiIrqPrams_t gL1IrqQ1Handler = {NULL, NULL};
    /* ========================================================================== */
    /*                 Internal Function Declarations                             */
    /* ========================================================================== */
    static void Intc_IntInstallIrqHandler(uint32_t *vec, InterIsrFuncPtr ptr);
    static void Intc_IntInstallRstIrqHandler(uint32_t *vec, InterIsrFuncPtr ptr);
    static void scanCombined(uint8_t *intNo, uint32_t flag, uint32_t combNo);
    void INTH_IRQHandler(uint8_t l1intNumber);
    
    interrupt void NmiHandler(void);
    interrupt void INTH_L1IRQ4Handler(void);
    interrupt void INTH_L1IRQ5Handler(void);
    interrupt void INTH_L1IRQ6Handler(void);
    interrupt void INTH_L1IRQ7Handler(void);
    interrupt void INTH_L1IRQ8Handler(void);
    interrupt void INTH_L1IRQ9Handler(void);
    interrupt void INTH_L1IRQ10Handler(void);
    interrupt void INTH_L1IRQ11Handler(void);
    interrupt void INTH_L1IRQ12Handler(void);
    interrupt void INTH_L1IRQ13Handler(void);
    interrupt void INTH_L1IRQ14Handler(void);
    interrupt void INTH_L1IRQ15Handler(void);
    
    /* ========================================================================== */
    /*                          Function Definitions                              */
    /* ========================================================================== */
    void Intc_IntRegister(uint16_t intrNum, IntrFuncPtr fptr, void *fun_arg)
    {
        if (1U == intrNum)
        {
            gL1IrqQ1Handler.fPtr = fptr;
            gL1IrqQ1Handler.args = fun_arg;
            /* Register Exception Handler */
            Intc_IntInstallIrqHandler(&(__ISR_Table[ISR_HANDLER_SIZE*(1U)]),
                                       &NmiHandler);
        }
        else if (intrNum > 3U)
        {
            /* reset counter and install handler */
            inth_IrqCount[intrNum]   = 0;
            inth_IrqHandler[intrNum] = fptr;
            argArray[intrNum]        = fun_arg;
        }
        else
        {
            /* Nothing */
        }
    } /* EVE_HOST_INTH_InterruptSetup() */
    
    void Intc_SystemEnable(uint16_t intrNum)
    {
        uint32_t uTmp;
        uint32_t rgs;
        uint32_t tempVal;
    
        uTmp = (uint32_t) intrNum >> 5;
    
        rgs     = get_int_evtmask(uTmp);
        tempVal = (~(uint32_t) ((uint32_t) 1U << ((uint32_t) intrNum & 0x1FU)));
        rgs    &= (uint32_t) tempVal;
        set_int_evtmask(uTmp, rgs);
    #if defined (TI814X_BUILD) || defined (TI8149_BUILD) || defined (TI811X_BUILD) || defined (SOC_K2G) || \
         defined(SOC_K2K)||defined(SOC_K2H)||defined(SOC_K2L)||defined(SOC_K2E)|| \
         defined(SOC_C6678)||defined(SOC_C6657)
    /* not required */
    #else
        DSP_WUGEN_IRQ_Enable(intrNum);
    #endif
    }
    
    void Intc_SystemDisable(uint16_t intrNum)
    {
        uint32_t uTmp;
        uint32_t rgs;
        uint32_t tempVal;
    
        uTmp = (uint32_t) intrNum >> 5;
    
        rgs     = get_int_evtmask(uTmp);
        tempVal = (uint32_t) ((uint32_t) 1U << (intrNum & 0x1FU));
        rgs    |= (uint32_t) tempVal;
        set_int_evtmask(uTmp, rgs);
    #if defined (TI814X_BUILD) || defined (TI8149_BUILD) || defined (TI811X_BUILD) || defined (SOC_K2G) || \
         defined(SOC_K2K)||defined(SOC_K2H)||defined(SOC_K2L)||defined(SOC_K2E)|| \
         defined(SOC_C6678)||defined(SOC_C6657)
    /* not required */
    #else
        DSP_WUGEN_IRQ_Disable(intrNum);
    #endif
    }
    
    void INTH_IRQHandler(uint8_t l1intNumber)
    
    {
        uint8_t  intNumber[32];
    
        uint32_t FlagLatch = 0;
        uint32_t pass;
    
        intNumber[0] = 0;
    
        switch (l1intNumber)
        {
            case (uint8_t) 4:
                FlagLatch = get_int_mevtflag((uint32_t) 0);
                clr_int_evt((uint32_t) 0, FlagLatch);
                scanCombined(intNumber, FlagLatch, (uint32_t) 0U);
                break;
            case (uint8_t) 5:
                FlagLatch = get_int_mevtflag((uint32_t) 1);
                clr_int_evt((uint32_t) 1, FlagLatch);
                scanCombined(intNumber, FlagLatch, (uint32_t) 1U);
                break;
            case (uint8_t) 6:
                FlagLatch = get_int_mevtflag((uint32_t) 2);
                clr_int_evt((uint32_t) 2, FlagLatch);
                scanCombined(intNumber, FlagLatch, (uint32_t) 2U);
                break;
            case (uint8_t) 7:
                FlagLatch = get_int_mevtflag((uint32_t) 3);
                clr_int_evt((uint32_t) 3, FlagLatch);
                scanCombined(intNumber, FlagLatch, (uint32_t) 3U);
                break;
            default:
                intNumber[0] = (uint8_t) INTH_intRouting[l1intNumber];
                intNumber[1] = 0;
                pass         = ((uint32_t) intNumber[0] >> 5U);
                clr_int_evt((uint32_t) pass,
                            ((uint32_t) 1U <<
                             ((uint32_t) intNumber[0] - (uint32_t) (pass << 5U))));
                break;
        }
    
        while (0U != FlagLatch)
        {
            /* Process all active interrupts */
            pass = 0;
            while (0 != intNumber[pass]) {
                /* increment interrupt counter */
                inth_IrqCount[intNumber[pass]]++;
    
                if (0 != inth_IrqHandler[intNumber[pass]])
                {
                    /* call regitered interrupt handler */
                    inth_IrqHandler[intNumber[pass]](argArray[intNumber[pass]]);
                }
                pass++;
            }
    
            switch (l1intNumber)
            {
                case (uint8_t) 4:
                    FlagLatch = get_int_mevtflag((uint32_t) 0);
                    clr_int_evt((uint32_t) 0, FlagLatch);
                    scanCombined(intNumber, FlagLatch, (uint32_t) 0);
                    break;
                case (uint8_t) 5:
                    FlagLatch = get_int_mevtflag((uint32_t) 1);
                    clr_int_evt((uint32_t) 1, FlagLatch);
                    scanCombined(intNumber, FlagLatch, (uint32_t) 1);
                    break;
                case (uint8_t) 6:
                    FlagLatch = get_int_mevtflag((uint32_t) 2);
                    clr_int_evt((uint32_t) 2, FlagLatch);
                    scanCombined(intNumber, FlagLatch, (uint32_t) 2);
                    break;
                case (uint8_t) 7:
                    FlagLatch = get_int_mevtflag((uint32_t) 3);
                    clr_int_evt((uint32_t) 3, FlagLatch);
                    scanCombined(intNumber, FlagLatch, (uint32_t) 3);
                    break;
                default:
                    intNumber[0] = (uint8_t) INTH_intRouting[l1intNumber];
                    intNumber[1] = 0;
                    pass         = ((uint32_t) intNumber[0] >> 5U);
                    clr_int_evt(pass,
                                ((uint32_t) 1U <<
                                 ((uint32_t) intNumber[0] -
                                  (uint32_t) (pass << 5U))));
                    break;
            }
        }
    }  /* INTH_IRQHandler() */
    
    void Intc_IntUnregister(uint16_t intrNum)
    {
        uint32_t L1int;
    
        /* Find and clean interrupt entry in INTH_intRouting table */
        for (L1int = 8U; L1int < 16U; L1int++)
        {
            if (INTH_intRouting[L1int] == intrNum)
            {
                /*reset interrupt routing entry*/
                INTH_intRouting[L1int] = 0;
    
                /*reset counter and deinstall handler*/
                inth_IrqCount[intrNum]   = 0;
                inth_IrqHandler[intrNum] = NULL;
            }
        }
    }
    
    void Intc_IntEnable(uint32_t status)
    {
        /* Set GIE */
        CSR |= (uint32_t) 0x1U;
    
    }
    
    uint32_t Intc_IntDisable(void)
    {
    
        /* Clear GIE */
        CSR &= ~(uint32_t) 0x1U;
    
        return ((uint32_t) 0U);
    }
    
    void Intc_IntPrioritySet(uint16_t intrNum, uint16_t priority,
                             uint8_t hostIntRoute)
    {
        /* Dummy function in DSP */
    }
    
    static void scanCombined(uint8_t *intNo, uint32_t flag, uint32_t combNo)
    {
        volatile uint32_t i, count;
    
        count = 0U;
        if (0U == combNo)
        {
            i = 4U;
        }
        else
        {
            i = 0U;
        }
    
        for (; i < 32U; i++)
        {
            if ((uint32_t) 0 != (flag & (uint32_t) ((uint32_t) 1U << i)))
            {
                intNo[count] = ((uint8_t) (i + (combNo << 5)));
                if (count < 31U)
                {
                    count++;
                }
            }
        }
    
        intNo[count] = 0;
    } /* scanCombined() */
    
    void Intc_Init(void)
    {
        uint32_t count;
        uint32_t mask;
    
        /* Now, enable the 4,5,6, and 7 bits of IER
         *     These involve the default priority mode which uses the interrupt
         *       combiner */
    
        /* Clear all entries in L2 interrupt handler */
        for (count = 0U; count < INTH_INT_TABLE_SIZE; count++)
        {
            inth_IrqHandler[count] = NULL;
        }
    
        /* Clear Routing Table */
        for (count = 0U; count < 16U; count++)
        {
            INTH_intRouting[count] = 0;
        }
    
        /* Route combined inputs */
        /*INTH_intRouting[4] = ((uint32_t) INTH_INT_ID_EVT0);
        INTH_intRouting[5] = ((uint32_t) INTH_INT_ID_EVT1);
        INTH_intRouting[6] = ((uint32_t) INTH_INT_ID_EVT2);
        INTH_intRouting[7] = ((uint32_t) INTH_INT_ID_EVT3);*/
    	INTH_intRouting[12] = ((uint32_t) INTH_INT_ID_EVT0);
        INTH_intRouting[13] = ((uint32_t) INTH_INT_ID_EVT1);
        INTH_intRouting[14] = ((uint32_t) INTH_INT_ID_EVT2);
        INTH_intRouting[15] = ((uint32_t) INTH_INT_ID_EVT3);
    
        /* Configure IC */
        /* Remove all inputs from combiner */
        for (count = 0U; count < 4U; count++)
    	{
            clr_int_evt(count, 0xFFFFFFFFU);
            set_int_evtmask(count, 0xFFFFFFFFU);
        }
    
        /*Mask dropped interrupts*/
        HW_WR_REG32((SOC_DSP_ICFG_BASE + DSP_INTDMASK), (uint32_t) 0xFFF0U);
    
        /*
         * Program the interrupt selector here,
         * the first 4 interrupt output of the interrupt selector is
         * routed from the interrupt combiner
         * Each of these interrupt line cater to 32 event input lines
         *
         * Below is the mapping -
         * 0 bit -> 0-31 event lines
         * 1 bit -> 32-63 event lines
         * 2 bit -> 64-95 event lines
         * 3 bit -> 96-127 event lines
         *
         */
        //HW_WR_REG32((SOC_DSP_ICFG_BASE + DSP_INTMUX1), 0x03020100U);
    	HW_WR_REG32((SOC_DSP_ICFG_BASE + DSP_INTMUX1), 0x77777777U);		
    
        /* Route unused EVT 119 to other interrupt inputs */
        HW_WR_REG32((SOC_DSP_ICFG_BASE + DSP_INTMUX2), 0x77777777U);
        //HW_WR_REG32((SOC_DSP_ICFG_BASE + DSP_INTMUX3), 0x77777777U);
    	/* Route combined output to IRQ[12-15] */
    	HW_WR_REG32((SOC_DSP_ICFG_BASE + DSP_INTMUX3), 0x03020100U);
    	
    
        ICR = 0xffffU;
    
        /*Setting vector table base address*/
        ISTP = (uint32_t)&(__ISR_Table[0]);
    
        /* Clear Dropped interrupts */
        HW_WR_REG32((SOC_DSP_ICFG_BASE + DSP_INTXCLR), (uint32_t) 0x1U);
    
         Intc_IntInstallRstIrqHandler(&(__ISR_Table[0]),  &init_regs);
        Intc_IntInstallIrqHandler(&(__ISR_Table[ISR_HANDLER_SIZE*(4U)]),
                                   &INTH_L1IRQ4Handler);
        Intc_IntInstallIrqHandler(&(__ISR_Table[ISR_HANDLER_SIZE*(5U)]),
                                   &INTH_L1IRQ5Handler);
        Intc_IntInstallIrqHandler(&(__ISR_Table[ISR_HANDLER_SIZE*(6U)]),
                                   &INTH_L1IRQ6Handler);
        Intc_IntInstallIrqHandler(&(__ISR_Table[ISR_HANDLER_SIZE*(7U)]),
                                   &INTH_L1IRQ7Handler);
        Intc_IntInstallIrqHandler(&(__ISR_Table[ISR_HANDLER_SIZE*(8U)]),
                                   &INTH_L1IRQ8Handler);
        Intc_IntInstallIrqHandler(&(__ISR_Table[ISR_HANDLER_SIZE*(9U)]),
                                   &INTH_L1IRQ9Handler);
        Intc_IntInstallIrqHandler(&(__ISR_Table[ISR_HANDLER_SIZE*(10U)]),
                                   &INTH_L1IRQ10Handler);
        Intc_IntInstallIrqHandler(&(__ISR_Table[ISR_HANDLER_SIZE*(11U)]),
                                   &INTH_L1IRQ11Handler);
        Intc_IntInstallIrqHandler(&(__ISR_Table[ISR_HANDLER_SIZE*(12U)]),
                                   &INTH_L1IRQ12Handler);
        Intc_IntInstallIrqHandler(&(__ISR_Table[ISR_HANDLER_SIZE*(13U)]),
                                   &INTH_L1IRQ13Handler);
        Intc_IntInstallIrqHandler(&(__ISR_Table[ISR_HANDLER_SIZE*(14U)]),
                                   &INTH_L1IRQ14Handler);
        Intc_IntInstallIrqHandler(&(__ISR_Table[ISR_HANDLER_SIZE*(15U)]),
                                   &INTH_L1IRQ15Handler);
    
        //mask = 0x000000f2U;
    	mask = 0x0000F002U;
        IER |= mask;
    
        /* Enable the Global Interrupt Enable bit in CSR register of GEM
         * Also enable Global Exception Enable and Maskable Exception Enable in TSR
         */
        CSR |= 0x00000001U;
        TSR |= 0x00000004U;
        TSR |= 0x00000008U;
    #if defined (TI814X_BUILD) || defined (TI8149_BUILD) || defined (TI811X_BUILD) || defined (SOC_K2G) || \
         defined(SOC_K2K)||defined(SOC_K2H)||defined(SOC_K2L)||defined(SOC_K2E)|| \
         defined(SOC_C6678)||defined(SOC_C6657)
    /* not required */
    #else
        DSP_WUGEN_IRQ_Init();
    #endif
    } /* INTH_InitIntTable() */
    
    static void Intc_IntInstallIrqHandler(uint32_t *vec, InterIsrFuncPtr ptr)
    {
       uint32_t low = (uint32_t)ptr & 0xffffU;
       uint32_t high = (uint32_t)ptr >> 16;
    
       vec[0] = 0x003C54F6U;                        /* STW.D2T2      B0,*B15--[2] */
       vec[1] = 0x0000002AU | ((low) << 7);         /* MVK.S2        #ptr,B0 */
       vec[2] = 0x0000006AU | ((high) << 7);        /* MVKH.S2       #ptr,B0 */
       vec[3] = 0x00000362U;                        /* B.S2          B0 */
       vec[4] = 0x003C52E6U;                        /* LDW.D2T2      *++B15[2],B0 */
       vec[5] = 0x00006000U;                        /* NOP 4 */
       vec[6] = 0x00000000U;                        /* NOP */
       vec[7] = 0x00000000U;                        /* NOP */
    }
    
    static void Intc_IntInstallRstIrqHandler(uint32_t *vec, InterIsrFuncPtr ptr)
    {
       uint32_t cst21 = ((uint32_t)ptr - (uint32_t)&vec[0]) >> 2;
    
       vec[0] = 0x00000012U | (cst21 << 7);         /* B.S2            #ptr */
       vec[1] = 0x00006000U;                        /* NOP 4 */
       vec[2] = 0x00006000U;                        /* NOP 4 */
       vec[3] = 0x00006000U;                        /* NOP 4 */
       vec[4] = 0x00006000U;                        /* NOP 4 */
       vec[5] = 0x00006000U;                        /* NOP 4 */
       vec[6] = 0x00006000U;                        /* NOP 4 */
       vec[7] = 0x00006000U;                        /* NOP 4 */
    }
    
    #ifdef __cplusplus
    #pragma NMI_INTERRUPT
    #else
    #pragma NMI_INTERRUPT( NmiHandler )
    #endif
    void NmiHandler(void)
    {
        if(gL1IrqQ1Handler.fPtr != NULL)
        {
            gL1IrqQ1Handler.fPtr(gL1IrqQ1Handler.args);
        }
        while(1)
        {
            /* Code is not expected to be returned after entering
            exception handler */
        }
    }
    
    interrupt void INTH_L1IRQ4Handler(void)
    {
        INTH_IRQHandler((uint8_t) 4);
    }
    
    interrupt void INTH_L1IRQ5Handler(void)
    {
        INTH_IRQHandler((uint8_t) 5);
    }
    
    interrupt void INTH_L1IRQ6Handler(void)
    {
        INTH_IRQHandler((uint8_t) 6);
    }
    
    interrupt void INTH_L1IRQ7Handler(void)
    {
        INTH_IRQHandler((uint8_t) 7);
    }
    
    interrupt void INTH_L1IRQ8Handler(void)
    {
        INTH_IRQHandler((uint8_t) 8);
    }
    
    interrupt void INTH_L1IRQ9Handler(void)
    {
        INTH_IRQHandler((uint8_t) 9);
    }
    
    interrupt void INTH_L1IRQ10Handler(void)
    {
        INTH_IRQHandler((uint8_t) 10);
    }
    
    interrupt void INTH_L1IRQ11Handler(void)
    {
        INTH_IRQHandler((uint8_t) 11);
    }
    
    interrupt void INTH_L1IRQ12Handler(void)
    {
        INTH_IRQHandler((uint8_t) 12);
    }
    
    interrupt void INTH_L1IRQ13Handler(void)
    {
        INTH_IRQHandler((uint8_t) 13);
    }
    
    interrupt void INTH_L1IRQ14Handler(void)
    {
        INTH_IRQHandler((uint8_t) 14);
    }
    
    interrupt void INTH_L1IRQ15Handler(void)
    {
        INTH_IRQHandler((uint8_t) 15);
    }
    
    /********************************* End of file ******************************/
    

  • It's probably not working due to the case numbers in INTH_IRQHandler(uint8_t l1intNumber) that I mentioned.  Try that and verify you are back to your original behavior.  That way we know we have succeeded in "moving" the combiner interrupts to a lower priority.  Then we can proceed to phase two where we use the direct interrupt.

  • Hi Brad,

    Finally it works!

    I reached to get the same behavior by modifying the case numbers inside the function INTH_IRQHandler(uint8_t l1intNumber). When I changed the table with my own ISR the delay is decreased from 3us to 500ns ! The modification shows a real benefit. Your feeling was good.

    It remain some questions:

    1. 500ns is a good progress but is still a bit long. Do you think if it's possible to decrease the delay a bit more?

    2. I didn't mask the event coming from the combiner so I wonder why I don't jump into the ISR two times.. one from IRQ4 and one from IRQ12 whish is coming from the combiner?

    Anyway thanks for your time. I made some good progress.

    Regards,

    Sylvain.

  • Sylvain PALMERI said:
    I reached to get the same behavior by modifying the case numbers inside the function INTH_IRQHandler(uint8_t l1intNumber). When I changed the table with my own ISR the delay is decreased from 3us to 500ns ! The modification shows a real benefit. Your feeling was good.

    Big improvement!  That's great news.  Thanks for the update.

    Sylvain PALMERI said:
    1. 500ns is a good progress but is still a bit long. Do you think if it's possible to decrease the delay a bit more?

    Your previous results indicated that a GPIO write takes around 200ns.  I'm assuming your 500ns number is the time until you see the pin change right?  That indicates the ISR latency is actually about 200ns less.

    What does your current memory map look like?  Is all of your code/data in L2 SRAM, or is it in DDR?  If it is in DDR, you can likely improve the latency a bit more by locating the ISR in L2 SRAM.  If you're already in L2 SRAM, I recommend stopping there, i.e. can't improve much more.

    Sylvain PALMERI said:
    2. I didn't mask the event coming from the combiner so I wonder why I don't jump into the ISR two times.. one from IRQ4 and one from IRQ12 whish is coming from the combiner?

    That surprises me too.  It would need further debug, which is probably not a good use of time.

  • Hi Brad,

    I'm about to evaluate the TI-RTOS, by implementing the same things that we discussed previously, so that I can compare the behaviour I had with baremetal.

    So, now with RTOS, I jump to the ecap ISR, but this time with a latency about 780ns, without any modification inside the CSL and OSAL libraries. It's much more better that my 3us I had in the same configuration in baremetal (if you remember)

    I still have around 220ns to toggle the GPIO, so the real latency is about 500ns actually

    Well, according to your different answers, there are several ways to reduce this latency:

    1. bypass the combiner, and link the interrupt directly to IRQ4. That's what I did, following your suggest, in the baremetal version and it worked pretty good. This time with the RTOS that use OSAL libraries, I found a comment that prevent to bypass the combiner when we use C66x : "Use Event Combiner ALWAYS for c6x." That's written in the file "RegisterIntr_tirtos.c" in the function "Osal_RegisterInterrupt()". So maybe this solution is not recommended when using RTOS?

    2. Bypass the RTOS for hardware interrupts. What does it mean? Could please explain a bit more?

    3. Runing part of software in the L2 SRAM. The code I implemented is based on the "rtos_template_app". So I don't know how the memory is mapped. But anyway, if I run the code inside the ISR into the SRAM, it will probably go faster, but why does this impact the ISR latency?

    Regards,

    Sylvain.

  • Sylvain PALMERI said:
    1. bypass the combiner, and link the interrupt directly to IRQ4. That's what I did, following your suggest, in the baremetal version and it worked pretty good. This time with the RTOS that use OSAL libraries, I found a comment that prevent to bypass the combiner when we use C66x : "Use Event Combiner ALWAYS for c6x." That's written in the file "RegisterIntr_tirtos.c" in the function "Osal_RegisterInterrupt()". So maybe this solution is not recommended when using RTOS?

    I'm more familiar with the RTOS kernel itself and not with the OSAL library specifically.  You will need to understand which of the 12 CPU interrupts are being used by that library.  You might need to "move" the interrupts similar to what you did before.  Using sysbios APIs, you should be able to use Hwi_eventMap() and Hwi_plug() to populate your interrupt.  Here's a link to documentation:

    http://software-dl.ti.com/dsps/dsps_public_sw/sdo_sb/targetcontent/bios/sysbios/6_76_03_01/exports/bios_6_76_03_01/docs/cdoc/index.html

    If you go to ti -> sysbios -> family -> c64p -> Hwi you will find the available API's.

    Sylvain PALMERI said:
    2. Bypass the RTOS for hardware interrupts. What does it mean? Could please explain a bit more?

    The Hwi_plug() function I mentioned does this.  It will directly populate one of the entries in the vector table with the instructions to jump to your ISR.  Correspondingly your ISR needs to use the "interrupt" keyword so as to correctly handle registers.  As noted in the Hwi_plug() documentation, you are not allowed to call any sysbios API's from your ISR when doing this.  That's because you are outside the "view" of sysbios.

    Sylvain PALMERI said:
    3. Runing part of software in the L2 SRAM. The code I implemented is based on the "rtos_template_app". So I don't know how the memory is mapped. But anyway, if I run the code inside the ISR into the SRAM, it will probably go faster, but why does this impact the ISR latency?

    There's a *.map file that gets generated along side the executable.  You can see exactly where everything was placed.  DDR latency will be higher:

    1. It's a shared interface so there will be some command queueing involved.
    2. DRAM operations take time, e.g. opening a new page of memory where your code resides.
    3. There's just more levels of logic to get through, e.g. you may have cache misses in L1 and L2 that eventually make their way through the interconnect, to the DDR controller, and finally to the DDR.  Then the actual code/data needs to make it's way back through all those layers.  While this isn't a huge amount of time, it will be significant given the time scale you're working with.

    Brad

  • Hi Brad,

    Thanks a lot for all this information. I will go through all of this, and see how I can proceed.

    It will probably take some time, but I will give you feedback afterwards.

    Regards,

    Sylvain

  • Hi Sylvain,

    I am marking this thread as "TI Thinks Resolved."  If you have additional feedback or questions, feel free to respond to this thread or start a new post.

    Regards,

    Melissa