|
|
View previous topic :: View next topic |
Author |
Message |
kgng97ccs
Joined: 02 Apr 2022 Posts: 97
|
Managing interrupts |
Posted: Sun May 22, 2022 8:38 pm |
|
|
I am using the PIC18LF46K22, CCS C compiler v5.078, and MPLAB IDE v8.92.
I understand that when an interrupt is triggered, the PIC MCU will jump to the interrupt service routine if it is defined, complete the task in the ISR, and then continue from where it left off in the main program.
Questions:
1. If while an ISR due to an interrupt is running and a second but different interrupt that is considered very important occurs, is it possible to abort the ISR that is currently running, and service the second interrupt? If yes, what settings can be used to achieve that?
2. If I have an ISR associated with an interrupt, but at some point in the program I wish to call that ISR to perform the task defined in it, how can I do that? Should I just do a regular function call (see illustration code below)? If yes, how will the MCU treat this ISR call? For example, will the MCU simply treat it as a regular function call and will the MCU do anything to the associated interrupt flag?
Illustration:
Code: | #int_timer1
void timer1_isr()
{
… /* perform a task */
}
void main()
{
…
… /* set up Timer1 */
…
timer1_isr(); /* call ISR associated with int_timer1 */
…
} |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Sun May 22, 2022 11:21 pm |
|
|
On the PIC18, there are two hardware interrupt levels.
Look in the #int section of the manual at 'HIGH' and 'FAST', and
#device HIGH_INTS=TRUE
However huge amounts of caveats. Depending on the PIC, when this
is enabled, some interrupts are always 'HIGH'. May cause problems.
Look at the data sheet for your chip. If the interrupt has a priority
it can be set HIGH or can be normal. If it doesn't, then it is always
HIGH.
On calling a function, don't.
Instead only call the function outside the interrupt. In the interrupt,
just set a flag that tells your main code to call this when you return.
Problem otherwise is that if you were calling the function in the main, and
then an interrupt occurred, you would be trying to call the function
inside itself. This results in 're-entrancy'. The PIC 16 and 18, do not
support re-entrant functions (because they do not have a stack for
variables).- If you do try to call a function both inside and outside the
interrupt, the compiler will disable interrupts when you are in the
external call, to prevent this happening. |
|
|
kgng97ccs
Joined: 02 Apr 2022 Posts: 97
|
|
Posted: Tue May 24, 2022 10:17 pm |
|
|
Thank you, Ttelmah, for your explanation and for directing me to the applicable resources.
In the PIC18LF46K22 datasheet (Section 9), I can see that there are many interrupts for which the priority bit can be set.
1. Does the CCS compiler control the default settings of these priority bits?
2. Under what circumstances would we want to use the #INT_xxxx FAST" directive, which can be issued only once and, for the PIC18, does not save or restore key registers?
3. If either “#int_xxxx HIGH” or "#INT_xxxx FAST" is used to set a priority interrupt, do we still need to use the “#device HIGH_INTS=TRUE” directive?
4. What will happen if we issue both “#int_xxxx HIGH” directives (or a "#INT_xxxx FAST" directive) and the “#device HIGH_INTS=TRUE” directive?
5. If there are multiple high priority interrupts, can we use the “#priority” directive to indicate the order in which they will be serviced?
6. Will a “#priority” directive in general override whatever priority settings that have been done before the “#priority” directive is issued?
I will appreciate any comments or corrections. Thank you. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Tue May 24, 2022 11:48 pm |
|
|
Yes, you need to have #device HIGH_INTS=TRUE, before you can
use HIGH or FAST. This adds the capability to use these.
FAST would only be used if _you_ are going to save the registers
needed for one interrupt that needs to be handled as fast as possible.
There is only one high priority. You can only have HIGH or FAST not
both. I think (if I remember correctly, will have to test), the compiler will
not allow both. There is one interrupt on some chips, that has no priority
bit.
Yes, if you try to select both, it warns that 'interrupt level changed
FAST>HIGH'. |
|
|
kgng97ccs
Joined: 02 Apr 2022 Posts: 97
|
|
Posted: Sat May 28, 2022 6:19 am |
|
|
Thank you, Ttelmah.
The CCS manual says that for PIC18 interrupts, one can have only one #int_xxxx FAST (p. 152, Nov 2021 manual). However, I could not find any clear indication in the datasheet about the number allowed for such a high priority interrupt.
I tested the following code: Code: | #device HIGH_INTS=TRUE
#int_rda FAST
#int_rda2 FAST
#int_tbe HIGH
#int_tbe2 HIGH |
The compiler did not give any error or warning.
Could it be that the PIC18LF46K22 chip actually does allow multiple FAST and multiple HIGH interrupts? |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9225 Location: Greensville,Ontario
|
|
Posted: Sat May 28, 2022 7:08 am |
|
|
Typically the 'ISR controller' or whatever they call the code that decides which interrupt to handle, will create a 'jump table' or some other mechanism with a 'top down' sequence or order of which interrupt to do 1st, 2nd, 3rd, etc.
If you dump the listing, you'll see this code...'somewhere'.
Others who KNOW the compiler can tell it better than me. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Sat May 28, 2022 9:57 am |
|
|
Understand that the hardware only gives one 'high priority' interrupt.
The same applies to normal interrupts.
The compiler then adds it's own 'dispatcher'. This polls the interrupts
on the hardware interrupt and dispatches the code to the specified
interrupt routine. It also saves the registers before this is done.
FAST, does not have a dispatcher.
It should give an error 138, if you try to have two fast interrupts.
But if you define an int as HIGH, and then another as FAST, all it does is
makes any interrupt defined as FAST, into one defined as HIGH.
Hence no error. The FAST interrupt then loses any speed advantage.
For HIGH, a standard dispatcher is added, so you can have as many
interrupt routines as you want. As Jay says, the order in the dispatcher
is top down. First interrupt defined is the first one polled. |
|
|
kgng97ccs
Joined: 02 Apr 2022 Posts: 97
|
|
Posted: Wed Jun 01, 2022 12:18 am |
|
|
Thank you, Jay and Ttelmah, for your explanations. I now have a better understanding of the way the compiler manages FAST and HIGH interrupts. |
|
|
kgng97ccs
Joined: 02 Apr 2022 Posts: 97
|
|
Posted: Wed Jun 15, 2022 9:48 pm |
|
|
I am using the PIC18LF46K22, CCS C compiler v5.078, and MPLAB IDE v8.92.
1. Is this correct?
If we enable the hardware priority interrupt, the int_ext interrupt (int0) will automatically be a high priority such that we do not need to specifically set the int_ext interrupt to a high priority.
Code: | #device HIGH_INTS=TRUE
#int_ext HIGH /* is this directive redundant */
|
2. Is this correct?
If we do not enable the hardware priority interrupt, and an int_ext interrupt (that has been enabled) occurs while an ISR for another interrupt is running, the ISR will not be interrupted by the int_ext interrupt. Meaning, as long as the hardware priority interrupt is not enabled, an ISR that is running can never be interrupted by another interrupt. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Wed Jun 15, 2022 11:59 pm |
|
|
1). Yes, but I'd always put it in. Problem is if you don't, looking at the
code later, would be easy to 'forget' that INT_EXT does not have a
priority bit.....
2) Yes. If two interrupts occur together, then the one that is defined
'first' will be the one serviced (or if a priority statement is used the one
first in this). The second interrupt will be serviced after this. Once the
interrupt servicing is actually started, then later interrupts are serviced
after the first terminates. |
|
|
kgng97ccs
Joined: 02 Apr 2022 Posts: 97
|
|
Posted: Fri Jun 24, 2022 12:44 am |
|
|
Thank you, Ttelmah, for your advice.
I understand that at any one time, only one HIGH priority interrupt can be serviced, and that a high priority interrupt can interrupt a normal ISR, but cannot interrupt a HIGH ISR.
For the situation in which interrupt priority is enabled and more than one high-priority interrupt is set, can the #priority directive be used to set
(a) the order in which the high priority interrupts are polled (if they are triggered at around the same time), and
(b) if low priority interrupts are also enabled, the order in which the low priority interrupts are polled?
For example, does this code make sense? Code: | #device HIGH_INTS=TRUE
#int_ext HIGH
#int_rda HIGH
#priority int_rda, int_ext
// or #priority int_rda, int_ext, int_timer0, int_timer1, if low priority interrupts are also enabled |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Fri Jun 24, 2022 6:18 am |
|
|
Yes, or (personally I think less likely to get confused), just declare
the interrupt handlers in the order you want the priority to happen.
What occurs, is that in the interrupt handler routine, the interrupt bits
are tested in the order from the declaration, or the priority. |
|
|
kgng97ccs
Joined: 02 Apr 2022 Posts: 97
|
|
Posted: Fri Jul 15, 2022 12:39 am |
|
|
I encountered this warning:
">>> Warning 216 "main_N892_v1.0_828B.c" Line 565(1,2): Interrupts disabled during call to prevent re-entrancy: (@WRITEBITA)"
"Line 565" is the line where the closing curly bracket ("}") for the main function is.
My code goes like this: Code: | ...
#include "f1.c" /* contains user-defined function 1 */
#include "f2.c" /* contains user-defined function 2 */
#include "f_int_timer1.c" /* contains #int_timer1 ISR, which does not call any user-defined function */
...
void main()
{
...
setup_timer_1(T1_external | T1_enable_sosc | T1_div_by_1);
...
/* These are the only 3 interrupt-related statements in the main() function */
clear_interrupt(int_timer1);
enable_interrupts(int_timer1);
enable_interrupts(global);
...
while (true)
{
if (T1_isr_done==1)
{
...
... /* call function 1 */
... /* call function 2 */
}
}
} |
Questions:
1. Does this warning mean that when the program execution enters any one of the user-defined functions, int_timer1 is disabled? If yes, will int_timer1 be automatically enabled when the program execution leaves the function?
2. What could be the cause of this warning?
3. What should I look out for in the program to prevent this warning? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Fri Jul 15, 2022 1:06 am |
|
|
1) No. It means the interrupts will be disabled when the WRITEBITA
function is called.
2) It means this function is being called both inside the ISR, and outside.
3) Do not use any function, that is not 'inline' both inside and outside
the ISR.
Now a simple 'output_high', (or low), will not cause this. However if
you do something more complex, like output using a variable, then this
becomes a distinct function, which introduces this.
So (using an example that was posted here a little while ago):
Code: |
int16 pins[8] = {PIN_A0,PIN_A4,PIN_A7,PIN_A5,PIN_B0,PIN_B4,PIN_B3,PIN_B1};
output_high(pins[0]);
|
If this function was called both inside and outside the ISR, this warning
would appear. |
|
|
|
|
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
|