2021-07-16 07:16 PM
Hi.
I’m working on a Nucleo-411, using CubeIDE, and HAL, and I want to read 4 PWM signals from am RC receiver. That is 4 50Hz signals, with a pulse width ranging from 0.5mS to 2.5mS. I’m following the reference manual, and some examples, and so far I can read one channel. Heres my setup for TIM4.
1) Select the active input = as per sConfigIC structure.
2) Program the input filter = NONE
3) Select the edge of the active transition = both edges
4) Program the input prescaler = 99
5) Enable capture from the counter into the capture register by setting the CC1E bit = as per sConfigIC structure.
6) Enable the related interrupt = HAL_TIM_IC_Start_IT(...)
As I understand there is only one interrupt vector for all TIM4 interrupts, and with this setup if I enable the interrupt say for CH1, the interrupt is generated, and I can then complete the ISR. If I enable both CH1 and CH2 interrupts with two separate calls to “HAL_TIM_IC_Start_IT(...)�? then everything freezes. My ISR routine is taken from one of ST's InputCapture examples.
Can someone help me clear up what else is needed.
I hope the code below helps.
TIM_IC_InitTypeDef sConfigIC = {0};
htim4.Instance = TIM4;
htim4.Init.Prescaler = 99;
htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
htim4.Init.Period = 0xFFFF;
htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_IC_Init(&htim4) != HAL_OK)
{
Error_Handler();
}
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_BOTHEDGE;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 0;
if (HAL_TIM_IC_ConfigChannel(&htim4, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_IC_ConfigChannel(&htim4, &sConfigIC, TIM_CHANNEL_2) != HAL_OK)
{
Error_Handler();
}
if(HAL_TIM_IC_Start_IT(&htim4, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
if(HAL_TIM_IC_Start_IT(&htim4, TIM_CHANNEL_2) != HAL_OK)
{
Error_Handler();
}
and for completeness.
__HAL_RCC_TIM4_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/**TIM4 GPIO Configuration
PB6 ------> TIM4_CH1
PB7 ------> TIM4_CH2
*/
GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF2_TIM4;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
HAL_NVIC_SetPriority(TIM4_IRQn, 0, 1);
HAL_NVIC_EnableIRQ(TIM4_IRQn);
2021-07-17 01:35 AM
> everything freezes
Observe in debugger, what does the program do when "frozen".
JW
2021-07-17 02:16 AM
Hi JW. After debugging, I eventually got it to work, I not sure know why??
I can now measure the pulse width on both CH1 and CH2, but I think because the PWM signal I'm measuring can and does occurs simultaneously, its very random as to which channels pulse width is displayed to terminal. I expected there to be a priority.
How can 2,3,or 4 PWM signals be measured using TIM4 and all 4 channels successfully?
In my ISR I check for which CH generated the ISR and then if its a high or low edge.
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
{
if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7)) //rising edge PB7 for TIM4
{
/* Get the 1st Input Capture value */
uwIC2Value1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2);
uhCaptureIndex = 1;
}
else
{
/* Get the 2nd Input Capture value */
uwIC2Value2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2);
/* Capture computation */
if (uwIC2Value2 > uwIC2Value1)
{
uwDiffCapture = (uwIC2Value2 - uwIC2Value1);
}
else if (uwIC2Value2 < uwIC2Value1)
{
uwDiffCapture = ((0xFFFF - uwIC2Value1) + uwIC2Value2) + 1;
}
else
{
/* If capture values are equal, we have reached the limit of frequency
measures */
Error_Handler();
}
uhCaptureIndex = 0;
uart_puts(&huart2,"t2= ");
print_ulong(&huart2,uwDiffCapture);
uart_puts(&huart2,"\r");
}
}
else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
{
if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6)) //rising edge PB6 for TIM4
{
/* Get the 1st Input Capture value */
uwIC2Value1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
uhCaptureIndex = 1;
}
else
{
/* Get the 2nd Input Capture value */
uwIC2Value2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
/* Capture computation */
if (uwIC2Value2 > uwIC2Value1)
{
uwDiffCapture = (uwIC2Value2 - uwIC2Value1);
}
else if (uwIC2Value2 < uwIC2Value1)
{
uwDiffCapture = ((0xFFFF - uwIC2Value1) + uwIC2Value2) + 1;
}
else
{
/* If capture values are equal, we have reached the limit of frequency
measures */
Error_Handler();
}
uhCaptureIndex = 0;
uart_puts(&huart2,"t1= ");
print_ulong(&huart2,uwDiffCapture);
uart_puts(&huart2,"\r");
}
}
}
2021-07-17 03:12 AM
> print_ulong(&huart2,uwDiffCapture);
in an ISR is rarely a good idea.
Cube/HAL is also unnecessarily extensive, especially its interrupts harness.
JW
2021-07-17 03:38 AM
JW, how would you do it?
2021-07-17 06:03 AM
Avoid lengthy blocking processes in ISR. Store results in global variables, set flags indicating there are new results, and process all that (including uart transfer etc.) in main().
JW
2021-07-17 06:28 AM
JW, great advice. Also I need to do some work at designing the staggered arrival of inputs.