cancel
Showing results for 
Search instead for 
Did you mean: 

TIM4 looses input capture events

wolfgang
Associate II
Posted on November 05, 2008 at 10:04

TIM4 looses input capture events

9 REPLIES 9
wolfgang
Associate II
Posted on May 17, 2011 at 12:50

Hi,

i´m using TIM4/CH4 for input capture. Because TIM4/CH3 generates PWM i have to count the update events for correct input capture calculation.

I calculate the IC period like this:

period= ( overflowcounter * TIM4->ARR + TIM4_CC4) - LastValueOf_TIM4_CC4;

overflowcoutner = 0;

LastValueOf_TIM4_CC4 = TIM4_CC4;

With this calculation sometimes the result is the double of the correct value. In this case the overflowcounter is the double of the correct value.

It seams that some edges were lost!!!

My signal is fine (voltage/frequency).

Regards,

Wolfgang Beck

ivanov-i
Associate II
Posted on May 17, 2011 at 12:50

Hi Wolfgang,

It is hard to make a conclusion only from a peace of code, but here some guidelines are:

- Is the calculation part of ISR, or from the main loop? In the second case you indeed could have big latency in checking the capture event.

- Even if both - incrementing of overflowcounter and capture processing are parts of a ISR it could happen that the both events happen very close each to other. In this case you should make a decision whether to increment the counter or not based on the value of TIM4_CC4 register.

wolfgang
Associate II
Posted on May 17, 2011 at 12:50

Hi,

Here my complete code. TIM4_SR_UPDATE and TIM4_SR_CC4 are defines for the interrupt flags (i use bitbanding). They both work fine.

Code:

u32 ulPeriod, ulCounter;

void TIM4_IRQHandler(void)

{

static u16 old=0;

if (TIM4_SR_UPDATE)

{

TIM4_SR_UPDATE=0;

ulCounter++;

}

if (TIM4_SR_CC4)

{

TIM4_SR_CC4=0;

ulPeriod=((TIM4->ARR*ulCounter)+TIM4->CCR4)-old;

ulCounter=0;

old=TIM4->CCR4;

}

}

ivanov-i
Associate II
Posted on May 17, 2011 at 12:50

Well, it could be the second case - the capture happens first and immediately after that the counter overflows. When you enter the ISR both flags are ready and you increment ulCounter but the correct value is the one before overflowing.

You could additionally check TIM4->CCR4 if it is less or higher than the half of the timer period. In the second case you should use ulCounter without incrementing if the overflow flag is also set.

wolfgang
Associate II
Posted on May 17, 2011 at 12:50

Hi,

that´s right for errors +/- one timer overflow. I did your suggestion in the past an could solve this issue. I didn´t mention it to keep it simple.

My problem is that the result vor ulPeriod is sometimes the DOUBLE of the correct value!!! (This error appears independent from the small capture error above)

Regards

ivanov-i
Associate II
Posted on May 17, 2011 at 12:50

Here is another possibility, although it seems to be very rare case.

I suppose that the operation:

TIM4_SR_UPDATE=0;

is implemented something like:

TIM4_SR_bit.UIF = 0;

In fact it is split by the compiler into 3 steps:

- reading TIM4_SR register

- clearing bit 0 of the value

- writing back the result to TIM4_SR

It could happen that when TIM4_SR is read the CC4IF is still cleared but the flag is set immediately after that. When you write the result back there is 0 on the place of CC4IF and it is cleared as a side effect of clearing the UIF.

As all bits in TIM4_SR are rc_w0 type nothing will happen if you write 1's in the bits, which shouldn't be affected. So, clearing of UIF could look like:

TIM4_SR = 0xFFFE;

Of course, you could use #define's to make the code more clear.

Another workaround is to use the bit-bang area of Cortex M3 - all peritheral registers are alliased there.

wolfgang
Associate II
Posted on May 17, 2011 at 12:50

Hi,

thanks a lot for your advise. Know it´s a littlebit better:

As i wrote in my older posting the TIM4_SR_UPDATE and TIM4_SR_CC4 are bitbanding defines for the interrupt flags. Unfortunatelley they didn´t work, because your suggestion to reset these bits works better.

My code now is:

Code:

u32 ulPeriod, ulCounter;

void TIM4_IRQHandler(void)

{

static u16 old=0;

TIM_Cmd(TIM4, DISABLE);

if (TIM4_SR_UPDATE)

{

TIM4->SR = 0xFFFE;

ulCounter++;

}

if (TIM4_SR_CC4)

{

TIM4->SR = 0xFFEF;

if (TIM4->CNT<TIM4->CCR4) //overflow after Capture till now?

{

ulPeriod=((TIM4->ARR*(ulCounter-1))+TIM4->CCR4)-old;

ulCounter=1;

}

else

{

ulPeriod=((TIM4->ARR*(ulCounter ))+TIM4->CCR4)-old;

ulCounter=0;

}

old=TIM4->CCR4;

}

TIM_Cmd(TIM4, ENABLE);

}

this code messures stable values. But there is a difference to the correct value because of stopping and starting the timer. Without these start/stop instructions the values are wrong.

How can i get stable values WITHOUT stopping the timer? I know this challange seems to be easy. But i worked much time on it, and i can´t solve it till now.

Regards,

ivanov-i
Associate II
Posted on May 17, 2011 at 12:50

Wolfgang, it is really complicated...

If the timer runs it could overflow between checking the TIM4_SR_UPDATE and condition (TIM4->CNT < TIM4->CCR4). In this case you will wrongly use (ulCounter-1).

Try to use a different condition for calculating ulPeriod. May be if you remember that you incremented ulCounter in this ISR entry and TIM4_SR_CC4 is also set check if TIM4->CCR4 is bigger than half of TIM4->ARR - in this case the capture happened before timer overflow.

One more correction - the timer overflow period is (TIM4->ARR + 1), not TIM4->ARR.

wolfgang
Associate II
Posted on May 17, 2011 at 12:50

Hi,

thanks a lot for your tips. Now it seems to work!!!

Here´s my code

Code:

u32 ulPeriod, ulCounter;

void TIM4_IRQHandler(void)

{

static UW_16 old=0;

BOOL bUpdateFlag=FALSE;

if (TIM4_SR_UPDATE)

{

TIM4->SR = 0xFFFE;

ulCounter++;

bUpdateFlag=TRUE;

}

if (TIM4_SR_CC4)

{

TIM4->SR = 0xFFEF;

if

(

(bUpdateFlag==TRUE)&&

(TIM4->CCR4 > (TIM4->ARR>>1))

)

{

ulPeriod=(((TIM4->ARR+1)*(ulCounter-1))+TIM4->CCR4)-old;

ulCounter=1;

}

else

{

ulPeriod=(((TIM4->ARR+1)*(ulCounter))+TIM4->CCR4)-old;

ulCounter=0;

}

old=TIM4->CCR4;

}

}

Regards,

Wolfgang Beck