interrupt priority of PIC18F452

Thread Starter

raychar

Joined Nov 8, 2011
82
Hello, everybody,

By my knowledge, 8051 have the default priority as follows if no priority flag is set:

Highest to lowest priority:
INT0
TF0
INT1
TF1
Serial communication
TF2

How about 18F452?
Thanks,
 

ErnieM

Joined Apr 24, 2011
8,377
Here's the fine manual you can read. Pay close attention to section 8.0.

There are about a gazillion interrupt sources inside this device, each having an enable, activity flag and a priority setting.

There are only two interrupt levels: high and low. AFAIK any source may be assigned to either priority.
 

upand_at_them

Joined May 15, 2010
940
Like Ernie said, the PIC interrupts can be assigned to either high or low priority. Other microcontrollers might give priority by peripheral, but PICs do not.
 

JohnInTX

Joined Jun 26, 2012
4,787
18F PICs do IRQs in the legacy mode (single, non-prioritized vector at 0008h like the 16xxx) or prioritized mode (two vectors, high priority at 0008h and low priority at 0018h). You pick one at the design stage. The PIC defaults at reset to legacy mode. Set RCON:7 to enable priority mode. When in prio mode, the various bits in the IPRx registers select the priority of each IRQ.

In either mode, when interrupted, you scan the various xxxIF bits that are expected to determine which IRQs are to be serviced. Usually, these must be manually cleared during service but some peripherials (USART for example) clear IF when they are read, etc. Its a good idea to also scan the xxxIE bits (interrupt enables) before xxxIF if there is any chance that the IRQ source may be turned off without disabling the peripherial (timers etc). After any IRQ service, I like to return to the TOP of the xxxIF polling (after context switch) to see if any others need service before exiting to save context-switching time.

Context saving:
The PIC has what they call a Fast Return Stack which during ANY interrupt copies WREG, BSR and STATUS to a single level register set which is restored when a retfie FAST is excuted. Unfortunately, it doesn't work properly on all chips (452 included). The issue involves 2-word instructions i.e. movff WREG right at an IRQ. Its supposedly fixed in later silicon but.. The fix is documented in the MPLAB chip documentation but essentially involves a CALL to the next instruction which is a POP. The stack stays the same but W,BSR, and STATUS are pushed and all is well when retfie FAST is executed. My hi level ISRs always have this construct. And obviously, since the Fast Return Stack is 1 level, its only useful for the higher of the two IRQ levels.

I only save the minimum required to get into/out of the IRQ. Any service routines that use other than the standard stuff are required to save any resources that they use (FSRx registers etc).

Finally, good programming practice would dictate that the IRQ setup be periodically examined by the code to make sure that the setup remains uncorrupted. I say this only because once I set a multi-thousand dollar caloric thermos afire when I inadvertently turned off the PID IRQ and left the heater on overnight.

BTW: consider the 18F4520.. its an upgrade to the 452.

Hope this helps..
 
Last edited:

Thread Starter

raychar

Joined Nov 8, 2011
82
Hello,

Thanks for the reply, knowing that 4520 is better and cheaper than 452 nowadays, however..my old version PIC18 complier doesn't work with it and assembly language is complicated for me.

When two interrupts A, B were assigned in High priority and two C, D were in Low priority. If A and B are triggered at the same time, which one will be serviced first? And how the flow of interrupts then when C and D are triggered at the same time later?

Below link has a good picture of how 8051 interrupt priority works but I didn't find PIC one in its data sheet...

http://what-when-how.com/8051-microcontroller/interrupt-priority-in-the-805152/

Thanks,
 

JohnInTX

Joined Jun 26, 2012
4,787
IRQ sources of the SAME priority must be sorted out by the service routine as all of the possible enabled IRQs are OR'ed together to generate the interrupt (Fig 8.1 in the link ErnieM provided).

In your example, when either or both of C and D interrupt the processor, the service routine at the low-priority address (18h) is executed. From there, its up to you to poll all of the enabled IRQ sources in whatever order you like, service the active ones and manually clear the IF flag(s) associated with them.

The same applies to the high priority IRQs. Once in the service routine, you have to manually poll the possible sources to see which one(s) are active.

Microchip's website has some application notes and other tutorial info that can help guide you.

BTW: depending on your current compiler, you may qualify for a free or low cost upgrade to the new XC-8 compiler available at http://www.microchip.com/pagehandler/en_us/promo/mplabxc/
 
Last edited:

Thread Starter

raychar

Joined Nov 8, 2011
82
Hello,
I have a program which likes as below. I haven't written priorities '0' or '1' for some interrupts, is it correct? Is it correct to write those two; LVD and TMR1 as priority 1 as I would like them to be in High priority area?

If the program runs. The TMR1 interrupts, program goes to HI_ISR() subroutine and start polling downward. No sooner had
it gone to check TMR1F==1 status, that is at the arrow pointed NOP() statement, there was another INT0 interrupt happened. I think the
program would not service INT0. But, in my purpose, it is wanted to be serviced priorer than TMR1. Can the program be amended to do it?

Thanks in advance

/*--------------------------------------------------*/
......
LVDIP=1;
......
......
TMR1IP=1;
......
......
ADIP=0;
......
......
TMR0IP=0;
......

/*--------------------------------------------------*/
void interrupt HI_ISR()
{
if(LVDIF==1)
{
...........
LVDIF=0;
LVDEN=0;
LVDIE=0;
...........
}
if(INT1IF==1)
...........
INT1IF=0;
INT0IE=0;
}
if(INT0IF==1&&INT0IE==1)
{
...........
TMR0ON=1;
...........
INT0IF=0;
}
---> NOP();
if(TMR1IF==1)
{
..........
..........
TMR1IF=0;
}
}
/*--------------------------------------------------*/
void interrupt low_priority LOW_ISR()
{
if(TMR0IF==1)
{
TMR0H=0XFB;
TMR0L=0X1D;
TMR0IF=0;
...........
}
if(ADIF==1)
{
ADIF=0;
AD_Flag=1;
}
}
/*--------------------------------------------------*/
main()
{
......
INTCON=INTCON|0xD2;
INTCON2=INTCON2|0x40;
INTCON3=INTCON3&0x09;
IPEN=1;
INTCON=INTCON|0xC0;
.......
}
 

JohnInTX

Joined Jun 26, 2012
4,787
Once the PIC is interrupted, it disables global interrupts (at the current priority) to prevent any further IRQs of that priority until RETFIE (return and RE-ENABLE interrupts) is executed.

At the NOP, you have already polled INT0IF, presumably found it 0 and have continued on. If INT0IF sets after that, INT0 will NOT be processed until 1) you exit the interrupt service block (where the compiler has put the RETFIE). The PIC will then recognize INT0IF and reenter the ISR block or 2) you re-sample INT0IF before leaving the ISR block and save lots of context switching time.

The main way to ensure fast, top priority handling of INT0 (or any other IRQ) is to make it the sole member of the high priority ISR. Any others will have to fight it out at the lower priority. Multiple high priority services are OK in most cases but will require careful thought to implement.

As a consequence of this, it should be apparent that the service routines need to be as short and fast as possible.

BTW: A good way to improve IRQ service performance is to look at the compiler-generated assembler code and try different equivalent constructs to see if one generates better code than the other for example, in PICC18 8.35PL3:

Rich (BB code):
if(INT0IF==1&&INT0IE==1)
generates way more code than
Rich (BB code):
if(INT0IF==1)
  if(INT0IE==1)
The first does two evaluations, saves a temp variable and does a compare, the second does two btfss instructions.
 
Last edited:

takao21203

Joined Apr 28, 2012
3,702
Interesting enough, interrupt flags also get set when the interrupt as such is not enabled.

This has funny consequences for instance if you enable one int, but still have code for another IF in the int handler.

You can even exploit this for instance you don't have to use interrupt for serial transfer completion, you can simply poll the int flag.

Priorities are first come first serve, if there is another int flag set at the end of int routine, you'll get a problem.

What I normally do is only to clear int flags, and to set a program flag, later I parse all these flags in the main routine.

But, in my purpose, it is wanted to be serviced priorer than TMR1. Can the program be amended to do it?

Yes, if you use secondary flags, and parse them in a way that they are prioritized. If you have for instance one very important interrupt, you can switch off all others within the code that handles the interrupts (in the main routine etc.), but, you leave that one important interrupt on.

So, the interrupt handler only resets the flag, and after that, the top priority interrupt can become handled anytime. For immediate execution maybe put it directly in the interrupt handler.
 

ErnieM

Joined Apr 24, 2011
8,377
If you have a flag get set during the interrupt service routine (ISR) that doesn't get cleared and you return... all that happens is the ISR gets called again and you then have another chance to handle it.

If you don't clear such flags ever you get stuck in the ISR. Note this does not apply to flags that do not generate an interrupt, you can leave those as you may and still exit the ISR.
 
Top