Inaccurate timing with 16 bit timer

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Inaccurate timing with 16 bit timer

1,070 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by nelmak on Thu Apr 19 11:28:33 MST 2012
Hey guys,

I am trying to time intervals between the peaks of pulses using the LPC 1227. I input a 1Hz pulse train into the LPC1227 GPIO and make it count the interval in between the peaks in milliseconds. However, I consistently get a reading of ~900 ms which is actually 1.11Hz. When I increase the frequency, the error actually becomes really large. I am using the 16 bit timer. Below is my code

    init_timer16(1);
    enable_timer16();
    LPC_SYSCON->SYSAHBCLKCTRL |= 0x8001001FUL;

    ADCInit(8000000);
    while(1) {
        adcval = ADCRead(0);
        if ((oldadcval > 800) && (adcval < 800))
        {
            disable_timer16();
            printf("New = %d, Old = %d, %d ms\n", adcval, oldadcval, counter);
            counter = 0;
            enable_timer16();
        }

        oldadcval = adcval;
    }
    return 0 ;
}

//Enable Timer
void enable_timer16(void)
{
      LPC_CT16B0->TCR = 1;
//      printf("Timer enabled\n");
      return;
}

void init_timer16(uint32_t delay)
{
    LPC_SYSCON->PRESETCTRL |= (0x1<<4);     //De-assert Reset
    LPC_SYSCON->SYSAHBCLKCTRL |= (0x1<<7);    //Enable clock for CT16B0
    LPC_CT16B0->PR  = 0x00;        /* set prescaler to zero */
    LPC_CT16B0->MR[0] = delay * (SystemCoreClock / 1000 - 1);
    LPC_CT16B0->IR  = 0xff;        /* reset all interrrupts */
    LPC_CT16B0->MCR = (0x3<<0);                //Interrupt and reset on MR0
    NVIC_EnableIRQ(13);                        //Enable timer0_16 interrupt
    counter = 0;
    printf("Timer initialized\n");

}

//Disable timer
void disable_timer16(void)
{
//      printf("Timer Disabled");
      LPC_CT16B0->TCR = 0;
      return;
}

void reset_timer16()
{
    LPC_CT16B0->TC = 0;
    counter = 0;
}

void TIMER16_0_IRQHandler()
{
      if ( LPC_CT16B0->IR & (0x1<<0) )
      {
        LPC_CT16B0->IR = 0x1<<0;            /* clear interrupt flag */
        counter++;                    //increment counter
      }
}

Can I get some feedback on my code and if I am making any mistakes to cause this error? Or would I need a faster processor to get more accurate timing?

Thanks in advance
0 Kudos
Reply
4 Replies

1,049 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by nelmak on Thu Apr 19 12:48:39 MST 2012
Yeah you are right. The printf has a lot of overhead. Approximately 100ms of overhead which is exactly what I am missing.

When I add another printf into the line, it increases the error by 100ms. Thanks guys.
0 Kudos
Reply

1,049 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Ex-Zero on Thu Apr 19 12:36:08 MST 2012
Or just store your values in a nice array :eek: and print them after 100? samples with a few additional statistical calculations :)
0 Kudos
Reply

1,049 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by frame on Thu Apr 19 12:10:45 MST 2012
That's correct. Your method is rather inaccurate. You call the [FONT=Courier New]printf[/FONT]() function synchronously, i.e. the time in this function adds directly to your next interval.
And, the timer precision is just secondary. The defining element is the ADC peak detection.

You need to decouple the peak detection from the output code, and I suggest to put the ADC reading in an interrupt routine.

This is a totally different design pattern than your linear code, but much more common in embedded systems.
0 Kudos
Reply

1,049 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by gbm on Thu Apr 19 11:40:13 MST 2012
I guess the problem lies in printf routines - semihotsing is quite slow. Try to display the results via UART and use simple conversion routines instead of printf, which may be quire robust and slow.
0 Kudos
Reply