cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4 input capture Confusion.

CPetr.1
Associate II

 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);

6 REPLIES 6

> everything freezes

Observe in debugger, what does the program do when "frozen".

JW

CPetr.1
Associate II

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");

  }

 }

}

> print_ulong(&huart2,uwDiffCapture);

in an ISR is rarely a good idea.

Cube/HAL is also unnecessarily extensive, especially its interrupts harness.

JW

CPetr.1
Associate II

JW, how would you do it?

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

CPetr.1
Associate II

JW, great advice. Also I need to do some work at designing the staggered arrival of inputs.