2024-10-23 02:08 AM - last edited on 2024-11-05 08:36 PM by Tesla DeLorean
Hi,
I am trying to configure an input capture on my STM32F051R8Tx. It works fine, I am supplying an external signal via a signal generator and my code measures exactly T=4ms pulses - which I expect. In my case, I am sampling with 24MHz, so the measured period is approx 96000. (96000/24000000 = 0.004 - nice!).
But now I am trying to change the sampling frequency and it does not work, I keep reading 96000 as the period. Here is what I tried:
// 1. change prescaler to divide timer clock by 24 - doesnt work
TIM2->PSC = 24-1;
// 2. divide PCLK (global timer clock) - works
RCC->CFGR |= 0b101<<8;
// 3. manipulating t_dts and using it in for input capture filter - doesnt work
TIM2->CR1 |= 0b01<<8; //t_dts = 2*clk_int
TIM2->CCMR1 |= 0b0111 << 4; //f_sampling = f_dts/ 4
The second method works but it is also chaning the frequnecy for my other timers which I dont really like. For 1. and 3. I keep reading the value 96000 at the capture event. But I guess this value would have to change since the timer counts slower so 4ms should equal some other value...
Here is my basic working code (without 1., 2. and 3.). It is initialising the timer and then waiting for 4 signal edges to determine three bit periods in between (T_OPT1, T_OPT_2, T_OPT_3).
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; //enable timer clock
NVIC_EnableIRQ(TIM2_IRQn); //enable tim2 global interrupts
TIM2->CCMR1 |= 0b01; //configure channel 1 as input
TIM2->CCMR1 |= 0b0011 << 4; //input capture filter
TIM2->CCER |= TIM_CCER_CC1P; //trigger at falling edge
edge_count = EDGE_1; //reset current edge count
synching = true; //synching = true, important for ISR
TIM2->DIER |= TIM_DIER_CC1IE; //enable interrupt at capture/compare on channel 1
TIM2->CCER |= TIM_CCER_CC1E; //enable capture on channel 1
TIM2->CR1 |= TIM_CR1_CEN; //enable counter
while(synching == true); //wait until 4 edges have been detected
And the interrupt service routine (ISR):
void TIM2_IRQHandler(void)
{
//TIM2 ISR
TIM2->SR &= ~ TIM_SR_CC1IF; //clear interrupt flag (also cleared when reading TIM2->CCR1)
TIM2->SR &= ~ TIM_SR_UIF; //clear update interrupt flag
TIM2->SR &= ~ TIM_SR_CC1OF;
if(synching == true)
{
//synchronisation process
switch (edge_count)
{
case EDGE_1:
//on first signal edge
TIM2->CNT = 0; //reset counter
edge_count = EDGE_2; //incremet edge_count
break;
case EDGE_2:
//on second signal edge
T_OPT_1 = (uint32_t)TIM2->CCR1; //capture first bit period
TIM2->CNT = 0; //reset counter
edge_count = EDGE_3; //incremet edge_count
break;
case EDGE_3:
//on third signal edge
T_OPT_2 = (uint32_t)TIM2->CCR1; //capture second bit period
TIM2->CNT = 0; //reset counter
edge_count = EDGE_4; //incremet edge_count
break;
case EDGE_4:
//on fourth signal edge
T_OPT_3 = (uint32_t)TIM2->CCR1; //capture third bit period
TIM2->CNT = 0; //reset counter
edge_count = EDGE_1; //reset edge_count
synching = false; //synching process done
//now reconfigure timer, but dont do that in ISR
break;
default:
edge_count = EDGE_1; //default, in case of unexpected out-of-range edge type
break;
}
}
else
{
...
}
}
Solved! Go to Solution.
2024-10-23 03:21 AM
Hi,
With a brief look at your code, I think you are missing something - setting the TIM_EGR_UG bit after you change things...
I hope that helps.
Kind regards
Pedro
2024-10-23 03:21 AM
Hi,
With a brief look at your code, I think you are missing something - setting the TIM_EGR_UG bit after you change things...
I hope that helps.
Kind regards
Pedro
2024-11-05 08:38 PM
Don't use the RMW form, it creates a hazard of clearing other interrupts
TIM2->SR &= ~ TIM_SR_CC1IF;
Just write the MASK
TIM2->SR = ~ TIM_SR_CC1IF;