AnsweredAssumed Answered

KL46z: PIT carry-over issues

Question asked by Christoph Berger on Jul 30, 2019
Latest reply on Aug 1, 2019 by Christoph Berger

Hi there,

 

I'm developing a sensor software based on the NXP FRDM-KL46Z evaluation kit. We are using the PIT as lifetime timer to keep track of timings. Thus, it is implemented as chained 64-bit counter as described in the reference manual. Everything works fine so far, expect on very rare occasions, it comes to some carry-over issues. The reference manual says:

 

"To use LTMR64H and LTMR64L, timer 0 and timer 1 need to be chained. To obtain the correct value, first read LTMR64H and then LTMR64L. LTMR64H will have the value of CVAL1 at the time of the first access, LTMR64L will have the value of CVAL0 at the time of the first access, therefore the application does not need to worry about carry-over effects of the running counter."

 

However, this seems not to be very reliable or I have overseen something.

 

This is the initialization code:

 

/************************************************
*** Initialize the PIT as lifetime counter. ***
************************************************/

/* Un-gate pit clock*/
CLOCK_EnableClock(kCLOCK_Pit0);

/* Enable PIT module clock*/
PIT->MCR &= ~PIT_MCR_MDIS_MASK;

/* Set timer to stop in debug mode*/
PIT->MCR |= PIT_MCR_FRZ_MASK;

/* Check the pit source clock frequency.
* PIT_Freq = 24000000 */

while(PIT_Freq != CLOCK_GetFreq(kCLOCK_BusClk)) assert(0);

// Initialize PIT timer instance for channel 0 and 1
PIT->CHANNEL[1].TCTRL |= PIT_TCTRL_CHN_MASK; // Set chain mode
PIT->CHANNEL[1].LDVAL = 0xffffffff; // Timer 1 counts sec
PIT->CHANNEL[0].LDVAL = (PIT_Freq - 1U); // Timer 0 counts us/24

// Start timer channels
PIT->CHANNEL[1].TCTRL |= PIT_TCTRL_TEN_MASK;
PIT->CHANNEL[0].TCTRL |= PIT_TCTRL_TEN_MASK;

 

And this is the code that fails randomly (debug code is added to catch the error):

void Timer_GetCounterValue(uint32_t * hct, uint32_t * lct)
{
  /* Debug variables to catch the error */
  static uint32_t LTMR64H2 = 0, LTMR64L2 = 0;


  /* Timer readout */
  __disable_irq();
  uint32_t LTMR64H = PIT->LTMR64H;
  uint32_t LTMR64L = PIT->LTMR64L;
  __enable_irq();

  /* Debug test */
  if(!((LTMR64H2 == 0) || ((LTMR64H == LTMR64H2) && (LTMR64L < LTMR64L2)) || (LTMR64H < LTMR64H2)))
  {
     BREAKPOINT();
  }

  *hct = ~(LTMR64H);
  *lct = ((PIT_Freq - 1U) - LTMR64L) / 24;

  LTMR64H2 = LTMR64H;
  LTMR64L2 = LTMR64L;
}

 

When the breakpoint hits, the state of the values is like this:

 

LTMR64H   = 4294964622    
LTMR64H2 = 4294964622    
LTMR64L    = 23999999    
LTMR64L2  = 1128    
Seems like the LTMR64L has already wrapped over to the reload value 23999999 but the LTMR64H has not been decreased yet.
Any help on the issue would be highly appreciated! Thanks in advance!

Outcomes