|
|
View previous topic :: View next topic |
Author |
Message |
zilog
Joined: 17 Aug 2007 Posts: 19
|
timer2 problems on pic 18f66j15 |
Posted: Thu Aug 23, 2007 3:17 am |
|
|
My system has a PIC18F66J15 running 4x10MHz, using CCS v4.050, and getting clocked by external negative edges on EXT3 with a frequency of 16.7Hz. PIN_E0 is connected in parallell with EXT3 to enable polling of the signal level. When the (stable) edges come in, I set timer2 to 100us, and wait for the interrupt to occur. INT_EXT3 is the only high priority interrupt currently active in my system. In #INT_EXT3 I set PIN_D1 high, and in #INT_TIMER2 I set it low. The problem is that I observe jitter on this timer - mostly the pulsewidth on PIN_D1 is ~120us, but every 5-6 cycles it triggers after only 20us - what kind of problem am I experiencing here? This is the only place I access TIMER2.
Code: |
//init timer2
setup_timer_2(T2_DIV_BY_16, 0, 1);
//setup current sense interrupt
ext_int_edge(3, H_TO_L);
|
Code: |
#INT_EXT3 high noclear
void ChainHighCurrentIsr(void)
{
#ifdef DEBUG_ISR
ScopeDebugViaAD(3);
#endif
Chain_INTEXT3_Counter++;
if (!input(PIN_E0)) { //cheap form of debounce
disable_interrupts(INT_EXT3);
clear_interrupt(INT_EXT3);
// if (!dostoptrigger) {
output_high(PIN_D1);
// }
output_high(PIN_D2);
Chain_TXPos = 0;
Chain_RXPos = 0;
output_low(PIN_G0); //output current = low
//Now we can be here because of transmission start or the emergency stop button
Chain_STOPCnt = 5;
Chain_STOPCntGo = TRUE;
Chain_RXTXCurrStarvationCnt = 30;
Chain_RXTXCurrStarvationCntGo = TRUE;
Chain_EnableCurrHigh_WhenTRMT = FALSE;
output_low(PIN_D2);
set_timer2((unsigned int8)(-63)); //100us
clear_interrupt(INT_TIMER2);
enable_interrupts(INT_TIMER2);
//output_low(PIN_D2);
} else if (Chain_INTEXT3_Counter > 3) {
Chain_INTEXT3_Counter = 0;
clear_interrupt(INT_EXT3);
}
#ifdef DEBUG_ISR
ScopeDebugViaAD(0);
#endif
}
|
Code: |
#INT_TIMER2 //high //one shot
void ChainFastTimerIsr(void)
{
#ifdef DEBUG_ISR
ScopeDebugViaAD(2);
#endif
Chain_FUCalculateByRX = FALSE;
CREN2 = 1; //enable RX2
clear_interrupt(INT_RDA2);
enable_interrupts(INT_RDA2);
disable_interrupts(INT_TIMER2);
// if (!dostoptrigger) {
output_low(PIN_D1);
// }
#ifdef DEBUG_ISR
ScopeDebugViaAD(0);
#endif
}
|
There is of course a lot of other code handling this state machine as well, INT_EXT3 will be ready to trigger upon each incoming negative edge. |
|
|
Ttelmah Guest
|
|
Posted: Thu Aug 23, 2007 5:58 am |
|
|
First comment. Your 'cheap form of debouce', is actually quite 'expensive'. The system will loop through restoring all the registers, and then because the interrupt is still set, retrigger, save all the registers again, and try again. Though I don't like delays in interrupts, you might as well just use one, and could then leave the handler clearing the interrupt itself.
What is happening, may be to do with the way timers update. In the past, Microchip, did publish data giving 'where' in the clock cycle transfers take place, and where interrupts etc., could be triggered. Often these are done on #1 of the following processor instruction clock. This implies that (for example), if the timer just happens to trigger an interrupt, it can be updated in the instruction 'after' the counter being set. Now they have stopped giving this data now, but the behaviour suggests this is what is happening.... :-(
I'd suggest trying the following change:
Code: |
set_timer2((unsigned int8)(-63)); //100us
enable_interrupts(INT_TIMER2);
clear_interrupt(INT_TIMER2);
|
Seems 'daft', and in normal use this would bring the possibility of the interrut being called uneccessarily, but since we are inside an interrupt handler, this won't happen, and the extra instruction ensures that if there was a 'late' trigger as the registers were updated, this won't give the spurious behaviour.
There is no need to daisy chain the signal to E0. You can simply read the pin being used to trigger the interrupt. It is still useable as an input, when the interrupt is enabled. Saves a pin.
Best Wishes |
|
|
zilog
Joined: 17 Aug 2007 Posts: 19
|
|
Posted: Thu Aug 23, 2007 6:11 am |
|
|
Ttelmah wrote: |
There is no need to daisy chain the signal to E0. You can simply read the pin being used to trigger the interrupt. It is still useable as an input, when the interrupt is enabled. Saves a pin.
Best Wishes |
Yes there is, we use INT_RB to read a quadrature encoder, and reading port b outside of that ISR will give us erroneous results. |
|
|
zilog
Joined: 17 Aug 2007 Posts: 19
|
|
Posted: Thu Aug 23, 2007 6:17 am |
|
|
Ttelmah wrote: |
What is happening, may be to do with the way timers update. In the past, Microchip, did publish data giving 'where' in the clock cycle transfers take place, and where interrupts etc., could be triggered. Often these are done on #1 of the following processor instruction clock. This implies that (for example), if the timer just happens to trigger an interrupt, it can be updated in the instruction 'after' the counter being set. Now they have stopped giving this data now, but the behaviour suggests this is what is happening.... :-(
I'd suggest trying the following change:
Code: |
set_timer2((unsigned int8)(-63)); //100us
enable_interrupts(INT_TIMER2);
clear_interrupt(INT_TIMER2);
|
Seems 'daft', and in normal use this would bring the possibility of the interrut being called uneccessarily, but since we are inside an interrupt handler, this won't happen, and the extra instruction ensures that if there was a 'late' trigger as the registers were updated, this won't give the spurious behaviour.
|
Thanks, this actually solved the problem- unbelievable.. |
|
|
Ttelmah Guest
|
|
Posted: Thu Aug 23, 2007 8:37 am |
|
|
zilog wrote: | Ttelmah wrote: |
There is no need to daisy chain the signal to E0. You can simply read the pin being used to trigger the interrupt. It is still useable as an input, when the interrupt is enabled. Saves a pin.
Best Wishes |
Yes there is, we use INT_RB to read a quadrature encoder, and reading port b outside of that ISR will give us erroneous results. |
True, but you say you are only using INT_EXT3, and the timer, in your other posts about your problems. If you are adding a quadrature routine, this is another subject.
Best Wishes |
|
|
Ttelmah Guest
|
|
Posted: Thu Aug 23, 2007 8:50 am |
|
|
zilog wrote: | Ttelmah wrote: |
What is happening, may be to do with the way timers update. In the past, Microchip, did publish data giving 'where' in the clock cycle transfers take place, and where interrupts etc., could be triggered. Often these are done on #1 of the following processor instruction clock. This implies that (for example), if the timer just happens to trigger an interrupt, it can be updated in the instruction 'after' the counter being set. Now they have stopped giving this data now, but the behaviour suggests this is what is happening.... :-(
I'd suggest trying the following change:
Code: |
set_timer2((unsigned int8)(-63)); //100us
enable_interrupts(INT_TIMER2);
clear_interrupt(INT_TIMER2);
|
Seems 'daft', and in normal use this would bring the possibility of the interrut being called uneccessarily, but since we are inside an interrupt handler, this won't happen, and the extra instruction ensures that if there was a 'late' trigger as the registers were updated, this won't give the spurious behaviour.
|
Thanks, this actually solved the problem- unbelievable.. |
Not 'unbelievable'. The problem is that the processor itself, is a state machine, driven by sub cycles of the external clock. Things don't just happen all at once. A lot is going on 'under the hood'. Generally, the exact timing doesn't matter, but it can show up in some things. You should find that:
Code: |
set_timer2((unsigned int8)(-63)); //100us
delay_cycles(1);
clear_interrupt(INT_TIMER2);
enable_interrupts(INT_TIMER2);
|
Will also fix the problem.
What is happening, is that the transfer of the new value to timer2, takes time. It occurs actually during the next instruction. The 'clear_interrupt' operation, has the behaviour that it won't clear the interrupt, if an interrupt occurs 'in' the instruction itself (this is documented in some chips data sheets). So, if the timer just happens to interrupt, before the value loads, the clear_interrupt instruction won't work, and you get an immediate timer interrupt, as soon as you exit the high priority routine. Reversing the operation order, saves one instruction to get round this.
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
|