Inaccurate timing with 16 bit timer

キャンセル
次の結果を表示 
表示  限定  | 次の代わりに検索 
もしかして: 

Inaccurate timing with 16 bit timer

1,069件の閲覧回数
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 件の賞賛
返信
4 返答(返信)

1,048件の閲覧回数
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 件の賞賛
返信

1,048件の閲覧回数
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 件の賞賛
返信

1,048件の閲覧回数
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 件の賞賛
返信

1,048件の閲覧回数
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 件の賞賛
返信