RAM NOINIT,利用看门狗中断恢复RTC

wangbing · 28次点击 · 7天前

核心问题:当看门狗复位发生时,RTC(实时时钟)和PMU TIMER(电源管理单元定时器)的硬件TICK会被重置为零。本文将重点放在RTC上。

相关技术依赖:

  • 硬件层面,看门狗中断函数以及RAM的前后8KB区域在看门狗复位时保持稳定不变。

  • 软件层面,通过修改连接脚本,在脚本中定义一段内存区域用于存储备份数据。


  1. 看门狗中断

根据Reference Manual的描述:

image.png

看门狗的计数器是一个20位的递减计数器,其时钟源为RC32K,并且已经分频至128Hz(即看门狗的时钟周期为128Hz,大约等于7.8毫秒)。一旦启用看门狗,计数值降至0xa时,将触发看门狗中断函数。此时,代码的中断向量处理函数WDT_IRQHandler将被调用。随后,看门狗计数器继续递减,直至值为0,此时系统将执行复位。因此,从WDT_IRQHandler执行到系统复位,大约有78毫秒的时间可用于处理紧急事务。鉴于RC32K时钟的精度,建议将处理任务的时间限制在最短范围内,例如20至30毫秒内,以确保安全。


1 初始化看门狗并启用中断

// 已经在wdt_bkup.c/h中提供 
void wdt_irq_enable(void) {
    // Enable WDT cpu en int     
    REGW1(&OM_PMU->WDT_STATUS, PMU_WDT_STATUS_WDT_INT_CPU_EN_MASK);
    // Enable WDT NVIC int     
    NVIC_ClearPendingIRQ(WDT_IRQn);     
    NVIC_SetPriority(WDT_IRQn, RTE_WDT_IRQ_PRIORITY);     
    NVIC_EnableIRQ(WDT_IRQn); 
} 

main.c 
... 
int main(void) {
    ...     
    drv_wdt_init(5000);     
    wdt_irq_enable(); // 打开看门狗中断     
    ...     
    ... 
}

2 利用看门狗实现快速复位,初始化值不宜过小,理论上不应低于86毫秒,以确保能够产生中断

#include "om_driver.h" 
#include "wdt_bkup.h" 
// 调用看门狗 
void app_reset(void) {
    // 时间必须大于78.125ms,内部按照ms*128/1000进行取整,必须满足这个值计算出来大于0x0a     
    // 比如要设置计数值位0x0b,那么反推计算(11*1000/128)=85.9375,向上取整为86     
    // 这里,故意让计数值比原理论值大于5, 那么(15*1000/128)=117.85≈118     
    drv_wdt_init(118);      
    wdt_irq_enable(); // 必须重新调用
    while(1); 
}


3 保留RAM区域

在看门狗复位时,RAM的前后各8KB区域将保持不变,而其他区域的内容在复位后会丢失。RAM后部的内容为系统保留。建议在RAM的起始前8KB区域中定义一段空间用于存储数据。

以Keil为例,通过修改link_flash.sct文件来实现。


4 修改链接脚本

以下为关键修改部分:

image.png

image.png


5 定义变量

// 魔术字用来标记当前区域保存的内容是否是手动保存
__attribute((section(".bss.NOINIT"))) volatile uint64_t backup_magic_word;

// 定义RTC备份的变量值
__attribute((section(".bss.NOINIT"))) volatile uint32_t rtc_time_backup;

// 定义其他值
__attribute((section(".bss.NOINIT"))) volatile uint32_t measure_start_backup;


6 在看门狗中断中保存变量

image.png


7 在main.c的早期阶段获取备份变量并清除魔术字

image.png


8 在初始化RTC时应用备份值

uint32_t rtc_val_init = 0; 
if (notinit_data_valid()) {     
    rtc_val_init = rtc_time_backup; 
} 
no_init_clear_magic(); 
// 初始化RTC 
#include <time.h> 
om_error_t err = drv_rtc_init(OM_RTC); 

... 
rtc_tm_t tm; 
time_t time_sec = rtc_val_init; 
memcpy(&tm, localtime(&time_sec), sizeof(rtc_tm_t));  
drv_rtc_timer_set(OM_RTC, &tm);



wdt_isr_ram_noinit-202504168882.zip
被收藏 0  ∙  1 赞  
加入收藏
点赞
0 回复  
善言善语 (您需要 登录 后才能回复 没有账号 ?)

请先登录网站