I am trying to control three phase BLDC with STM32F030C8T6 using Hall sensors and dead time.I am trying to enable non-inverted pwm and complementary pwm for the motor based on hal signals.
void set_phase(uint8_t hall)
{
// Turn off all channels first
// __HAL_TIM_MOE_DISABLE(&htim1);
TIM1->CCER &= ~(TIM_CCER_CC1E | TIM_CCER_CC1NE |
TIM_CCER_CC2E | TIM_CCER_CC2NE |
TIM_CCER_CC3E | TIM_CCER_CC3NE);
switch(hall)
{
case 0b001: // C+, B-
TIM1->CCER = TIM_CCER_CC3E | TIM_CCER_CC2NE;
break;
case 0b101: // A+, B-
TIM1->CCER = TIM_CCER_CC1E | TIM_CCER_CC2NE;
break;
case 0b100: // A+, C-
TIM1->CCER = TIM_CCER_CC1E | TIM_CCER_CC3NE;
break;
case 0b110: // B+, C-
TIM1->CCER = TIM_CCER_CC2E | TIM_CCER_CC3NE;
break;
case 0b010: // B+, A-
TIM1->CCER = TIM_CCER_CC2E | TIM_CCER_CC1NE;
break;
case 0b011: // C+, A-
TIM1->CCER = TIM_CCER_CC3E | TIM_CCER_CC1NE;
break;
default:
TIM1->CCER = 0; // Brake
break;
}
__HAL_TIM_MOE_ENABLE(&htim1); // Re-enable outputs
}
I pass hall output to this function that will enable the respective high and low side for each phase. What happens is that as this function runs the high (non-inverted) and low side (inverted)(inverted signal becomes non-inverted) pwm signals become exactly the same (80% duty and similar frequency) and short igbts.
Following is my TIM1 initialization:
static void MX_TIM1_Init(void)
{
/* USER CODE BEGIN TIM1_Init 0 */
/* USER CODE END TIM1_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
/* USER CODE BEGIN TIM1_Init 1 */
/* USER CODE END TIM1_Init 1 */
htim1.Instance = TIM1;
htim1.Init.Prescaler = 0;
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = 65535;
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.RepetitionCounter = 0;
htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 32767;
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();
}
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
{
Error_Handler();
}
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
sBreakDeadTimeConfig.DeadTime = 255;
sBreakDeadTimeConfig.BreakState = TIM_BREAK_ENABLE;
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_ENABLE;
if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM1_Init 2 */
/* USER CODE END TIM1_Init 2 */
HAL_TIM_MspPostInit(&htim1);
}
The expected waveform is one channel high with 80% duty and the other channel is its complementary with almsot 20% duty.
This is how the complementary outputs work: once their "straight" counterpart gets disabled, they stop inverting.
This feature is well documented in RM, e.g. in the Output control bits for complementary OCx and OCxN channels with break feature table. If desired, the waveform can be easily inverted using the respective TIMx_CCER.CCxNP bit.