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.

RTOS: How does hardware interrupt pre-empt logic works in SYS_BIOS

Other Parts Discussed in Thread: OMAP-L138, SYSBIOS

Tool/software: TI-RTOS

Hi there,

I am using OMAP-L138 SoC and in the DSP side on the core I am trying to use two interrupts .

SPI1 set to interrupt number 5 and UART0 set to interrupt number 7. I am not currently using any priorities for these. 

Below is the configuration info:

var hwi5Params = new Hwi.Params();
hwi5Params.instance.name = "hwi5";
hwi5Params.priority = -1;
hwi5Params.eventId = 38;
Program.global.hwi5 = Hwi.create(5, "&uart0ISR", hwi5Params);

var hwi7Params = new Hwi.Params();
hwi7Params.instance.name = "hwi7";
hwi7Params.eventId = 43;
hwi7Params.priority = -1;
hwi7Params.maskSetting = xdc.module("ti.sysbios.interfaces.IHwi").MaskingOption_SELF;
Program.global.hwi7 = Hwi.create(7, "&SPI1Isr", hwi7Params);

SPI1 ISR runs for around 1.2ms and the UART0 ISR runs of 200usec but the frequency of UART0 is higher hence I assigned interrupt number 5 for higher priority that the SPI1 interrupt. But for some reason SPI1 interrupt doesn't pre-empt when there is UART0 interrupt. Am I doing anything wrong here?? Thanks

  • Mitesh Hiran said:
    SPI1 ISR runs for around 1.2ms and the UART0 ISR runs of 200usec

    Are those the periods of the ISRs or the durations of ISR execution times?

    Mitesh Hiran said:
    but the frequency of UART0 is higher hence I assigned interrupt number 5 for higher priority that the SPI1 interrupt.

    On the C6x DSP the HW interrupt priority does not indicate the preemptability of one interrupt vs another, it simply indicates which interrupt will be taken first when both are present in a given CPU cycle.

    In SYS/BIOS, you control the preemptability of ISRs with the masking.  You have chosen MaskingOption_SELF for the SPI ISR in hwi7, which means that every other interrupt can preempt (i.e., interrupt) it.  You have not specified a maskSetting for the UART interrupt hwi5, but the default setting (which is being used for hwi5) is MaskingOption_SELF, so every other interrupt should be able to interrupt hwi5.

    This all seems like it should be OK for your setup.

    Can you show me the complete source code for your ISRs for hwi5 and hwi7 (the uart0ISR and SPI1Isr)?

    Regards,

    - Rob

  • I had another thought about what might be happening...

    Is it possible that:

    1. uart0ISR runs, masking itself (hwi5)
    2. SPI1Isr preempts uart0ISR (hence running with hwi5 & hwi7 masked), and while it is executing ...
    3. ... another UART0 interrupt happens, but since it can't preempt itself, it is held off until the instance of uart0ISR from step 1. finishes.

    If this is the case happening for you, then you can fix it by setting hwi5's 'maskSetting' to MaskingOption_ALL, which will prevent the SPI1Isr from running while uart0ISR runs.  But, if you need SPI1Isr to preempt uart0ISR then this won't work for you.

    Regards,

    - Rob

  • Hi Rob, thanks for your replies.
    Thanks for pointing it out, regarding the masking logic for UART and SPI.
    However, it looks like it's should work..
    If the SPI ISR is running and then if there is an UART interrupt .... Then it should preempt SPI to UART .
    Since the UART is interrupt number 5 and SPI is interrupt number 7, I guess generally SPI should be preempted by the UART (And since UART is highest priority it can never be preempted!!!)
    So it should never get in the situation you mentioned.
  • Hi Rob, here is the ISR code

    void SPI1Isr(void)
    {
    unsigned int intCode = 0;

    #ifdef _TMS320C6X
    IntEventClear(CSL_INTC_EVENTID_SPIINT1);
    #else
    IntSystemStatusClear(56);
    #endif

    intCode = SPIInterruptVectorGet(CSL_SPI_1_REGS);

    while (intCode)
    {
    // Setting FPGA Data Flag
    if(intCode == SPI_TX_BUF_EMPTY)
    {

    SPITransmitData1(CSL_SPI_1_REGS, *p_tx);

    }

    if(intCode == SPI_RECV_FULL)
    {
    *p_rx = (unsigned short) SPIDataReceive(CSL_SPI_1_REGS); //(char)

    }
    }
    intCode = SPIInterruptVectorGet(CSL_SPI_1_REGS);
    }
    }

    And UART ISR:

    void uart0ISR() {

    unsigned int int_id = 0;
    unsigned char dataRdy=0;
    extern unsigned char GPSDataInt;

    /* This determines the cause of UART0 interrupt.*/
    int_id = UARTIntStatus(CSL_UART_0_REGS);

    #ifdef _TMS320C6X
    // Clear UART0 system interrupt in DSPINTC
    IntEventClear(SYS_INT_UART0_INT);
    #else
    /* Clears the system interupt status of UART0 in AINTC. */
    IntSystemStatusClear(SYS_INT_UARTINT0);
    #endif

    /* Checked if the cause is transmitter empty condition.*/
    if(UART_INTID_TX_EMPTY == int_id)
    {
    if (length > 0)
    {
    /* Write a byte into the THR if THR is free. */
    UARTCharPutNonBlocking(CSL_UART_0_REGS, gpsInit[count]);
    length--;
    count++;
    //Dummy read
    UARTCharGetNonBlocking(CSL_UART_0_REGS);
    }
    if(length == 0)
    {
    /* Disable the Transmitter interrupt in UART.*/
    UARTIntDisable(CSL_UART_0_REGS, UART_INT_TX_EMPTY);
    count = 0;
    //Dummy read
    UARTCharGetNonBlocking(CSL_UART_0_REGS);
    // Enable RX interrupt
    UARTIntEnable(CSL_UART_0_REGS, (UART_INT_LINE_STAT | UART_INT_RXDATA_CTI ));
    }
    }

    /* Check if the cause is receiver data condition.*/
    if(UART_INTID_RX_DATA == int_id)
    {
    // Reset Char length start of ISR
    CharLen = 0;
    // Notify Interrupt Received
    GPSDataInt = 1;

    do {
    // Reading a character from the FIFO
    // Write received character into a Buffer
    GPSMesgBuffer[wrIdx] = (char) UARTCharGetNonBlocking(CSL_UART_0_REGS);
    // Number of Char Rx
    CharLen++;
    wrIdx++;
    // Reset Buf pointer
    if (wrIdx == 1008) {
    wrIdx = 0;
    }
    dataRdy = (char) UARTCharsAvail(CSL_UART_0_REGS);
    } while (dataRdy == 0x01 && CharLen <= 15);
    wrIdx = 0;
    Semaphore_post(GPSDecode_SEM);

    }

    /* Check if the cause is receiver line error condition.*/
    if(UART_INTID_RX_LINE_STAT == int_id)
    {
    while(UARTRxErrorGet(CSL_UART_0_REGS))
    {
    /* Read a byte from the RBR if RBR has data.*/
    UARTCharGetNonBlocking(CSL_UART_0_REGS);
    }
    }
    return;
    }
  • And the timing, I mentioned are the time spend in the ISRs.
  • In the attached graph, the time when SPI ISR (interrupt number 7) is running it doesn't let msCounter (interrupt number 6) and UART (interrupt number 5) to preempt.. This is what I don't understand..
  • Mitesh Hiran said:
    Since the UART is interrupt number 5 and SPI is interrupt number 7, I guess generally SPI should be preempted by the UART (And since UART is highest priority it can never be preempted!!!)

    As I stated in my initial reply, the hardware interrupt priority doesn't work this way, it serves only to decide which interrupt to take *on a given CPU cycle*.  Let me explain with an example...

    Suppose interrupts are globally disabled (by GIE=0 in CSR), and during this disabled period two separate interrupts fire, causing their flags to be set in the Interrupt Flag Register (IFR).  Since interrupts are globally disabled, neither of these will be taken.  When the code gets around to enabling global interrupts again, the CPU needs to decide which of these two interrupts to service.  It will service the interrupt with the higher HW priority (hwi5 in this case).  This is the only time that HW priority matters.  Then, with DSP/BIOS HWI dispatching, hwi5's interrupt mask will be applied to the Interrupt Enable Register (IER), masking itself, and then global interrupts will be enabled by the dispatcher to allow nested interrupts, and hwi5's ISR will be called.  However, as soon as interrupts are enabled by the HWI dispatcher, hwi7 will get serviced since it is not masked.  The HW priority doesn't matter here since there is only one interrupt flagged in the IFR.  You can prevent hwi7 from interrupting hwi5 only by setting the maskSetting to a value that masks off hwi5, such as MaskingOption_ALL or MaskingOption_BITMASK with a bitmask value of 0x0080.

    The C6x DSP is different in this regard from a lot (if not most) other CPUs and MCUs where a lower priority interrupt can't preempt a higher priority interrupt's ISR.

    So, again, the only way to prevent hwi7 from interrupting hwi5 is to tell the DSP/BIOS dispatcher to mask hwi7, with either ALL or a BITMASK of 0x0080 (IER is a 16-bit register).

    Mitesh Hiran said:
    So it should never get in the situation you mentioned.

    I hope you understand now that it can, and will, get in the situation I mentioned.

    Regards,

    - Rob

  • Mitesh Hiran said:
    In the attached graph, the time when SPI ISR (interrupt number 7) is running it doesn't let msCounter (interrupt number 6) and UART (interrupt number 5) to preempt.. This is what I don't understand..

    Can you zoom-in on the execution graph and post the new, more detailed screenshot?  I want to see more detail for the grey rectangles.  I would like to see the detail for one of the smaller rectangles and the rectangle just before the long red line of the SPI ISR.

    Regards,

    - Rob

  • Mitesh Hiran said:

    void SPI1Isr(void)
    {
       unsigned int intCode = 0;
     
    #ifdef _TMS320C6X
       IntEventClear(CSL_INTC_EVENTID_SPIINT1);
    #else
       IntSystemStatusClear(56);
    #endif

       intCode = SPIInterruptVectorGet(CSL_SPI_1_REGS);

       while (intCode)
       {
         // Setting FPGA Data Flag
         if(intCode == SPI_TX_BUF_EMPTY)
         {
            SPITransmitData1(CSL_SPI_1_REGS, *p_tx);
          }

         if(intCode == SPI_RECV_FULL)
         {
           *p_rx = (unsigned short) SPIDataReceive(CSL_SPI_1_REGS); //(char)
          }
       }

    Your "while (intCode)" loop doesn't change intCode, so it will never terminate.  Not sure if this explains all you're seeing, but seems bad to me.

    Regards,

    - Rob

  • Also, please try setting the UART ISRs Hwi.maskSetting = MaskingOption_ALL and report back the results.

    Regards,

    - Rob
  • Hi Rob,

    right, now I understand.. So if I need UART interrupt to preempt all other interrupts that is not possible. All I can control is if there are more than one interrupt pending and at that time priority of an interrupt triggers.

    SO does this means, if an interrupt is processing NO other interrupt can preempt it. 

  • I had tried this before and there was no difference.
  • Oh that "intCode = SPIInterruptVectorGet(CSL_SPI_1_REGS);" is present in the while loop.. it might have got missed, while I was pasting here and editing extra code..
  • Mitesh Hiran said:
    So if I need UART interrupt to preempt all other interrupts that is not possible

    That is certainly possible.  I'm just trying to tell you to forget about HW priority, it basically doesn't exist, and instead use SW priority.

    SW priority is where the software controls the relative interrupt priorities with the mask setting.  So, you want UART to preempt all other interrupts (except itself, probably)?  This is accomplished by not masking the UART interrupt for all other interrupts.

    To put it another way, you want the UART interrupt (hwi5) to have higher scheduling priority than the SPI interrupt (hwi7). You can accomplish this by having the UART Hwi's maskSetting = MaskingOption_BITMASK and its disableMask and restoreMask = 0x00A0.  SPI's Hwi would have maskSetting = MaskingOption_SELF, since all Hwis should prevent self-nesting.  In this way, SPI cannot preempt UART, but UART can preempt SPI.

    Mitesh Hiran said:
    SO does this means, if an interrupt is processing NO other interrupt can preempt it.

    Certainly not.  You have full control over which Hwi can or cannot preempt any other Hwi.

    Regards,

    - Rob

  • Mitesh Hiran said:
    Oh that "intCode = SPIInterruptVectorGet(CSL_SPI_1_REGS);" is present in the while loop.. it might have got missed, while I was pasting here and editing extra code..

    OK.  There was an extra closing brace in your function so I wasn't sure.

    So, in your execution graph, why do the first few SPI Hwis execute for a very short time, and then the last SPI Hwi executes for a very long time?

    Regards,

    - Rob

  • Hi Rob, thanks.. I will try to do this with the masking options.

    In the cfg file how can one change the bitmask?

    I tried the maskingOption_Lower.. which is the best one to use but looks like that is not yet supported.

  • right, will add the following line in the cfg file
    hwi5Params.disableMask = 0x00A0
  • Hi Rob,
    The reason is for the last SPI word we Rx there are extra calculations done which should take less than 1ms.
  • Mitesh Hiran said:
    I tried the maskingOption_Lower.. which is the best one to use but looks like that is not yet supported.

    This option is available for targets that have true HW priority.  Since the C6x doesn't have that, it's not supported on C6x DSPs, nor will it ever be.

    Regards,

    - Rob

  • Mitesh Hiran said:
    right, will add the following line in the cfg file
    hwi5Params.disableMask = 0x00A0

    Be sure to also set

    hwi5Params.restoreMask = 0x00A0;

    Without this, those interrupts would remain disabled upon returning from the interrupt.

    Regards,

    - Rob

  • Mitesh Hiran said:
    The reason is for the last SPI word we Rx there are extra calculations done which should take less than 1ms.

    It would help to see that last block on the execution graph be more detailed: (having trouble getting screenshot to be embedded, so if you don't see it, please open attachement)

    The grey rectangle on the left is a bunch of logging activity that's all squished together.  You can zoom in on the execution graph to show finer granularity.

    Would you be able to capture this zoomed in to more detail?

    Thanks & Regards,

    - Rob

  • Hi Rob,

    In my design, we are using NDK and the interrupt definition for TX and RX are run-time and it doesn't have restoreMask !! So if we don't have restoreMask, would the default be selfMask? 

    However, I'm not able to add restoreMask and disableMask in cfg file. Could you please, let me know how to add those, please.

  • Sorry Rob, I thought, I have done that. Will do ASAP.
  • Mitesh Hiran said:
    However, I'm not able to add restoreMask and disableMask in cfg file. Could you please, let me know how to add those, please.

    The restoreMask and disableMask are elements of the c64p-specific Hwi parameters.  The package ti.sysbios.family.c64p.Hwi inherits from ti.sysbios.hal.Hwi.

    I assume that you're currently including ti.sysbios.hal.Hwi in your C code:

        #include <ti/sysbios/hal/Hwi.h>

    Instead, you should:

        #include <ti/sysbios/family/c64p/Hwi.h>

    When doing so your Hwi_Params structure comes from the c64p Hwi, and it contains the disableMask & restoreMask elements.

    The same applies when doing the equivalent thing from the .cfg file:

        var Hwi = xdc.useModule('ti.sysbios.family.c64p.Hwi');

    Regards,

    - Rob

  • Hi Rob, thanks for your reply.

    I did change as per your previous mail. I am not getting this warning: 

    "Non default mask setting but dispatcherAutoNestingSupport is disabled."

    Should I need to enable auto nesting feature??? 

  • Mitesh Hiran said:

    "Non default mask setting but dispatcherAutoNestingSupport is disabled."

    Should I need to enable auto nesting feature???

    Hmmm, the default value for dispatcherAutoNestingSupport is "true" (or enabled), so I'm wondering how this is being set to "false" (or disabled).  Is your configuration setting it false?  You mentioned that you were using NDK, so I'm also wondering if NDK is setting this to false.

    A configuration can have it set to false without any error being produced only if maskSetting = MaskingOption_SELF, which is what you used to have before I recommended that you use MaskingOption_BITMASK.  But now that you're using BITMASK, this error is happening since you've asked for masking with the BITMASK setting but for some reason the dispatcher's nesting has been disabled.

    This would explain why your UART interrupt is not able to preempt the SPI interrupt, so let's just find out how it is getting disabled.  You could try manually setting it to "true" to see what happens.

    Regards,

    - Rob

  • Hi Rob,

    Yeah, I changed it to "true" in the cfg file and looks like all the warning are gone. But I didn't realise this will otherwise stop pre-empt of interrupts.

    I'm sorry, for not uploading the graph yet.. Will do soon ;)

    Thanks.

  • Mitesh Hiran said:

    Yeah, I changed it to "true" in the cfg file and looks like all the warning are gone. But I didn't realise this will otherwise stop pre-empt of interrupts.

    I'm sorry, for not uploading the graph yet.. Will do soon ;)

    Perhaps you don't need to upload the graph anymore, since this change you have just made could well fix the issue.

    Does the issue still happen after this change?  If so, please upload the execution graph snippet that I requested.

    Thanks & Regards,

    - Rob