一、启动时钟
PWC_Fcg2PeriphClockCmd(PWC_FCG2_TMR6_x, Enable);
TMR6对应FCG2,根据PWM输入引脚来确定是TMR6_x(本例为TMR6_2)。运行以后PWC的FCG2寄存器相应位被清0。
同时TM62的这些寄存器被全部置1,GCONR的DIR位被置一。
以上步骤类似STM32的开启RCC时钟。
二、功能初始化
设置TIM62的GCONR寄存器。
/* Timer6 general count function configuration */
stcTIM6BaseCntCfg.u32CntMode = TMR6_MODE_SAWTOOTH;
stcTIM6BaseCntCfg.u32CntDir = TMR6_CNT_INCREASE;
stcTIM6BaseCntCfg.u32CntClkDiv = TMR6_CLK_PCLK0_DIV1024;
stcTIM6BaseCntCfg.u32CntStpAftOvf = TMR6_CNT_CONTINUOUS;
(void)TMR6_Init(M4_TMR6_2, &stcTIM6BaseCntCfg);
设为锯齿波(TMR6_MODE_SAWTOOTH),计数增长(TMR6_CNT_INCREASE),1024分频(TMR6_CLK_PCLK0_DIV1024),计满溢出后继续计数(TMR6_CNT_CONTINUOUS)。
三、配置GPIO为PWM输入
本例为PB07
PB07可以作为TIM62_PWM的A通道使用
#define TMR6_2_PWMA_PORT (GPIO_PORT_B)
#define TMR6_2_PWMA_PIN (GPIO_PIN_07)
GPIO_SetFunc(TMR6_2_PWMA_PORT, TMR6_2_PWMA_PIN, GPIO_FUNC_3_TIM62_PWMA, PIN_SUBFUNC_DISABLE);
四、确立TMR62定时周期
/* Period register set */
u32Period = 0xFFFFFFFFu;
TMR6_SetPeriodReg(M4_TMR6_2, TMR6_PERIOD_REG_A, u32Period);
TMR62是32位计数器最大值可以设置到0xFFFFFFFF。对PERAR寄存器设置0xFFFFFFFF。PERBR和PERCR可以作为缓存,这里不用,不管它们。
五、开启外部PWM信号捕获并配置滤波
设定端口控制寄存器PCNAR(PCNBR)的 CAPMDA(CAPMDB)位为1,捕获输入功能变为有效,同时设置FCNGR的对应A或B开启滤波,并配置其时钟分频。本例使用channel A。
/* Capture input port configuration */
stcTIM6PortInCfg.u32PortMode = TMR6_PORT_CAPTURE_INPUT;
stcTIM6PortInCfg.u32FilterSta = TMR6_PORT_INPUT_FILTER_ON;
stcTIM6PortInCfg.u32FltClk = TMR6_INPUT_FILTER_PCLK0_DIV16;
(void)TMR6_PortInputConfig(M4_TMR6_2,TMR6_IO_PWMA, &stcTIM6PortInCfg);
在滤波采样基准时钟采样到端口上 3 次一致的电平时,该电平被当作有效电平传送到模块内部;小于 3 次一致的电平会被当作外部干扰滤掉,不传送到模块内部。其动作。
六、配置PWM捕获(HCPAR)
这个库函数是专门配置通道A的,操作寄存器HCPAR。
TMR6_HwCaptureChACondCmd(M4_TMR6_2, TMR6_HW_CTRL_PWMA_RISING, Enable);
请注意,如果需要使用通道B,则需要换函数。
void TMR6_HwCaptureChBCondCmd(M4_TMR6_TypeDef *TMR6x,
uint32_t u32CondSrc,
en_functional_state_t enNewState)
七、捕获到跳变沿后,计数器计数硬件清零(HCLRR)
配置硬件清零事件选择寄存器(HCLRR),使得每次发生捕获事件后,计数器从0开始重新计数。
如果想测量PWM周期,则应该与捕获条件一致,本例捕获为上升沿,所以清0条件也应为上升沿。
TMR6_HwClrCondCmd(M4_TMR6_2, TMR6_HW_CTRL_PWMA_RISING, Enable);
TMR6_HwClrFuncCmd(M4_TMR6_2, Enable);
八、配置中断(ICONR,发生捕获时触发)
启动捕获功能时,每当发生捕获事件,当前的计数值就被保存到相应的捕获寄存器(GCMAR、GCMBR)中,本例使用GCMAR。我们开启ICONR寄存器中的最低位。
/* Enable M4_TMR6_2 GCMAR interrupt */
TMR6_IntCmd(M4_TMR6_2, TMR6_IRQ_EN_CNT_MATCH_A, Enable);
这样就可以在发生捕获时触发中断。
到这里总结一下,当外部上升沿进来时,TMR62会直接产生:
- 产生捕获事件
- 计数器清零0
进而由于产生捕获事件间接产生:
- 触发中断
九、配置中断向量及回调函数(NVIC)
STM32F4的中断向量通道和对应功能是固定死的,而HC32F4A0的非常灵活,可以自由配置。不过使用STM32的标准库函数来配NVIC非常方便,所以移植了STM32F4的misc.c文件,来对HC32F4A0进行NVIC配置。移植的时候需要修改以下几处:
1.misc.h
2. misc.c
然后即可使用misc文件里面的函数来配置NVIC了。
/**因为HC32F4A0的中断向量通道与中断源以及相应的中断服务函数可以灵活映射,所以需要手动配置**/
stcIrqRegiConf.enIRQn = Int003_IRQn; /* Register INT_TMR6_2_GCMA Int to Vect.No.003 */
stcIrqRegiConf.enIntSrc = INT_TMR6_2_GCMA; /* Select Event interrupt of M4_TMR6_2 */
stcIrqRegiConf.pfnCallback = &Tmr6_2_CapInputCallBack; /* Callback function */
(void)INTC_IrqSignIn(&stcIrqRegiConf);
/**后面就使用移植过来的misc文件中的库函数来配置NVIC了,注意ENABLE要改为Enable,其它跟STM32一样了**/
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = Int003_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = Enable;
NVIC_Init(&NVIC_InitStructure);
Intxxx_IRQn可选择为Int000_IRQn ~ Int031_IRQn,以及Int056_IRQn ~ Int061_IRQn。