This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Wrong GPTimer1 1ms Tick Generation (with sample code & video)

Other Parts Discussed in Thread: SYSCONFIG

I did setup the GPTimer1 as described in the TRM. However the tick is not 1ms. Can someone tell me what's wrong?
If i follow the values provided by the TRM, the timer is wrong..

SPRUF98M, Page 2579 (Chapter 16.2.4.2)
TPIR = 232000
TNIR = -768000
TLDR = 0xFFFF FFE0

If i increase the TLDR to 0xFFFF FFE2, it's more accurate but a little bit too fast. With 0xFFFF FFE1 it's still a little bit too slow.
But i would like to have a precise timer, not one calibrated with trial & error! What's wrong?

Example Video:
As you can see in this video, the timer drifts away about 4s within two minutes: youtube GPTimer1 demo

GPTimer1 Registers:

Sourcecode:

void TimerInterrupt::initTickTimer(){

 // -------------- GPTIMER1 module intialization --------------
 // enable clock
 volatile OMAP_PRCM_WKUP_CM_REGS* pPrcmWkupRegs = (OMAP_PRCM_WKUP_CM_REGS*)OMAP_PRCM_WKUP_CM_REGS_PA;
 // GPTIMER 1 source clock is 32,768Hz
 CLRREG32(&pPrcmWkupRegs->CM_CLKSEL_WKUP, CLKSEL_GPT1);
 // enable GPTIMER 1 functional clock
 SETREG32(&pPrcmWkupRegs->CM_FCLKEN_WKUP, CM_CLKEN_GPT1);
 // enable GPTIMER 1 interface clock
 SETREG32(&pPrcmWkupRegs->CM_ICLKEN_WKUP, CM_CLKEN_GPT1);
 
 // reset
 // wait until GPTimer is ready to use
 unsigned int totalWaitTimeMs = 0;
 while (INREG32(&pPrcmWkupRegs->CM_IDLEST_WKUP) & CM_IDLEST_ST_GPT1) {
  totalWaitTimeMs++;
 }
 
 // configure timer
 volatile OMAP_GPTIMER_REGS* pTimerReg = (OMAP_GPTIMER_REGS*)OMAP_GPTIMER1_REGS_PA;
 
 // Soft reset GPTIMER and wait until finished
 SETREG32(&pTimerReg->TIOCP, SYSCONFIG_SOFTRESET);
 totalWaitTimeMs = 0;
 while ((INREG32(&pTimerReg->TISTAT) & GPTIMER_TISTAT_RESETDONE) == 0) {
  totalWaitTimeMs++;
 }
 // clear interrupts
 OUTREG32(&pTimerReg->TISR, 0x7);
 // enable overflow interrupt
 OUTREG32(&pTimerReg->TIER, GPTIMER_TIER_OVERFLOW);
 
 // change period to 1ms with correction for 32.768 Hz clock (see 16.2.4.2)
 pTimerReg->TPIR = 232000;
 pTimerReg->TNIR = -768000;
 pTimerReg->TLDR = 0xFFFFFFE0;

}

void TimerInterrupt::enableTickTimerInterrupt() {

 // enable the GPTIMER1 as IRQ source in the interrupt controller
 InterruptController::enableInterrupt(IRQ_GPTIMER1);
 
 // ----------- counter setup -------------
 // Trigger a counter reload by writing to TTGR 
 volatile OMAP_GPTIMER_REGS* pTimerReg = (OMAP_GPTIMER_REGS*)OMAP_GPTIMER1_REGS_PA;
 OUTREG32(&pTimerReg->TTGR, 0xFFFFFFFF);
 
 // Write pending for register GPT_TTGR
 unsigned int totalWaitTimeMs = 0;
 while ((INREG32(&pTimerReg->TWPS) & GPTIMER_TWPS_TTGR) == 1) {
  totalWaitTimeMs++;
 }
 
 // Start the timer, set for auto reload, enable and wait until complete
 OUTREG32(&pTimerReg->TCLR, GPTIMER_TCLR_ST|GPTIMER_TCLR_AR);
 
 // Write pending for register GPT_TCLR
 totalWaitTimeMs = 0;
 while ((INREG32(&pTimerReg->TWPS) & GPTIMER_TWPS_TCLR) == 1) {
  totalWaitTimeMs++;
 }

}

  • I have no explanation at all, but with those values it looks much better (acurate over several minutes):

    pTimerReg->TPIR = 232000;
    (int&)(pTimerReg->TNIR) = -96000;
    pTimerReg->TLDR = 0xFFFFFFE1;

    Does someone have an explanation? I am missing the explanation of TLDR value in the formula on page 2579 in the TRM.