MCU看门狗使用注意事项

前言

最近因为项目产品硬件设计有问题,导致设计的一款产品把硬件电源开关以及硬件系统复位功能去掉了。更严重的是,这产品已经开始生产了,硬件已经无法修改,所以软件必须上看门狗,否则设备死机或是异常后就只能拆设备拔电池复位了。

我们使用的MCU是普冉的PY32F030,这颗芯片在低功耗应用场景下,使用看门狗会有很多的问题和缺陷,需要非常注意,稍有不慎,就会出问题。

关于看门狗在低功耗场景下的应用,几个问题点可以提前思考一下:

  1. 看门狗是在中断中喂狗还是在主程序中喂狗比较好?
  2. 看门狗初始化可以放到时钟初始化之前么?
  3. 如果时钟死掉了,看门狗还能正常工作么?
  4. 低功耗深度休眠后还需要喂狗么?如果需要,要怎么设计?使用什么唤醒设备喂狗?
  5. 软件独立看门狗与硬件独立看门狗它们有什么区别?
  6. 在看门狗初始化之前系统异常了会怎样?
  7. 选项字节里开启硬件看门狗与软件代码开启有什么区别?
  8. 如果异常不可避免,有没一个地方可以缓存设备状态,系统异常复位后状态不被清除

(一)看门狗分类

看门狗的分类,根据实现方式的不同,可以分为软件看门狗和硬件看门狗:

  • 软件看门狗:通过软件实现的一种机制,通常由系统中的软件来设置和管理
  • 硬件看门狗: 嵌入在处理器或芯片中的专用硬件模块

根据使用方式的不同,又可以区分为独立看门狗和窗口看门狗

  • 独立看门狗: 独立看门狗通常用于监控整个系统的运行状态,而不特定于某个任务或进程,当系统故障,死锁,无响应的时候,应用程序无法进行正常喂狗,看门狗超时从而产生复位。

  • 窗口看门狗: 窗口看门狗更专注于监控特定任务或进程的运行状态,并在特定的时间窗口内完成。比如在某个任务中,它的执行时间要求非常高,可以使用窗口看门狗,它有一个时间窗口,如果太早喂狗和太晚喂狗,都会产生异常,正因为它喂狗时间有个时间窗口,所以才叫窗口看门狗。

我使用的普冉PY32F030系列MCU,它是32位Cortex-M0+的内核,里面带有一个独立看门狗IWDG和一个窗口看门狗WWDG。

其中,独立看门狗和窗口看门狗,还有软件和硬件的区别,主要差异是在看门狗的启动方式上不同。下面我们的介绍,主要针对独立看门狗。

(二)启动看门狗

看门狗的启动有多种方式:

  • 通过接口设置启动
  • 直接设置寄存器启动
  • 设置选项字节启动

(1)通过接口设置

这里可以直接参考官方sample进行初始化:

复制代码
`    IWDG_HandleTypeDef   IwdgHandle;`
`    HAL_Init();`
`    /*##-3- Configure & Start the IWDG peripheral #########################################*/`
`    IwdgHandle.Instance = IWDG;`
`    IwdgHandle.Init.Prescaler = IWDG_PRESCALER_32;//T=1MS`
`    IwdgHandle.Init.Reload = (1000);              //1ms*1000=1s`
`    IwdgHandle.Init.Window = IWDG_WINDOW_DISABLE;`
`    if(HAL_IWDG_Init(&IwdgHandle) != HAL_OK)`
`    {`
`        /* Initialization Error */`
`        Error_Handler();`
`    }`

这里需要特别注意,因为IWDG是依赖于LSI时钟的,也就是在HAL_IWDG_Init 函数调用之前,必须先打开LSI时钟。

官方给的sample中,是在HAL_Init()中把LSI时钟打开了。当你把上面这段代码移植到你自己工程上,如果你LSI没有开启,或者是在HAL_IWDG_Init后面才开LSI时钟,你调用HAL_IWDG_Init就会一直失败,系统一直ERROR,整个MCU会启动不了。

(2)通过寄存器直接设置

直接往 IWDG_SR,IWDG_RLR,IWDG_KR三个寄存器地址写入对应的参数,使能IWDG

复制代码
`void init_wtd(void)`
`{`
`	volatileu int32_t *IWDG_KR_ADDR = (volatileuint32_t *)0x40003000UL;`
`	volatileu int32_t *IWDG_PR_ADDR = (volatileuint32_t *)0x40003004UL;`
`	volatileu int32_t *IWDG_RLR_ADDR = (volatileuint32_t *)0x40003008UL;`
`	`
`	*IWDG_KR_ADDR = 0x5555;`
`	*IWDG_PR_ADDR = 0x03;`
`	*IWDG_RLR_ADDR = 0xF40;	`
`}`

实际IWDG是有四个寄存器,还有一个IWDG_PR,它与前面一样,如果不初始化时钟,看门狗会启动不了,就算是设置了,看门狗也是不会启动。

如果要使能时钟,可以添加时钟设置语句:

复制代码
`SET_BIT(RCC->CSR, RCC_CSR_LSION);`

直接设置寄存器有一个好处,就是在boot中, 因为对代码量要求比较高,可以比较精简的实现功能

(3)通过选项字节配置

MCU上内部有一个小的flash,里面有个FLASH user option,在这里面可以设置MCU的一些配置参数

这个参数是可以通过烧录器在烧录的时候就把参数配置进去,对于已经烧录的设备,可以通过写选项字节的方式把IWDG_SW置位或是清零。

复制代码
`void Option_config_NRST_to_gpio_hwwdg(void)`
`{`
`	FLASH_OBProgramInitTypeDef OBInitCfg;`

`	/* Reset of all peripherals, Initializes the Flash interface and the Systick. */`

`	/* 初始化flash擦写时间参数 */`
`	HAL_FLASH_Init(FLASH_PROGRAM_ERASE_CLOCK_8MHZ);`

`	/* 获取option bytes数据 */`
`	HAL_FLASHEx_OBGetConfig(&OBInitCfg);`
`	`
`	//配置Nreset为GPIO`
`	if(((OBInitCfg.USERConfig & OB_RESET_MODE_GPIO) != OB_RESET_MODE_GPIO)||((OBInitCfg.USERConfig & OB_IWDG_SW) == OB_IWDG_SW))`
`	{`
`		/* 修改 USER(RESET , WWDG, IWDG) 配置值 , 注意一定要3个一起配置*/`
`		OBInitCfg.OptionType = OPTIONBYTE_USER;`
`		MODIFY_REG(OBInitCfg.USERConfig, (OB_RESET_MODE_GPIO|OB_WWDG_SW|OB_IWDG_SW), (OB_RESET_MODE_GPIO | OB_WWDG_SW | OB_IWDG_HW));`
`		/* 启动option byte编程 */`
`		HAL_FLASHEx_OBProgram(&OBInitCfg);`

`		/* 产生一个复位,option byte装载 */`
`		HAL_FLASH_OB_Launch(); `
`	}`
`}`

通过选项字节配置了硬件看门狗之后,芯片会自动开启LSI时钟,这个时候,软件要关闭LSI时钟是关闭不了的。

软件独立看门狗与硬件独立看门狗的区别

  1. 软件独立看门狗通过软件初始化,可以通过关闭时钟的方式把它关闭了
  2. 如果在设备上电到看门狗初始化之前系统异常了,看门狗是不生效的,这种情况比较多的出现在软件初始化的时候异常卡死。
  3. 硬件独立看门狗通过烧录器烧录的时候配置,或者是通过软件程序,修改选项字节里面参数进行修改
  4. 硬件独立看门狗一但配置上,它从上电的时候就会开始生效,停止不了,除非重新修改配置项参数。
  5. 硬件独立看门狗开启之后,LSI时钟会自动开启,并且关闭不了。

(三)休眠唤醒喂狗

在低功耗设备中,MCU更加多的时候是在深度睡眠的模式,以达到省功耗的目的。在深度休眠模式下,看门狗还是在正常运行的。

也就是说,在深度休眠模式下,还是需要定时唤醒设备进行喂狗,喂完狗之后,设备再重新进入休眠。

(1)常规方式

官方补充文档上有介绍,在PY32F030、PY32F003、PY32F002A系列上,在休眠前,需要进行下面几个操作:

  1. 关闭非唤醒源中断
  2. 关闭系统滴答 HAL_SuspendTick();
  3. 保证RTC稳定 while(RTC->DIVL<2);

实际在使用的时候,我们比较常用的方式是,使用RTC的秒中断,在休眠的时候,每秒唤醒一下设备,然后进行喂狗操作,最后再休眠下去。

(2)异常情况

实际测试的时候发现,在普冉030使用RTC唤醒喂狗的方式,随着时间的推移,设备会出现异常导致看门狗复位。

我们升级五百台设备,24小时内,会有几台设备偶尔出现该问题,36小时后,大部分的设备基本上都会出现这个异常。

普冉官方的解释是,它们RTC作为唤醒源确实是会存在这个问题,没有好的解决方案,只能是改用LPTIM来做唤醒源。出现这类问题的根本原因是如果休眠的stop指令与唤醒源中断同一时间触发,那么他们芯片就会挂死。

实际使用的时候,使用LPTIM的方式,还是会存在上面的内容,只是出现的概率会比较低而已。

(3)补救方案

上面的异常情况,是设备在产线上才发现的,那要怎么解?客户肯定也是接受不了这种频繁重启的情况,特别是在低功耗设备上。

最后的方式是将RAM进行分区,分出一个IRAM2区,将一些状态位保存在IRAM2区,该区启动的时候不进行初始化,看门狗复位的时候,该区的数据也不会被清除掉。

如果是检测到看门狗异常导致的复位,可以通过保存在状态位信息恢复到复位前的状态。

使用IRAM2区不初始化的方式需要注意一点:如果程序分为boot和app两个部分,需要在boot和app上同时设置该区域,否则可能在boot运行阶段,IRAM2区的数据就被清除掉了。

结尾

针对普冉PY32F030 MCU,如果要使用独立看门狗,需要注意几点:

  1. 最好是在烧录的时候就直接配置启动硬件看门狗
  2. 不要使用RTC作为休眠唤醒源进行喂狗
  3. 最好预留一个IRAM分区,以备不时之需

有些坑,没踩之前并不知道这是一个坑,对于做嵌入式应用软件的工程师而言,他并不知道芯片设计上会存在什么样的缺陷。

如果一颗芯片,价格比别人便宜很多倍,那么在使用的时候就需要特别注意了,为啥它可以做到这么便宜?是不是哪里有坑我们不清楚?就算时间再紧急,最好也要小批量试产之后才能批量使用。

---------------------------End--------------------------- 如需获取更多内容 请关注 liwen01 公众号