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.

Nested interrupts and jump table



We are using an 'F5659 with a bootloader in the first page of Flash and an application beginning in the 2nd page.  In order to reduce interrupt latency for one critical interrupt, we allowed all other ISRs to be nested by simply setting GIE as early as possible in the ISRs.

However, we recently changed our project's interrupt strategy from one of moving our interrupt table to RAM (SYSCTL |= SYSRIVECT), to one of using a jump table, and now nesting the ISRs crashes the system.


In our original scenario, since the bootloader and application both used interrupts, we designed so that when the application started up, it moved it's table to RAM and also copied it's ISRs from a table in flash to low RAM.  That way, the ISRs remained callable by the vector table, but were free to access FAR data and we did not have to disturb the bootloader's space.

The change to using a jump table meant that we simply changed our old ISRs to normal functions, left them in upper flash pages and our new ISRs simply made far function calls to them.

Now, however, when the new ISR calls the isr function (which sets the GIE bit), we get mysterious crashes.  Everything works fine if we disable nesting.


Does anyone have any idea as to why setting the GIE bit inside a function that is called from an ISR would be an issue?  Does it have something to do with how the stack is unwound if that function is then interrupted?

The sequence would go something like this:

Interrupt->IV->ISR->function->GIE->Interrupt->IV->ISR->function->return->ISR return->function rtn->ISR rtn.

I've tried to figure out the stack in this scenario but cannot see a problem.  The fact remains, though, that allowing nesting crashes the new project whereas it worked fine in the old project.

Any ideas?

Thanks.

  • It looks like TI in general DOES NOT recommend to use nested interrupts under MSP430 architecture. See

    http://processors.wiki.ti.com/index.php/Getting_Started_with_the_MSP430_LaunchPad_Workshop

    It is stated in 'Interrupts' video there. It may give some idea why they don't.

    Also search for 'nested interrupts' in this forum. There are several threads about this subject, with explanations why

    'setting GIE as early as possible in the ISRs' is not very good thing to do, like

    http://e2e.ti.com/support/microcontrollers/msp430/f/166/t/258640.aspx.

  • Mark Rush1 said:
    Does anyone have any idea as to why setting the GIE bit inside a function that is called from an ISR would be an issue? 

    For one thing, if the peripheral requesting the interrupt requires you to manually clear the IFG and you haven't done so, you enter the brief recursive loop until your stack overflows.

    Your ISR should really only handle the bare interrupt function (retrieving data, putting data into UART, etc) and the rest of the data processing should happen in a background loop.

  • Thank you for your reply.

    You are correct re: calling functions from within ISRs.  Function call overhead and all that...

    However, we have been pressed into our present configuration because we had to service our interrupts using FAR ISRs.

    And you are also correct re: clearing the IFG.  That was already being done.

    As far as I can tell, the only difference between our old method (having ISRs in near RAM) and our present method (having simple ISRs in near memory that simply call a function - our old ISRs - in FAR memory) is the function call itself.  We are delaying setting the GIE bit until after we are in the called function - which is, incidently, responsible for making sure the IFG is cleared first.

  • Without setting GIE inside ISRs, different ISRs are served on first come first served bases. When GIE is set inside ISRs, the parts after setting GIE are served on first come last served bases. Thus a small delay in each ISR can accumulate to a large delay for that poor first ISR being served last.

    Could this be the reason for your problem?

    The other possible cause is, you have good intention, but did not implement it right.

  • old_cow_yellow said:

    Without setting GIE inside ISRs, different ISRs are served on first come first served bases. When GIE is set inside ISRs, the parts after setting GIE are served on first come last served bases. Thus a small delay in each ISR can accumulate to a large delay for that poor first ISR being served last.

    Could this be the reason for your problem?

    Probably not, since nesting worked before.

    The other possible cause is, you have good intention, but did not implement it right.

    Well, the system crashes, so you're probably right.

  • Mark Rush1 said:
    Probably not, since nesting worked before.

    In general, nested interrupts work. But you need to ensure that all interrupts are serviced in time, no recursion on non-recursive code, and enough stack space for deepest nesting. All the above limitations depend on CPU execution time of the ISRs. Your old scheme did not reach the tipping point. Your new scheme could have crossed that line, even if you implemented it "correctly".

  • Indeed, nested interrupts are possible. However, they require lots of experience, as you easily get into trouble that it almost impossible to debug.
    Your ISRs need to be reentrant, you need lots of stack size and you can easily mess things up. And using LPMs with nested interrupts is a nightmare (as the nested interrupt cannot exit LPM)
    But in general, if you think you need nested interrupts, then your code design is bad.
    I only used nested interrupts in two occasions so far. One was a scheduler ISR for multithreading, where the ISR had to go to sleep if all threads are sleeping, and needs to be waked by the timer (and with an idle thread, I could have done without nested interrupts). The other one was the background SD card init function, which was called by the 1ms interrupt. However, the function had a guard so it was never entered twice, and it used a state machine to do only one step at a time, then exit until next timer interrupt. If I had been less lazy, I could have extended the state machine so nested interrupts wouldn’t have been necessary.
    So on the bottom line, I’ve never had a situation in which nested interrupt shave been really necessary. If you need them, you’re doing something wrong.

    OCY: Your ‘first come, first serve’ is not entirely true. Yes, the first ISR is effectively finished last, when it sets GIE and is interrupted. So first come, last serve is partly true and depends on when the ISR sets GIE. However, the interrupting ISRs are handled based on priorities. So while GIE is clear (which it is when the ISR is called), multiple interrupts may happen, and the one with the highest priority is served, once GIE gets set again. Of course, if all ISRs set GIE, then indeed, the last (or lowest priority, which is the last then)  will likely complete first – unless another one which has already been interrupted, triggers again.

**Attention** This is a public forum