cancel
Showing results for 
Search instead for 
Did you mean: 

Identical PWM output setting behave differently on General and Advanced timer at duty 0

filvas
Associate II

Hi!
The PWM signals are identical and work as  normal except when HAL_TIM_PWM_Stop (or HAL_TIM_PWM_Start) is called at duty 0. The Advanced timer work as expected and cause the output PWM to go low, while both PWM signals go low for the General timer.


I've tried reading the RM0440 Reference manual sections "28 Advanced-control timers (TIM1/TIM8/TIM20)" and "30 General purpose timers (TIM15/TIM16/TIM17)", but has found no clear cause of this.

Below are both my configurations and Oscilloskop output for both control signals and output PWM
Advacned timerTIM8 configuration

__HAL_RCC_TIM8_CLK_ENABLE();

htim8.Instance = TIM8;
htim8.Init.Prescaler = PRESCALER_VALUE;
htim8.Init.CounterMode = TIM_COUNTERMODE_UP;
htim8.Init.Period = HAL_PWM_DEFAULT_PERIOD;
htim8.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim8.Init.RepetitionCounter = 0;
htim8.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
TIM8->AF2 = 0;
if (HAL_TIM_PWM_Init(&htim8) != HAL_OK)
{
// Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim8, &sMasterConfig)
!= HAL_OK)
{
// Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
if (HAL_TIM_PWM_ConfigChannel(&htim8, &sConfigOC, TIM_CHANNEL_1)
!= HAL_OK)
{
// Error_Handler();
}

sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
sBreakDeadTimeConfig.DeadTime = 0xff;
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
sBreakDeadTimeConfig.BreakFilter = 0;
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
if (HAL_TIMEx_ConfigBreakDeadTime(&htim8, &sBreakDeadTimeConfig)
!= HAL_OK)
{
// Error_Handler();
}

__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
/**TIM8 GPIO Configuration
PC10 ------> TIM8_CH1N PWM_5_CPU
PA15 ------> TIM8_CH1 PWM_6_CPU
*/
HAL_PWM_TIM8_GPIO_ReInit_PWM(FALSE);
HAL_PWM_TIM8_GPIO_ReInit_PWMN(FALSE);

/* Special handling, always keep PWM running, just enable/disable output pin */
HAL_TIM_PWM_Start(&htim8, TIM_CHANNEL_1);
HAL_TIMEx_PWMN_Start(&htim8, TIM_CHANNEL_1);

General timer TIM15 configuration:

__HAL_RCC_TIM15_CLK_ENABLE();

htim15.Instance = TIM15;
htim15.Init.Prescaler = PRESCALER_VALUE;
htim15.Init.Period = HAL_PWM_DEFAULT_PERIOD;
htim15.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim15.Init.RepetitionCounter = 0;
htim15.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_PWM_Init(&htim15) != HAL_OK)
{
// Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim15, &sMasterConfig)
!= HAL_OK)
{
// Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0;
/* Use HIGH polarity, different from TIM8 due to the fact that 1 and 1N are swapped for TIM8 vs TIM15:
PC10 ------> TIM8_CH1N PWM_5_CPU
PA15 ------> TIM8_CH1 PWM_6_CPU

PB14 ------> TIM15_CH1 PWM_7_CPU
PB15 ------> TIM15_CH1N PWM_8_CPU
*/
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
if (HAL_TIM_PWM_ConfigChannel(&htim15, &sConfigOC, TIM_CHANNEL_1)
!= HAL_OK)
{
// Error_Handler();
}
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
sBreakDeadTimeConfig.DeadTime = 0xFF;
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
sBreakDeadTimeConfig.BreakFilter = 0;
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
if (HAL_TIMEx_ConfigBreakDeadTime(&htim15, &sBreakDeadTimeConfig)
!= HAL_OK)
{
// Error_Handler();
}
__HAL_RCC_GPIOB_CLK_ENABLE();
/**TIM15 GPIO Configuration
PB14 ------> TIM15_CH1 PWM_7_CPU
PB15 ------> TIM15_CH1N PWM_8_CPU
*/
HAL_PWM_TIM15_GPIO_ReInit_PWM(FALSE);
HAL_PWM_TIM15_GPIO_ReInit_PWMN(FALSE);

/* Special handling, always keep PWM running, just enable/disable output pin */
HAL_TIM_PWM_Start(&htim15, TIM_CHANNEL_1);
HAL_TIMEx_PWMN_Start(&htim15, TIM_CHANNEL_1);

This is both PWM signals at 50% duty, and work as intended

Media.jpg
This is the Advanced timer at 0% duty, and as expected the output is now 0 with 1 signals hight and 1 low

filvas_1-1725870069184.jpeg

This is the General timer at duty 0%

filvas_2-1725870118266.jpeg

1 ACCEPTED SOLUTION

Accepted Solutions
filvas
Associate II

After much further examination, I have concluded that controlling the PB15 (Green) signal manually at duty zero instead will be easier, as I still have not figured out why the timers work differently after many days.

View solution in original post

6 REPLIES 6

On those pictures, green and blue are the two complementary outputs, correct? And what is the purple one?

Read out and compare/post TIM registers content for the two timers (and perhaps also the relevant GPIO registers content).

JW

LCE
Principal

Maybe try another value for idle mode(s):

/** @defgroup TIM_Output_Compare_Idle_State TIM Output Compare Idle State
  * @{
  */
#define TIM_OCIDLESTATE_SET                TIM_CR2_OIS1                         /*!< Output Idle state: OCx=1 when MOE=0 */
#define TIM_OCIDLESTATE_RESET              0x00000000U                          /*!< Output Idle state: OCx=0 when MOE=0 */
/**
  * @}
  */

/** @defgroup TIM_Output_Compare_N_Idle_State TIM Complementary Output Compare Idle State
  * @{
  */
#define TIM_OCNIDLESTATE_SET               TIM_CR2_OIS1N                        /*!< Complementary output Idle state: OCxN=1 when MOE=0 */
#define TIM_OCNIDLESTATE_RESET             0x00000000U                          /*!< Complementary output Idle state: OCxN=0 when MOE=0 */
/**
  * @}
  */

 

The purple one is an output controlled by the two complementary outputs depending on their duty.

Thanks.

I was more interested in the registers content, though.

JW

filvas
Associate II

After much further examination, I have concluded that controlling the PB15 (Green) signal manually at duty zero instead will be easier, as I still have not figured out why the timers work differently after many days.

That is not a solution (remove that mark). Its a different approach. Also you still might have a problem, that will come back one day and haunt you!