0
\$\begingroup\$

With an STM32 microcontroller I use timer 2 channel 4 to generate PWM:

HAL_TIM_PWM_Start_IT(&htim2, TIM_CHANNEL_4);

And I use HAL_TIM_PWM_PulseFinishedCallback to send data through SPI at the end of each PWM falling edge. It means at the end of each PWM pulse(end of duty cycle), PWM_PulseFinishedCallback is called and I implement SPI transmit function in there.

But I noticed it takes several microseconds between the time the actual pulse is finished(falling edge) and the time when the PWM_PulseFinishedCallback is called.

enter image description here

As you see after the actual pulse is finished(falling edge of PWM) some extra time passes until the callback is called and SPI enable pin goes LOW.

So how can I modify the IRQ handler so that HAL_TIM_PWM_Start_IT can be called earlier?:

@verbatim
 ==============================================================================
 ##### IRQ handler management #####
 ==============================================================================
 [..]
 This section provides Timer IRQ handler function.
@endverbatim
 * @{
 */
/**
 * @brief This function handles TIM interrupts requests.
 * @param htim TIM handle
 * @retval None
 */
void HAL_TIM_IRQHandler(TIM_HandleTypeDef *htim)
{
 /* Capture compare 1 event */
 if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC1) != RESET)
 {
 if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC1) != RESET)
 {
 {
 __HAL_TIM_CLEAR_IT(htim, TIM_IT_CC1);
 htim->Channel = HAL_TIM_ACTIVE_CHANNEL_1;
 /* Input capture event */
 if ((htim->Instance->CCMR1 & TIM_CCMR1_CC1S) != 0x00U)
 {
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
 htim->IC_CaptureCallback(htim);
#else
 HAL_TIM_IC_CaptureCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
 }
 /* Output compare event */
 else
 {
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
 htim->OC_DelayElapsedCallback(htim);
 htim->PWM_PulseFinishedCallback(htim);
#else
 HAL_TIM_OC_DelayElapsedCallback(htim);
 HAL_TIM_PWM_PulseFinishedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
 }
 htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;
 }
 }
 }
 /* Capture compare 2 event */
 if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC2) != RESET)
 {
 if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC2) != RESET)
 {
 __HAL_TIM_CLEAR_IT(htim, TIM_IT_CC2);
 htim->Channel = HAL_TIM_ACTIVE_CHANNEL_2;
 /* Input capture event */
 if ((htim->Instance->CCMR1 & TIM_CCMR1_CC2S) != 0x00U)
 {
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
 htim->IC_CaptureCallback(htim);
#else
 HAL_TIM_IC_CaptureCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
 }
 /* Output compare event */
 else
 {
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
 htim->OC_DelayElapsedCallback(htim);
 htim->PWM_PulseFinishedCallback(htim);
#else
 HAL_TIM_OC_DelayElapsedCallback(htim);
 HAL_TIM_PWM_PulseFinishedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
 }
 htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;
 }
 }
 /* Capture compare 3 event */
 if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC3) != RESET)
 {
 if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC3) != RESET)
 {
 __HAL_TIM_CLEAR_IT(htim, TIM_IT_CC3);
 htim->Channel = HAL_TIM_ACTIVE_CHANNEL_3;
 /* Input capture event */
 if ((htim->Instance->CCMR2 & TIM_CCMR2_CC3S) != 0x00U)
 {
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
 htim->IC_CaptureCallback(htim);
#else
 HAL_TIM_IC_CaptureCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
 }
 /* Output compare event */
 else
 {
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
 htim->OC_DelayElapsedCallback(htim);
 htim->PWM_PulseFinishedCallback(htim);
#else
 HAL_TIM_OC_DelayElapsedCallback(htim);
 HAL_TIM_PWM_PulseFinishedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
 }
 htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;
 }
 }
 /* Capture compare 4 event */
 if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC4) != RESET)
 {
 if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC4) != RESET)
 {
 __HAL_TIM_CLEAR_IT(htim, TIM_IT_CC4);
 htim->Channel = HAL_TIM_ACTIVE_CHANNEL_4;
 /* Input capture event */
 if ((htim->Instance->CCMR2 & TIM_CCMR2_CC4S) != 0x00U)
 {
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
 htim->IC_CaptureCallback(htim);
#else
 HAL_TIM_IC_CaptureCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
 }
 /* Output compare event */
 else
 {
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
 htim->OC_DelayElapsedCallback(htim);
 htim->PWM_PulseFinishedCallback(htim);
#else
 HAL_TIM_OC_DelayElapsedCallback(htim);
 HAL_TIM_PWM_PulseFinishedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
 }
 htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;
 }
 }
 /* TIM Update event */
 if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_UPDATE) != RESET)
 {
 if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_UPDATE) != RESET)
 {
 __HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
 htim->PeriodElapsedCallback(htim);
#else
 HAL_TIM_PeriodElapsedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
 }
 }
 /* TIM Break input event */
 if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_BREAK) != RESET)
 {
 if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_BREAK) != RESET)
 {
 __HAL_TIM_CLEAR_IT(htim, TIM_IT_BREAK);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
 htim->BreakCallback(htim);
#else
 HAL_TIMEx_BreakCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
 }
 }
#if defined(TIM_BDTR_BK2E)
 /* TIM Break2 input event */
 if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_BREAK2) != RESET)
 {
 if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_BREAK) != RESET)
 {
 __HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_BREAK2);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
 htim->Break2Callback(htim);
#else
 HAL_TIMEx_Break2Callback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
 }
 }
#endif /* TIM_BDTR_BK2E */
 /* TIM Trigger detection event */
 if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_TRIGGER) != RESET)
 {
 if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_TRIGGER) != RESET)
 {
 __HAL_TIM_CLEAR_IT(htim, TIM_IT_TRIGGER);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
 htim->TriggerCallback(htim);
#else
 HAL_TIM_TriggerCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
 }
 }
 /* TIM commutation event */
 if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_COM) != RESET)
 {
 if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_COM) != RESET)
 {
 __HAL_TIM_CLEAR_IT(htim, TIM_FLAG_COM);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
 htim->CommutationCallback(htim);
#else
 HAL_TIMEx_CommutCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
 }
 }
}
/**
 * @}
 */
/** @defgroup TIM_Exported_Functions_Group8 TIM Peripheral Control functions
 * @brief TIM Peripheral Control functions
 *
@verbatim
Velvet
4,9085 gold badges18 silver badges32 bronze badges
asked Feb 3, 2023 at 10:39
\$\endgroup\$
5
  • 3
    \$\begingroup\$ If preformance and low delays became important, than it is time to put HAL aside. Write your own interrupt handler, that contains only the required code, the default handler contains a lot of code, that is not required for practical needs. Sending data with HAL functions also can take it's toll. \$\endgroup\$ Commented Feb 3, 2023 at 11:44
  • \$\begingroup\$ Yes I know thats why I asked the question for help. I dont use HAL for SPI enable pin and SPI data transfer. I use HAL only for that PWM_PulseFinishedCallback. I need help how I can take it earlier in the loops in HAL_TIM_IRQHandler. \$\endgroup\$ Commented Feb 3, 2023 at 12:19
  • \$\begingroup\$ It looks like your "several microseconds" is close to \90ドル \mu \mathrm s\$ -- yes? It would be good to edit your question with this information. I initially took "several" to mean "up to 10". Or just show a screen shot of the whole oscilloscope screen, so folks can see for themselves. \$\endgroup\$ Commented Feb 3, 2023 at 15:38
  • \$\begingroup\$ @TimWescott FYI. Its not 90us. Thats something else. Difference between the PWM falling edge(purple) and SPI enable(orange falling edge) is around 4us \$\endgroup\$ Commented Feb 3, 2023 at 15:58
  • \$\begingroup\$ Please edit your question then. Either say that it's 4us, or show the entire oscilloscope capture so that people know what the time base is. 4us is short enough that you're probably just looking at the interrupt response time, and if you want faster response you need hardware aids. \$\endgroup\$ Commented Feb 3, 2023 at 16:46

1 Answer 1

1
\$\begingroup\$

If I'm reading that HAL code correctly, the PWM callback function is getting called early in the process. You may just be exceeding the performance boundaries of the chip.

  • Make sure you don't have some other interrupt active at the same time that's blocking your timer interrupt from excecuting.
  • If you need some bit of hardware (like an ADC) synchronized to the PWM pulse, then you may want to do that in hardware, with a separate timing output.
  • If you can stand some uncertainty about whether your code will pop off slightly before or after the PWM pulse, and you have the timer resources, you can have a separate timer that goes off some predictable time before your PWM output goes off. This will require either an unused capture/compare channel on the timer you're using, or the ability to put another timer into service and synchronize it to your "master" timer.
answered Feb 3, 2023 at 15:43
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.