Skip to main content
Visitor II
September 9, 2024
Solved

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

  • September 9, 2024
  • 4 replies
  • 1732 views

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

    This topic has been closed for replies.
    Best answer by filvas

    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.

    4 replies

    Super User
    September 9, 2024

    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

    filvasAuthor
    Visitor II
    September 9, 2024

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

    Graduate II
    September 9, 2024

    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 */
    /**
     * @}
     */

     

    Super User
    September 9, 2024

    Thanks.

    I was more interested in the registers content, though.

    JW

    filvasAuthorAnswer
    Visitor II
    September 16, 2024

    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.

    Graduate
    September 16, 2024

    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!