SmartOS/WatchDog.cpp

195 lines
5.1 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "WatchDog.h"
/*
独立看门狗IWDG——有独立时钟内部低速时钟LSI---40KHz所以不受系统硬件影响的系统故障探测器。主要用于监视硬件错误。 
窗口看门狗WWDG——时钟与系统相同。如果系统时钟不走了这个狗也就失去作用了主要用于监视软件错误。 
独立看门狗
看门狗定时时限=IWDG_SetReload()的值 / 看门狗时钟频率
看门狗时钟频率=LSI内部低速时钟的频率40KHz/ 分频数
独立看门狗(IWDG)由专用的40kHz的低速时钟为驱动。因此即使主时钟发生故障它也仍然有效。
窗口看门狗由从APB1时钟分频后得到的时钟驱动通过可配置的时间窗口来检测应用程序非正常的过迟或过早的行为。
IWDG_SetPrescaler() 分频4~256
IWDG_SetReload() 计数值12位 0~0x0FFF
IWDG_ReloadCounter() 喂狗必须在计数值减到1之前喂狗
IWDG_PR和IWDG_RLR寄存器具有写保护功能。要修改这两个寄存器的值必须先向IWDG_KR寄存器中写入0x5555。
以不同的值写入这个寄存器将会打乱操作顺序,寄存器将重新被保护。重装载操作(即写入0xAAAA)也会启动写保护功能。
#define IWDG_WriteAccess_Enable ((uint16_t)0x5555)
#define IWDG_WriteAccess_Disable ((uint16_t)0x0000)
void IWDG_WriteAccessCmd(uint16_t IWDG_WriteAccess)
{
assert_param(IS_IWDG_WRITE_ACCESS(IWDG_WriteAccess));
IWDG->KR = IWDG_WriteAccess;
}
void IWDG_ReloadCounter(void)
{
IWDG->KR = KR_KEY_Reload;
}
void IWDG_Enable(void)
{
IWDG->KR = KR_KEY_Enable;
}
void IWDG_SetPrescaler(uint8_t IWDG_Prescaler)
{
assert_param(IS_IWDG_PRESCALER(IWDG_Prescaler));
IWDG->PR = IWDG_Prescaler;
}
void IWDG_SetReload(uint16_t Reload)
{
assert_param(IS_IWDG_RELOAD(Reload));
IWDG->RLR = Reload;
}
*/
/*WatchDog::WatchDog(uint ms)
{
Timeout = ms;
Config(ms);
}*/
WatchDog::~WatchDog()
{
ConfigMax();
}
void OpenWatchDog()
{
RCC_LSICmd(ENABLE);
/* 检查系统是否从IWDG重置恢复 */
if (RCC_GetFlagStatus(RCC_FLAG_IWDGRST) != RESET)
{
/* 清除重置标识 */
RCC_ClearFlag();
}
/* 打开IWDG_PR和IWDG_RLR寄存器的写访问 */
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
}
void SetWatchDog(byte pre, uint reload)
{
IWDG_SetPrescaler(pre);
/*if(ms < (0x0FFF * 32 / 40))
{
// IWDG计数器时钟: LSI/32=40KHz/32=1250Hz每周期0.8ms
IWDG_SetPrescaler(IWDG_Prescaler_32);
}
else
{
// IWDG计数器时钟: LSI/64=40KHz/64=625Hz每周期0.4ms
IWDG_SetPrescaler(IWDG_Prescaler_64);
// 直接除以2后面不用重复计算
ms >>= 2;
}*/
/* 设置计数器重载值为超时时间
Counter Reload Value = ms / 1000 / IWDG计数器时钟周期
= ms / 1000 / (1/(LSI/mul))
= ms * LSI / (mul * 1000)
= ms * 40k / (mul * 1000)
= ms * 40 / mul
*/
IWDG_SetReload(reload);
/* 重载 IWDG 计数器 */
IWDG_ReloadCounter();
/* 打开 IWDG (LSI将由硬件打开) */
IWDG_Enable();
}
bool WatchDog::Config(uint ms)
{
if(ms == 0)
{
debug_printf("WatchDog msTimeout %dms must larger than 0ms\r\n", ms);
return false;
}
OpenWatchDog();
byte pre = IWDG_Prescaler_4;
int mul = 4;
// 计数器12位 0~0x0FFF有reload = ms/1000 / (1/(LSI/mul)) = ms * LSI / (mul*1000) = ms * 40 / mul
// 考虑到reload溢出的可能每种分频最大ms = reload * mul / 40 ~= 102 * mul
int i=0;
/*
#define IWDG_Prescaler_4 ((uint8_t)0x00)
#define IWDG_Prescaler_8 ((uint8_t)0x01)
#define IWDG_Prescaler_16 ((uint8_t)0x02)
#define IWDG_Prescaler_32 ((uint8_t)0x03)
#define IWDG_Prescaler_64 ((uint8_t)0x04)
#define IWDG_Prescaler_128 ((uint8_t)0x05)
#define IWDG_Prescaler_256 ((uint8_t)0x06)
*/
for(i = IWDG_Prescaler_4; i <= IWDG_Prescaler_256; i++)
{
pre = i;
mul = 1 << (i + 2);
// 判断是否在范围之内
if(ms * 40 / mul < 0x0FFF) break;
}
if(i > IWDG_Prescaler_256)
{
debug_printf("WatchDog msTimeout must smaller than %dms\r\n", 0x0FFF * 256 / 40);
return false;
}
/* 设置计数器重载值为超时时间
Counter Reload Value = ms / 1000 / IWDG计数器时钟周期
= ms / 1000 / (1/(LSI/mul))
= ms * LSI / (mul * 1000)
= ms * 40k / (mul * 1000)
= ms * 40 / mul
*/
SetWatchDog(pre, ms * 40 / mul);
Timeout = ms;
return true;
}
void WatchDog::ConfigMax()
{
OpenWatchDog();
SetWatchDog(IWDG_Prescaler_256, 0x0FFF);
Timeout = 0x0FFF * 256 / 40;
}
void WatchDog::Feed()
{
IWDG_ReloadCounter();
}
void FeedDogTask(void* param)
{
WatchDog* dog = (WatchDog*)param;
dog->Feed();
}
void WatchDog::Start(uint ms, uint msFeed)
{
static WatchDog dog;
static uint tid = 0;
if(ms > 0x0FFF)
dog.ConfigMax();
else
dog.Config(ms);
if(!tid && msFeed > 0 && msFeed <= 26000)
{
debug_printf("WatchDog::Start ");
tid = Sys.AddTask(FeedDogTask, &dog, msFeed, msFeed, "看门狗");
}
}