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.

A SWI never gets interrupted by HW Interrupts

Other Parts Discussed in Thread: SYSBIOS

Hi all,

I'm new to the SysBIOS world, and I have a problem related to HWI preemption over SWI. Things seem to be working pretty fine, except for this case where I have the following situation :

An Interrupt occurs, resulting in an HWI being called (Timer_Handler). This HWI posts a SWI (mySwi). This SWI is called after completion of the first HWI.
Then during execution of the SWI, another Interrupt occurs (I2C_Handler). My problem is that this new Interrupt doesn't preempt the SWI, though I need it to.

I am running SysBIOS on a platform similar to Stellaris, with a Cortex-M4F.

Here is the code for setting up the corresponding HWI and SWI dynamically :
Swi_Handle mySwi;

Int main()
{
Hwi_Params hwiParams;
Swi_Params swiParams;
Hwi_Handle myHwi[64];

Swi_Params_init(&swiParams);
swiParams.priority = 0x40;

// create new SWI
mySwi = Swi_create(sensorSwi, &swiParams, NULL);
if(mySwi == NULL) {
send_msg(1,0xBAD00);
}

Hwi_Params_init(&hwiParams);
hwiParams.arg = 0;
hwiParams.enableInt = FALSE;
hwiParams.priority = 0x20; // > 0x0, reserved for zero-latency interrupt

myHwi[33] = Hwi_create(49, I2C_Handler, &hwiParams, NULL);
if(myHwi[39] == NULL){
send_msg(1,0xBAD00+49);
}

myHwi[39] = Hwi_create(55, Timer_Handler, &hwiParams, NULL);
if(myHwi[39] == NULL){
send_msg(1,0xBAD00+39);
}

Hwi_enableInterrupt(49);
Hwi_enableInterrupt(55);

BIOS_start();

return 0;
}

Then the Timer_Handler HWI :

Void Timer_Handler(UArg arg)
{
u32 swiKey;

// we disable SWI so it can be posted upon completion of the HWI
swiKey = Swi_disable();

// [...]
Swi_post(mySwi);
// [...]

clr_pending_irq();

// we restore the SWI and the remaining SWIs can be posted
Swi_restore(swiKey);
}

Does somebody have an idea why the SWI never gets interrupted by the Hardware Interrupt ?
Thanks in advance,

Michael

  • Which version of SYS/BIOS are you using?

    Can you try setting the interrupt priority to 0x40 and see if this changes the behavior?

    Are you certain the I2C interrupt is going off during the execution of the Swi?

    Within your Swi code please add this snippet and report the value of hwiKey:

          UInt hwiKey;

          hwiKey = Hwi_disable();

          Hwi_restore(hwiKey);

    Alan

  • Michael,

    I don't see much problem in the logic..

    Is this ok..?

    Michael Fillinger said:
    myHwi[33] = Hwi_create(49, I2C_Handler, &hwiParams, NULL);
    if(myHwi[39] == NULL){
    send_msg(1,0xBAD00+49);
    }

    You seem to be assigning for myHwi[33] and checking/handling the error for myHwi[39].  Does this mess up your system (that code is not here).

    Hope this helps..

    With best regards,

    Madhvapathi Sriram

  • Something else a little troublesome about your code is that  the array of Hwi Handles (myHwi[]) is defined as a local variable in main().

    Hopefully you're not referencing this array somewhere else in your code.

    Alan

  • Hi all

    thank you for all your answers. You're right about the myHwi[33] referencing. This was corrected since and of course didn't change the problem.

    I've had environment problems since I posted this thread, so I haven't been able to get the keyHwi yet, but hopefully things will run correctly again today. 

    Also, I'm not referencing myHwi anywhere, but for the sake of it, I'll have it global, since there's no point in having it declared locally in main, as you rightfully suggested !

    I'm certain the I2C IRQ is firing, because I'm running everything on RTL simulation, and I can see the isr bus of the CM4, and more specifically the I2C IRQ toggling. Then in simulation it stays asserted forever, and by looking at the instruction bus of the CM4, I can see it's stuck in the SWI function, waiting for a flag to toggle.

    I'll post again today, as soon as everything's back up again.

    Thanks again

    Michael

  • Hi again,

    ok so I could re-run the whole thing.

    I've added the code for keyHwi, and got keyHwi = 0x0

    Also, I made a mistake in my first message : when I put hwiParams.priority = 0x20; the I2C interrupt never gets serviced, independantly of being in a SWI or not ! In a smaller testcase that I have which only exercises I2C, it wouldn't work with priority = 0x20;

    This smaller test does work with hwiParams.priority = 0x0; but then the problem stated in this thread occurs, whatever priority I put for my SWI.

    In the end, it appears I have 2 issues : why wouldn't the interrupt be serviced with a priority of 0x20, and why my SWI doesn't get interrupted ?

    Best regards

    Michael

  • Intriguing indeed..

    Not being carried away by your latest findings (which indeed can be some more issues), coming back to the original post and your finding with the hwiKey.

    Looks like between, the first h/w interrupt handler and the next somewhere the HWIs are getting disabled.

    1) So, need to see what's so special code in the Timer_Handler() that can potentially disable interrupts. For example, what does clr_pending_irq() do?

    2) Is there anything in the SWI that has something potentially damaging?

  • Hi,

    very good point. I kind of forgot about that custom function I had to write. 

    It doesn't do much, but still, it could break something I guess :

    1. On our platform, there is an Interrupt Distributor that forwards Interrupts to other IPs, the CM4 in our case. So we first need to clear the IRQ at Interrupt Distributor level.

    2. The only other thing it's doing, is clearing the interrupt at NVIC level. Now I guess that's where there could be an issue : somehow, it wouldn't work at the beginning of the project, so I added the clear manually in my code. 

    I just I removed the NVIC clearing, so now all that remains is the INTDIST clearing, and though the good thing is that all that was working before is still working, it didn't solve our issue.

    In the SWI, I don't see what could be wrong : the first thing it does -- and that's where it gets stuck -- is performing an I2C read, and thus writing to a bunch of I2C registers, and then waiting for a flag to toggle, telling that data has been received. This flag is supposed to toggle upon I2C interrupt reception.

    I guess I could share the whole code, but I cannot do it in an external forum unfortunately.

    Regards

    Michael

    Note : I'm running on SysBIOS 6.33.03.33 and XDC Tools 3.23.01.43

  • Michael,

    The activity on this thread has died down and I'm wondering if you still have an outstanding issue.  Can you summarize where you are on this and what further help you are seeking?

  • Hi David,

    thanks for following up on this.

    Unfortunately, I still have the issue, and I had to move on to something else in the meanwhile (I can avoid the problem by using polling for now). 

    To summarize my problem, I've got the following sequence occuring : 

    1. An interrupt occurs, lauching an ISR

    2. This ISR posts a SWI and exits

    3. The SWI is waiting for another interrupt to occur (which should toggle a flag)

    4. The other interrupt does occur (visible in Simulation), but the SWI is not interrupted, and is stuck in an endless loop

    Best regards

    Michael

  • Michael,

    Is the flag being polled in the Swi in step #3 declared as a volatile?  Is it possible the ISR is indeed running but the flag check was optimized away?

    Scott

  • Hi Scott

    yes all my flags are declared globally as volatile (in fact, being slightly paranoid on this one, I've declared all my globals as volatile ...)

    I'm sure the ISR never launches, as I'm sniffing the instruction bus of the CM4 and once it gets to the instructions within the SWI, it never ever leaves. In particular, it doesn't fetch the exception vector related to the IRQ coming in...

    Michael

  • I believe the problem is due to setting the interrupt priority to zero.

    This value informs Hwi_create() that you are defining a zero-latency-interrupt. This topic is discussed here (see "Configuring a Zero Latency Interrupt"):

        http://processors.wiki.ti.com/index.php/SYS/BIOS_for_Stellaris_Devices#SYS.2FBIOS_M3_Hardware_Interrupt_.28Hwi.29_Handling

    Consequently, the interrupt is NOT routed through the dispatcher.

    This results in the Swi function running within the interrupt thread itself, at the same thread (NVIC) priority as the interrupt.

    Consequently, the interrupt can NOT interrupt itself.

    Zero Latency Interrupts are NOT ALLOWED TO POST Swis or Semaphores! Behavior such as you're seeing (or WORSE) will result.

    I think you have to find out why the interrupt doesn't go off when you set the priority to 0x20.

    One thing to keep in mind is that all dispatched interrupts (ie non-Zero Latency interrupts) are disabled in main().

    They get enabled by SYS/BIOS within the BIOS_start() call.

    Alan

  • Hi,

    ok I'm back on this issue (I cannot work 100% on it unfortunately).

    The good news is, after a lot of trials and errors, I finally found the solution to my problem, though I'm not entirely sure if it's normal that it works ;)

    The solution was not only to have the HWI that posts the SWI with an interrupt priority of 0x20 (which I understand), but also the HWI that interrupts the SWI, even though that one doesn't contain any Swi_post or anything else.

    Do you feel that this is the expected behavior ?

    Michael

  • I'm glad its working. But no, this doesn't sound right to me.

    The Hwi that interrupts the Swi that doesn't contain any Swi_post() or anything else should be able to be configured as a zero latency interrupt (ie priority = 0).

    Just to get current, please list the interrupts and their respective priorities defined in your application.

    Alan

  • Hi,

    here is the interrupt list and their priorities :

    - 1 SWI which has priority 1 (though I don't think it really matters in the end)

    - 64 HWI, though "only" 30 are created and enabled. In the working code, all of them have priority 0x20. When it wasn't working, only the Timer HWI which was posting the SWI had a priority of 0x20, all others had 0x0. In the use case I am running, just 3 HWI are being used (the Timer HWI, the I2C HWI and another HWI which is completely unrelated and wasn't occuring at the same time). 

    Do you think there is something I can do to help understand this behavior ? 

    By the way, something is still a bit off, because I have another issue, which is basically, that I cannot create all 64 HWI that would be needed by my application. But that's probably another subject that I will try to solve, or else post another thread in these forums.

    Regards

    Michael

  • I can believe that the use-case which had all but one interrupt priority set to zero would fail. Zero latency interrupts (ie non-masked interrupts) must be very carefully used since they do not honor critical section protection and are not managed by the interrupt dispatcher.

    In the trimmed down use-case with just 3 interrupts what are the interrupt priorities? And are you saying that if you set the priority of the I2C interrupt to zero then the use case fails? And if so, is the I2C interrupt calling ANY SYS/BIOS APIs?

    Alan

  • Hi

    in the use case with just 3 interrupts enabled, for the working case, all of their priority is set to 0x20. If I set either Timer or I2C HWI priority to 0x0, it starts to fail. I didn't try for the other HWI, because it's not really correlated and don't have much to do with the rest of it.

    The I2C interrupt is as simple as it can be and doesn't call any SysBIOS API : just reads a couple of registers, set some flag for SW, clears IRQ and exits.

    The only thing I can think of, is that the SWI and the HWI are both sharing some resources : the flags (SWI is waiting for it to toggle, HWI is toggling it), but also some array containing I2C samples.

    Do you think I'm missing some kind of resource sharing protection ? 

    Regards,

    Michael

  • Yes. I think/hope that is PRECISELY the problem.

    The zero latency interrupt will pre-empt ANY code.There is no critical section protection against these non-masked interrupts.

    If your Swi is doing a read-modify-write of a variable shared with a non-masked interrupt, things will likely go horribly wrong.

    Is the timer you mention the timer used by the Clock module? If so, this timer interrupt definitely can NEVER be configured as a zero-latency interrupt as the Clock tick function interacts with internal SYS/BIOS objects and posts Swis.

    Alan

  • I think the Swi code that clears the flag may be being interrupted by the interrupt that sets the flag:

    if (flag) {

         do work                    

         flag = 0;

    }

    The region of code between the "if (flag)" and the "flag = 0" is unprotected against the interrupt that comes in and sets the flag. Consequently an I2C interrupt can get missed.

    Alan

  • Well, the reason why I did it that way, is that the resource sharing is only one way : the I2C HWI is only writing to those resources, the SWI is only reading from these... except for the flag, which is initialized at the very beginning of the SWI ... 

    The Timer I mention is not used by the Clock module. We have 4 timers in our system, and I'm using 3&4 for the application to be safe (1&2 are used by SysBIOS) .

    Michael

  • Which interrupt is posting the Swi?

    Alan

  • The Timer interrupt is posting the SWI, but for this one I had always put priority of 0x20, for this very reason.

    Michael

  • Ok. Good.

    So could the problem be as I suggested in the code snippet? The flag is being unilaterally cleared immediately after the I2C interrupt sets it, thus leading to a missed I2C event?

    Alan

  • Hi

    not really. It is done like this, in summary (no clear at the end of the SWI) :

    swi() {

    flag = 0;

    do work;

    while(!flag);

    }

    hwi() {

    flag = 1;

    }

    Michael