2012-08-07 01:02 PM
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
2012-08-08 03:44 AM
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.2012-08-08 04:29 AM
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
2012-08-08 04:51 AM
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.
2012-08-08 04:58 AM
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?
2012-08-08 05:45 AM
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.2012-08-08 06:02 AM
Point well taken. So I tried it and still no change.
2012-08-08 07:40 AM
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;