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/KconfigMIDDLEWARE_WDT 构建选项及依赖。
code/middleware/wdt/CMakeLists.txt在 CONFIG_MIDDLEWARE_WDT=y 时加入 MID 源文件和头文件目录。
code/middleware/wdt/example/main/main.cHP_WDT DIRECT 模式示例。

2. 资源模型与公开类型

2.1 实例

MID 枚举硬件实例基地址
IM_WDT_INSTANCE_HPHP_WDT0x13740000
IM_WDT_INSTANCE_LPLP_WDT0x100CE000

两种实例均支持直接复位模式。当前只有 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_DIRECTFULL 到期后直接进入硬件复位流程。
IM_WDT_RESET_IRQFULL 先触发 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,但不启动计数。

主要流程:

  1. 校验实例、复位模式和 IRQ 参数。
  2. 打开 CPM WDT 时钟门控并获取 RTCLK。
  3. 关闭并释放上一次由 MID 管理的 IRQ。
  4. 初始化 HAL 句柄和 WDT 外设。
  5. 根据 RTCLK、超时和分频写入 HAL 配置。
  6. IRQ 模式下注册 HAL 超时桥接回调。
  7. 发布新的 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 主动复位芯片。

主要流程:

  1. 从 CPM 获取 RTCLK;查询失败时保持当前 WDT 状态不变。
  2. 停止当前 WDT 并释放 IRQ。
  3. 使用最短合法超时、自动分频和 DIRECT 模式重新配置 WDT。
  4. 启动计数。
  5. 成功后将 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 模式约束

实例DIRECTIRQ 后复位
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。