2025-11-05 1:38 PM
Hello ST,
I am having some trouble generating two PWM signals for a push pull converter.
Ideally I would like the PWM outputs to look like this,
I would like the PWM frequency to be 100kHz and a duty cycle range of 0% to 50%.
I have connected the push pull converter to PA0 and PA1.
First I configure the GPIO Pins,
void MX_PWM_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* Enable clocks */
__HAL_RCC_TIM2_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/* Configure PA0 for TIM2_CH1 */
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF2_TIM5; //CH1
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* Enable clocks */
__HAL_RCC_TIM5_CLK_ENABLE();
/* Configure PA1 for TIM5_CH2
* NOTE: Using CH2 on PA1 to avoid conflict with TIM2_CH1 on PA0
* You can use different pins if needed
*/
GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF1_TIM2; //CH2
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_Delay(10);
}Then I configure TIM2 and TIM5.
//TIM5 -> MASTER CONFIG
//TIM5 CH1 -> PA0
void MX_TIM5_Init_PushPull(void)
{
TIM_OC_InitTypeDef sConfigOC = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
/* Timer base configuration */
htim5.Instance = TIM5;
htim5.Init.Prescaler = 0; // 84 MHz (no prescaling)
htim5.Init.CounterMode = TIM_COUNTERMODE_UP;
htim5.Init.Period = 1679; // 84 MHz / 840 = 100 kHz
htim5.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim5.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
if (HAL_TIM_PWM_Init(&htim5) != HAL_OK)
{
PWM_Error_Handler();
}
/* Configure TIM2 as Master (to trigger TIM5) */
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim5, &sMasterConfig) != HAL_OK)
{
PWM_Error_Handler();
}
/* PWM Channel 1 configuration - 25% duty cycle */
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 420; // 25% of 840 = 210
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim5, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
{
PWM_Error_Handler();
}
/* Enable output compare preload */
TIM5->CCMR1 |= TIM_CCMR1_OC1PE;
}//TIM2 -> SLAVE CONFIG
//TIM2 CH2 -> PA1
void MX_TIM2_Init_PushPull(void)
{
TIM_OC_InitTypeDef sConfigOC = {0};
TIM_SlaveConfigTypeDef sSlaveConfig = {0};
/* Timer base configuration */
htim2.Instance = TIM2;
htim2.Init.Prescaler = 0; // 84 MHz (no prescaling)
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 1679; // Same as TIM2 = 100 kHz
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
if (HAL_TIM_PWM_Init(&htim2) != HAL_OK)
{
PWM_Error_Handler();
}
/* PWM Channel 1 configuration - 25% duty cycle */
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 420; // 25% of 840 = 210
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
{
PWM_Error_Handler();
}
/* Configure TIM5 as Slave (synchronized to TIM2) */
sSlaveConfig.SlaveMode = TIM_SLAVEMODE_TRIGGER;
sSlaveConfig.InputTrigger = TIM_TS_ITR2; // TIM2 is ITR1 for TIM5
if (HAL_TIM_SlaveConfigSynchronization(&htim2, &sSlaveConfig) != HAL_OK)
{
PWM_Error_Handler();
}
//Enable output compare preload for CH2 */
TIM2->CCMR1 |= TIM_CCMR1_OC2PE;
}Then I tell the timers to start,
void PushPull_Start(void)
{
//0. Offset TIM2 CH2 - SLAVE.
__HAL_TIM_SET_COUNTER(&htim2, 420);
//1. TIM5 CH1 - MASTER
HAL_TIM_PWM_Start(&htim5, TIM_CHANNEL_1);
//2. TIM2 CH2 - SLAVE
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
}main() is here,
int main(void)
{
//Vars
eMBErrorCode eStatus;
//0. Initialize HAL
HAL_Init();
//1. System Clock Config
SystemClock_Config();
MX_UART1_GPIO();
MX_USART1_UART_Init();
//2. GPIO Config
//a. UART
MX_GPIO_Init();
HAL_Delay(10);
//b. PWM
MX_PWM_GPIO_Init();
MX_TIM5_Init_PushPull();
MX_TIM2_Init_PushPull();
HAL_Delay(10);
PushPull_Start();
return 0;
}The problem I am having is with PA1. I am not getting a signal.
Channel 1 (Yellow) is PA0 and Channel 2 (Green) is PA1.
Does anyone have any suggestions on how to get PA1 working?
Thanks,
Allan
2025-11-05 1:44 PM
I believe what you need to do is to configure complementary output from a single PWN channel with dead time. You need to use TIMxCHy and TIMxCHyN outputs. TIM1, 8, 15, 16, 17 may be used for that purpose.
2025-11-05 1:49 PM
Hi gbm,
I thought of using TIM1, but the resolution is not high enough for my application. I needed a 32 bit resolution which is why I am using TIM2 and TIM5.
Thanks,
Allan
2025-11-05 2:22 PM
ARR is preloaded. Generate an update event on each timer after ARR is set and before you start them. Or wait until 2^32 ticks happen (25sec).