cancel
Showing results for 
Search instead for 
Did you mean: 

TIM15 - PWM CH1/CH1N - One Pulse Mode: how to avoid ''glitch'' ?

Ronny Landsverk
Associate III
Posted on April 21, 2018 at 23:02

I am generating stimuli for a CPLD circuit using my Discovery board - STM32F303VCT.

I use CubeMX for peripheral/clock initialisation, and AC6 (Eclipse) for code.

I am using TIM15 - PWM CH1/CH1N - One Pulse Mode - with RCR of some value, say N-1.

The PWM signals are to run a half-bridge for an AC motor, and hence need to be complementary with a small dead-time. That is, when CH1 is high, then CH1N is low and vica verca, but with a small period where both are low to prevent shorting the bridge. Both may be low, but both may never be high s

imultaneously

.

The code in question is pure polling, where I start the timer-pwm using HAL functions.

The first pulse-train is working fine... Both pwm-signals start from idle and generate N pulses with a small dead-time.

After those pulses, I have a 500 ms delay, and then generate N new pulses, using HAL again. However, this time I always get a ''glitch'' in the ''pwm1'' signal, prior to the pulse-train, as shown

The majority of the code is generated by CubeMX, with generally default settings for the TIM15

0690X00000604UjQAI.jpg

and (relevant) user-code in the while(1)-loop

if (HAL_GPIO_ReadPin(GPIOA, bluePB_Pin) == GPIO_PIN_SET)

{

HAL_Delay(200);

HAL_TIM_PWM_Start(&htim15, TIM_CHANNEL_1);

HAL_TIMEx_PWMN_Start(&htim15, TIM_CHANNEL_1);

HAL_Delay(500);

HAL_TIM_PWM_Start(&htim15, TIM_CHANNEL_1);

}

I guess the code is quite naïve, but it works fine for a single PWM signal, and BTW don't worry - I am not the one coding the microcontroller that will generate our PWM signals for our real motor !

I know of a couple of application notes, e.g. ''AN4013 STM32 cross-series timer overview'' and ''AN4776 - General purpose timer cookbook'', but they take some time to digest, and my goal here is just to generate stimuli to test my CPLD.

So, my question is how should I generate complementary pwm pulse-trains with no glitch ?

Also, anyone is very much welcome to refer to (free) tutorials / lectures / best-practice regarding STM32 timers.

https://community.st.com/tags/?tags=tim%20pwm

,

https://community.st.com/tags/?tags=one%20pulse%20mode

‌,

https://community.st.com/tags/?tags=learning%20stm32

one-pulse-mode tim-pwm learning-stm32

1 ACCEPTED SOLUTION

Accepted Solutions
Posted on April 24, 2018 at 01:49

Here is what I think has happened (I don't have the 'F3 Cube, this is based on some random version of 'F4 Cube, so I may be wrong): you haven't told us which channel is which, but given PWM1 on normal output is high when CNT is below CCR, pwm2 is the normal output (TIM15_CH1) and pwm1 is the inverted one (TIM15_CH1N).

After the number of pulses programmed in RCR (plus one) is output, in one-pulse mode, TIM15_CR1.CEN is cleared by hardware, but that's it, nothing else happens, i.e. the outputs remain enabled (including TIM15_BDTR.MOE). As TIM15_CNT is then 0, the normal output stays high and the inverted low, actively driven (i.e. not high-Z).

Then you call

HAL_TIM_PWM_Start

(). That basically does three things:

  /* Enable the Capture compare channel */

  TIM_CCxChannelCmd(htim->Instance, Channel, TIM_CCx_ENABLE);

  if(IS_TIM_ADVANCED_INSTANCE(htim->Instance) != RESET)  

  {

    /* Enable the main output */

    __HAL_TIM_MOE_ENABLE(htim);

  }

  /* Enable the Peripheral */

  __HAL_TIM_ENABLE(htim);

The last one is setting TIM15_CR1.CEN, which is the only thing really needed here,  so that's OK. The thing before that, setting BDCR.MOE, is superfluous at this moment, as MOE remained set; but harmless. The first one is the culprit. Let's have a look at it:

void TIM_CCxChannelCmd(TIM_TypeDef* TIMx, uint32_t Channel, uint32_t ChannelState)

{

  uint32_t tmp = 0U;

  /* Check the parameters */

  assert_param(IS_TIM_CC1_INSTANCE(TIMx));

  assert_param(IS_TIM_CHANNELS(Channel));

  tmp = TIM_CCER_CC1E << Channel;

  /* Reset the CCxE Bit */

  TIMx->CCER &= ~tmp;

  /* Set or reset the CCxE Bit */

  TIMx->CCER |= (uint32_t)(ChannelState << Channel);

}

So it unconditionally clears the respective enable bit for the channel, and then - as called with the appropriate constant for enable - reenables it.

That causes the normal channel to go High-Z briefly - would there be any significant pulldown on that pin, you'd see a 'negative glitch' on it. But, what's more important here, the complementary output CH1N in the STM32 timers has a tricky property: when the normal output is disabled, it stops to be complementary (i.e. inverted to the normal output) and takes the polarity of the normal output. That causes that actively driven glitch.

JW

View solution in original post

3 REPLIES 3
Posted on April 23, 2018 at 23:43

I guess the code is quite naïve

If you call 'relying on some other unknown code' naive, then yes...

know of a couple of application notes, e.g. 'AN4013 STM32 cross-series timer overview' and 'AN4776 - General purpose timer cookbook', but they take some time to digest,

Then take that time. And start with the timer chapter in RM (don't start with the advanced timers, even if that's what you are using here, as digesting them may be a bit harder than you want at the start). They are badly written, so take your time, re-read them, and experiment.

There ain't any silver bullet in embedded programming, just lots of snake oil.

JW

Posted on April 24, 2018 at 01:49

Here is what I think has happened (I don't have the 'F3 Cube, this is based on some random version of 'F4 Cube, so I may be wrong): you haven't told us which channel is which, but given PWM1 on normal output is high when CNT is below CCR, pwm2 is the normal output (TIM15_CH1) and pwm1 is the inverted one (TIM15_CH1N).

After the number of pulses programmed in RCR (plus one) is output, in one-pulse mode, TIM15_CR1.CEN is cleared by hardware, but that's it, nothing else happens, i.e. the outputs remain enabled (including TIM15_BDTR.MOE). As TIM15_CNT is then 0, the normal output stays high and the inverted low, actively driven (i.e. not high-Z).

Then you call

HAL_TIM_PWM_Start

(). That basically does three things:

  /* Enable the Capture compare channel */

  TIM_CCxChannelCmd(htim->Instance, Channel, TIM_CCx_ENABLE);

  if(IS_TIM_ADVANCED_INSTANCE(htim->Instance) != RESET)  

  {

    /* Enable the main output */

    __HAL_TIM_MOE_ENABLE(htim);

  }

  /* Enable the Peripheral */

  __HAL_TIM_ENABLE(htim);

The last one is setting TIM15_CR1.CEN, which is the only thing really needed here,  so that's OK. The thing before that, setting BDCR.MOE, is superfluous at this moment, as MOE remained set; but harmless. The first one is the culprit. Let's have a look at it:

void TIM_CCxChannelCmd(TIM_TypeDef* TIMx, uint32_t Channel, uint32_t ChannelState)

{

  uint32_t tmp = 0U;

  /* Check the parameters */

  assert_param(IS_TIM_CC1_INSTANCE(TIMx));

  assert_param(IS_TIM_CHANNELS(Channel));

  tmp = TIM_CCER_CC1E << Channel;

  /* Reset the CCxE Bit */

  TIMx->CCER &= ~tmp;

  /* Set or reset the CCxE Bit */

  TIMx->CCER |= (uint32_t)(ChannelState << Channel);

}

So it unconditionally clears the respective enable bit for the channel, and then - as called with the appropriate constant for enable - reenables it.

That causes the normal channel to go High-Z briefly - would there be any significant pulldown on that pin, you'd see a 'negative glitch' on it. But, what's more important here, the complementary output CH1N in the STM32 timers has a tricky property: when the normal output is disabled, it stops to be complementary (i.e. inverted to the normal output) and takes the polarity of the normal output. That causes that actively driven glitch.

JW

Shreekant Tembhekar
Associate II

Use below code,

if (HAL_GPIO_ReadPin(GPIOA, bluePB_Pin) == GPIO_PIN_SET)

{

HAL_Delay(200);

HAL_TIM_PWM_Start(&htim15, TIM_CHANNEL_1);

HAL_TIMEx_PWMN_Start(&htim15, TIM_CHANNEL_1);

HAL_Delay(500);

TIM15->CCER = 0; //This is added to avoid glitch.

HAL_TIM_PWM_Start(&htim15, TIM_CHANNEL_1);

}