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.

TM4C123GH6PGE: TimerValueGet() using input capture mode is not accurate with OS task delay.

Part Number: TM4C123GH6PGE

Hi,

I'm working on a TM4C123GH launchpad with FreeRTOS.

I have a square wave input into PC7 at between 50 Hz and 400 Hz. I have configured my timer count down, capture the timer at each rising edge per the code below:

/* Enable the Timer
	 * Note that the GP Timer module clock must be enabled before the registers can be programmed
	 * (see page 338 or page 357). There must be a delay of 3 system clocks after the Timer module clock
	 * is enabled before any Timer module registers are accessed.
	 */
	MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_WTIMER1);

	// Set the IO pin to be an input for wide timer
	// Use PC7 which is input 8, which is an ODD input (i.e. TIMER B)
	GPIOPinConfigure(GPIO_PC7_WT1CCP1);
	MAP_GPIOPinTypeTimer(GPIO_PORTC_BASE, GPIO_PIN_7);

	// Configure the timer
	// Capture the time value at each event edge
	MAP_TimerConfigure(WTIMER1_BASE, (TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PERIODIC | TIMER_CFG_B_CAP_TIME));

	// Count on Positive Edges
	MAP_TimerControlEvent(WTIMER1_BASE, TIMER_B, TIMER_EVENT_POS_EDGE);

	// The timer starts at 0xFFFFFFFF and counts down.
	MAP_TimerLoadSet(WTIMER1_BASE, TIMER_B, 0x00FFFFFF);
	MAP_TimerMatchSet(WTIMER1_BASE, TIMER_B, 0x00FFFFFE);

	// Configure the prescaler
	// Note: I can not see when this is operating in our split timer mode
	MAP_TimerPrescaleSet(WTIMER1_BASE, TIMER_B, 0xFF);
	MAP_TimerPrescaleMatchSet(WTIMER1_BASE, TIMER_B, 0xFE);

	// Configure the update mode
	TimerUpdateMode(WTIMER1_BASE, TIMER_B, TIMER_UP_LOAD_IMMEDIATE);

	// Clear the interrupt for TIMER_B capture event
	MAP_TimerIntClear(WTIMER1_BASE, TIMER_CAPB_EVENT);

	// Start the timer
	MAP_TimerEnable(WTIMER1_BASE, TIMER_B);

I also have a main task where I check if a capture event has occurred, read the timer, and compute the difference, per below:

while(1)
	{

		// Check if we have status
		/* Poll the CnERIS bit in the GPTMRIS register or wait for the interrupt to be generated (if enabled).
		 * In both cases, the status flags are cleared by writing a 1 to the CnECINT bit of the GPTM
		 * Interrupt Clear (GPTMICR) register. The time at which the event happened can be obtained
		 * by reading the GPTM Timer n (GPTMTnR) register.
		 */
		u32Status = MAP_TimerIntStatus(WTIMER1_BASE, 0);
		if((u32Status & TIMER_CAPB_EVENT) == TIMER_CAPB_EVENT)
		{
			// Count of timer ticks between pulses
			m_u32RawCount = (Luint32)TimerValueGet(WTIMER1_BASE, TIMER_B);

			// As we are counting down do the difference
			// It may be that the variant of the CPU we use does not have an up-counter function?
			u32Diff = (0xFFFFFFFF - m_u32RawCount);

			// Work out the difference
			m_u32TimerCount = u32Diff - u32TempPrev;

			// Save the prev value
			u32TempPrev = u32Diff;

			// Clear the flag again for next time
			MAP_TimerIntClear(WTIMER1_BASE, TIMER_CAPB_EVENT);

		}

		vTaskDelay(pdMS_TO_TICKS(1));
	}

We notice that if the frequency is 50 Hz, the timer value is always reasonable, however once we start going above 100 Hz, any change to the OS task delay value (say from 1ms to 10ms) affects the value we read from the timer. This effect is semi random, however the timer value seems to alternate between the correct value and about 1/2 of the expected value.

My understanding is the capture event occurs and the value of the free running timer is transferred into the timer value register, which we then read at some point in the future.

Can anyone speculate why the speed at which we call TimerValueGet() affects the accuracy of the timer value?

Thanks.

  • At 100Hz, there is an event every 10ms. If you stop looking for 10ms, it's quite possible that two events will happen in that time, and you'll miss the first one; in this case the arithmetic will indicate a period twice as long (half the speed).

    I suggest an ISR which feeds a Queue. That way you don't have to guess how often to poll.

  • Hi,

    In writing this I think I see the logic there, if I miss one timer event, the difference between the previous event and the next event I sample will be twice the time.

    Thanks.!