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:
Master timer
Timer A to D
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.
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.
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)
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)