API GUIDE / WDT / Middleware
G32S10 WDT Middleware 接口
Middleware 层接口:两种实例均支持直接复位模式。
1. 构建配置与文件组织
1.1 文件职责
| 文件 | 说明 |
|---|---|
code/middleware/wdt/include/im_wdt.h | 公开枚举、配置结构、回调和 API 声明。 |
code/middleware/wdt/im_wdt.c | 单例状态、CPM 时钟读取、HAL 编排、IRQ 生命周期和 API 实现。 |
code/middleware/wdt/Kconfig | MIDDLEWARE_WDT 构建选项及依赖。 |
code/middleware/wdt/CMakeLists.txt | 在 CONFIG_MIDDLEWARE_WDT=y 时加入 MID 源文件和头文件目录。 |
code/middleware/wdt/example/main/main.c | HP_WDT DIRECT 模式示例。 |
2. 资源模型与公开类型
2.1 实例
| MID 枚举 | 硬件实例 | 基地址 |
|---|---|---|
IM_WDT_INSTANCE_HP | HP_WDT | 0x13740000 |
IM_WDT_INSTANCE_LP | LP_WDT | 0x100CE000 |
两种实例均支持直接复位模式。当前只有 HP_WDT 支持中断后复位模式。
2.2 公开枚举
2.2.1 im_wdt_instance_t
typedef enum {
IM_WDT_INSTANCE_HP = 0,
IM_WDT_INSTANCE_LP,
} im_wdt_instance_t;| 值 | 说明 |
|---|---|
IM_WDT_INSTANCE_HP | 使用 HP_WDT,支持 DIRECT 和 IRQ 后复位模式。 |
IM_WDT_INSTANCE_LP | 使用 LP_WDT,当前只支持 DIRECT 模式。 |
2.2.2 im_wdt_reset_mode_t
typedef enum {
IM_WDT_RESET_DIRECT = 0,
IM_WDT_RESET_IRQ,
} im_wdt_reset_mode_t;| 值 | 说明 |
|---|---|
IM_WDT_RESET_DIRECT | FULL 到期后直接进入硬件复位流程。 |
IM_WDT_RESET_IRQ | FULL 先触发 HP_WDT 中断,MID 回调返回并应答 FULL 后进入复位流程。 |
IM_WDT_RESET_IRQ 与 IM_WDT_INSTANCE_LP 组合时,im_wdt_init() 返回 IM_ERR_UNSUPPORTED。
2.2.3 im_wdt_prescaler_t
typedef enum {
IM_WDT_PRESCALER_1 = 0,
IM_WDT_PRESCALER_4,
IM_WDT_PRESCALER_16,
IM_WDT_PRESCALER_64,
IM_WDT_PRESCALER_256,
IM_WDT_PRESCALER_1024,
} im_wdt_prescaler_t;这些枚举值与 HAL 分频字段编码一致。除特别说明外,应优先使用 auto_prescaler = true,由 HAL 根据目标超时和实际 RTCLK 自动选择分频。
2.3 单例和生命周期
im_wdt_* 接口管理模块内的一个静态单例,没有公开设备句柄。一个系统只能同时使用一个 WDT 实例和一个配置。
MID 内部主要状态如下:
| 内部状态 | 说明 |
|---|---|
| 未初始化 | im_wdt_init() 尚未成功。start、feed、stop、restart 返回 IM_ERR_NOT_READY。 |
| 已初始化、未启动 | HAL 已完成配置,可以调用 im_wdt_start()。 |
| 运行中 | WDT 正在计数,可调用 im_wdt_feed() 或 im_wdt_stop()。再次调用 im_wdt_start() 返回 IM_ERR_BUSY。 |
| 重启等待 | im_wdt_restart() 已成功启动最短 DIRECT 复位。后续 init、start、feed、stop 返回 IM_ERR_BUSY,直到芯片复位。 |
3. 公开接口规范
3.1 im_wdt_config_default
error_code_t im_wdt_config_default(im_wdt_config_t *config);
填充一份默认配置,不访问硬件。
| 字段 | 默认值 |
|---|---|
instance |
IM_WDT_INSTANCE_HP |
timeout_ms |
HAL_WDT_DEFAULT_TIMEOUT_MS,当前为 1000 ms |
prescaler |
IM_WDT_PRESCALER_1 |
auto_prescaler |
true |
reset_mode |
IM_WDT_RESET_DIRECT |
irq_id |
0 |
irq_name |
NULL |
timeout_callback |
NULL |
user_data |
NULL |
返回 IM_OK 表示填充成功;config == NULL 时返回 IM_ERR_INVALID_PARAM。
3.2 im_wdt_init
error_code_t im_wdt_init(const im_wdt_config_t *config);
初始化并配置单例 WDT,但不启动计数。
主要流程:
- 校验实例、复位模式和 IRQ 参数。
- 打开 CPM WDT 时钟门控并获取 RTCLK。
- 关闭并释放上一次由 MID 管理的 IRQ。
- 初始化 HAL 句柄和 WDT 外设。
- 根据 RTCLK、超时和分频写入 HAL 配置。
- IRQ 模式下注册 HAL 超时桥接回调。
- 发布新的 MID 活动配置。
主要返回值:
| 返回值 | 说明 |
|---|---|
IM_OK |
配置成功,可以调用 im_wdt_start()。 |
IM_ERR_INVALID_PARAM |
config 为空、实例/模式非法、IRQ ID 非法、超时无法表示或 HAL 参数错误。 |
IM_ERR_BUSY |
WDT 正在运行,或 im_wdt_restart() 已进入等待复位阶段。 |
IM_ERR_UNSUPPORTED |
LP_WDT 配置为 IRQ 模式。 |
| 其他错误码 | CPM、IRQ 或 HAL 初始化失败。 |
补充说明:
- 重新调用
im_wdt_init()可以切换实例、超时或复位模式,但当前 WDT 必须不在运行状态。 - HAL 句柄初始化或 HAL 配置失败时,MID 会停止 HAL WDT、关闭 MID 管理的 IRQ 并清空活动配置。若在读取 CPM 时钟阶段失败,则硬件尚未被重新配置。
3.3 im_wdt_start
error_code_t im_wdt_start(void);
使用最近一次成功的 im_wdt_init() 配置启动 WDT,并清空计数器。
| 场景 | 行为 |
|---|---|
| DIRECT 模式 | 直接调用 HAL 启动,不需要 IRQ。 |
| HP_WDT IRQ 模式 | 先注册并使能 PLIC IRQ,再启动 HP_WDT 中断后复位模式。 |
主要返回值:
| 返回值 | 说明 |
|---|---|
IM_OK |
启动成功,进入看门狗运行状态。 |
IM_ERR_NOT_READY |
尚未成功初始化,或 HAL 尚未完成配置。 |
IM_ERR_BUSY |
WDT 已在运行,或正在等待重启复位。 |
IM_ERR_UNSUPPORTED |
IRQ 框架不支持普通 PLIC 注册/使能。 |
IM_ERR_ALREADY_REGISTERED |
指定的 HP_WDT IRQ 已被其它模块占用。 |
| 其他错误码 | PLIC 或 HAL 启动失败。 |
IRQ 模式下如果启动失败,MID 会关闭本次临时打开的 IRQ。启动成功后,IRQ 会保持打开,直到 im_wdt_stop()、重新 im_wdt_init() 或 im_wdt_restart()。
3.4 im_wdt_feed
error_code_t im_wdt_feed(void);
清除 WDT 当前计数值,即执行一次喂狗。
| 返回值 | 说明 |
|---|---|
IM_OK |
喂狗成功。 |
IM_ERR_NOT_READY |
WDT 尚未初始化或尚未启动。 |
IM_ERR_BUSY |
已进入重启等待复位阶段。 |
| 其他错误码 | HAL 喂狗失败。 |
喂狗周期必须小于实际 WDT 超时时间。阻塞时间较长、可能关闭中断或暂停调度的代码路径,应额外留出余量。
3.5 im_wdt_stop
error_code_t im_wdt_stop(void);
停止 WDT 计数,并关闭、释放 MID 管理的 HP_WDT IRQ。
| 返回值 | 说明 |
|---|---|
IM_OK |
计数已停止,IRQ 已释放。 |
IM_ERR_NOT_READY |
WDT 尚未成功初始化。 |
IM_ERR_BUSY |
已进入重启等待复位阶段,不允许取消。 |
| 其他错误码 | HAL 停止或 IRQ 释放失败。 |
补充说明:
- 已初始化配置仍然保留,可再次调用
im_wdt_start()。 - 该接口不是反初始化接口,不会清空
im_wdt_config_t的配置快照。 - 当前 MID 没有公开的
im_wdt_deinit()。
3.6 im_wdt_restart
error_code_t im_wdt_restart(void);
请求通过 WDT 主动复位芯片。
主要流程:
- 从 CPM 获取 RTCLK;查询失败时保持当前 WDT 状态不变。
- 停止当前 WDT 并释放 IRQ。
- 使用最短合法超时、自动分频和 DIRECT 模式重新配置 WDT。
- 启动计数。
- 成功后将 MID 标记为“重启等待”,后续控制接口返回
IM_ERR_BUSY,等待硬件复位。
| 返回值 | 说明 |
|---|---|
IM_OK |
最短 DIRECT 复位流程已启动;函数返回后芯片将在随后发生复位。 |
IM_ERR_NOT_READY |
WDT 尚未成功初始化。 |
IM_ERR_BUSY |
已经有一次重启正在等待复位。 |
| 其他错误码 | HAL 停止、CPM 时钟查询、HAL 配置或启动失败。 |
im_wdt_restart() 不是同步复位调用。返回值只表示复位倒计时已经成功启动,函数返回前芯片不会立即复位。
3.7 超时回调
typedef void (*im_wdt_timeout_callback_t)(void *user_data);
该回调只在 HP_WDT + IM_WDT_RESET_IRQ 模式使用。
- 回调运行在 WDT IRQ 上下文。
- 回调返回且 HAL 应答 FULL 后,硬件才继续进入复位流程。
- 回调中不得阻塞、睡眠、等待锁、输出大量日志或调用任何
im_wdt_*控制接口。 - 必须复位前完成的关键数据保存应尽量简短;复杂处理应投递到任务后立即返回。
4. 行为约束与资源管理
4.1 HP/LP 模式约束
| 实例 | DIRECT | IRQ 后复位 |
|---|---|---|
IM_WDT_INSTANCE_HP | 支持 | 支持 |
IM_WDT_INSTANCE_LP | 支持 | 不支持 |
4.2 IRQ 资源
HP_WDT IRQ 模式使用调用方指定的
irq_id,典型值为IRQ_TCU_WDT。MID 在
im_wdt_start()中注册并使能 IRQ,在停止、重新初始化和重启前释放。irq_id必须大于IRQ_PLIC_START且小于IRQ_NUMS。CONFIG_IRQ_SIMPLE_DISPATCH=y时,普通 PLIC 注册接口可能返回IM_ERR_UNSUPPORTED,此时只能使用 DIRECT 模式。其它模块已经注册同一个 IRQ 时,MID 返回
IM_ERR_ALREADY_REGISTERED,不会抢占该 IRQ。
4.3 并发和线程约束
MID 使用内部互斥锁保护初始化、启动、停止和重启流程。
im_wdt_feed()可以在任务中调用,不能在 WDT 回调内部调用。多个任务不应无协调地重复启动或停止 WDT。
WDT 回调在 IRQ 上下文执行,不能调用 MID 控制 API。
4.4 重新配置和时钟变化
WDT 运行时调用
im_wdt_init()返回IM_ERR_BUSY。需要先停止 WDT。im_wdt_start()使用已保存的配置,不重新查询 CPM。如果 CPM RTCLK 在初始化后发生变化,应停止 WDT、重新调用
im_wdt_init(),再启动;或直接使用im_wdt_restart()。
5. 典型用法
5.1 HP_WDT 直接复位看门狗
#include "im_error.h"
#include "im_time.h"
#include "im_wdt.h"
error_code_t wdt_keepalive_init(void)
{
im_wdt_config_t config;
error_code_t ret;
ret = im_wdt_config_default(&config);
if (ret != IM_OK) {
return ret;
}
config.instance = IM_WDT_INSTANCE_HP;
config.timeout_ms = 5000U;
config.auto_prescaler = true;
config.reset_mode = IM_WDT_RESET_DIRECT;
ret = im_wdt_init(&config);
if (ret != IM_OK) {
return ret;
}
return im_wdt_start();
}
error_code_t wdt_keepalive_feed(void)
{
return im_wdt_feed();
}应用应以明显短于 5000 ms 的周期调用 wdt_keepalive_feed()。示例程序使用 1000 ms 周期。
5.2 LP_WDT 直接复位看门狗
im_wdt_config_t config;
error_code_t ret;
ret = im_wdt_config_default(&config);
if (ret != IM_OK) {
return ret;
}
config.instance = IM_WDT_INSTANCE_LP;
config.timeout_ms = 5000U;
config.auto_prescaler = true;
config.reset_mode = IM_WDT_RESET_DIRECT;
ret = im_wdt_init(&config);
if (ret == IM_OK) {
ret = im_wdt_start();
}LP_WDT 不能配置为 IM_WDT_RESET_IRQ,超时后直接进入复位流程。
5.3 HP_WDT 中断后复位
static void wdt_timeout_callback(void *user_data)
{
(void)user_data;
/* 只执行 ISR 安全且必须在复位前完成的最小动作。 */
}
error_code_t wdt_irq_mode_init(void)
{
im_wdt_config_t config;
error_code_t ret;
ret = im_wdt_config_default(&config);
if (ret != IM_OK) {
return ret;
}
config.instance = IM_WDT_INSTANCE_HP;
config.timeout_ms = 3000U;
config.auto_prescaler = true;
config.reset_mode = IM_WDT_RESET_IRQ;
config.irq_id = (uint32_t)IRQ_TCU_WDT;
config.irq_name = "app_wdt";
config.timeout_callback = wdt_timeout_callback;
config.user_data = NULL;
ret = im_wdt_init(&config);
if (ret != IM_OK) {
return ret;
}
return im_wdt_start();
}应用必须在启动 WDT 前完成 IRQ 框架初始化。回调返回后,硬件进入复位流程。
5.4 主动请求复位
error_code_t ret;
ret = im_wdt_restart();
if (ret == IM_OK) {
/* WDT 已启动最短合法 DIRECT 复位,等待硬件复位。 */
}成功返回后不要再调用 im_wdt_feed() 或 im_wdt_stop() 尝试取消复位,这些接口会返回 IM_ERR_BUSY。