STM32独立看门狗和低功耗模式_RTC定时唤醒来喂狗

在stm32开发中经常会用到独立看门狗(iwdg)和低功耗模式,看门狗是为了检测和解决由软件错误引起的故障,低功耗模式是为了在cpu不需要继续运行时进入到休眠模式用以节省电能。其中独立看门狗的时钟由独立的rc振荡器(stm32f10x一般为40khz)提供,即使在主时钟出现故障时,也仍然有效,因此可以在停止和待机模式下工作。而且独立看门狗一旦启动,除了系统复位,它不能再被停止。但这样引发的一个问题是当mcu进入到低功耗模式后由于cpu停止运行无法喂狗,会导致系统频繁复位。那如何解决这个问题呢,难道独立看门狗和低功耗模式没法同时使用?
一个很好的方式是在休眠模式下通过rtc定时唤醒来喂狗,喂完够在进入继续进入到休眠模式。比如看门狗复位的时间间隔为10s。那么在进入休眠模式前设置rtc闹钟中断时间为5s。这样每隔5s唤醒一次喂一次狗。便可以很好的解决这个问题。
while(1)
{
// 执行任务
task1();
task2();
// ..
// 喂狗
dev_iwdg_feed();
// 进入待机模式开关
if(m_benterstandbymode)
{
// 使能外部中断,gpiob3,用以mcu从待机模式唤醒
dev_exti_enable(true);
enterstopmode:
// 设置rtc闹钟,5秒钟产生一次rtc闹钟中断*/
dev_rtc_setalarm(5);
// 进入停止模式(低功耗),直至外部中断触发时被唤醒
pwr_enterstopmode(pwr_regulator_lowpower, pwr_stopentry_wfi);
// 是否是rtc闹钟中断唤醒
if(dev_rtc_isalarm())
{
// 喂狗
dev_iwdg_feed();
// 喂完狗继续进入停止模式
goto enterstopmode;
}
// 禁止外部中断
dev_exti_enable(false);
// 从停止模式唤醒后恢复系统时钟
dev_clk_restore();
}
}
以下是完整的参考代码:
//**********************************************************************************************
// stm32f10x stopmode rtc feed dog
// compiler: keil uv3
// 2013-01-04 , by friehood
//**********************************************************************************************
#include stm32f10x_lib.h
#include platform_config.h
static boolean g_brtcalarm = false;
/*******************************************************************************
* function name : rcc_configuration
* description : configures the different system clocks.
* input : none
* output : none
* return : none
*******************************************************************************/
void rcc_configuration(void)
{
/* rcc system reset(for debug purpose) */
rcc_deinit();
/* enable hse */
rcc_hseconfig(rcc_hse_on);
/* wait till hse is ready */
if(rcc_waitforhsestartup() == success)
{
/* enable prefetch buffer */
flash_prefetchbuffercmd(flash_prefetchbuffer_enable);
//flash时序控制
//推荐值:sysclk = 0~24mhz latency=0
// sysclk = 24~48mhz latency=1
// sysclk = 48~72mhz latency=2
//flash_setlatency(flash_latency_1); //警告:修改为1会对dma值有影响(如adc采集值会错位)
flash_setlatency(flash_latency_2);
/* hclk = sysclk */
rcc_hclkconfig(rcc_sysclk_div1);
/* pclk2 = hclk */
rcc_pclk2config(rcc_hclk_div1);
/* pclk1 = hclk/2 */
rcc_pclk1config(rcc_hclk_div2);
/* pllclk = 12mhz * 3 = 36 mhz */
rcc_pllconfig(rcc_pllsource_hse_div1, rcc_pllmul_3);
/* enable pll */
rcc_pllcmd(enable);
/* wait till pll is ready */
while(rcc_getflagstatus(rcc_flag_pllrdy) == reset)
{
}
/* select pll as system clock source */
rcc_sysclkconfig(rcc_sysclksource_pllclk);
/* wait till pll is used as system clock source */
while(rcc_getsysclksource() != 0x08)
{
}
}
/* enable pwr and bkp clock */
rcc_apb1periphclockcmd(rcc_apb1periph_pwr | rcc_apb1periph_bkp, enable);
/* enable afio clock */
rcc_apb2periphclockcmd(rcc_apb2periph_afio, enable);
}
/*******************************************************************************
* function name : nvic_configuration
* description : configures the nested vectored interrupt controller.
* input : none
* output : none
* return : none
*******************************************************************************/
void nvic_configuration(void)
{
nvic_inittypedef nvic_initstructure;
#ifdef vect_tab_ram
/* set the vector table base location at 0x20000000 */
nvic_setvectortable(nvic_vecttab_ram, 0x0);
#else /* vect_tab_flash */
/* set the vector table base location at 0x08000000 */
nvic_setvectortable(nvic_vecttab_flash, 0x0);
#endif
/* configure one bit for preemption priority */
nvic_prioritygroupconfig(nvic_prioritygroup_1);
}
/*******************************************************************************
* function name : systick_configuration
* description : configures the systick to generate an interrupt each 1 millisecond.
* input : none
* output : none
* return : none
*******************************************************************************/
void systick_configuration(void)
{
/* select ahb clock(hclk) as systick clock source */
systick_clksourceconfig(systick_clksource_hclk);
/* set systick priority to 3 */
nvic_systemhandlerpriorityconfig(systemhandler_systick, 3, 0);
/* systick interrupt each 1ms with hclk equal to 72mhz */
systick_setreload(72000);
/* enable the systick interrupt */
systick_itconfig(enable);
}
/*******************************************************************************
* function name : delay
* description : inserts a delay time.
* input : ntime: specifies the delay time length, in milliseconds.
* output : none
* return : none
*******************************************************************************/
void delay(u32 ntime)
{
/* enable the systick counter */
systick_countercmd(systick_counter_enable);
timingdelay = ntime;
while(timingdelay != 0);
/* disable the systick counter */
systick_countercmd(systick_counter_disable);
/* clear the systick counter */
systick_countercmd(systick_counter_clear);
}
/*******************************************************************************
* function name : rtc_configuration
* description : configures rtc clock source and prescaler.
* input : none
* output : none
void rtc_configuration(void)
{
exti_inittypedef exti_initstructure;
nvic_inittypedef nvic_initstructure;
/* rtc clock source configuration ------------------------------------------*/
/* allow access to bkp domain */
pwr_backupaccesscmd(enable);
/* reset backup domain */
bkp_deinit();
/* enable the lsi osc */
rcc_lsicmd(enable);
/* wait till lsi is ready */
while (rcc_getflagstatus(rcc_flag_lsirdy) == reset){}
/* select the rtc clock source */
rcc_rtcclkconfig(rcc_rtcclksource_lsi);
/* enable the rtc clock */
rcc_rtcclkcmd(enable);
/* rtc configuration -------------------------------------------------------*/
/* wait for rtc apb registers synchronisation */
rtc_waitforsynchro();
/* set rtc prescaler: set rtc period to 1sec */
rtc_setprescaler(40000);
/* wait until last write operation on rtc registers has finished */
rtc_waitforlasttask();
/* enable the rtc alarm interrupt */
rtc_itconfig(rtc_it_alr, enable);
/* wait until last write operation on rtc registers has finished */
rtc_waitforlasttask();
/* configure exti line17(rtc alarm) to generate an interrupt on rising edge */
exti_clearitpendingbit(exti_line17);
exti_initstructure.exti_line = exti_line17;
exti_initstructure.exti_mode = exti_mode_interrupt;
exti_initstructure.exti_trigger = exti_trigger_rising;
exti_initstructure.exti_linecmd = enable;
exti_init(&exti_initstructure);
/* enable the rtc interrupt */
nvic_initstructure.nvic_irqchannel = rtcalarm_irqchannel;
nvic_initstructure.nvic_irqchannelpreemptionpriority = 0;
nvic_initstructure.nvic_irqchannelsubpriority = 0;
nvic_initstructure.nvic_irqchannelcmd = enable;
nvic_init(&nvic_initstructure);
}
/*******************************************************************************
* function name : rtcalarm_irqhandler
* description : this function handles rtc alarm interrupt request.
* input : none
* output : none
* return : none
*******************************************************************************/
void rtcalarm_irqhandler(void)
{
if(rtc_getitstatus(rtc_it_alr) != reset)
{
/* set the rtc alarm flag */
g_brtcalarm = true;
/* clear exti line17 pending bit */
exti_clearitpendingbit(exti_line17);
/* check if the wake-up flag is set */
if(pwr_getflagstatus(pwr_flag_wu) != reset)
{
/* clear wake up flag */
pwr_clearflag(pwr_flag_wu);
}
/* wait until last write operation on rtc registers has finished */
rtc_waitforlasttask();
/* clear rtc alarm interrupt pending bit */
rtc_clearitpendingbit(rtc_it_alr);
/* wait until last write operation on rtc registers has finished */
rtc_waitforlasttask();
}
}
/*******************************************************************************
* function name : dev_rtc_setalarm
* description : 设置rtc闹钟。
* input : 闹钟时间
* output : none
* return : none
*******************************************************************************/
void dev_rtc_setalarm(u32 alarmvalue)
{
/* clear the rtc sec flag */
rtc_clearflag(rtc_flag_sec);
/* wait clear rtc flag sccess */
while(rtc_getflagstatus(rtc_flag_sec) == reset);
/* wait until last write operation on rtc registers has finished */
rtc_waitforlasttask();
/* sets the rtc alarm value */
rtc_setalarm(rtc_getcounter() + alarmvalue);
/* wait until last write operation on rtc registers has finished */
rtc_waitforlasttask();
}
/*******************************************************************************
* function name : dev_rtc_isalarm
* description : rtc闹钟是否触发
* input : none
* output : none
* return : true:已触发,false,未触发
*******************************************************************************/
boolean dev_rtc_isalarm(void)
{
if(g_brtcalarm)
{
/* clear the rtc alarm flag */
g_brtcalarm = false;
return true;
}
return false;
}
void dev_iwdg_init(void)
{
/* enable write access to iwdg_pr and iwdg_rlr registers */
iwdg_writeaccesscmd(iwdg_writeaccess_enable);
/* iwdg counter clock: 40khz(lsi) / 256 = 0.15625 khz */
iwdg_setprescaler(iwdg_prescaler_256);
/* set counter reload value to 1562 */
iwdg_setreload(1562); // 10s
/* reload iwdg counter */
iwdg_reloadcounter();
/* enable iwdg (the lsi oscillator will be enabled by hardware) */
iwdg_enable();
}
void dev_iwdg_feed(void)
{
iwdg_reloadcounter();
}
/*******************************************************************************
* function name : dev_clk_restore
* description : restore system clock after wake-up from stop: enable hse, pll
* and select pll as system clock source.
* input : none
* output : none
* return : none
*******************************************************************************/
void dev_clk_restore(void)
{
/* enable hse */
rcc_hseconfig(rcc_hse_on);
/* wait till hse is ready */
hsestartupstatus = rcc_waitforhsestartup();
if(hsestartupstatus == success)
{
/* enable pll */
rcc_pllcmd(enable);
/* wait till pll is ready */
while(rcc_getflagstatus(rcc_flag_pllrdy) == reset)
{
}
/* select pll as system clock source */
rcc_sysclkconfig(rcc_sysclksource_pllclk);
/* wait till pll is used as system clock source */
while(rcc_getsysclksource() != 0x08)
{
}
}
}
/*******************************************************************************
* function name : exti_configuration
* description : configures exti line3.
* input : none
* output : none
* return : none
*******************************************************************************/
void exit_configuration(void)
{
exti_inittypedef exti_initstructure;
gpio_extilineconfig(gpio_portsourcegpiob,gpio_pinsource3);
exti_clearitpendingbit(exti_line3);
exti_initstructure.exti_line = exti_line3;
exti_initstructure.exti_mode = exti_mode_interrupt;
exti_initstructure.exti_trigger = exti_trigger_falling;
exti_initstructure.exti_linecmd = enable;
exti_init(&exti_initstructure);
}
void dev_exti_enable(boolean benable)
{
nvic_inittypedef nvic_initstructure;
/* clear the key button exti line pending bit */
exti_clearitpendingbit(exti_line3);
nvic_clearirqchannelpendingbit(exti3_irqchannel);
nvic_initstructure.nvic_irqchannel = exti3_irqchannel;
nvic_initstructure.nvic_irqchannelpreemptionpriority = 0;
nvic_initstructure.nvic_irqchannelsubpriority = 0;
nvic_initstructure.nvic_irqchannelcmd = benable ? enable : disable;
nvic_init(&nvic_initstructure);
}
/*******************************************************************************
* function name : main
* description : main program.
* input : none
* output : none
* return : none
*******************************************************************************/
int main(void)
{
/* system clocks configuration */
rcc_configuration();
/* nvic configuration */
nvic_configuration();
/* configure rtc clock source and prescaler */
rtc_configuration();
/* configure the systick to generate an interrupt each 1 millisecond */
systick_configuration();
/* configures exti line3 */
exit_configuration();
/* iwdg initialize*/
dev_iwdg_init();
while(1)
{
// 执行任务
task1();
task2();
// 。。
// 喂狗
dev_iwdg_feed();
// 进入待机模式开关
if(m_benterstandbymode)
{
// 使能外部中断,gpiob3,用以mcu从待机模式唤醒
dev_exti_enable(true);
enterstopmode:
// 设置rtc闹钟,5秒钟产生一次rtc闹钟中断*/
dev_rtc_setalarm(5);
// 进入停止模式(低功耗),直至外部中断触发时被唤醒
pwr_enterstopmode(pwr_regulator_lowpower, pwr_stopentry_wfi);
// 是否是rtc闹钟中断唤醒
if(dev_rtc_isalarm())
{
// 喂狗
dev_iwdg_feed();
// 喂完狗继续进入停止模式
goto enterstopmode;
}
// 禁止外部中断
dev_exti_enable(false);
// 从停止模式唤醒后恢复系统时钟
dev_clk_restore();
}
}
}

Imagination 推出全球最高品质的 WebRTC 媒体引擎
有风的地方也有AR,亮风台带你去这样的浪漫大理
医疗和健身监视器的无线连接方案介绍
封测涨价延续至明年二季度;苹果还会自研基带吗? | 一周科技热评
基于紫外光辐照/电解质调控VO2非易失相变的新型神经形态光电传感器
STM32独立看门狗和低功耗模式_RTC定时唤醒来喂狗
海信升级ULED技术 发布一系列新品
5G将至 三大运营商亮出自己的计划
特斯拉超级电池工厂在内华达州获1.5亿美元税收优惠 总投资26亿美元
微型自动增益控制分类的红外接收器AGC5
派克Parker伺服驱动器 高性能电机控制系统的应用详解
让美国畏惧的华为5G,将如何影响自动驾驶发展?
意法半导体正式退出 意法爱立信前途渺茫
基于nRF24E1无线耳麦的设计与实现
随着信息力量的迅速壮大,人工智能正在走向2.0时代
FPC柔性线路板铜箔表面处理工序 铜箔等离子清洗处理工艺
物联网的连接纽带——蓝牙技术【技术周刊】
贸泽电子发布EIT计划2021系列最后一期 探讨工业自动化新兴趋势
结构体使用方法
十三五期间,华为对上海GDP总体拉动近千亿元