Interrupts
Interrupts can be easily handled by means of reserved words interrupt
and iv
. mikroC PRO for PIC implictly declares function interrupt
which cannot be redeclared. Its prototype is:
void interrupt(void);
For P18 low priorty interrupts reserved word is interrupt_low
:
void interrupt_low(void);
You are expected to write your own definition (function body) to handle interrupts in your application.
mikroC PRO for PIC saves the following SFR on stack when entering interrupt and pops them back upon return:
- PIC12 family:
W
,STATUS
,FSR
,PCLATH
- PIC16 family:
W
,STATUS
,FSR
,PCLATH
- PIC18 family:
FSR
(fast context is used to saveWREG
,STATUS
,BSR
)
Disable Context Saving
Use the #pragma disablecontextsaving
to instruct the compiler not to automatically perform context-switching.
This means that no register will be saved/restored by the compiler on entrance/exit from interrupt service routine, except STATUS, WREG and BSR registers in high priority interrupt ('Fast Register Stack').
This exception can be overridden by placing an asm RETFIE 0
instruction at the end of the high priority interrupt routine (with redirecting all routine exits to this instruction).
Thus, #pragma disablecontextsaving
pragma enables the user to manually write code for saving registers upon entrance and to restore them before exit from interrupt.
P18 priority interrupts
- function with name
interrupt
will be linked as ISR (interrupt service routine) for high level interrupt - function with name
interrupt_low
will be linked as ISR for low level interrupt_low
If interrupt priority feature is to be used then the user should set the appropriate SFR bits to enable it. For more information refer to datasheet for specific device.
Function Calls from Interrupt
Calling functions from within the interrupt() routine is now possible. The compiler takes care about the registers being used, both in "interrupt" and in "main" thread, and performs "smart" context-switching between the two, saving only the registers that have been used in both threads.Check functions reentrancy.
Interrupt Handling
For the sake of interrupt handling convenience, new keywords, iv
and ics
, are introduced :
void Timer0_Interrupt() iv 0x000008 ics ICS_OFF { counter++; TMR0 = 96; INTCON = 0x20; }
where :
iv
- reserved word that inform the compiler that it is an interrupt service routine.ics
- Interrupt Context Saving; Interrupt Context Saving can be performed in several ways :ICS_OFF
- No context savingICS_AUTO
- Compiler chooses whether the context saving will be perfomed or not.
As you can see, any valid routine name can be used as a interrupt routine name.
Bear in mind that appropriate interrupt vector address must be used (high priority interrupt vector is at 0x000008, while the low priority interrupt vector is at 0x000018) because in any other case compiler will report an error.
User can explicitly declare starting interrupt routine address using org
directive :
void Timer0_Interrupt() org 0x600 iv 0x000008 { counter++; TMR0 = 96; INTCON = 0x20; }
In this way, the user can allocate the interrupt routine by its discretion, except for P16 family, where the interrupt routine must be allocated in the first bank.
Interrupt Examples
Here is a simple example of handling the interrupts from TMR0
(if no other interrupts are allowed):
void interrupt() { counter++; TMR0 = 96; INTCON = 0x20; }
In case of multiple interrupts enabled, you need to test which of the interrupts occurred and then proceed with the appropriate code (interrupt handling):
void interrupt() { if (INTCON.TMR0IF) { counter++; TMR0 = 96; INTCON.TMR0IF = 0; } else if (INTCON.RBIF) { counter++; TMR0 = 96; INTCON.RBIF = 0; } }
What do you think about this topic ? Send us feedback!