cancel
Showing results for 
Search instead for 
Did you mean: 

Strange values when reading timer CNT

Guidoted
Associate III

I have a timer (TIM10) with a period of 500 us, running without interrupt or any other function.

Then I have a rising+falling signal interrupt on PB0 (EXTI0) driven with a 31.25 kHz square wave.

In EXTI0 I read the CNT value into a variable New, evaluate the difference with the previous CNT value Old (obviously considering the case when Old value is greater than New value) and copy the New into Old for the next EXTI0 interrupt.

What I see is that many times the difference between New and Old, which should be about 16 us, is even 40, 80, 100 us or more!

I've checked with a signal output on a pin and a scope that I have EXTI0 interrupts correctly every 16 us, without any interrupt loose or other strange behaviours.

Seem's like sometimes (many times...) the CNT value read is not the current one but some strange old value.

What could be the problem?

Thanks

 

1 ACCEPTED SOLUTION

Accepted Solutions

> Are you saying that debugger is changing the variable values?

No.

The debugger stops execution upon your breakpoint, but TIM10 continues to run and rolls over many times until you start executing again (and also EXTI continues to be triggered by the incoming pulses).

That, unless you have set the respective DBGMCU_APBx_FZ.DBG_TIMx_STOP bit, directly or indirectly through some tickbox in your debugging environment/IDE). But even then, the "problem" with EXTI being already triggered while execution is stopped, remains, so the next difference will not reflect the true difference between edges anyway.

I repeat, debug this in some other way, which does not involve breakpoints and execution stops. Or, if you insist, take this effect into account - e.g. have a counter in the ISR, which allows it to be executed at least twice in a row without the breakpoint, and only then allow the breakpoint:

static uint32_t cnt;

... // do the thing with reading TIMx_CNT and making the diff here
if (cnt == 2) {
  __NOP; // place breakpoint here
  cnt = 0;
} else {
  cnt++;
}

JW

View solution in original post

15 REPLIES 15

Show code.

JW

 

PS.

> I have a timer (TIM10) with a period of 500 us

How did you verify this?

It is programmed with a prescaler of 10 and a period of 49999.

 

> In EXTI0 I read the CNT value into a variable New, evaluate the difference with the previous CNT value Old (obviously considering the case when Old value is greater than New value) and copy the New into Old for the next EXTI0 interrupt.

Show code.

> What I see is that many times the difference between New and Old, which should be about 16 us, is even 40, 80, 100 us or more!

How do you "see" that?

JW

I discarded the code, but i was about so:

(newTimer and oldTimer defined as uint32_t global variables)

...

newTimwer = TIM11->CNT;

if(newTimer > oldTimer) {

....

}

else {

....

}

 

oldTimer = newTimer;

....

 

With a breakpoint on "oldTimer = newTimer;" line, I watch the values of both variables

 

If you stop mcu execution by breakpoint and the external pulse train and/or TIM keep running, the results are confusing.

Chose a different method of debugging - using debuggers is intrusive.

JW

 

PS.

newTimwer = TIM11->CNT;

This won't work well with TIM10.

There is no need for two cases. Just do:

 

 

static uint16_t PrevVal;
uint16_t CurrVal = TIM10->CNT;
uint16_t lap = CurrVal - PrevVal;
PrevVal = CurrVal;

 

lap variable will always have a proper value, regardless of timer rollover. It's all about proper data types. :) No need for global (maybe lap should be global if it's used outside of ISR).

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice

@gbm 

Using implicit modulo through casting to uint16_t is perhaps the way to go, but will work only if ARR=0xFFFF, which obviously is not the case here.

JW

Thanks JW and Gdm, I will investigate further.

 

P.S. newTimwer = TIM11->CNT;  instead of newTimwer = TIM10->CNT; was a mistypo ;)

So, this is the code that currently gives me the same wrong results with both 16 and 32 bit variables.

 

void EXTI0_IRQHandler(void)

{

static uint16_t timerNew16, timerOld16, timerDiff16;

static uint32_t timerNew32, timerOld32, timerDiff32;

 

DBG2_GPIO_Port->ODR |= DBG2_Pin;

 

if(__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_0) != RESET) {

__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0);

}

 

timerNew16 = TIM10->CNT;

timerNew32 = TIM10->CNT;

 

if(timerNew16 > timerOld16) {

timerDiff16 = timerNew16 - timerOld16;

}

else {

timerDiff16 = timerNew16 + (49999 - timerOld16);

}

 

if(timerNew32 > timerOld32) {

timerDiff32 = timerNew32 - timerOld32;

}

else {

timerDiff32 = timerNew32 + (49999 - timerOld32);

}

 

timerOld16 = timerNew16;

timerOld32 = timerNew32;

 

if(__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_0) != RESET) {

__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0);

}

 

DBG2_GPIO_Port->ODR &= ~DBG2_Pin;

}

 

This is timer setup (clock 100 MHz):

htim10.Instance = TIM10;

htim10.Init.Prescaler = 0;

htim10.Init.CounterMode = TIM_COUNTERMODE_UP;

htim10.Init.Period = 49999;

htim10.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;

 

MCU is STM32F412RET6

 

Double checked again with DBG2 output pin and a scope that with 31.25 kHz square wave

on PB0, the interrupt happens about 16 us.

Here some values of timerDiff16 (same value in timerDiff32) with breakpoint in line timerOld16 = timerNew16:

10359, 40760, 31317, 1673, 560, 6105...

 

What is wrong in my code?

Thanks