Search code examples
ctimerembeddedstm32stm32cubeide

STM32 HRTIM PWM only work when master compare is > 70ns


STM32G474

STM32CubeIDE 1.7.0

I need to implement four different PWM channels where they can be shifted in 5 degree intervals (e.g. A = 0°, B = 5°, C = 10°, D = 180°). The PWM output has a duty cycle of 50%. Important is only the shift between the channels.

Implementation:

timer setup

Master timer

  • HRTIM input clock: 170 MHz
  • Master timer PWM frequency: 1.6 MHz
  • Prescaler ratio: HRTIM Clock Multiplied by 32 -> fHRCK = 5.44E9 Hz
  • Period: HRTIM_INPUT_CLOCK * 32 / TIMM_PWM_FREQ = 3400
  • Master timer has four Compares masterCompareN= period/360*shift

Timer A to D

  • Prescaler ratio: HRTIM Clock Multiplied by 32 -> fHRCK = 5.44E9 Hz
  • Each timer has one compare = (masterCompareN + (period/2)) % period

A master timer compare event will trigger the corresponding timer (e.g. A) output to high, the timer (A) compare event will set the output (A) to low.

correct output (all > 10° shift)

Output is as expected if all shifts are 8° / 70ns. Below this threshold (e.g. A is shifted 5°) sometimes there is no output. It appears like the compare of A does not work.

missed master compare events

A (red) 2° B (blue) 5° C (green) 7° D (yellow) 10°

  // static void MX_HRTIM1_Init(void)
  // Master Timer
  LL_HRTIM_TIM_SetPrescaler(HRTIM1, LL_HRTIM_TIMER_MASTER, LL_HRTIM_PRESCALERRATIO_MUL32);
  LL_HRTIM_TIM_SetCounterMode(HRTIM1, LL_HRTIM_TIMER_MASTER, LL_HRTIM_MODE_CONTINUOUS);
  LL_HRTIM_TIM_SetPeriod(HRTIM1, LL_HRTIM_TIMER_MASTER, TIMM_PERIOD);
  LL_HRTIM_TIM_SetRepetition(HRTIM1, LL_HRTIM_TIMER_MASTER, 0x00);
  LL_HRTIM_TIM_DisableHalfMode(HRTIM1, LL_HRTIM_TIMER_MASTER);
  LL_HRTIM_TIM_SetInterleavedMode(HRTIM1, LL_HRTIM_TIMER_MASTER, LL_HRTIM_INTERLEAVED_MODE_DISABLED);
  LL_HRTIM_TIM_DisableStartOnSync(HRTIM1, LL_HRTIM_TIMER_MASTER);
  LL_HRTIM_TIM_DisableResetOnSync(HRTIM1, LL_HRTIM_TIMER_MASTER);
  LL_HRTIM_TIM_SetDACTrig(HRTIM1, LL_HRTIM_TIMER_MASTER, LL_HRTIM_DACTRIG_NONE);
  LL_HRTIM_TIM_DisablePreload(HRTIM1, LL_HRTIM_TIMER_MASTER);
  LL_HRTIM_TIM_SetUpdateGating(HRTIM1, LL_HRTIM_TIMER_MASTER, LL_HRTIM_UPDATEGATING_INDEPENDENT);
  LL_HRTIM_TIM_SetUpdateTrig(HRTIM1, LL_HRTIM_TIMER_MASTER, LL_HRTIM_UPDATETRIG_NONE);
  LL_HRTIM_TIM_SetBurstModeOption(HRTIM1, LL_HRTIM_TIMER_MASTER, LL_HRTIM_BURSTMODE_MAINTAINCLOCK);
  LL_HRTIM_ForceUpdate(HRTIM1, LL_HRTIM_TIMER_MASTER);
  LL_HRTIM_TIM_SetCompare1(HRTIM1, LL_HRTIM_TIMER_MASTER, TIMM_Compare1);
  LL_HRTIM_TIM_SetCompare2(HRTIM1, LL_HRTIM_TIMER_MASTER, TIMM_Compare2);
  LL_HRTIM_TIM_SetCompare3(HRTIM1, LL_HRTIM_TIMER_MASTER, TIMM_Compare3);
  LL_HRTIM_TIM_SetCompare4(HRTIM1, LL_HRTIM_TIMER_MASTER, TIMM_Compare4);

  // Timer A
  LL_HRTIM_TIM_SetPrescaler(HRTIM1, LL_HRTIM_TIMER_A, LL_HRTIM_PRESCALERRATIO_MUL32);
  LL_HRTIM_TIM_SetCounterMode(HRTIM1, LL_HRTIM_TIMER_A, LL_HRTIM_MODE_CONTINUOUS);
  LL_HRTIM_TIM_SetPeriod(HRTIM1, LL_HRTIM_TIMER_A, TIMM_PERIOD);
  LL_HRTIM_TIM_SetRepetition(HRTIM1, LL_HRTIM_TIMER_A, 0x00);
  LL_HRTIM_TIM_SetUpdateGating(HRTIM1, LL_HRTIM_TIMER_A, LL_HRTIM_UPDATEGATING_INDEPENDENT);
  LL_HRTIM_TIM_SetCountingMode(HRTIM1, LL_HRTIM_TIMER_A, LL_HRTIM_COUNTING_MODE_UP);
  LL_HRTIM_TIM_SetComp1Mode(HRTIM1, LL_HRTIM_TIMER_A, LL_HRTIM_GTCMP1_GREATER);
  LL_HRTIM_TIM_SetDACTrig(HRTIM1, LL_HRTIM_TIMER_A, LL_HRTIM_DACTRIG_NONE);
  LL_HRTIM_TIM_DisableHalfMode(HRTIM1, LL_HRTIM_TIMER_A);
  LL_HRTIM_TIM_SetInterleavedMode(HRTIM1, LL_HRTIM_TIMER_A, LL_HRTIM_INTERLEAVED_MODE_DISABLED);
  LL_HRTIM_TIM_DisableStartOnSync(HRTIM1, LL_HRTIM_TIMER_A);
  LL_HRTIM_TIM_DisableResetOnSync(HRTIM1, LL_HRTIM_TIMER_A);
  LL_HRTIM_TIM_DisablePreload(HRTIM1, LL_HRTIM_TIMER_A);
  LL_HRTIM_TIM_DisableResyncUpdate(HRTIM1, LL_HRTIM_TIMER_A);
  LL_HRTIM_TIM_SetUpdateTrig(HRTIM1, LL_HRTIM_TIMER_A, LL_HRTIM_UPDATETRIG_NONE|LL_HRTIM_UPDATETRIG_NONE);
  LL_HRTIM_TIM_SetResetTrig(HRTIM1, LL_HRTIM_TIMER_A, LL_HRTIM_RESETTRIG_NONE);
  LL_HRTIM_TIM_DisablePushPullMode(HRTIM1, LL_HRTIM_TIMER_A);
  LL_HRTIM_TIM_DisableDeadTime(HRTIM1, LL_HRTIM_TIMER_A);
  LL_HRTIM_TIM_SetBurstModeOption(HRTIM1, LL_HRTIM_TIMER_A, LL_HRTIM_BURSTMODE_MAINTAINCLOCK);
  LL_HRTIM_ForceUpdate(HRTIM1, LL_HRTIM_TIMER_A);
  LL_HRTIM_TIM_SetCompare1(HRTIM1, LL_HRTIM_TIMER_A, TIMA_Compare1);
  LL_HRTIM_OUT_SetPolarity(HRTIM1, LL_HRTIM_OUTPUT_TA1, LL_HRTIM_OUT_POSITIVE_POLARITY);
  LL_HRTIM_OUT_SetOutputSetSrc(HRTIM1, LL_HRTIM_OUTPUT_TA1, LL_HRTIM_OUTPUTSET_MASTERCMP1);
  LL_HRTIM_OUT_SetOutputResetSrc(HRTIM1, LL_HRTIM_OUTPUT_TA1, LL_HRTIM_OUTPUTRESET_TIMCMP1);
  LL_HRTIM_OUT_SetIdleMode(HRTIM1, LL_HRTIM_OUTPUT_TA1, LL_HRTIM_OUT_NO_IDLE);
  LL_HRTIM_OUT_SetIdleLevel(HRTIM1, LL_HRTIM_OUTPUT_TA1, LL_HRTIM_OUT_IDLELEVEL_INACTIVE);
  LL_HRTIM_OUT_SetFaultState(HRTIM1, LL_HRTIM_OUTPUT_TA1, LL_HRTIM_OUT_FAULTSTATE_NO_ACTION);
  LL_HRTIM_OUT_SetChopperMode(HRTIM1, LL_HRTIM_OUTPUT_TA1, LL_HRTIM_OUT_CHOPPERMODE_DISABLED);

  // Timer B
  // Timer C
  // Timer D

2021-10-15 Added __disable_irq() to see if the problem is related to reload some register in the timers. Doesn't seem to be the case.

2021-10-15 LL_HRTIM_TIM_SetCompare1() function indicates that the compare value must be above or equal to 3 periods of the fHRTIM clock. fHRTIM is 170 MHz -> 5.88 ns. 3 x 5.88 ns = 17.65 ns This seems to be the case... 10° (which works) I can measure a delta of about 12+ ns (when the 0° occasionally works)


Solution

  • As Updated the question above, I think I have found the issue.

    Looking in the code of the LL_HRTIM_TIM_SetCompare1() function, it indicates that the compare value must be above or equal to 3 periods of the fHRTIM clock.

    fHRTIM is 170 MHz -> 5.88 ns. 3 x 5.88 ns = 17.65 ns

    This seems to be the case... 10° (which works) I can measure a delta time of about 12+ ns (when the 0° occasionally works)

    /**
      * @brief  Set the compare value of the compare unit 1.
      * @rmtoll MCMP1R      MCMP1       LL_HRTIM_TIM_SetCompare1\n
      *         CMP1xR      CMP1x       LL_HRTIM_TIM_SetCompare1
      * @param  HRTIMx High Resolution Timer instance
      * @param  Timer This parameter can be one of the following values:
      *         @arg @ref LL_HRTIM_TIMER_MASTER
      *         @arg @ref LL_HRTIM_TIMER_A
      *         @arg @ref LL_HRTIM_TIMER_B
      *         @arg @ref LL_HRTIM_TIMER_C
      *         @arg @ref LL_HRTIM_TIMER_D
      *         @arg @ref LL_HRTIM_TIMER_E
      *         @arg @ref LL_HRTIM_TIMER_F
      * @param  CompareValue Compare value must be above or equal to 3
      *         periods of the fHRTIM clock, that is 0x60 if CKPSC[2:0] = 0,
      *         0x30 if CKPSC[2:0] = 1, 0x18 if CKPSC[2:0] = 2,...
      * @retval None
      */
    __STATIC_INLINE void LL_HRTIM_TIM_SetCompare1(HRTIM_TypeDef *HRTIMx, uint32_t Timer, uint32_t CompareValue)