|
|
View previous topic :: View next topic |
Author |
Message |
Lykos1986
Joined: 26 Nov 2005 Posts: 68
|
Interrupts Handling |
Posted: Thu Sep 27, 2012 7:41 am |
|
|
Hello! I have a question about how CCS handles interrupts.
I know that CCS automatically adds in the interrupt service routine the "disable_interrupt" at the beginning and "enable_interrupt" an the end of the routine (correct me if I am wrong). But what happens if I have multiple interrupt sources?
For example lets assume that I am having Timer0, and RB0 interrupts enabled. At an X period of time the RB0 interrupt service routine is executed due to an external event. In this service routine the RB0 interrupt is disabled by CCS and enabled again at the end of the routine. But what is happening with Timer0 interrupts? Those are disabled as well until the end of the RB0 interrupt service routine finish or are enabled by default (and in a case of Timer0 overflow the instruction pointer will go immediately at the Timer0 interrupt service routine no matter if the RB0 service routine is finished or not)? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Thu Sep 27, 2012 8:10 am |
|
|
No. CCS does not disable the interrupts.
The PIC _hardware_ disables the interrupts.
The PIC, does not have a 'variable stack'. As such therefore functions cannot have multiple copies of local variables, so cannot be called inside themselves, without variables being corrupted. Calling functions from themselves is called 'recursion'. While most processors support this, the PIC does not.
There is only one main interrupt handler, which calls the separate interrupt routines. Since this can't be called inside itself, interrupts can't be called from inside other interrupts.
So the PIC _hardware_ automatically disables interrupts when the interrupt handler is called. To ensure that the handler cannot be called while you are inside the handler. So that the interrupt won't be re-enabled while you are still in the routine, there is a special 'return' instruction called 'RETFIE' (return from interrupt enable), which enables the interrupts immediately _after_ it returns. This is used at the end of the interrupt code.
It is _all_ interrupts that are disabled, not just a specific one. Remember though that the interrupt flag will be set on the event, so in the case you describe, the timer0 flag will be set while you are in the INT_RB routine, and it's routine will be called as soon as you return from this. Hence provided interrupt routines are kept _short_ there is not normally any problem.
_If_ you are using a PIC18, this allows two separate handlers to be generated using "#device HIGH_INTS=TRUE" When this is done, interrupts can be allocated to use one handler or the second, by defining it with "#INT_TIMER0 HIGH" for example, which then allocates this interrupt to the _second_ handler. Since two handlers are then used, such an interrupt can then interrupt another interrupt without recursion.
In your case, you could use #INT_TIMER0 HIGH to allow timer0 to interrupt INT_RB.
_But_ INT_EXT, has no such setting, and will _always_ be allocated to the second handler if used, so nothing can ever interrupt this. A 'caveat' with this interrupt.
Best Wishes |
|
|
Lykos1986
Joined: 26 Nov 2005 Posts: 68
|
|
Posted: Thu Sep 27, 2012 1:31 pm |
|
|
A perfect reply! Thank you very much! It seems that I have to change my code a little bit in order to have the function I want! |
|
|
Douglas Kennedy
Joined: 07 Sep 2003 Posts: 755 Location: Florida
|
|
Posted: Thu Sep 27, 2012 6:45 pm |
|
|
Ok,
So a 18Fxxx will permit a high priority interrupt to break into say an already called and processing isr linked to a lower priority interrupt. Then when the higher priority isr is done control transfers to the lower priority isr and presuming no other higher priority interrupt is called the lower level priority isr completes. The value is presumably that if the lower priority isr chews up cycles to the extent some other time critical event would be blocked; then placing the time critical event in a high priority isr saves the day.
If I have this wrong maybe Ttelmah can comment. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Fri Sep 28, 2012 1:07 am |
|
|
No, that is perfectly correct.
However (as with most things PIC), there are caveats....
First, as already mentioned INT_EXT does not have a priority bit, and is always high priority.
As soon as you have more than one 'HIGH' ISR, you get the problem back. This can happen 'unexpectedly', because of the INT_EXT restriction. So if you use this interrupt, you can find your 'time critical' interrupt still being blocked by this one. That this is automatically 'HIGH', is handled silently by the compiler, so you have to be aware of this.
Then the processor has a single 'fast return' set of registers, allowing three things to be rapidly saved/restored (W, BSR, and the status). If two sets of handlers are used, these are allocated to the 'HIGH' routine, meaning that normal interrupts will actually be handled slightly slower (typically about 8 clock cycles extra overhead) .
Then obviously extra RAM used to save all the registers, and extra program space for the two handlers.
It still takes typically about 30 machine instructions to get into the 'HIGH' routines, so response is by no means super fast.
Worth also adding an understanding of the 'priority' directive.
The main ISR handlers scan to find which interrupt has triggered (and therefore give 'priority' to the ones checked first), in the order the interrupt handlers are declared in the code, _or_ the order in the #priority statement, if one is present.
It goes back to the old "keeping the ISR's quick" being really the best solution, but can be very useful for a single time critical interrupt.
Best Wishes |
|
|
|
|
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
|