[En-Nut-Discussion] AT91SAM7X256 TC1 Timer being disabled

Timothy M. De Baillie debaillie at ciholas.com
Fri Jul 10 18:12:41 CEST 2009


Coleman Brumley wrote:
> What I'm finding, though, is that after some amount of time (several hours,
> for instance) the TC1 interrupt is being disabled.  If I toggle a PIO pin in
> TC1TimerIntr and the app gets in this state, then the PIO pin is not longer
> being toggled.   I can find no reference to NutIrqDisable for sig_TC1 in the
> code though.  
>
>  
>
> Has anyone else come across this type of scenario?  I'm using Nut/OS v4.6.4.
>   
This is a problem we have seen on many occasions.  The problem lies in 
that Ethernut does not allow re-entrance of IRQs.  If you are to get two 
interrupts on your timer before you are able to handle them, then it 
causes the timer to just stop.

The REAL solution is to rewrite the IRQ_ENTRY and IRQ_EXIT to allow for 
re-entrance of IRQs (and not disable IRQs).

Our temporary solution involves using a wrapping timer instead of a 
resetting timer.  Additionally, if the timer's accuracy is highly 
important, you should check for overflow and handle it (ie: two 
interrupts before handler, should be detectable by amount in TC1_CV)

// CODE

#define COMPARE_ADDER 0xdc8
signed short compare_value = COMPARE_ADDER;

static void RealTimeClock(void *arg){

   local_clock++;

   //you could check for overflow here

   //increase compare value to next interrupt value
   //(signed short allows for overflow wrapping)
   compare_value += COMPARE_ADDER;
   outr(TC1_RC, compare_value);

}

void InitTimer1(void){

   //change the AIC to allow handle of TC1 interrupt
   outr(AIC_IECR, _BV(TC1_ID));

   //enable timer1 clock
   outr(PMC_PCER, _BV(TC1_ID));

   //disable the timer
   outr(TC1_CCR, TC_CLKDIS);

   //disable interrupts on the timer
   outr(TC1_IDR, 0xFFFFFFFF);

   //reading the status register will clear any pending interrupt
   inr(TC1_SR);

   //Select MCK/32, inc on + edge (45.1584MHz/32 = 1.4112MHz)
   outr(TC1_CMR, TC_CLKS_MCK32);

   //set compare value to 2.50ms (.0025 * 1411200) = 3528 (0xdc8)
   outr(TC1_RC, COMPARE_ADDER);

   //enable the timer
   outr(TC1_CCR, TC_CLKEN);

   //enable the rc compare interrupts
   outr(TC1_IER, TC_CPCS);

   //register the interrupt
   NutRegisterIrqHandler(&sig_TC1, RealTimeClock, 0);

   //set to highest priority (7)
   NutIrqSetPriority(&sig_TC1, 7);

   //enable the interrupt
   NutIrqEnable(&sig_TC1);

   //reset the counter and start the clock
   outr(TC1_CCR, TC_SWTRG);

}

//END CODE

Hope this helps,

Tim DeBaillie


More information about the En-Nut-Discussion mailing list