ESP32S3:解决RWDT无法触发中断问题,二次开发者怎么才能使用内部RTC看门狗中断RWDT呢?

发布时间:2026/8/28 13:09:49
ESP32S3:解决RWDT无法触发中断问题,二次开发者怎么才能使用内部RTC看门狗中断RWDT呢? 目录基于ESP32S3解决RWDT无法触发中断问题引言解决方案1. 查看报错日志2. 分析报错及一步一步找到解决方法3.小结我的源码基于ESP32S3解决RWDT无法触发中断问题引言在嵌入式系统中RWDT看门狗定时器是确保系统稳定性的重要组件。然而在某些情况下RWDT可能无法触发预期的中断。本文旨在探讨此问题的原因及解决方案。解决方案1. 查看报错日志从上图可以知道错误是程序那个位置发生的那么报错的程序如下图所示2. 分析报错及一步一步找到解决方法从上面已经知道了导致报错的程序位置了那么我调用esp_intr_alloc函数传入的形参与对比官方的源码调用esp_intr_alloc来看都没有什么问题猜测一般是该中断源可能已经被使用过导致的我们可以分析一下esp_intr_alloc函数。跳转到esp_intr_alloc函数中如下图所示可以看到该函数其只是调用esp_intr_alloc_intrstatus函数而已那么跳转到esp_intr_alloc_intrstatus函数中如下图所示我们可以在红色框框看出该函数内使用的是ESP_EARLY_LOGV函数进行日志输出。结果调用这个函数后并没有ESP_EARLY_LOGV函数后并没有生效没用对应的日志输出出来那我们先看看函数的介绍如下图log文件路径\Espressif\frameworks\esp-idf-v5.1.2\components\log\log.c从上面可只log_levelESP_LOG_VERBOSE而LOG_LOCAL_LEVEL和esp_log_default_level又是哪里定义的呢下图是我找到其定义从上面可分析出ESP_EARLY_LOGV日志输出使能条件是 CONFIG_LOG_MAXIMUM_LEVELESP_LOG_VERBOSE 和 CONFIG_LOG_DEFAULT_LEVELESP_LOG_VERBOSE 同时成立。而CONFIG_LOG_MAXIMUM_LEVEL和CONFIG_LOG_DEFAULT_LEVEL都是在sdkconfig上定义的那么我们可以通过menuconfig图形化工具进行设置如下重新编译运行后ESP_EARLY_LOGV就能正常输出日志了但是因为这种设置时全局的导致系统所有的日志都输出出来这是不想看到的因此只在这个函数修改 LOG_LOCAL_LEVEL和esp_log_default_level即可那么就不会影响到全局了操作如下图所示这是日志也能正常输出了从上面申请中断的日志和RTC中断源号可看出在进入主函数和系统调度前就已经申请了所以这也就是为什么申请RTC中断失败的原因了。那么现在就是要找找到底是哪里申请了该RTC中断了可以在函数调用中加esp_backtrace_print这个函数这个函数是打印堆栈信息的如下输出日志如下从上面日志可以确定调用的文件是如下图因此我们可以通过menuconfig将该功能禁用掉如下图这时再次运行RWDT中断实验程序就没问题了。CONFIG_ESP_BROWNOUT_DET一般不能关闭这个关闭后就无法检测芯片的电源电压这个检测保护机制了中断服务程序如下我又在想如果CONFIG_ESP_BROWNOUT_DE不禁用貌似我们无法使用RWDT中断功能了那我们先看看BROWNOUT使用RTC中断做什么如下红色框框调用的rtc_isr_ensure_installed函数以名称看内部应该就包含中断的申请操作了跳转rtc_isr_ensure_installed函数中如下图所示我在rtc_isr_ensure_installed函数中其调用的esp_intr_alloc传入的参数有个参数不同寻常那就是rtc_ist这个跳转该参数中如下图所示从上面分析可得*it-handler(it-handler_arg)item-handler handler; item-handler_arg handler_arg;rtc_brownout_isr_handler。可以看出这个中断服务程序实质去遍历s_rtc_isr_handler_list链表调用链表中的函数从而调用BROWNOUT的中断服务程序。BROWNOUT的中断服务程序如下经过查看CONFIG_ESP_SYSTEM_BROWNOUT_INTR这个宏定义是没用定义的也就是说BROWNOUT中断功能默认是没开启的所以前面我们提到的CONFIG_ESP_BROWNOUT_DET一般不能关闭这个关闭后就无法检测芯片的电源电压这个检测保护机制了实质打开了CONFIG_ESP_BROWNOUT_DET这个配置也是该功能没用生效的。经上面分析可知我做的rwdt_isr_handler中断服务程序应该叫处理函数可以修改成使用rtc_isr_register函数注册通过插入s_rtc_isr_handler_list链表形式导入到真正的rtc_isr中断服务程序中进行索引所有注册的处理函数进行调用如下图所示3.小结通过调整日志设置、优化中断处理、使用调试工具以及仔细检查系统配置可以有效地解决RWDT无法触发中断的问题。希望本文能为读者在解决类似问题时提供帮助。我的源码/** **************************************************************************************************** * file m_rwdt.c * author 邓家文 * version V1.0 * date 2025-02-09 * brief RWDT驱动代码 * license Copyright (c) * blog https://blog.csdn.net/morecrazylove?typeblog **************************************************************************************************** */#includem_rwdt.h/* * 超级看门狗 (SWD) 是模拟域的超低功耗电路可以防止系统在数字电路异常状态下运行并在必要时复位系统。 * SWD 包含一个看门狗电路需在每个超时阶段约不足一秒至少喂狗一次。该电路会在看门狗超时时间约 100 * ms 之前发送 WD_INTR 信号提醒系统喂狗。 * 如果系统不回应 SWD 的喂狗请求看门狗超时SWD 会产生系统电平信号 SWD_RSTB复位芯片上的整个数 * 字电路。 * 正常状态下 * • SWD 控制器收到 SWD 的喂狗请求。 * • SWD 控制器可以向主 CPU 或 ULP-RISC-V 发送中断。 * • 主 CPU 可以决定是通过置位 RTC_CNTL_SWD_FEED 直接喂狗还是发送中断让 ULP-RISC-V 置位该字 * 段喂狗。 * • CPU 或 ULP-RISC-V 喂狗时需要先向 RTC_CNTL_SWD_WKEY 写 0x8F1D312A 关闭 SWD 控制器的写 * 保护。这样做可以防止系统在数字电路异常状态下运行时误喂 SWD。 * • 如将 RTC_CNTL_SWD_AUTO_FEED_EN 置 1SWD 控制器也可配置为在不需要 CPU 或 ULP-RISC-V 干 * 预的情况下喂 SWD。 * 复位后 * • 可查看 RTC_CNTL_RESET_CAUSE_PROCPU[5:0] 获知 CPU 复位原因。 * 如 RTC_CNTL_RESET_CAUSE_PROCPU[5:0] 0x12则表示上一次复位的原因是 SWD 复位。 * • 置位 RTC_CNTL_SWD_RST_FLAG_CLR 清除 SWD 复位标志。 * * (因此一般情况下不允许用户使用SWD的) *//* ################################################################################################################### */wdt_hal_context_trtc_wdt_ctx{0};// 看门狗定时器上下文结构体intr_handle_trwdt_intr_handle{0};// 中断处理程序句柄/** * brief 看门狗定时器中断服务程序。 * * 该函数是看门狗定时器的中断服务程序 (ISR)。它处理由看门狗定时器触发的中断。 * * param arg 传递给ISR的参数指针。可以用来传递上下文或数据给ISR。 */IRAM_ATTRstaticvoidrwdt_isr_handler(void*arg){esp_rom_printf([RWDT] Stage0 timeout detected!\n);gpio_set_level(GPIO_NUM_40,0);wdt_hal_write_protect_disable(rtc_wdt_ctx);// 关闭RWDT写保护wdt_hal_handle_intr(rtc_wdt_ctx);// 清除中断标志 喂狗wdt_hal_write_protect_enable(rtc_wdt_ctx);// 启用RWDT写保护}/** * brief 初始化看门狗定时器RWDT。 * * 该函数配置并启动了RWDT用于监控系统异常。 * 包括配置中断、设置超时时间、以及配置RWDT的行为。 * * 注意目前尝试了很多方法看门狗触发中断功能都无法正常使用只能看门狗触发系统复位解决该问题调用rtc_isr_register */voidrwdt_init(void){wdt_hal_init(rtc_wdt_ctx,WDT_RWDT,0,true);// 初始化RWDTuint32_tstage_timeout_ticks_ms(uint32_t)((uint64_t)rtc_clk_slow_freq_get_hz()/1000);// 计算超时时间以ticks为单位printf(rtc_clk_slow_freq_get_hz%d\n,rtc_clk_slow_freq_get_hz());// 获取RTC慢时钟频率wdt_hal_write_protect_disable(rtc_wdt_ctx);// 关闭RWDT写保护wdt_hal_config_stage(rtc_wdt_ctx,WDT_STAGE0,2000*stage_timeout_ticks_ms,WDT_STAGE_ACTION_INT);// 配置阶段0 2秒超时 触发中断wdt_hal_config_stage(rtc_wdt_ctx,WDT_STAGE1,5000*stage_timeout_ticks_ms,WDT_STAGE_ACTION_RESET_SYSTEM);// 配置阶段0 1秒超时 系统复位/* 注册中断处理程序中断源ETS_RTC_CORE_INTR_SOURCE一般不使用因为这个是在rtc_brownout_isr_handler用于检测电源电压异常的 */// ESP_ERROR_CHECK(esp_intr_alloc(ETS_RTC_CORE_INTR_SOURCE,// ESP_INTR_FLAG_IRAM,// rwdt_isr_handler,// NULL,// rwdt_intr_handle));#defineRWDT_OUT_INT_HANDLER_SOURCE_MASK888// RWDT中断服务程序源掩码等于服务程序的标牌rtc_isr_register(rwdt_isr_handler,NULL,RWDT_OUT_INT_HANDLER_SOURCE_MASK,RTC_INTR_FLAG_IRAM);// 注册中断处理程序wdt_hal_enable(rtc_wdt_ctx);// 使能RWDTwdt_hal_write_protect_enable(rtc_wdt_ctx);// 重新启用写保护}/** * brief 喂养实时看门狗定时器 (RWDT) 以防止其复位系统。 * * 该函数应定期调用以重置RWDT计数器防止系统被复位。RWDT通常用于确保系统正常运行并从软件故障中恢复。 */voidfeed_rwdt(void){wdt_hal_write_protect_disable(rtc_wdt_ctx);// 关闭RWDT写保护wdt_hal_feed(rtc_wdt_ctx);// 喂狗wdt_hal_write_protect_enable(rtc_wdt_ctx);// 重新启用写保护}