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.

Long HWI interrupt latency on OMAP-L138 DSP (C6748); improvements?

Other Parts Discussed in Thread: OMAP-L138, SYSBIOS

A question about interrupt latencies.  We're using an OMAP-L138 running at 456MHz.  The DSP has two critical interrupts to service: the UPP DMA which receives periodic data from an FPGA for processing; and the SPI which handles high-priority commands.  The UPP DMA runs at 120kHz (8.3us intervals) for each packet of data.  SPI uses the 4-line-with-enable mode, and the SPI driver is currently interrupting every byte.  We're using the "bitmask" mode on the HWIs so that the SPI HWI can preempt the UPP DMA HWI.  The whole thing is using SYS/BIOS 6.35.4.50, building in release mode with full optimisation for speed, and with all the code and data for the UPP and SPI handling in L2 RAM. That's the context...

We've got a couple of GPIO lines which go high at the start of each HWI and go low at the end, and we've got access to the UPP and SPI pins, so I can directly measure latencies on a scope.  What I'm seeing is that there is around 560ns between the end of the UPP packet and the start of the UPP HWI; and around 460ns between the end of a SPI byte and the start of the SPI HWI.  This is unacceptably slow.

I dug around and found the SYS/BIOS benchmarks for the C6748.  These quote 91 cycles for interrupt latency, 114 cycles for the HWI prolog, 224 cycles for the HWI dispatcher, and 118 cycles for the HWI epilog.  Unfortunately, this explains why we'd see times like that.

Is there any way within SYS/BIOS to reduce these latencies to something more acceptable for hard-real-time performance?  Or is SYS/BIOS inherently unable to do better than this?

Looking in the HWI docs, I've found a reference to "HWI_plug()" which allows HWIs without the SYS/BIOS overhead.  The docs note that HWI_enable/disableIER must be called manually to mask this and/or other interrupts, which is easy enough.  The docs don't explain anything else about how to use this though.  Do I need to use the "interrupt" keyword for the compiler to set up the context switch?  And is there anything else which would be needed?  (I don't have any other calls to SYS/BIOS within these HWIs, so that's OK.)

Also, should I still expect 91 cycles of interrupt latency even with using "HWI_plug()"?

  • Hi,

    Moreover, this issue is related to SYSBIOS issue, I am moving your post to right forum to be better answered.

    Thanks & regards,

    Sivaraj K

  • OK, thanks Sivaraj. It's probably specific to the OMAP-L138 (or C6748) SYSBIOS though, so it does cross both categories.  See what you guys think anyway.

    Just to make sure you have all the right info, I should also mention that I'm using the C6x/Hwi module instead of the generic Hwi module.

  • Hi Graham,

           You're on the right path. A lot of the extra-cycles you're seeing are part of the overhead of using the Hwi dispatcher. Using Hwi_plug get's rid of all that and you should see even less than 91 cycles. Here's sample code that uses the Hwi_plug.

    6116.HwiTest2.c

    2604.HwiTest2.cfg

    Let me know if this helps.

    Moses

  • Thanks Moses - that's great.  I'll give that a go and see how it works.

  • Cool, I've got that working.  I'm getting definite improvements with that.  Interrupt latency seems to vary between 70-90 ticks at 456MHz, which is a whole lot more acceptable!

    The documentation and your example are not brilliant for this though, so for the benefit of anyone else trying this...

    Contrary to Moses' example above, the config functions "Hwi.plugMeta" and "Hwi.eventMapMeta" in the CFG file don't seem to do anything, at least with SYSBIOS 6.35.4.50 and XDCtools 3.25.3.72 for C6478/OMAP-L13x.  (Perhaps they work in more recent versions?)  But it doesn't matter, because you don't need them.

    You need to run some setup stuff as follows:-

    void myInterruptSetup()
    {
    /* Set up the peripheral */
    /* Your stuff here */

    /* Set up the ISR */
    Hwi_eventMap(myInterruptNumber, myEventSource);
    Hwi_plug(myInterruptNumber, myIsrFunction);

    /* Prepare the peripheral interrupt, including clearing interrupt flags initially */
    /* Your stuff here */

    /* Start interrupts */
    Hwi_enableIER(1 << myInterruptNumber);
    }

    Run that, and the interrupts are going.  (After you've run BIOS_start, of course.)

    You then need your ISR to look something like this:-

    interrupt void myIsrFunction()
    {
    /* Selectively disable interrupts */
    uint16_t restoreInterruptState = Hwi_disableIER((1 << myInterruptNumber) |
            (1 << lowerPriorityInterruptNumber) |
            (1 << anotherLowerPriorityInterruptNumber));

    /* Clear this interrupt */
    Hwi_clearInterrupt(myInterruptNumber);

    /* Do your ISR stuff here */

    /* Restore interrupts */
    Hwi_restoreIER(restoreInterruptState);
    }

    The important undocumented part is that you need to call Hwi_clearInterrupt in the ISR, otherwise you won't get another interrupt.

    I've also explicitly given an example of preempting a couple of lower priority interrupts, which is something else which is almost completely undocumented.  In practise of course you would make this more efficient by setting up a constant value instead of calculating this in the ISR, but this is how you'd set up preemption in the C6748/OMAP-L13x.

    Note that if your ISR needs to trigger a SWI or a semaphore, then you're better off sticking with a HWI (and in the case of semaphores you have no choice but to do it that way, according to the docs).  But if you're just servicing an interrupt with data that comes from/goes to elsewhere, replacing those HWIs with real ISRs will give you some very serious performance improvements.

  • Quick note...

    myEventSource is the event ID, which comes from the OMAP-L138 spec (e.g. 37 for the SPI peripheral or 94 for the UPP peripheral).

    myInterruptNumber will be between 4 and 15 for the C6748/OMAP-L138, as per the docs for the interrupt module.  (Interrupts 0-3 are non-maskable.)

    I thoroughly recommend setting up the interrupt as a HWI first and then changing it to use this pattern later.  The reason is that SYSBIOS sets up hidden interrupts for other things (e.g. timer interrupt).  TI has not written a single word of documentation about this - not about which interrupt numbers are used where, nor their latencies, nor how they play with other interrupts.  Nor can you configure it anywhere - it's hardcoded.  So the only way you'll ever find you've got a conflict is if you set up a HWI with that interrupt number and the RTSC build spots the conflict whilst generating the code for your HWI configuration.  If you go straight for the ISR approach, you have no such warnings.  (Perhaps the Hwi_plugMeta config function checks this?  Unknown.)