想使用STM32G474VET6的TIM1(高级定时器)作为PWM输出控制三相电机,希望使用互补带死区功能CH1,CH1N,CH2,CH2N,CH3,CH3N。参考官方Demo和CubeMx,使用以下代码生成PWM
TIM_HandleTypeDef htim1;
void InitTimer1(void){
TIM_OC_InitTypeDef sConfigOC = {0};
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
__HAL_RCC_TIM1_CLK_ENABLE();
htim1.Instance = TIM1;
htim1.Init.Prescaler = 0;
htim1.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED2;
htim1.Init.Period = 4249; //170MHz / 20KHz / 2 - 1
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
htim1.Init.RepetitionCounter = 0;
HAL_TIM_PWM_Init(&htim1);
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig);
//TODO
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig);
sConfigOC.OCMode = TIM_OCMODE_PWM1; //CCMR1_OCxM
sConfigOC.Pulse = 300;
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;
HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1);
HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2);
HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_3);
__HAL_TIM_ENABLE_OCxPRELOAD(&htim1, TIM_CHANNEL_1);
__HAL_TIM_ENABLE_OCxPRELOAD(&htim1, TIM_CHANNEL_2);
__HAL_TIM_ENABLE_OCxPRELOAD(&htim1, TIM_CHANNEL_3);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3);
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_3);
LL_TIM_GenerateEvent_UPDATE(TIM1);
}
static void SetSysClockTo170_HSE8(void){
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1_BOOST);
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV2;
RCC_OscInitStruct.PLL.PLLN = 85; //8-127
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV16;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV6;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK){
while(1);
}
/*The maximum frequency of the AHB, the APB1 and the APB2 domains is 170 MHz.*/
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK){
while(1);
}
}
int main(void){
HAL_Init();
SetSysClockTo170_HSE8();
InitGpio();
InitTimer1();
//InitTimer1_LL();
while(1){
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
HAL_Delay(250);
}
return 0;
}
void InitGpio(void){
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; //推挽
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
//LED Red-PE0 Green-PE1
GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; //推挽
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
//upper bridge arm U-PA8 V-PA9 W-PA10
GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; //复用推挽
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF6_TIM1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
//lower bridge arm U-PB13 V-PB14
GPIO_InitStruct.Pin = GPIO_PIN_13 | GPIO_PIN_14;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; //复用推挽
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF6_TIM1;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
//lower bridge arm W-PB15
GPIO_InitStruct.Pin = GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; //复用推挽
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF4_TIM1;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
经过测试,发现在使能输出以后,正脉冲宽度会有波动,在示波器上可以看出明显余晖,如下图所示,按照代码设计,PWM频率应为20KHz,占空比约为7.06%,正脉冲宽度约为3.529us,大部分波形符合预期。

小部分波形脉冲宽度仅为3.375us,缩小画面后发现波形异常时PWM频率为20.06KHz


使用示波器脉冲宽度小于阈值触发多个波形可以发现,正常波形占大多数,异常波形不会连续出现(下图图片上方白色倒三角为搜索正脉冲宽度小于3.4us的波形所在位置)

通过查阅手册以及在开发板上测试,发现仅开启一组互补输出时,不会发生该现象,如仅开启CH1,CH1N;开启两组及两组以上互补输出时,会发生该现象;计数器使用上升或下降模式(边沿)计数时,不会发生该现象;使用上下模式(中心对称)计数时会产生此现象。
已尝试的方法还有
1、使用LL库
2、修改HAL库,修改外设使能顺序,MOE,UG寄存器使能顺序
3、去掉死区
以上方法均不能解决该问题,请求各位帮助👀️
不过板子上用的是24MHZ 晶振。
昨晚我看见您的回复以后,连夜又贴了两块板子。今早测试发现确实是MCU的问题。十分感谢您的测试,截图和回复🎉️