|
|
View previous topic :: View next topic |
Author |
Message |
benoitstjean
Joined: 30 Oct 2007 Posts: 566 Location: Ottawa, Ontario, Canada
|
PIC24EP512 - Disable interrupt within its own interrupt |
Posted: Tue Feb 16, 2021 8:05 pm |
|
|
Compiler: 5.026
Device: PIC24EP512GP806
Hi all,
I realize this is probably a redundant / common question and I will admit I feel like an amateur asking this because I know I've read about this topic elsewhere but searching this forum returns way too many results (and my patience is growing thin). Anyhow....
This is my interrupt routine:
Code: | #INT_RDA LEVEL=7
void My_RDA_Interrupt( void )
{
// Code here
} |
When the interrupt is entered, should I call disable_interrupts( INT_RDA ); and just before exiting, call enable_interrupts( INT_RDA ); like this:
Code: | #INT_RDA LEVEL=7
void My_RDA_Interrupt( void )
{
disable_interrupts( INT_RDA );
// Code here
enable_interrupts( INT_RDA );
} |
Is there any value in doing this? Or is it just redundant code because it is already done internally (sorry, I don't speak assembly language)?
In other words, when any interrupt occurs, is _that_ interrupt automatically disabled when the code jumps into the ISR and re-enabled when the ISR is exit? Or is this something I must manage?
Thanks.
Ben |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1909
|
|
Posted: Tue Feb 16, 2021 8:52 pm |
|
|
Putting in the extra disable and then enable interrupt is redundant because while the ISR is being executed, that particular interrupt can't be interrupted again by that same source (RDA in your example). If you have a processor that supports interruptible interrupts, and you don't want a particular higher priority interrupt to be able to interrupt a lower priority interrupt, then you can add code like you've shown to prevent that.
The confusing part is the hidden code the compiler automatically adds for each interrupt to clear that interrupt. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19546
|
|
Posted: Wed Feb 17, 2021 1:55 am |
|
|
It is both simpler and more complex than you may think.
By default, the compiler does not clear the interrupt till you exit the handler.
There is no 'stacking' of interrupt bits, so the already set bit can't get
set again while you are in the handler.
Now there are situations, where you might deliberately 'want' to let the
interrupt become set again. This is handled by coding like:
Code: |
#INT_RDA CLR_FIRST
void My_RDA_Interrupt( void )
{
//handler code
}
|
This then clears the interrupt at the entry point to the handler. With this,
the interrupt can become triggered again. Normally you would want this,
if you wanted to ensure an event cannot be missed. However on the
PIC16/18 you then need to be careful, since in fact the RDA interrupt
cannot actually be cleared, until the character has been read. So on these
chips you instead have to behave like:
Code: |
#INT_RDA NOCLEAR
void My_RDA_Interrupt( void )
{
chr=getc(); //physically get the character
clear_interrupt(INT_RDA); //then immediately clear the interrupt
//now the rest of the handler code
}
|
So here, you physically handle the 'event' (get the character), 'ASAP', and
clear the interrupt just one instruction later, which then allows the
interrupt to trigger again after this point.
Now the interrupt bit being set at the exit of the routine, then simply means
that the routine will then be called again. Throughout the handling, the
physical chip hardware 'makes sure' an interrupt cannot be called inside
itself. On the PIC16/18, as soon as an interrupt is called the GIE bit
(for the applicable 'level' on the PIC18), gets turned off when an interrupt
is called, and is not re-enabled until the RETFIE at the end of the handler.
On the PIC24/30/33, it is instead handled by the processor priority
mechanism. An interrupt can only interrupt code that is at a lower priority
level than the CPU is currently running. The normal CPU code is level0.
Note the 'lower', not 'equal'. This is why if you assign an interrupt to
level0, it is effectively disabled, since it can never actually interrupt
anything. Now in your interrupt at level7, it can only be interrupted by
trap events (so things like address errors), not by any other user interrupt
(since they will all be 'below' this level), including itself, since the level
is the same.
There is though another 'caveat' here.
In the PIC24/30/33, there is a character buffer for the RDA event,
that is several characters deep. The interrupt will not re-trigger if
another character arrives in the buffer before an existing character
is read. So on these, the RDA handler needs to be coded as:
Code: |
#INT_RDA
void character(void)
{
uint16_t chr;
//receive characters from serial
do
{
chr=fgetc(RDAROURCE); //whatever your stream name is
//your handler code to save character here
} while (kbhit(RDAROURCE));
}
|
Otherwise characters can gradually build in the receive hardware buffer. |
|
|
benoitstjean
Joined: 30 Oct 2007 Posts: 566 Location: Ottawa, Ontario, Canada
|
|
Posted: Thu Feb 18, 2021 1:11 pm |
|
|
Fair enough, thanks for the detailed info, I will look into it.
Cheers,
Ben |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|