|
|
View previous topic :: View next topic |
Author |
Message |
Zer0flag Guest
|
Interrupt handling |
Posted: Fri Dec 07, 2007 9:47 am |
|
|
Hi all!
After reading the CCS PICC manual I could not find a definitive answer to the following questions:
Let's say I have:
enable_interrupts(INT_TIMER0);
this will activate TIMER0. Then I use:
disable_interrupts(INT_TIMER0);
as far as I understand this will prevent the interrupt from firing but the interrupt flag will still be set if the TIMER0 overflows. Is this correct?
If so when I enter next:
enable_interrupts(INT_TIMER0);
the Timer0 interrupt should fire immediately because the flag is already set. To prevent this I should use:
clear_interrupt(INT_TIMER0);
before reenabling the interrupt. Is this correct?
Thanks for any help!
Regards,
Zer0flag |
|
|
Ken Johnson
Joined: 23 Mar 2006 Posts: 197 Location: Lewisburg, WV
|
|
Posted: Fri Dec 07, 2007 10:13 am |
|
|
I believe you are correct, except for the possible meaning of this phrase:
Quote: |
enable_interrupts(INT_TIMER0);
this will activate TIMER0.
|
You also need setup_timer0() to *activate* timer0, before it can overflow and cause an interrupt when enabled (also enable global interrupts).
Ken |
|
|
Zer0flag Guest
|
|
Posted: Fri Dec 07, 2007 10:47 am |
|
|
Thank you for your comment. You are correct. I'm sorry, I wanted to say: "will enable the Timer0 interrupt".
Ken Johnson wrote: | I believe you are correct, except for the possible meaning of this phrase:
Quote: |
enable_interrupts(INT_TIMER0);
this will activate TIMER0.
|
You also need setup_timer0() to *activate* timer0, before it can overflow and cause an interrupt when enabled (also enable global interrupts).
Ken |
|
|
|
rnielsen
Joined: 23 Sep 2003 Posts: 852 Location: Utah
|
|
Posted: Fri Dec 07, 2007 11:06 am |
|
|
Actually, you really don't need the setup_timer0() statement to enable the timer. If I read the spec. sheet properly for the 18FXX2 PIC's the MCU resets with 0xFF in T0CON which will turn on the timer. Setup_timer0() is used to configure things the way you want them to be. As long as you enable the interrupts, the timer will, most likely, run at a default configuration.
Now, as far as needing to clear the interrupt before you enable it, on many PIC's it is possible to turn on/off the timer which will keep the interrupt flag from being set. I have used this in many applications. This can be used to conserve power, keep the timer from using unnesessary cpu time or many other uses.
Now, I'm not sure about this but if you use the clear_interrupt() command the interrupt is cleared but I believe the register will still have whatever value it has incremented to which could fire the interrupt right after it is cleared, if the register is close to turning over. This could cause you unexpected headaches if you don't clean things up so this doesn't happen.
Ronald |
|
|
Zer0flag Guest
|
|
Posted: Fri Dec 07, 2007 3:28 pm |
|
|
rnielsen wrote: |
Now, as far as needing to clear the interrupt before you enable it, on many PIC's it is possible to turn on/off the timer which will keep the interrupt flag from being set. I have used this in many applications. This can be used to conserve power, keep the timer from using unnesessary cpu time or many other uses.
|
You mean you can stop the timer from incrementing? How do you do that? Is there any CCS function for that or is it only possible through direct register manipulation?
Quote: |
Now, I'm not sure about this but if you use the clear_interrupt() command the interrupt is cleared but I believe the register will still have whatever value it has incremented to which could fire the interrupt right after it is cleared, if the register is close to turning over. This could cause you unexpected headaches if you don't clean things up so this doesn't happen.
Ronald |
You are right, from my experience a timer keeps running and overflowing, running and overflowing forever, even if interrupts are disabled. But to keep things right I would just use set_timer0(0); before reenabling the interrupt. This way I make sure that the interrupt starts incrementing from 0 and then I would enable interrupts.
Some more info on my problem: All I want for my application is to make sure that I won't miss any timer interrupts if I disable them for a short time and then reenable them. This will probably work ok if the interrupt flag is set on timer overflow even when interrupts are disabled at that time - that way the ISR just won't execute until I reenable the timer interrupt but then it will execute immediately if I understand things right. I am doing this because when I am manipulating non-atomic variables of 16 bit or 32 bit in my main() function I have to make sure that a timer ISRs won't interrupt this manipulation in the middle of the assembler instructions. I have to make sure that this does not happen because I evaluate these variables in the ISR later. Some books are discribing this as "the data-sharing problem" between main code and ISRs. Unfortunately I could not find much PIC-specific info on that topic :( |
|
|
Ken Johnson
Joined: 23 Mar 2006 Posts: 197 Location: Lewisburg, WV
|
|
Posted: Sat Dec 08, 2007 10:03 am |
|
|
You are correct again - disable interrupts when manipulating non-atomic variables shared by an isr.
I usually (but not always) disable ALL interrupts (global) when doing this. If you disable only timer0 interrupts, but several other interrupts could occur, you can end up with timer0 interrupt disabled longer than just the time to copy the non-atomic variables - this may not be important, but think about it.
Note also that I said "copy" the non-atomic variable. For example, if timer0 increments a 16- or 32-bit counter, don't use the counter itself in your main-loop code. Rather, make a copy of it first (disable ints, copy, enable ints), then use the copy. The copy operation is pretty quick, whereas add/compare or other operations probably take longer.
You're on the right track - go for it
Ken |
|
|
Zer0flag Guest
|
|
Posted: Mon Dec 10, 2007 3:53 am |
|
|
Many thanks for the hints Ken! |
|
|
Ttelmah Guest
|
|
Posted: Mon Dec 10, 2007 4:13 am |
|
|
Ken's aproach is the best one.
Copying a value, takes just a few instructions. Disabling the global interrupt, prevents the interrupt handler(s) from being called, but the flags will in either case, still be set. So as soon as you re-enable the interrupts, any events that have happened in the meantime, will be responded to.
There is a caveat though. If (for instance), you disable the interrupt inside a routine, which is itself called from another routine, which has already disabled interrupts, and then you re-enable the interrupts, you can end up enabling the interrupts, when you really want them still disabled. This is why in some of the example code, and some of the internal CCS code, you will find routtines like:
Code: |
#bit GIE= (set this to suit the processor involved)
int1 ints_were_on=FALSE;
while (GIE) {
ints_were_on=TRUE
disable_interrupts(GLOBAL);
} //This as written, also handles an erratum, on some chips.
//Copy the values here
if (ints_were_on) enable_interrupts(GLOBAL);
|
This only disables the interrupts, and re-enables them after the code, if they were enabled in the first place, and also handles the erratum, where if an interrupt occurs inside the disable instruction itself, the interrupt can get turned back on...
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
|