cancel
Showing results for 
Search instead for 
Did you mean: 

TIM2 input capture - what is wrong with my init

Maddi.Mike
Associate II
Posted on August 07, 2012 at 22:02

I have an embedded system built around a STM8S105 which, among other things, must measure the frequency of a pulsed input. The pulses are coming in on pin 29 (PD4/TIM2 CH1) anywhere from 0 to about 1200 pulses per second. What follows is my initialization of the timer and the interrupt function. I know the interrupts are happening at the input rate because I checked with an oscilloscope and a test output in the interrupt function. But when I read the counter register in the interrupt function, it is always different, almost random. It looks like the counter never resets but I don't know why. I know it is counting input pulses because when I stop the input, the interrupts stop. Please take a look at my init and interrupt functions and tell me what I am doing wrong.

Thanks My initialize function:



TIM2->CCER1 = TIM2_CCER1_CC1E;
TIM2->IER = TIM2_IER_CC1IE;
TIM2->CR1 = TIM2_CR1_CEN;
i = (u16)(CLK_GetClockFreq() / 62500);
TIM2->ARRH = (u8)((i >> 8) & 0xFF);
TIM2->ARRL = (u8)(i & 0xFF);
TIM2->EGR = TIM2_EGR_CC1G;

My interrupt function:

u16 h,l;
h = (u16)TIM2->CCR1H;
l = (u16)TIM2->CCR1L;
inPulseCount = (h << 
8
) | l;
TIM2->SR1 = TIM2_SR1_RESET_VALUE;
TIM2->SR2 = TIM2_SR2_RESET_VALUE;

#stm8 #capture #tim2
7 REPLIES 7
klaasdc
Associate II
Posted on August 08, 2012 at 12:44

I think it is better to disable the timer at the beginning of the interrupt, resetting its value, and then enabling it again. I'm not sure if the timer's counter value is correctly written otherwise.

Alternatively, you could use Timer1 trigger controller in slave mode reset, so that it restarts automatically.

fggnrc2
Associate II
Posted on August 08, 2012 at 13:29

madroadbiker,

I think you should read TIM2->CCR1 as follows:

u8 h,l;
h = TIM2->CCR1H;
l = TIM2->CCR1L;

If you use a u16 variable, the compiler may use a 16 bit wide read which may have unexpected side effects. Regards, EtaPhi
Maddi.Mike
Associate II
Posted on August 08, 2012 at 13:51

Thanks for your reply. Disabling then re-enabling will cause a loss of counts on the input. Timer1 on this project is all used up.

Maddi.Mike
Associate II
Posted on August 08, 2012 at 13:58

Thanks for your reply. You have a valid point about 16 vs 8 bit reads. So I changed the interrupt function to:

u8 h,l;
// Get the count
h = TIM2->CCR1H;
l = TIM2->CCR1L;
inPulseCount = ((u16)h << 
8
) | l;
TIM2->SR1 = TIM2_SR1_RESET_VALUE;
TIM2->SR2 = TIM2_SR2_RESET_VALUE;

However it still looks odd. Now instead of random results, it looks like it counts down then back up. Really weird. And the reason I read the low byte last is because, according to the RM0016 reference manual, the CC1 bit of register SR1 is cleared by a software read of CCR1L. But I tried swapping the byte read order anyway with no change in results. Maybe someone can implement this algorithm on their system and try it out?
klaasdc
Associate II
Posted on August 08, 2012 at 14:45

Loss of counts depends on the speed of your counter and the speed of the measured pulses.

You said 1200 Hz so having the timer frequency at 12kHz or 120 kHz will be plenty for most applications. Then, if your MCU is at 16 MHz, two instructions are peanuts.

Have you actually tried it? Even if you don't want to do it that way, it is helpful to see if it changes the problem.

Maddi.Mike
Associate II
Posted on August 08, 2012 at 15:02

Point well taken. So I tried it and still no change.

Maddi.Mike
Associate II
Posted on August 08, 2012 at 16:40

To all. I finally realized my dumb mistake. I was setting the ARR register and leaving the PSCR register at its default. I should have been setting PSCR and leaving ARR alone. I had it backwards. Now my init looks like this and it works fine.

Thanks to all for your input.

TIM2->PSCR = 0x08;
TIM2->CCMR1 = TIM2_CCER1_CC1E; 
TIM2->CCER1 = TIM2_CCER1_CC1E; 
TIM2->IER = TIM2_IER_CC1IE;
TIM2->CR1 = TIM2_CR1_CEN;