cancel
Showing results for 
Search instead for 
Did you mean: 

Push Pull PWM

allanoverst
Associate II

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,

allanoverst_0-1762377988597.png

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.

PWM PA0 and PA1.png

Channel 1 (Yellow) is PA0 and Channel 2 (Green) is PA1.

Does anyone have any suggestions on how to get PA1 working?

Thanks,

Allan

3 REPLIES 3
gbm
Principal

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.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice
allanoverst
Associate II

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

TDK
Super User

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).

If you feel a post has answered your question, please click "Accept as Solution".