2019-04-04 10:53 AM
I want to generate bursts of complimetary PWM to drive a half bridge. I have the PWM working fine, with deatime etc... but when I call:
HAL_TIM_PWM_Stop(&htim1,TIM_CHANNEL_1);
HAL_TIMEx_PWMN_Stop(&htim1,TIM_CHANNEL_1);
Rather than stopping to a defined state, it goes to (I think) reset state and drifts down to 0V. I want it to pull both lines LOW when I stop the PWM, so that the Half-Bridge goes to floating.
Timer init code is:
static void MX_TIM1_Init(void)
{
TIM_MasterConfigTypeDef sMasterConfig;
TIM_OC_InitTypeDef sConfigOC;
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig;
htim1.Instance = TIM1;
htim1.Init.Prescaler = 0;
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = 256;
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.RepetitionCounter = 0;
htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 500;
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(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sConfigOC.Pulse = 0;
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
sBreakDeadTimeConfig.DeadTime = 5;
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_LOW;
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
HAL_TIM_MspPostInit(&htim1);
}
2019-04-04 11:37 AM
How about turn the output as output GPIO with low level?
Or short the output with another GPIO which is open drain and force a low level whenever needed?
2019-04-04 12:16 PM
These would both potentially work, but turning the output to GPIO involves resetting all the pinstates and re-running the init funcitons (slow, tedious...surely there's a better way?)
Shorting the output with a GPIO 1) uses extra GPIO and 2) 1 messup and your chip is dead.
On the Atmel chips (for example) there is a bitmask where you can just write enable alternative function and otherwise it just goes to the state as if the timer was not running PWM.
I tried initialising the pins as GPIO and writing low before initialising the timer, but no luck. As soon as you init the timer PWM, the old GPIO init is essentially dead...
2019-04-04 12:27 PM
De-initialising the timer is also not an option, I need to keep the other channels running PWM.
2019-04-04 12:57 PM
> On the Atmel chips (for example) there is a bitmask where you can just write enable alternative function and otherwise it just goes to the state as if the timer was not running PWM.
It's the same in STM32, if you ditch Cube and read the reference manual (GPIOx_MODER).
JW
2019-04-04 02:02 PM
OK,
So, init()ing as GPIO, then writing GPIO on PA7 and 8 low... Then init()ing timer, then in while(1) loop I put:
HAL_Delay(1);
GPIOA->MODER &= ~0b00000000000000111100000000000000;
GPIOA->MODER |= 0b00000000000000010100000000000000;
HAL_Delay(1);
GPIOA->MODER &= ~0b00000000000000010100000000000000;
GPIOA->MODER |= 0b00000000000000101000000000000000;
I get the desired effect. I think this should scale to the other GPIOs/timer channels.
Cheers Jan!