打印

【GD32 MCU入门教程】四、GD32 MCU 常见外设介绍(9)FWDG 模块介绍

[复制链接]
1559|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 聚沃科技 于 2024-9-18 15:33 编辑

9.1.FWDG 简介
本章我们主要分析独立看门狗(FWDG)的功能框图和它的应用。独立看门狗用通俗一点的话来解释就是一个12位的递减计数器,当计数器的值从某个值一直减到0的时候,系统就会产生一个复位信号,即FWDGTRSTF。如果在计数没减到0之前,刷新了计数器的值的话,那么就不会产生复位信号,这个动作就是我们经常说的喂狗。看门狗功能由 VDD 电压域供电,在停止模式和待机模式下仍能工作。独立看门狗定时器有独立的时钟源(IRC40K) 。 即使主时钟失效, FWDGT依然 能保持正常工作状态, 适用于需要独立环境且对计时精度要求不高的场合。
9.2.GD32 FWDG 外设原理简介
因篇幅有限,本文无法详细介绍GD32所有系列FWDG外设接口,下面以GD32F30x为列,着重介绍下GD32F30x的FWDG外设简介和结构框图,后介绍下各个系列的差异。
GD32 FWDG 主要特性
◼ 自由运行的12位向下计数器;
◼ 如果看门狗定时器被使能,那么当向下计数器的值达到0时产生系统复位;
◼ 独立时钟源,独立看门狗定时器在主时钟故障(例如待机和深度睡眠模式下)时仍能工作;
◼ 独立看门狗定时器硬件控制位,可以用来控制是否在上电时自动启动独立看门狗定时器;
◼ 可以配置独立看门狗定时器在调试模式下选择停止还是继续工作。
FWDG 功能结构框图
FWDG时钟:如FWDG框图的①所示, FWDG的时钟由独立的RC振荡器IRC40K提供,即使主时钟发生故障它仍然有效,非常独立。IRC的频率根据温度和工作场合会有一定的漂移,我们一般取40KHZ,所以FWDG的定时时间并不一定非常精确,只适用于对时间精度要求相对较低的场合。
计数器时钟:如FWDG框图的②所示, 递减计数器的时钟由IRC40K经过一个8位的预分频器得到,我们可以操作预分频器寄存器FWDG_PSC来设置分频因子,分频因子可以是:[4,8,16,32,64,128,256]。
计数器:如图 0-28 FWDG框图的③所示, FWDG的计数器是一个12位的递减计数器,最大值为0XFFF,当计数器减到0时,会产生一个复位信号: FWDGTRSTF,让程序重新启动运行,如果在计数器减到0之前刷新了计数器的值的话,就不会产生复位信号,重新刷新计数器值的这个动作我们俗称喂狗。
重装载寄存器:如FWDG框图的④所示, 重装载寄存器是一个12位的寄存器,里面装着要刷新到计数器的值,这个值的大小决定着FWDG的溢出时间。超时时间Tout = (42^prv) / 40 rlv (s) ,prv是预分频器寄存器的值,rlv是重装载寄存器的值。
控制寄存器:如FWDG框图的⑤所示, 控制寄存器FWDG_CTL可以说是独立看门狗的一个控制寄存器,主要有三种控制方式,往这个寄存器写入下面三个不同的值有不同的效果。具体如下表控制寄存器取值枚举
状态寄存器:如FWDG框图的⑥所示, 状态寄存器STAT只有位0:PUD和位1:RUD有效,这两位只能由硬件操作,软件操作不了。RUD:看门狗计数器重装载值更新,硬件置1表示重装载值的更新正在进行中,更新完毕之后由硬件清0。PUD: 看门狗预分频值更新,硬件置‘1‘指示预分频值的更新正在进行中,当更新完成后,由硬件清0。所以只有当RUD/PUD等于0的时候才可以更新重装载寄存器/预分频寄存器。
注意:
  • 如果在选项字节中打开了“硬件看门狗定时器”功能,那么在上电的时候看门狗定时器就被自动打开。为了避免系统复位,软件应该在计数器达到0x000之前重装载计数器;
  • 如果DBG控制寄存器0(DBG_CTL0) 中的FWDGT_HOLD位被清0,即使Cortex®-M4内核停止(调试模式下) 独立看门狗定时器依然工作。如果FWDGT_HOLD位置1,独立看门狗定时器将在调试模式下停止工作。

各系列 FWDG 功能差异
F4xx系例FWDG时钟为32K,因此要注意FWDG的定时时间。
9.3.硬件连接说明
FWDG属于单片机内部资源,不需要外部电路,需要一个外部的按键和LED,通过按键来喂狗,喂狗成功LED亮,喂狗失败,程序重启,LED灭一次。
9.4.软件配置说明
本小节讲解FWDG_Example例程中FWDG模块的实验讲解,主要包括FWDG配置函数、FWDG喂狗函数、主函数介绍以及运行结果。
FWDG 配置函数
外设时钟配置
外设时钟配置如代码清单FWDG例程时钟配置所示,在GD32全系列MCU中需打开GPIOA(LED)的时钟,另外,在GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X || GD32F1X0 || GD32F3X0 || GD32E230中需要打开IRC40K,GD32F4XX中需要打开IRC32K。
void rcu_config(void)
{
#if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X || GD32F1X0 || GD32F4XX || GD32F3X0 ||
GD32E230
rcu_periph_clock_enable(RCU_GPIOA);
#if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X || GD32F1X0 || GD32F3X0 || GD32E230
/* enable IRC40K */
rcu_osci_on(RCU_IRC40K);
/* wait till IRC40K is ready */
while(SUCCESS != rcu_osci_stab_wait(RCU_IRC40K)){
}
#elif GD32F4XX
/* enable IRC32K */
rcu_osci_on(RCU_IRC32K);
/* wait till IRC32K is ready */
while(SUCCESS != rcu_osci_stab_wait(RCU_IRC32K)){
}
#endif
#endif
}
GPIO(LED)引脚配置
GPIO引脚配置如代码清单FWDG例程GPIO(LED)引脚配置所示,GD32F10X、GD32F30X、GD32F20X、GD32E10X系列GPIO配置相同, PA3、PA4作为LED引脚配置为推挽输出模式;GD32F1X0、GD32F4XX、GD32F3X0、GD32E23X系列GPIO配置基本相同。配置完成后将PA3 和PA4拉低。
void gpio_led_config(void)
{
#if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X
gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_3);
gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_4);
#elif defined GD32F1X0 || GD32F4XX || GD32F3X0 || GD32E230
gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_3);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_3);
gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_4);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_4);
#endif
GPIO_BC(GPIOA) = GPIO_PIN_3;
GPIO_BC(GPIOA) = GPIO_PIN_4;
}
按键初始化配置
按键初始化配置如代码清单按键初始化配置所示。本例程中默认使用PA0下降沿进入中断,GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X系列配置基本相同,GD32F1X0 || GD32F3X0系列配置类似。GD32E230中断分组只有抢占优先级没有子优先级。
void key_init(void)
{
#if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X
rcu_periph_clock_enable(RCU_AF);
gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_0);
/* enable and set key EXTI interrupt to the lowest priority */
nvic_irq_enable(EXTI0_IRQn, 2U, 0U);
/* connect key EXTI line to key GPIO pin */
gpio_exti_source_select(GPIO_PORT_SOURCE_GPIOA, GPIO_PIN_SOURCE_0);
/* configure key EXTI line */
exti_init(EXTI_0, EXTI_INTERRUPT, EXTI_TRIG_FALLING);
exti_interrupt_flag_clear(EXTI_0);
#elif defined GD32F1X0 || GD32F4XX || GD32F3X0 || GD32E230
#if defined GD32F1X0 || GD32F3X0
rcu_periph_clock_enable(RCU_CFGCMP);
/* configure button pin as input */
gpio_mode_set(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE,GPIO_PIN_0);
/* enable and set key EXTI interrupt to the lowest priority */
nvic_irq_enable(EXTI0_1_IRQn, 2U, 0U);
#elif defined GD32E230
rcu_periph_clock_enable(RCU_CFGCMP);
/* configure button pin as input */
gpio_mode_set(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE,GPIO_PIN_0);
/* enable and set key EXTI interrupt to the lowest priority */
nvic_irq_enable(EXTI0_1_IRQn, 2U);
#elif defined GD32F4XX
rcu_periph_clock_enable(RCU_SYSCFG);
/* configure button pin as input */
gpio_mode_set(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE,GPIO_PIN_0);
/* enable and set key EXTI interrupt to the lowest priority */
nvic_irq_enable(EXTI0_IRQn, 2U, 0U);
#endif
/* connect key EXTI line to key GPIO pin */
syscfg_exti_line_config(EXTI_SOURCE_GPIOA, EXTI_SOURCE_PIN0);
/* configure key EXTI line */
exti_init(EXTI_0, EXTI_INTERRUPT, EXTI_TRIG_FALLING);
exti_interrupt_flag_clear(EXTI_0);
#endif
}
FWDG 配置函数
FWDG配置函数如代码清单FWDG配置配置所示。当时钟为40K时,溢出时间Tout =prv/40 rlv (s),prv可以是[4,8,16,32,64,128,256];rlv的取值范围为0~0XFFF。如果我们需要设置1s的超时溢出, prv 可以取 FWDGT_PSC_DIV64 , rlv 取 625 ,即调用 : fwdgt_config(625,FWDGT_PSC_DIV64)。Tout=64/40625=1s。GD32F4XX系列IRC为32K则定时时间1.25s。
void FWDGT_init(void)
{
/* confiure FWDGT counter clock: 40KHz(IRC40K) / 64 = 0.625 KHz GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X
|| GD32F1X0 || GD32F3X0 || GD32E23X*/
/* confiure FWDGT counter clock: 32KHz(IRC32K) / 64 = 0.5 KHz GD32F4XX*/
fwdgt_config(625, FWDGT_PSC_DIV64);
/* after 1.x seconds to generate a reset */
fwdgt_enable();
}
中断喂狗
中断喂狗函数如代码清单中断喂狗所示。当进进入PA0外部中断时执行喂狗函数。
#if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X || GD32F4XX
void EXTI0_IRQHandler(void)
{
/* make sure whether the tamper key EXTI Line is interrupted */
if(RESET != exti_interrupt_flag_get(EXTI_0)){
/* reload FWDGT counter */
fwdgt_counter_reload();
}
/* clear the interrupt flag bit */
exti_interrupt_flag_clear(EXTI_0);
}
#elif defined GD32F1X0 || GD32F4XX || GD32F3X0 || GD32E230
void EXTI0_1_IRQHandler(void)
{
/* make sure whether the tamper key EXTI Line is interrupted */
if(RESET != exti_interrupt_flag_get(EXTI_0)){
/* reload FWDGT counter */
fwdgt_counter_reload();
}
/* clear the interrupt flag bit */
exti_interrupt_flag_clear(EXTI_0);
}
#endif
主函数说明
主函数如代码清单FWDG例程主函数所示,主函数中我们初始化好LED和按键相关的配置,设置FWDG 1s 超时溢出之后,进入while死循环,通过按键来喂狗,如果喂狗成功,则LED2(PA4)点亮,如果喂狗失败的话,系统重启,程序重新执行,当执行到rcu_flag_get函数的时候,则会检测到是FWDG复位,然后让LED1(PA3)亮。如果喂狗一直失败的话,则会一直产生系统复位,加上前面延时的效果,则会看到LED1(PA3)一直闪烁。
int main(void)
{
/* peripheral clock enable */
rcu_config();
/* config systick */
systick_config();
/* GPIO config */
gpio_led_config();
key_init();
delay_1ms(500);
FWDGT_init();
/* check if the system has resumed from FWDGT reset */
if(RESET != rcu_flag_get(RCU_FLAG_FWDGTRST)){
/* turn on LED1 */
GPIO_BOP(GPIOA) = GPIO_PIN_3;
/* clear the FWDGT reset flag */
rcu_all_reset_flag_clear();
while(1);
}
else{
/* turn on LED2 */
GPIO_BOP(GPIOA) = GPIO_PIN_4;
}
while(1)
{
}
}
运行结果
把编译好的程序下载到开发板,在1s的时间内通过按键来不断的喂狗,如果喂狗失败,LED1闪烁。如果一直喂狗成功,则LED2常亮。
9.5.FWDG 使用注意事项
(1) FWDG在Debug仿真时,请将DBG控制寄存器0(DBG_CTL0) 中的FWDGT_HOLD位置1,来关闭FWDG功能。
(2) 没有开启软件看门狗时,程序自动复位,可能在选项字节里开启了硬件看门狗。
(3) 同时使用FWDG、Standby或Deep-sleep模式时,无法喂狗:在reload命令后,硬件清除reload信号之前,进入Deepsleep或者standby模式,会导致后续reload命令无法正常响应。软件保证在reload命令和进入Deepsleep/standby mode的命令中间有3个LXTAL clock(100us)以上的时间间隔。
(4) 由于环境温度影响,独立看门狗定时器超时周期会有些许波动,可以通过校准IRC40K使独立看门狗定时器超时更加精确。
教程由GD32 MCU方案商聚沃科技原创发布,了解更多GD32 MCU教程,关注聚沃科技官网,GD32MCU技术交流群:859440462

使用特权

评论回复
沙发
classroom| | 2024-8-19 18:46 | 只看该作者
支持一下,介绍的很详细了

使用特权

评论回复
板凳
丙丁先生| | 2024-8-20 08:51 | 只看该作者
GD32 MCU的FWDG模块是一种独立看门狗定时器,具备12位向下计数功能,并在计数值减到0时产生系统复位信号。以下将详细解读GD32 MCU的FWDG模块:

1. FWDG模块概述
   功能框图与应用:独立看门狗(FWDG)可以视为一个12位递减计数器,当计数器从预设值递减至0时,会输出一个系统复位信号FWDGTRSTF。若在计数过程中刷新计数器的值,即“喂狗”动作,则不会引发系统复位。
   独立时钟源:FWDG拥有独立的时钟源IRC40K,即使主时钟失效,FWDG仍能正常工作。这使得FWDG适用于那些需要独立运行且对计时精度要求不高的环境。

2. FWDG外设原理
   主要特性:核心特性包括12位向下计数器、独立时钟源、硬件控制位、以及调试模式下可选择停止或继续工作。
   时钟与计数器:FWDG时钟源自IRC40K RC振荡器,其频率会有漂移,一般取40KHz。计数器的时钟经过8位预分频器得到,允许通过设置分频因子调整计数速度。
   重装载寄存器:该寄存器负责保存要重新装载到计数器的值,此值决定了FWDG的溢出时间。溢出时间Tout的计算公式为(42^prv) / (40 rlv)秒,其中prv是预分频器的值,rlv是重装载寄存器的值。

3. FWDG控制与状态寄存器
   控制寄存器FWDG_CTL:这是FWDG的核心控制寄存器,能够实现三种控制方式,具体效果依据寄存器的具体写入值而变化。
   状态寄存器STAT:包含两位重要状态位PUD和RUD,它们由硬件操作且不能通过软件修改。只有在RUD/PUD为0的情况下,才能更新重装载寄存器或预分频寄存器。

4. FWDG在不同系列的MCU中的差异
  各系列差异说明:不同系列的GD32 MCU中,FWDG的时钟频率可能有所不同,如F4xx系列的FWDG时钟频率为32KHz,这会影响到FWDG的定时时间。

5. 硬件连接与软件配置
   硬件连接说明:FWDG作为单片机内部资源,无需外部电路支持。通常结合外部按键和LED使用,通过按键执行“喂狗”操作,成功则LED亮起,失败则程序重启。
   软件配置详解:配置FWDG涉及初始化并启动时钟,配置GPIO引脚,设置FWDG相关参数,并通过编程实现喂狗动作。

总的来说,GD32 MCU的FWDG模块为系统稳定性和自动复位提供了一种简易而有效的机制。设计人员应充分利用这一功能,增强产品的可靠性,同时注意根据不同型号的MCU调整FWDG的配置和期望。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

170

主题

190

帖子

10

粉丝