cancel
Showing results for 
Search instead for 
Did you mean: 

Timer input capture multiple overflows happens sometimes

Photek
Associate II

Hi all.

I'm currently have the encoders from a motor connected to a timer block and I'm simply measuring the period for one of the pulses to determine the frequency.

On the first rising edge of the pulse, I set the counter (CNT register) to 0 and then enable the counter overflow interrupt enable flat.

 

On the next rising edge, I capture the counter value and add this to the amount of overflows which have happen. 

 

All is well and I can confirmed the period is exactly as I expect as I've measuring this using my logic analyser (saleae logic analyzed)

 

However the problem:

 

I'm printing out the period of the motor encoder timings over the USB serial port and I'm logging the readings to a CSV file. I've capturing around 10k samples using different PWM values. I'm plotting the results, where the x axis is the time which a period was captured and the y axis is the time of the motor encoder period (usually around 1.2ms period, assuming 100% PWM)

 

However, I noticed out of the 10k+ samples, I come across peaks in my data, where the periods are around 1.2ms and all of a sudden I might get a peak, where the period is around 10ms! My logic analyser shows none of the pulses are never 10ms.

 

I've dumped the registers for every motor encover capture and I noticed when the massive peak occurs, there are around 5-7 overflows which have happened between when I reset the counter to zero and on the next rising edge.

My code is simply polling the interrupt registers and I've confirmed the same issue happens even if I decode my pulses using interrupt handlers.

 

I'll post my code tomorrow and some screenshot to fully explain the situation but I cannot figure why in some cases, I get these multiple overflows?

It's as if there could be a situation where I have a rising edge from the motor encoder which allows me to set the CNT register to 0 and for some reason, I'm missing a load of rising edges (voltage too low) and then I get a valid pulse. However my logic analyser doesn't show any pulses being missed.

 

6 REPLIES 6
TDK
Super User

Likely the USB or something else is running which prevents your polling loop from catching the flag in time. Toggle a pin when you check the flag. You'll see gaps where the cpu is off doing other things. Probably that gap is 10ms in places based on your symptoms.

Interrupts or DMA are better ways to service timely events like input capture.

If you feel a post has answered your question, please click "Accept as Solution".
Photek
Associate II

Excellent thanks. 

I had a slight feeling the USB could be the cause of the issue. 

 

What I'll do to diagnose this, if I take the difference between the period of encoder samples and if the different is greater than one, I'll know I have a spike between my timings

I'll do this without and USB being transmitted and use a breakpoint to trigger if the difference within the period are greater than 1

Ozone
Principal III

> I'm printing out the period of the motor encoder timings over the USB serial port and I'm logging the readings to a CSV file

As already noted, this is almost certainly the problem.
Most likely, this "printing" code is executed within interrupt context (a callback), which blocks the timer interrupts.

I think a thorough consultation of the MCU reference manual is at hand.

Thanks.

 

I'm not sending stuff whilst within an interrupt handler. I'm polling the timer input capture interrupt flags, decoding the pulses, then sending the data over USB. The whole process repeats as whilst my motors are turning.

Photek
Associate II

Please see the code which I've implemented to handle decoding my pulses

 

uint32_t CalculateEncoderPeriod(struct PulseData* pulseDataPtr)
{
	uint32_t startTick = HAL_GetTick();
	const uint32_t timeoutMs = 200u;
	uint32_t capturedAllSamples = 0u;

	memset(pulseDataPtr, 0u, sizeof(*pulseDataPtr));

	uint32_t timerInit = 0u;

	// Disable updates
	// This prevents the overflow interrupt from
	// being set and is only enabled once
	// a single input capture has been detected.
	inputCaptureTimer.Instance->CR1 |= TIM_CR1_UDIS;

	while ((capturedAllSamples == 0u) && ((HAL_GetTick() - startTick) <= timeoutMs))
	{
		if (inputCaptureTimer.Instance->SR & TIM_SR_CC1IF) // Connected to D0 in the logic analyser
		{
			const uint16_t cnt = HAL_TIM_ReadCapturedValue(&inputCaptureTimer, TIM_CHANNEL_1);

			if (timerInit == 0u)
			{
				inputCaptureTimer.Instance->CR1 &= ~TIM_CR1_UDIS;
				inputCaptureTimer.Instance->CNT = 0u;
				pulseDataPtr->overflows = 0u;
				timerInit = 1u;
			}
			else
			{
				pulseDataPtr->risingEdgeA = cnt;
			}
		}


		if (inputCaptureTimer.Instance->SR & TIM_SR_UIF)
		{
			pulseDataPtr->overflows++;
			inputCaptureTimer.Instance->SR &= ~TIM_SR_UIF;
		}

		capturedAllSamples = pulseDataPtr->risingEdgeA;

		if (capturedAllSamples)
		{
			pulseDataPtr->periodT1 = ((float)((65535u * pulseDataPtr->overflows) + pulseDataPtr->risingEdgeA )) / 1e5;
		}
	}

	return capturedAllSamples;

 

The following shows where I'm logging the pulses which contain a period of 5ms:

 

ts=14, ERROR PULSE=6.589740
ts=26, ERROR PULSE=5.970020
ts=38, ERROR PULSE=5.569540
ts=48, ERROR PULSE=5.227210
ts=491006, ERROR PULSE=6.573730
ts=501404, ERROR PULSE=6.583630
ts=505395, ERROR PULSE=6.525930
ts=508946, ERROR PULSE=6.531430
ts=512834, ERROR PULSE=6.528640
ts=513041, ERROR PULSE=6.530430
ts=514278, ERROR PULSE=6.572220
ts=514301, ERROR PULSE=6.573430
ts=515575, ERROR PULSE=6.583730
ts=516290, ERROR PULSE=6.517850
ts=519997, ERROR PULSE=6.517940                                                                                                                                                                                   
ts=524208, ERROR PULSE=6.592990                                                                                                                                                                                   
ts=524693, ERROR PULSE=6.592330                                                                                                                                                                                   
ts=576834, ERROR PULSE=6.527480                                                                                                                                                                                   
ts=586004, ERROR PULSE=6.527640                                                                                                                                                                                   
ts=586340, ERROR PULSE=6.531400                                                                                                                                                                                   
ts=587283, ERROR PULSE=6.523590                                                                                                                                                                                   
ts=589038, ERROR PULSE=6.530260

Hal tick is on the left, with the period being on the right. It makes sense that at the start, we exceed 5ms due to the motors starting. However, I'm leaving the motors running for a period of time. After around 500 seconds in from start the motors, I start to get some errors where the pulses exceed my 5ms threshold.

 

Whilst the motors are running, the period is around 3.16ms (as seen in the screenshot). 

Photek
Associate II
ts=14, ERROR PULSE=6.574470, ovf=10
ts=26, ERROR PULSE=5.847360, ovf=8
ts=37, ERROR PULSE=5.402610, ovf=8
ts=47, ERROR PULSE=5.048170, ovf=7
ts=13987, ERROR PULSE=6.532960, ovf=9
ts=15984, ERROR PULSE=6.527110, ovf=9
ts=18105, ERROR PULSE=6.580190, ovf=10

I've just done some more logging now printing out the amount of overflows between pulses. 13 seconds in, I get periods of 6.5ms and during this time, the overflow register has been set for 9 - 10 iterations between rising and falling edge of pulses.