CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

timer2 problems on pic 18f66j15

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
zilog



Joined: 17 Aug 2007
Posts: 19

View user's profile Send private message

timer2 problems on pic 18f66j15
PostPosted: Thu Aug 23, 2007 3:17 am     Reply with quote

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







PostPosted: Thu Aug 23, 2007 5:58 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Aug 23, 2007 6:11 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Aug 23, 2007 6:17 am     Reply with quote

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







PostPosted: Thu Aug 23, 2007 8:37 am     Reply with quote

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







PostPosted: Thu Aug 23, 2007 8:50 am     Reply with quote

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
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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