View previous topic :: View next topic |
Author |
Message |
johnl
Joined: 30 Sep 2003 Posts: 120
|
Question about interrupt enabling |
Posted: Wed Mar 02, 2022 5:08 pm |
|
|
I have A0 set up to wake up a 16F18323 which works fine:
Code: | enable_interrupts(INT_RA0);
|
This works without using enable_interrupts(GLOBAL).
But a timer0 overflow interrupt (during non-sleep) does not work without enabling interrupts "GLOBAL".
Code: |
#int_timer0
T0ISR()
{
output_toggle(PIN_A2);
}
...
setup_timer_0(T0_INTERNAL | T0_DIV_16 |T0_16_BIT);
enable_interrupts(INT_TIMER0 );
enable_interrupts(GLOBAL); //must have
|
Why the different requirements? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Mar 02, 2022 6:31 pm |
|
|
Look at Figure 8-1: Interrupt Logic on page 85 in the PIC data sheet.
The diagram shows that Wake Up does not require the GIE signal.
But if you want to interrupt the CPU when it's running, then the GIE
signal is required. GIE = Global interrupts enabled.
16F18323 data sheet:
https://ww1.microchip.com/downloads/en/DeviceDoc/40001799F.pdf |
|
|
johnl
Joined: 30 Sep 2003 Posts: 120
|
|
Posted: Wed Mar 02, 2022 9:11 pm |
|
|
Thanks PCM. That explains it.
I have a loop that takes pin input from timer1, reads eeprom and outputs highs and lows on pins to flash LEDs with delays from delay_ms and delay_us, but if I set up timer0 and enable interrupts global, it doesn't work. I'll post code after I simplify the long loop, but in the meantime, can you think of any reason why enable global would cause the loop to not run properly? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Mar 03, 2022 1:38 am |
|
|
Please post your test program that demonstrates the failure. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19496
|
|
Posted: Thu Mar 03, 2022 3:17 am |
|
|
Having an interrupt enabled, without a handler being present for that
interrupt will cause complete disaster. This is probably the most likely
one. It results in the code jumping into the middle of the wrong
location...
Understand, if an interrupt 'event' occurs it sets that interrupts 'flag',
If the interrupt itself is 'enabled' at this point, this can wake a chip.
If the global enable if also set, then when this happens the code will
call the 'handler'. This is a hardware call to a specific location at the
bottom of the memory. If no 'handler' exists at this point, then you
have just 'derailed' the program...
Or having an interrupt that doesn't clear the 'event'. This doesn't apply
to the timer, but does to things like INT_RDA. If you don't read the
character in the interrupt, this will immediately re-trigger.
Result main code will stop.
The timer could do the same, if (for example), you had a timer interrupt
handler that set the timer count to just one less that the 'wrap' value,
by the time the code got out of the interrupt it'd have triggered again.
Again result main code will stop. |
|
|
johnl
Joined: 30 Sep 2003 Posts: 120
|
|
Posted: Thu Mar 03, 2022 6:49 am |
|
|
Is there something missing in this handler? It does repeatedly toggle the output as expected.
Code: |
#int_timer0
T0ISR()
{
output_toggle(PIN_A2);
}
...
setup_timer_0(T0_INTERNAL | T0_DIV_16 |T0_16_BIT);
enable_interrupts(INT_TIMER0 );
enable_interrupts(GLOBAL);
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19496
|
|
Posted: Thu Mar 03, 2022 10:26 am |
|
|
That looks perfectly reasonable.
With obviously caveats about if any other interrupts are enabled. For
example if your RA0 interrupt gets left enabled, then a handler needs to
exist for this. Important therefore to make sure that when you are using
this to wake, you disable_interrupts(GLOBAL), before you enable this,
and then disable this when you wake, before you enable_interrupts(GLOBAL).
If you don't do this, then a handler must exist (with will need to read PortA
to clear the interrupt flag). This will be called when the chip wakes if the
global interrupt is enabled. |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1345
|
|
Posted: Fri Mar 04, 2022 12:55 pm |
|
|
Most of the chips I use (PIC24) don't require the interrupt to even be enabled specifically to wake. It just wakes from any source that can wake it from sleep (defined in the data sheet) and the only usage of enable_interrupts() disable_interrupts() is purely for the ISR.
I don't know if the OP's chip is the same as the ones I use though. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Mar 04, 2022 1:12 pm |
|
|
johnl wrote: |
I'll post code after I simplify the long loop. | |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9221 Location: Greensville,Ontario
|
|
Posted: Fri Mar 04, 2022 3:32 pm |
|
|
complicated main() ?? |
|
|
johnl
Joined: 30 Sep 2003 Posts: 120
|
|
Posted: Fri Mar 04, 2022 7:05 pm |
|
|
I think the problem is that the external pin wake-up interrupt does not have a handler and/or the interrupt flag never gets cleared. It works fine to wake the chip up but when the timer0 int is set up later, it requires an enable_interrupts(GLOBAL) and that tries to process the external int flag. As Ttelmah mentioned , an interrupt that's not handled can wreak havoc. Am I thinking about this correctly?
Code: | void main()
{
init();
do {
clear_interrupt(INT_RA);
enable_interrupts(INT_RA0);
sleep();
delay_cycles(1);
disable_interrupts(INT_RA0); //////(INT_RA); //Now turn interrupt off
}
run_mode(); //timer0 int is set up in run_mode() along with enable_interrupts(GLOBAL)
} while (TRUE);
}//end of main()
|
|
|
|
johnl
Joined: 30 Sep 2003 Posts: 120
|
|
Posted: Fri Mar 04, 2022 7:19 pm |
|
|
Yep that did it. Adding a clear_interrupt(INT_RA0) did the trick:
Code: |
Code:
void main()
{
init();
do {
clear_interrupt(INT_RA);
enable_interrupts(INT_RA0);
sleep();
delay_cycles(1);
disable_interrupts(INT_RA0); //////(INT_RA); //Now turn interrupt off
clear_interrupt(INT_RA0) ;
}
run_mode(); //timer0 int is set up in run_mode() along with enable_interrupts(GLOBAL)
} while (TRUE);
}//end of main() |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19496
|
|
Posted: Sat Mar 05, 2022 6:58 am |
|
|
That makes total sense.
Glad you have found it. |
|
|
|