前言
最近在学习使用兆易的车规MCU——GD32A503,看到手册里面有个外设叫多功能通信接口(MFCOM),查看官方提供的Demo,只有关于MFCOM作为I2C、I2S、SPI、USART此类典型通讯接口的Demo,而手册中所见,是可以作为PWM输出,遂产生自己写一个输出PWM功能的想法,且写下文章,记录学习的进度和成果。
A503用户手册
官方Demo目录
官方资料
既然官方没有现成的Demo,那按照以往的经验,应该先看看官方的用户手册,有的芯片用户手册会有详细的配置教程。所以第一步我们先看官方的用户手册。
从框图上看跟我们想输出PWM有关的也就定时器、触发和输出引脚,而且定时器可以直接与输出引脚连接,输出PWM应该不会是一个比较难的事情。
从手册上看,PWM模式配置后,通过触发信号,即可输出PWM信号。
配置简单MFCOM输出PWM
通过参考MFCOM_USART的USART_polling写出以下配置代码
void mfcom_init(void) { //选用输出引脚为PA11 MFCOM_D4 rcu_periph_clock_enable(RCU_GPIOA);//配置引脚时钟 rcu_periph_clock_enable(RCU_MFCOM);//配置MFCOM时钟 gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_11);//PA11 D4 gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_11); gpio_af_set(GPIOA, GPIO_AF_6, GPIO_PIN_11);//PA11复用功能4为MFCOM_D4 mfcom_timer_parameter_struct mfcom_timer; mfcom_timer.trigger_select = MFCOM_TIMER_TRGSEL_EXTERNAL0;//触发事件,因为后续使用ALWAYS使能,所以该配置先忽略 mfcom_timer.trigger_polarity = MFCOM_TIMER_TRGPOL_ACTIVE_HIGH;//触发极性,配置为高触发,但与trigger_select原因一致,先忽略 mfcom_timer.pin_config = MFCOM_TIMER_PINCFG_OUTPUT;//引脚配置,设置为输出 mfcom_timer.pin_select = MFCOM_TIMER_PINSEL_PIN4;//引脚选择 mfcom_timer.pin_polarity = MFCOM_TIMER_PINPOL_ACTIVE_HIGH;//引脚极性,设置为高电平有效 mfcom_timer.mode = MFCOM_TIMER_PWMMODE;//定时器模式,设置为PWM模式 mfcom_timer.output = MFCOM_TIMER_OUT_HIGH_EN;//定时器输出 mfcom_timer.decrement = MFCOM_TIMER_DEC_CLK_SHIFT_OUT;//定时器递减 mfcom_timer.reset = MFCOM_TIMER_RESET_NEVER;//定时器复位,配置为定时器从不复位 mfcom_timer.disable = MFCOM_TIMER_DISMODE_NEVER;//禁能定时器 mfcom_timer.enable = MFCOM_TIMER_ENMODE_ALWAYS;//定时器使能,设定为一直使能 mfcom_timer.stopbit = MFCOM_TIMER_STOPBIT_DISABLE;//定时器停止位 mfcom_timer.startbit = MFCOM_TIMER_STARTBIT_DISABLE;//定时器启动位 mfcom_timer.compare = 0xffff;//定时器比较值 mfcom_timer_init(MFCOM_TIMER_0, &mfcom_timer); }
如上,将MFCOM配置为简单的PWM输出模式,没有用到特定的触发事件和移位器,想能正常输出PWM后,再逐步添加其他东西。
如上图,当配置为PWM模式后,比较值16位寄存器分为高低8位,用于配置高低电平的周期,而我的代码中compare为0xFFFF,实际出现的PWM信号为占空比50%,频率为
195KHz。
而当我把比较值设置为0x0000后,出现如下波形,占空比50%,频率50MHz。
MFCOM比较值寄存器与频率关系
首先在上文配置MFCOM输出PWM中,根据TMCVALUE寄存器的说明,我们可以得知16位寄存器中,分为高低两位设定高低电平的出现周期,但显然该寄存器配置的周期是缺少一个单位的。例如,当我将寄存器设定为0xFFFF后,高低电平出现周期应该都为0xFF+1,即256,但这个256的单位是什么,手册里面是没有的,所以在后续配置准确的输出频率时,是一个难题。
那么根据现有线索我们需要做一些小小的推理和验证。
目前的线索有:1.在主频为100MHz时,寄存器配置为0x0000,输出PWM频率为50MHz。
2.在主频为100MHz时,寄存器配置为0xFFFF,输出PWM频率为195KHz。
首先,前文中我们将定时器设定为不需触发、ALWAYS启动的模式,所以这个频率应该与触发无关。在平时使用定时器的时候,一般我们都是将总线时钟分频,然后再设定计数值去实现想要的频率输出。那么会不会,MFCOM定时器也是一种总线分频类型的定时器呢。
通过手册,可见MFCOM是挂载在AHB1总线上的,当我的主频设定为100MHz时,AHB1总线也为100MHz,如果说TMCVALUE实际为AHB1总线的时钟分频系数,那么当寄存器值为0x0000时,高低8位分别为1+1=2,频率则为100/2=50MHz;当寄存器值为0xFFFF时,高低8位分别为256+256=512,100/512=195.3KHz,是符合现象的。进一步推论,TIMCVALUE在8位PWM模式下,输出频率为AHB1/(TIMCVALUE[7:0]+TIMCVALUE[15:8]+2),占空比为TIMCVALUE[7:0]/TIMCVALUE[15:8]
那么就需要下面几个实验验证这种猜想:
1.主频100MHz下,设置寄存器值为0x3131,理想输出频率为1MHz,占空比为50%的PWM波。
2.主频100MHz下,设置寄存器值为0x184A,理想输出频率为1MHz,占空比为75%的PWM波。
3.主频48MHz下,设置寄存器值为0x0000,理想输出频率为24MHz,占空比50%的PWM波。
4.主频48MHz下,设置寄存器值为0xFFFF,理想输出频率为93.7KHz,占空比为50%的PWM波。
实验一
实验二
实验三
实验四
结论
由上可见,四个实验都按照理想值输出了相应的PWM波,故可印证:
1.TMCVALUE寄存器实际为AHB1总线的时钟分频系数。
2.MFCOM PWM模式下,PWM频率为AHB1/(TIMCVALUE[7:0]+TIMCVALUE[15:8]+2)。
3.MFCOM PWM模式下,PWM占空比为TIMCVALUE[7:0]/TIMCVALUE[15:8]
触发方式启停PWM
回顾上文MFCOM框图和手册。MFCOM的触发方式可以分为两类,一类是外部触发用到了TRIGSEL触发选择控制器,一类是内部触发,可通过移位器和其他的MFCOM_TIMER进行触发,下面来讲一下不同触发方式的配置方法和实验结果。
TRIGSEL触发PWM
该种触发方式用到了TRIGSEL触发选择控制器,而关于TRIGSEL部分的内容这里不做细究,如果能坚持写博客的话,后续再考虑写一篇。
本次实验,运用PA1作为外部输入触发的引脚,PA11依旧为PWM信号输出的引脚,当PA1为高电平时,PA11输出PWM信号;当PA1为下降沿时,PA11停止输出。话不多说,直接来看代码。
引脚配置
void gpio_config(void) { rcu_periph_clock_enable(RCU_GPIOA); rcu_periph_clock_enable(RCU_SYSCFG); gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_11);//配置PA11->D4 gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_11); gpio_af_set(GPIOA, GPIO_AF_6, GPIO_PIN_11); //IO功能复用 /*配置触发引脚*/ gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_1); gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_1); }
MFCOM配置
void mfcom_init(void) { rcu_periph_clock_enable(RCU_MFCOM); mfcom_timer_parameter_struct mfcom_timer; mfcom_timer.trigger_select = MFCOM_TIMER_TRGSEL_EXTERNAL0; //配置为外部输出0 mfcom_timer.trigger_polarity = MFCOM_TIMER_TRGPOL_ACTIVE_HIGH; //触发信号高电平有效 mfcom_timer.pin_config = MFCOM_TIMER_PINCFG_OUTPUT; //D4配置为输出 mfcom_timer.pin_select = MFCOM_TIMER_PINSEL_PIN4; //MFCOM_D4 mfcom_timer.pin_polarity = MFCOM_TIMER_PINPOL_ACTIVE_HIGH; //引脚高电平有效 mfcom_timer.mode = MFCOM_TIMER_PWMMODE; //PWM模式 mfcom_timer.output = MFCOM_TIMER_OUT_LOW_EN_RESET; mfcom_timer.decrement = MFCOM_TIMER_DEC_CLK_SHIFT_OUT; mfcom_timer.reset = MFCOM_TIMER_OUT_LOW_EN; mfcom_timer.disable = MFCOM_TIMER_DISMODE_TRIGFALLING; //下降沿禁能TIMER mfcom_timer.enable = MFCOM_TIMER_ENMODE_TRIGHIGH; //高电平使能TIMER mfcom_timer.stopbit = MFCOM_TIMER_STOPBIT_DISABLE; mfcom_timer.startbit = MFCOM_TIMER_STARTBIT_DISABLE; mfcom_timer.compare = 0x184A; //输出1MHz,50%占空比PWM mfcom_timer_init(MFCOM_TIMER_0, &mfcom_timer); }
Main函数&TRIGSEL绑定配置
int main(void) { gpio_config(); mfcom_init(); mfcom_enable(); //使能MFCOM,要在使能RCU_MFCOM后 /* enable TRIGSEL clock */ rcu_periph_clock_enable(RCU_TRIGSEL); /* select TRIGSEL_IN0 to trigger TIMER1 */ trigsel_init(TRIGSEL_OUTPUT_MFCOM_TRG_TIMER0, TRIGSEL_INPUT_TRIGSEL_IN0); /* lock trigger register */ trigsel_register_lock_set(TRIGSEL_OUTPUT_MFCOM_TRG_TIMER0); //寄存器上锁 while(1); }
根据上面的配置,有下面的现象。而上面配置中的触发方式,触发引脚,都可以按照自己不同的需要去配置,这里就不赘述了。
下图中黄线为PA11,绿线为PA1,可见实际情况跟我们要配置的情况是一致的。
PA1为上升沿时,PWM输出
PA1为下降沿时,PWM停止输出
总结
明显MFCOM输出PWM信号,在比较值上是有限制的。 目前实验到这里为止,后续会补齐移位器和触发操作。最近还有别的事情要忙,只能等闲下来后再研究了。
本文为本人学习的记录,可能会比较粗糙和不专业。希望各位大神可以指出问题!