Electronic – Multiple simultaneous Interrupts PIC16F88

interruptsmicrocontrollerpicpwm

I'm new to PIC microcontrollers (I have some experience with Arduino but wanted some "real" experience =P ). I got myself a PIC16F88 and I intend to make a simple robot with two 2 DC motors. Each motor will be independently controlled via PWM.

I want to implement the PWM signals in software (ya I know, quite a good learning experience!). This microcontroller only has one PWM module, but I would want to do it in software even if it had more.

Without further ado:

What happens when two timer overflow interrupts occur at the same time? Does the controller ignore one? Will they both call the interrupt vector one after another?

Best Answer

Say that you have enabled the TMR0 and TMR1 interrupts by setting TMR0IE and TMR1IE. When either of the interrupt events happen, their interrupt flags (TMR0IF or TMR1IF) get set. This doesn't cause the code to actually vector to the interrupt routine unless the GIE (global interrupt enable) bit is also set.

So, say that GIE has been set, and you get a TMR0 overflow. This sets TMR0IF, vectors to the interrupt location, and clears the GIE bit. Now that GIE is cleared, future interrupt triggers won't cause any code vectoring. However, the interrupt flags still get set.

Now, say that you are in your interrupt routine. The TMR1 interrupt gets triggered. This sets the TMR1IF bit, but doesn't do anything else. The bit simply stays set.

When your interrupt routine is finished, you use a RETFIE statement (in assembly) or a return(); (in c). This vectors back to your mainline code, and sets the GIE bit.

Now that both the GIE and TMR1IF bits are set, it causes an immediate vector back into your interrupt code.

So, you don't really lose interrupt data; it just gets delayed.

An common way to structure an ISR is like this:

if (TMR0IF && TMR0IE)
{
    (do something)
    TMR0IF = 0; // Clear the flag!
    return();
}
else if (TMR1IF && TMR1IE)
{
    (do something else)
    TMR1IF = 0;
    return();
}

But, if you expect to have concurrent interrupts, you might want to allow them both to be processed in just one pass through the ISR:

if (TMR0IF && TMR0IE)
{
    (do something)
    TMR0IF = 0;
}
if (TMR1IF && TMR1IE) // Notice this isn't an "else if"
{
    (do something else)
    TMR1IF = 0;
}
return();

There's one last issue to be aware of. Say that both interrupt flags get set at the same time (or very close to the same time). By the time the code vectors to the interrupt routine both flags will already be set. The ISR doesn't know which one got set first; it simply runs through your code. So in my earlier examples the TMR0 interrupt will get serviced first, even if the TMR1 flag was slightly earlier.

I hope this helps :)