cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 Timer PWM mode, strange behaviour

benjamin Gräf
Associate II

Hello!

I am using a STM32F303 MCU. I am generating a complementary PWM signal with a dead time. During operation I am changing the dutycycle of the PWM. I noticed a very strange behaviour. As soon as the counter value reaches the compare value, the output of the timer pin is changed. This is normal, but sometimes (when i recompile my program and download it to the MCU) the PWM signal is inverted, meaning that the ON time is now the OFF time. So instead of a dutycycle of e.g. 30% I get a dutycycle of 70%. Anyone an Idea what could be the cause of that? I do not change anything in the timer setup when I recompile. I am using CubeMX and HAL.

Here my timer configuration.

TIM_MasterConfigTypeDef sMasterConfig;

 TIM_OC_InitTypeDef sConfigOC;

 TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig;

 htim20.Instance = TIM20;

 htim20.Init.Prescaler = 0;

 htim20.Init.CounterMode = TIM_COUNTERMODE_UP;

 htim20.Init.Period = 360;

 htim20.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;

 htim20.Init.RepetitionCounter = 0;

 htim20.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;

 if (HAL_TIM_PWM_Init(&htim20) != HAL_OK)

 {

  _Error_Handler(__FILE__, __LINE__);

 }

 sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;

 sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;

 sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;

 if (HAL_TIMEx_MasterConfigSynchronization(&htim20, &sMasterConfig) != HAL_OK)

 {

  _Error_Handler(__FILE__, __LINE__);

 }

 sConfigOC.OCMode = TIM_OCMODE_PWM1;

 sConfigOC.Pulse = 150;

 sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;

 sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;

 sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;

 sConfigOC.OCIdleState = TIM_OCIDLESTATE_SET;

 sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;

 if (HAL_TIM_PWM_ConfigChannel(&htim20, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)

 {

  _Error_Handler(__FILE__, __LINE__);

 }

 if (HAL_TIM_PWM_ConfigChannel(&htim20, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)

 {

  _Error_Handler(__FILE__, __LINE__);

 }

 sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;

 sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;

 sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;

 sBreakDeadTimeConfig.DeadTime = 10;

 sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;

 sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;

 sBreakDeadTimeConfig.BreakFilter = 0;

 sBreakDeadTimeConfig.Break2State = TIM_BREAK2_DISABLE;

 sBreakDeadTimeConfig.Break2Polarity = TIM_BREAK2POLARITY_HIGH;

 sBreakDeadTimeConfig.Break2Filter = 0;

 sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;

 if (HAL_TIMEx_ConfigBreakDeadTime(&htim20, &sBreakDeadTimeConfig) != HAL_OK)

 {

  _Error_Handler(__FILE__, __LINE__);

 }

 HAL_TIM_MspPostInit(&htim20);

}

Here I start the PWM output:

//Start the pwm output

HAL_TIM_PWM_Start(&htim20, TIM_CHANNEL_1);

HAL_TIM_PWM_Start(&htim20, TIM_CHANNEL_2);

//Start the pwm complementary output

HAL_TIMEx_PWMN_Start(&htim20, TIM_CHANNEL_1);

HAL_TIMEx_PWMN_Start(&htim20, TIM_CHANNEL_2);

and thats how I change my dutycycle:

__HAL_TIM_SET_COMPARE(&htim20, TIM_CHANNEL_2, BC1_dutycycle);

__HAL_TIM_SET_COMPARE(&htim20, TIM_CHANNEL_1, TIM_DUTYCYCLE_MAX);

Best regards, Benjamin

EDIT:

I am shutting down the output of the PWM signal (with HAL_TIM_PWM_Stop(&htim20, TIM_CHANNEL_2); , then this behavour is occuring). How can i just set the main output of the PWM to 0 but the complementary one should still switch?

6 REPLIES 6

> Anyone an Idea what could be the cause of that?

Some uninitialized struct field?

Read out the timer registers in the "normal" and "inverted" state and compare them; focus on CCER and CCMR.

> I am shutting down the output of the PWM signal (with HAL_TIM_PWM_Stop(&htim20,

> TIM_CHANNEL_2); , then this behavour is occuring). How can i just set the main output of the PWM to 0

> but the complementary one should still switch?

Change the given pin from AF to Output in respective GPIOx_MODER.

You could disable it by clearing respective TIMx_CCER.CCxE, but you'd also need to change the polarity of the complementary pin e.g. by flipping TIMx_CCER.CCxNP; and the result would be a threestated pin rather than actively pulled to 0 (unless TIMx_BDTR.OSSR is set).

I don't Cube.

JW

Thanks for your answere I will check them later this week. I just found in the reference manual this section:

Forced output mode

In output mode (CCxS bits = 00 in the TIMx_CCMRx register), each output compare signal (OCxREF and then OCx/OCxN) can be forced to active or inactive level directly by software, independently of any comparison between the output compare register and the counter. To force an output compare signal (OCXREF/OCx) to its active level, you just need to write 101 in the OCxM bits in the corresponding TIMx_CCMRx register. Thus OCXREF is forced high (OCxREF is always active high) and OCx get opposite value to CCxP polarity bit. For example: CCxP=0 (OCx active high) => OCx is forced to high level. The OCxREF signal can be forced low by writing the OCxM bits to 100 in the TIMx_CCMRx register. Anyway, the comparison between the TIMx_CCRx shadow register and the counter is still performed and allows the flag to be set. Interrupt and DMA requests can be sent accordingly. This is described in the output compare mode section below.

Does this also work in complementary PWM mode? I cannot find anything regarding my problem in the reference manual besides this.

The OCxRef signal is the output from the PWM generation unit. It is then split into two channels, one direct and one inverted. In other words, if you Force a level onto OCxRef, both outputs will stop, in mutually inverted state.

JW

hmm ok thanks. So is there no way to force a output to just one channel without influencing the other one?

best regards, Benjamin.

But I told you above, how to do it: the easiest way to do it is to change the pin you want to "force" from AF to output in GPIO (in GPIO_MODER register, and of course setting the required level in GPIO_ODR).

Another option is also to clear the respective enable bit in TIMx_CCER, but the fact that disabling the "straight" output changes the "complementary" output to "straight", may come as a surprise (not that it can't be handled by the polarity bits, but one has to be aware of this fact).

It's just the Forced mode in TIMx_CCMR.CCxS which can't be used for this purpose.

JW

Thanks, I just cleared the TIM enable bit (Thats what I also tryed before) and also set the according polarity bit of the complementary output to 1. This worked 🙂

Best regards, Benjamin.