1.概述
小华HC32F448系列MCU带有一个高级控制定时器 6(Timer6)外设,它是一个 16 位计数宽度的高性能定时器,能在各种复杂应用场景中提供丰富、灵活的搭配组合和各种中断、事件、 PWM 输出。该定时器支持锯齿波和三角波两种波形模式,可生成各种 PWM 波形(单边对齐独立 PWM、双边对称独立 PWM、双边对称互补 PWM、双边非对称 PWM等);单元间可实现软件同步和硬件同步(同步启动、停止、清零、刷新等);各基准值寄存器支持缓存功能(单级缓存和双级缓存);支持脉宽测量和周期测量;支持 2 相正交编码计数和 3 相正交编码计数;支持 EMB 控制。
2.功能框图
3.例程功能
3.1.我们参考官方的示例程序,结合EV_F448_LQ80_Rev1.0开发板,通过TIMER6的PWM三角波模式,通过单缓存输出占空比动态配置的功能
3.2.示例程序
#define EXAMPLE_PERIPH_WE (LL_PERIPH_GPIO | LL_PERIPH_EFM | LL_PERIPH_FCG | LL_PERIPH_PWC_CLK_RMU | LL_PERIPH_SRAM)
#define EXAMPLE_PERIPH_WP (LL_PERIPH_EFM | LL_PERIPH_FCG | LL_PERIPH_SRAM)
#define TMR6_1_PWMA_PORT (GPIO_PORT_A)
#define TMR6_1_PWMA_PIN (GPIO_PIN_08)
#define TMR6_1_PWMA_FUNC (GPIO_FUNC_3)
#define TMR6_1_PWMB_PORT (GPIO_PORT_A)
#define TMR6_1_PWMB_PIN (GPIO_PIN_07)
#define TMR6_1_PWMB_FUNC (GPIO_FUNC_3)
#define PWM_PERIODVALUE (3125U)
static uint8_t u8Duty_pos = 1U;
static uint16_t au16Cmp_buf[] = {PWM_PERIODVALUE/10, PWM_PERIODVALUE/10, 0, PWM_PERIODVALUE/10, PWM_PERIODVALUE/10, PWM_PERIODVALUE};
static void Duty_Set(CM_TMR6_TypeDef *TMR6x, uint32_t u32Index, uint16_t cmp_value)
{
if (TMR6_GetCompareValue(TMR6x, u32Index) != cmp_value) {
TMR6_SetCompareValue(TMR6x, u32Index, cmp_value);
if (cmp_value == 0U) {
if (u32Index % 2U) {
TMR6_PWM_SetPolarity(TMR6x, TMR6_CH_B, TMR6_STAT_DOWN_CNT_MATCH_B, TMR6_PWM_HOLD);
} else {
TMR6_PWM_SetPolarity(TMR6x, TMR6_CH_A, TMR6_STAT_DOWN_CNT_MATCH_A, TMR6_PWM_HOLD);
}
} else if (cmp_value == PWM_PERIODVALUE) {
if (u32Index % 2U) {
TMR6_PWM_SetPolarity(TMR6x, TMR6_CH_B, TMR6_STAT_OVF, TMR6_PWM_INVT);
} else {
TMR6_PWM_SetPolarity(TMR6x, TMR6_CH_A, TMR6_STAT_OVF, TMR6_PWM_INVT);
}
} else {
if (u32Index % 2U) {
TMR6_PWM_SetPolarity(TMR6x, TMR6_CH_B, TMR6_STAT_OVF, TMR6_PWM_HOLD);
TMR6_PWM_SetPolarity(TMR6x, TMR6_CH_B, TMR6_STAT_DOWN_CNT_MATCH_B, TMR6_PWM_HIGH);
} else {
TMR6_PWM_SetPolarity(TMR6x, TMR6_CH_A, TMR6_STAT_OVF, TMR6_PWM_HOLD);
TMR6_PWM_SetPolarity(TMR6x, TMR6_CH_A, TMR6_STAT_DOWN_CNT_MATCH_A, TMR6_PWM_HIGH);
}
}
}
}
static void Tmr6_UnderFlow_CallBack(void)
{
TMR6_ClearStatus(CM_TMR6_1, TMR6_FLAG_UDF);
Duty_Set(CM_TMR6_1, TMR6_CMP_REG_C, au16Cmp_buf[u8Duty_pos]);
Duty_Set(CM_TMR6_1, TMR6_CMP_REG_D, au16Cmp_buf[u8Duty_pos]);
if (++u8Duty_pos >= sizeof(au16Cmp_buf)/sizeof(au16Cmp_buf[0])) {
u8Duty_pos = 0;
}
}
int32_t main(void)
{
stc_tmr6_init_t stcTmr6Init;
stc_tmr6_pwm_init_t stcPwmInit;
stc_irq_signin_config_t stcIrqRegiConf;
stc_tmr6_buf_config_t stcBufConfig;
/* Unlock peripherals or registers */
LL_PERIPH_WE(EXAMPLE_PERIPH_WE);
/* Configure BSP */
BSP_CLK_Init();
(void)TMR6_StructInit(&stcTmr6Init);
(void)TMR6_PWM_StructInit(&stcPwmInit);
(void)TMR6_BufFuncStructInit(&stcBufConfig);
FCG_Fcg2PeriphClockCmd(FCG2_PERIPH_TMR6_1, ENABLE);
/* Timer6 PWM output port configuration */
GPIO_SetFunc(TMR6_1_PWMA_PORT, TMR6_1_PWMA_PIN, TMR6_1_PWMA_FUNC);
GPIO_SetFunc(TMR6_1_PWMB_PORT, TMR6_1_PWMB_PIN, TMR6_1_PWMB_FUNC);
TMR6_DeInit(CM_TMR6_1);
/* Timer6 general count function configuration */
stcTmr6Init.sw_count.u32CountMode = TMR6_MD_TRIANGLE;
stcTmr6Init.sw_count.u32ClockDiv = TMR6_CLK_DIV32;
stcTmr6Init.u32PeriodValue = PWM_PERIODVALUE;
(void)TMR6_Init(CM_TMR6_1, &stcTmr6Init);
/* General compare buffer function configure */
stcBufConfig.u32BufNum = TMR6_BUF_SINGLE;
stcBufConfig.u32BufTransCond = TMR6_BUF_TRANS_OVF;
(void)TMR6_GeneralBufConfig(CM_TMR6_1, TMR6_CH_A, &stcBufConfig);
(void)TMR6_GeneralBufConfig(CM_TMR6_1, TMR6_CH_B, &stcBufConfig);
TMR6_GeneralBufCmd(CM_TMR6_1, TMR6_CH_A, ENABLE);
TMR6_GeneralBufCmd(CM_TMR6_1, TMR6_CH_B, ENABLE);
/* Set General Compare RegisterA Value */
TMR6_SetCompareValue(CM_TMR6_1, TMR6_CMP_REG_C, au16Cmp_buf[0]); /* General comprare register C, buffer for GCMAR */
TMR6_SetCompareValue(CM_TMR6_1, TMR6_CMP_REG_D, au16Cmp_buf[0]); /* General comprare register D, buffer for GCMBR */
/* Configure PWM output CHA */
stcPwmInit.u32CompareValue = au16Cmp_buf[0];
stcPwmInit.u32CountDownMatchBPolarity = TMR6_PWM_HOLD;
stcPwmInit.u32CountUpMatchBPolarity = TMR6_PWM_HOLD;
stcPwmInit.u32CountDownMatchAPolarity = TMR6_PWM_HIGH;
stcPwmInit.u32CountUpMatchAPolarity = TMR6_PWM_LOW;
stcPwmInit.u32UdfPolarity = TMR6_PWM_HOLD;
stcPwmInit.u32OvfPolarity = TMR6_PWM_HOLD;
stcPwmInit.u32StopPolarity = TMR6_PWM_LOW;
stcPwmInit.u32StartPolarity = TMR6_PWM_LOW;
(void)TMR6_PWM_Init(CM_TMR6_1, TMR6_CH_A, &stcPwmInit);
/* CHB */
stcPwmInit.u32CompareValue = au16Cmp_buf[0];
stcPwmInit.u32CountDownMatchBPolarity = TMR6_PWM_HIGH;
stcPwmInit.u32CountUpMatchBPolarity = TMR6_PWM_LOW;
stcPwmInit.u32CountDownMatchAPolarity = TMR6_PWM_HOLD;
stcPwmInit.u32CountUpMatchAPolarity = TMR6_PWM_HOLD;
(void)TMR6_PWM_Init(CM_TMR6_1, TMR6_CH_B, &stcPwmInit);
/* PWM pin function set */
TMR6_SetFunc(CM_TMR6_1, TMR6_CH_A, TMR6_PIN_CMP_OUTPUT);
TMR6_SetFunc(CM_TMR6_1, TMR6_CH_B, TMR6_PIN_CMP_OUTPUT);
/* PWM output command */
TMR6_PWM_OutputCmd(CM_TMR6_1, TMR6_CH_A, ENABLE);
TMR6_PWM_OutputCmd(CM_TMR6_1, TMR6_CH_B, ENABLE);
/* Enable interrupt */
TMR6_IntCmd(CM_TMR6_1, TMR6_INT_UDF, ENABLE);
stcIrqRegiConf.enIRQn = INT002_IRQn;
stcIrqRegiConf.enIntSrc = INT_SRC_TMR6_1_UDF;
stcIrqRegiConf.pfnCallback = &Tmr6_UnderFlow_CallBack;
(void)INTC_IrqSignIn(&stcIrqRegiConf);
NVIC_ClearPendingIRQ(stcIrqRegiConf.enIRQn);
NVIC_SetPriority(stcIrqRegiConf.enIRQn, DDL_IRQ_PRIO_15);
NVIC_EnableIRQ(stcIrqRegiConf.enIRQn);
/* Start timer6 */
TMR6_Start(CM_TMR6_1);
for (;;) {
;
}
}
3.3.运行结果
我们使用逻辑分析仪来测试PA8和PA7的输出波形,看到PA8(Timer6_1 PWMA)和PA7(Timer6_1 PWMB)输出频率为1KHz(10%->10%之间的频率),且占空比按照10%->10%->0%->10%->10%->100%循环变化。
4.扩展
在3.3中的运行结果是不是有点看不懂,没关系,我们将代码修改一下,如下所示:
static uint16_t au16CmpB_buf[] = {PWM_PERIODVALUE/2, PWM_PERIODVALUE/2, PWM_PERIODVALUE/2, PWM_PERIODVALUE/2, PWM_PERIODVALUE/2, PWM_PERIODVALUE/2};
static void Tmr6_UnderFlow_CallBack(void)
{
TMR6_ClearStatus(CM_TMR6_1, TMR6_FLAG_UDF);
Duty_Set(CM_TMR6_1, TMR6_CMP_REG_C, au16Cmp_buf[u8Duty_pos]);
Duty_Set(CM_TMR6_1, TMR6_CMP_REG_D, au16CmpB_buf[u8Duty_pos]);
if (++u8Duty_pos >= sizeof(au16Cmp_buf)/sizeof(au16Cmp_buf[0])) {
u8Duty_pos = 0;
}
}
int32_t main(void)
{
......
/* CHB */
stcPwmInit.u32CompareValue = au16CmpB_buf[0];
stcPwmInit.u32CountDownMatchBPolarity = TMR6_PWM_HIGH;
stcPwmInit.u32CountUpMatchBPolarity = TMR6_PWM_LOW;
stcPwmInit.u32CountDownMatchAPolarity = TMR6_PWM_HOLD;
stcPwmInit.u32CountUpMatchAPolarity = TMR6_PWM_HOLD;
(void)TMR6_PWM_Init(CM_TMR6_1, TMR6_CH_B, &stcPwmInit);
......
}
通过上述的修改,这样我们可以把CHB固定在50%输出占空比……运行监测的波形如下所示:
为了更好的理解上图中波形的含义,我们需要参考UM手册中19.3.5小节的比较输出功能,19.3.14.2小节中的双边对称独立PWM输出功能,我们可以通过如下图,可以直观理解上图中的输出波形:
本帖最后由 xld0932 于 2024-2-1 11:32 编辑