I have a STM32F302CBT6 (running at 72MHz) project where i need to measure the frequencies of 4 signals, that are around 250kHz each. The signals are connected to TIM1 channels 1 - 4.
Now, understanding, that 250kHz is too fast (or is it?) to handle all those input capture interrupts simultaneously (because they might be synced or happen at the same time...) i figured to measure each channel one by one. I initialized all the channels at the start of my program and thought to enable the corresponding interrupts one by one after each channel is measured. Is this an appropriate idea or am i missing something?
The problem is that after serving the first interrupt for channel 1, the next ones never get served because although the interrupts are not enabled, status register has multiple other interrupts pending (CCxIF and CCXOF, and also CxIF) and also the overcapture flags set. I have tried to avoid this problem by reading all the capture values or setting the TIMx->SR = 0 but no help.
How would i go about measuring those signals and what would be the correct way to ensure each channel gets captured correctly?
I am quite lost on this and would appreciate some insight how this kind of processing is/should be done or if you can point out what i am doing wrong. Thanks.
My current relevant code is right below.
Here is the interrupt handler:
void TIM1_CC_IRQHandler(void) {
if (TIM_GetITStatus(IC_TIMER, IC_CH1) == SET) {
/* Clear TIM1 Capture compare interrupt pending bit */
TIM_ClearITPendingBit(IC_TIMER, IC_CH1);
//Read the capture value
raw_captures[capture_index] = TIM_GetCapture1(IC_TIMER);
capture_index++;
//Also read the others to avoid overcaptures
TIM_GetCapture2(IC_TIMER);
TIM_GetCapture3(IC_TIMER);
TIM_GetCapture4(IC_TIMER);
if(capture_index == 2) {
TIM_ITConfig(IC_TIMER, IC_CH1, DISABLE);
}
} else if (TIM_GetITStatus(IC_TIMER, IC_CH2 == SET)) {
TIM_ClearITPendingBit(IC_TIMER, IC_CH2);
//Read the capture value
raw_captures[capture_index] = TIM_GetCapture2(IC_TIMER);
capture_index++;
TIM_GetCapture1(IC_TIMER);
TIM_GetCapture3(IC_TIMER);
TIM_GetCapture4(IC_TIMER);
if(capture_index == 4) {
TIM_ITConfig(IC_TIMER, IC_CH2, DISABLE);
}
} else if (TIM_GetITStatus(IC_TIMER, TIM_IT_CC3 == SET)) {
//Read the capture value
raw_captures[capture_index] = TIM_GetCapture3(IC_TIMER);
capture_index++;
TIM_GetCapture1(IC_TIMER);
TIM_GetCapture2(IC_TIMER);
TIM_GetCapture4(IC_TIMER);
if(capture_index == 6) {
TIM_ITConfig(IC_TIMER, IC_CH3, DISABLE);
}
} else if (TIM_GetITStatus(IC_TIMER, TIM_IT_CC4 == SET)) {
TIM_ClearITPendingBit(IC_TIMER, TIM_IT_CC4);
//Read the capture value
raw_captures[capture_index] = TIM_GetCapture4(IC_TIMER);
capture_index++;
TIM_GetCapture2(IC_TIMER);
TIM_GetCapture3(IC_TIMER);
TIM_GetCapture1(IC_TIMER);
if(capture_index == 8) {
TIM_ITConfig(IC_TIMER, IC_CH4, DISABLE);
}
} else {
//LOG_WARNING("Unhandled interrupt in the TIM1_CC_IRQHandler"NL);
IC_TIMER->SR = 0; //Clear all other pending interrupts
}
}
Here is my initialization code, that largely based on the Std_Periph_Example:
void input_capture_setup(void) {
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
/* TIM clock enable */
RCC_APB2PeriphClockCmd(IC_CLK, ENABLE);
/* GPIOA clock enable */
RCC_AHBPeriphClockCmd(IC_PORT_CLK, ENABLE);
/* TIM1 channels 1 - 4 pins PA8 - PA11 configuration */
GPIO_InitStructure.GPIO_Pin = IC1_PIN | IC2_PIN | IC3_PIN | IC4_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Connect TIM pins to AF1 */
GPIO_PinAFConfig(IC_PORT, IC1_PINSRC, GPIO_AF_6);
GPIO_PinAFConfig(IC_PORT, IC2_PINSRC, GPIO_AF_6);
GPIO_PinAFConfig(IC_PORT, IC3_PINSRC, GPIO_AF_6);
GPIO_PinAFConfig(IC_PORT, IC4_PINSRC, GPIO_AF_11);
/* Enable the TIM global Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* TIM configuration: Input Capture mode ---------------------
The external signals are connected to TIM1 CH1 - CH4 pin (PA8 - PA11)
The Rising edge is used as active edge,
The TIM1 CCR1 - CCR4 are used to compute the frequency value
------------------------------------------------------------ */
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV8;
TIM_ICInitStructure.TIM_ICFilter = 0x0;
//Initialize all channels one by one
TIM_ICInitStructure.TIM_Channel = IC1;
TIM_ICInit(IC_TIMER, &TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel = IC2;
TIM_ICInit(IC_TIMER, &TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel = IC3;
TIM_ICInit(IC_TIMER, &TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel = IC4;
TIM_ICInit(IC_TIMER, &TIM_ICInitStructure);
/* TIM enable counter */
TIM_Cmd(IC_TIMER, ENABLE);
}
In the mainloop i have the following code to trigger the next channel after the previous one has been registered:
void node_handle_capture(void) {
if(!capture_enabled) {
TIM_ITConfig(IC_TIMER, IC_CH1, ENABLE);
capture_enabled = true;
}
else {
switch (capture_index) {
case 2:
LOG_DEBUG("CH1 captured"NL);
TIM_ITConfig(IC_TIMER, IC_CH2, ENABLE);
break;
case 4:
LOG_DEBUG("CH2 captured"NL);
TIM_ITConfig(IC_TIMER, IC_CH3, ENABLE);
break;
case 6:
LOG_DEBUG("CH3 captured"NL);
TIM_ITConfig(IC_TIMER, IC_CH4, ENABLE);
break;
case 8:
LOG_DEBUG("All channels captured"NL);
capture_index = 0;
break;
default:
break;
}
}
}