API GUIDE / PLIC / API OVERVIEW
PLIC API 概述
irq api
G32S10 IRQ 接口文档
1. 文档范围
本文档定义 G32S10 SDK IRQ 框架的公开接口和推荐用法,覆盖普通 PLIC 外设 IRQ、V0 ACC/V1 非 ACC 路径、handler 分发、优先级嵌套以及 V0/V1 owner 同步。
主要公开头文件:
code/include/drivers/imsis/im_irq.h
2. 构建配置
2.1 IRQ 框架
CONFIG_DRIVER_IRQ=y
启用后编译 IRQ 框架。
2.2 自定义分发模式
CONFIG_IRQ_SIMPLE_DISPATCH=y
默认值为 n。启用后不编译内置 IRQ 注册表,sys_irq_request() 和 sys_irq_release() 返回 IM_ERR_UNSUPPORTED,应用必须自行实现 sys_irq_dispatch(uint32_t irq_id)。依赖默认注册表的中间件通常不能与该配置同时使用。
2.3 V0 ACC 模式
CONFIG_IRQ_ACC_MODE=y
ACC 是 V0 的硬件辅助中断控制路径。它不是一套软件架构,而是改变“硬件如何选择 IRQ、建立中断上下文、进入向量和返回”的底层执行模型。
该配置只依赖并作用于 BUILD_CORE_V0。V1 没有 ACC:V1 不编译 ACC 专用 IRQ handler,也不使用 ACC 的 MINTCTRL/MSP/PSP 初始化路径。
2.3.1 ACC 与普通 machine external 路径的区别
非 ACC 模式下,普通 PLIC 外部中断的入口只有一个:
PLIC pending
↓
RISC-V machine external trap
↓
sys_irq_plic_dispatch()
↓
软件读取 PLIC claim ID
↓
sys_irq_dispatch(irq_id)
↓
软件 complete PLIC source
V0 ACC 模式下,PLIC/ACC 硬件在产生 machine interrupt 时已经完成 source 选择和向量索引,入口变成:
PLIC/ACC source
↓
ACC vector slot
↓
IRQ_xxx_handler
↓
sys_irq_dispatch(IRQ_xxx)
因此 ACC 普通 IRQ handler 不会调用 sys_irq_plic_dispatch(),也不会在软件中执行普通路径的 claim/complete。代码中的注释明确规定:PLIC claim/complete 由非 ACC external IRQ 路径使用,ACC 路径直接按 source 进入 per-source handler。
这并不意味着 PLIC source 配置被绕过。ACC 模式仍然需要:
- 配置 source priority;
- 使能对应 PLIC source;
- 打开 CPU 的 machine external delivery;
- 打开设备自身的中断产生位。
在默认 SDK 分发路径下,变化只在于“source 被选中后如何进入软件”,而不是取消 PLIC 的 source enable/priority 配置。若采用后文的 ACC 直达 handler 高级用法,则还可以绕过软件注册表,但不能绕过 PLIC 和设备本身的使能配置。
2.3.2 ACC 向量表布局
ACC 相关向量从 vector table 的 IRQ 32 基址之后开始:
| 向量槽/IRQ | 含义 |
|---|---|
| IRQ 32 | ACC 外部中断总入口 |
| source 0 | 保留槽,不作为普通 source 使用 |
| source 1~63 | 映射到普通外设 IRQ handler |
本地和虚拟 IRQ 的向量槽由 SDK、OS 或 IPC 内部使用,不作为普通应用 IRQ 接口说明。
2.3.3 ACC 直接覆盖 IRQ_xxx_handler(高级用法)
V0 ACC 的每个外设向量最终都会跳转到对应的 IRQ_xxx_handler。SDK 默认实现使用弱符号提供这些入口,默认逻辑只是把向量号转换成软件 IRQ 号,再调用 sys_irq_dispatch(IRQ_xxx):
ACC vector
↓
IRQ_xxx_handler(SDK 默认弱定义)
↓
sys_irq_dispatch(IRQ_xxx)
↓
sys_irq_request() 注册的业务 handler
对于对中断延迟特别敏感的 V0 ACC 外设,可以在应用中提供同名的强符号,覆盖 SDK 的弱定义,直接在向量入口处理业务:
/* 仅适用于 V0 + CONFIG_IRQ_ACC_MODE */
void IRQ_UART0_handler(void)
{
/* 在此直接读取 UART0 状态、处理业务并清除 UART0 的 pending 条件 */
}
覆盖后路径变为:
ACC vector
↓
应用自定义 IRQ_UART0_handler()
↓
直接处理 UART0
该用法的特点和约束如下:
- 函数名必须与 ACC 向量使用的符号完全一致,例如
IRQ_UART0_handler; - 入口是向量入口函数,不是
irq_handler_t回调,通常定义为void IRQ_xxx_handler(void),不能按sys_irq_request()的(irq_id, arg)形式实现; - 该路径不经过
sys_irq_dispatch(),也不使用sys_irq_request()注册的同一 IRQ 的软件 handler,因此可以省去软件注册表查找和二次函数调用; - 仍然必须配置 PLIC priority、使能 PLIC source、打开 CPU machine external,以及打开设备内部中断;
- handler 必须自行读取并清除设备的 pending 条件,否则会重复进入中断;
- 不要在该 handler 中再次调用
sys_irq_plic_dispatch(),ACC 路径不走普通 external IRQ 的 PLIC claim/complete 软件流程; - 裸机 ACC 下可以直接使用这种方式;
- FreeRTOS ACC 下,SDK 默认弱 handler 还承担 MIE 保存/恢复和 ISR nesting 维护。直接覆盖会同时覆盖这些包装逻辑,只有在自定义入口自行保留等价的上下文、嵌套和返回约束时才可使用,通常应继续使用 SDK 默认 wrapper +
sys_irq_dispatch()路径。
该高级用法只改变“向量进入业务代码”的方式,不改变 IRQ 号、PLIC source 映射和硬件使能关系。V1 和 V0 非 ACC 不使用这套 per-source ACC handler 覆盖机制。
注意:绕过中断时的软件分发,不等于可以跳过公共 API 的注册检查。默认注册表模式下,sys_irq_enable() 仍要求该 IRQ 已通过 sys_irq_request() 注册,否则返回 IM_ERR_NOT_READY。可保留注册用于资源管理,同时由同名强符号让 ACC 中断直接进入业务处理。
完整的入口定义、初始化和停用示例见后文 15.2 V0 ACC 直达 handler 高级用法模板。
2.4 IRQ owner 同步
CONFIG_IRQ_OWNER_SYNC=y
该配置依赖 G32S10 V0 IPC(核间通信)。启用后,V0/V1 通过 IPC 同步普通 PLIC IRQ 的启用状态,用于记录 IRQ 使用核并检测双核冲突。它是状态同步和冲突告警机制,不是硬件互斥锁;当前实现发现双方同时启用同一 IRQ 时只打印 warning。
3. IRQ 资源模型
3.1 软件 IRQ 和 PLIC source 映射
IRQ 表定义在 code/include/soc/g32s10/irq_table.def:
software_irq_id = plic_source_id + IRQ_PLIC_START
当前 IRQ_PLIC_START 为 0,因此普通 PLIC source ID 和软件 IRQ ID 相同。
3.2 IRQ 编号范围
| 范围 | 类型 | 说明 |
|---|---|---|
0 |
保留 | IRQ_PLIC_START,不能注册为普通软件 IRQ |
1~63 |
普通 PLIC IRQ | UART、GPIO、DMA、GMAC、I2C 等外设 |
本地和虚拟 IRQ 编号由 SDK、OS 或 IPC 内部使用,不作为普通应用 IRQ 接口说明。
普通 PLIC IRQ 使用 sys_irq_request()、sys_irq_enable() 等接口。本地和虚拟 IRQ 由 SDK、OS 或 IPC 内部管理,应用通常不需要直接操作。
4. 返回码约定
IRQ 接口使用 SDK 公共返回码 error_code_t。
| 返回值 | 说明 |
|---|---|
IM_OK |
操作成功 |
IM_ERR_INVALID_PARAM |
IRQ ID、handler、优先级或其他参数非法 |
IM_ERR_NOT_READY |
handler 未注册、子系统未初始化或状态未准备好 |
IM_ERR_UNSUPPORTED |
当前配置或当前 CPU 不支持该操作 |
IM_ERR_ALREADY_REGISTERED |
指定 IRQ 已经有 handler |
| 其他错误码 | 底层 PLIC、IPC 或硬件初始化失败 |
5. 初始化和生命周期
5.1 sys_irq_init
error_code_t sys_irq_init(void);
功能说明:
初始化 IRQ 框架、PLIC、ACC 相关状态以及可选的 owner/IPC 服务。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
| 无 | — | — | 本接口无参数 |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK |
接口执行成功 |
| 其他错误码 | PLIC、ACC、owner 表或 IPC 初始化失败 |
补充说明:
- 本接口可重复调用;实际系统通常只需全局调用一次。
- PLIC 初始化会关闭所有 source、清零优先级并将 threshold 设为 0。
- 应在注册设备 IRQ 之前调用;本接口不会自动注册业务 handler,也不会自动打开 CPU 全局中断。
5.2 推荐生命周期
sys_irq_init()
↓
sys_irq_request()
↓
sys_irq_set_priority() 可选
↓
sys_irq_enable()
↓
im_cpu_irq_enable_mexternal()
↓
设备运行
↓
sys_irq_disable()
↓
sys_irq_release()
sys_irq_release() 不会自动关闭硬件 source,释放前必须先调用 sys_irq_disable()。
6. 软件 IRQ 注册接口
6.1 irq_handler_t
typedef void (*irq_handler_t)(uint32_t irq_id, void *arg);
irq_id 是当前 IRQ 编号,arg 是注册时传入的用户上下文。handler 运行在 IRQ/trap 上下文,必须短小、非阻塞。
6.2 sys_irq_request
error_code_t sys_irq_request(uint32_t irq_id,
irq_handler_t handler,
const char *name,
void *arg);
功能说明:
注册软件 IRQ handler,并为映射的 PLIC source 设置框架默认优先级。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
irq_id |
uint32_t |
输入 | IRQ_xxx 枚举值,不能为保留值 0 |
handler |
irq_handler_t |
输入 | 必须非 NULL |
name |
const char * |
输入 | 可选调试名字,可为 NULL |
arg |
void * |
输入 | 传给 handler 的上下文,可为 NULL |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK |
接口执行成功 |
IM_ERR_INVALID_PARAM |
参数非法 |
IM_ERR_ALREADY_REGISTERED |
指定 IRQ 已经有 handler |
IM_ERR_UNSUPPORTED |
当前配置不支持软件注册 |
| 其他错误码 | 底层 PLIC 优先级设置失败 |
补充说明:
- 注册不等于使能;source 仍可能关闭。
- 普通情况下默认优先级为
HAL_PLIC_PRIORITY_1;ACC + FreeRTOS 默认优先级为HAL_PLIC_PRIORITY_3。 name不会被复制,调用方须保证字符串生命周期有效。
6.3 sys_irq_release
error_code_t sys_irq_release(uint32_t irq_id);
功能说明:
清除 handler、名字和参数,并将映射的 PLIC source 优先级恢复为 0。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
irq_id |
uint32_t |
输入 | 已注册的 IRQ_xxx 枚举值 |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK |
接口执行成功 |
IM_ERR_INVALID_PARAM |
IRQ ID 非法 |
IM_ERR_NOT_READY |
指定 IRQ 未注册 |
| 其他错误码 | 底层 PLIC 操作失败 |
补充说明:
- 正确顺序为
sys_irq_disable(irq_id)→sys_irq_release(irq_id)。 - 本接口不会清除设备自身 pending 状态,也不会关闭外设内部的 IRQ 产生条件。
7. 普通 PLIC IRQ 控制
7.1 sys_irq_enable
error_code_t sys_irq_enable(uint32_t irq_id);
功能说明:
打开普通 PLIC source。默认注册表模式下,要求该 IRQ 已注册 handler。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
irq_id |
uint32_t |
输入 | 普通 PLIC source 对应的 IRQ ID |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK |
source 已打开;owner sync 失败可能只记录 warning |
IM_ERR_INVALID_PARAM |
IRQ 不是普通 PLIC source |
IM_ERR_NOT_READY |
handler 尚未注册 |
| 其他错误码 | 底层 PLIC 操作失败 |
补充说明:
- 本接口不打开 CPU
mie.MEIE,还需要im_cpu_irq_enable_mexternal();也不直接打开全局mstatus.MIE。 - V1 +
IRQ_OWNER_SYNC会更新本地 owner 表;V0 +IRQ_OWNER_SYNC会通过 IPC 向 V1 发送 enable 通知。
7.2 sys_irq_disable
error_code_t sys_irq_disable(uint32_t irq_id);
功能说明:
关闭普通 PLIC source。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
irq_id |
uint32_t |
输入 | 普通 PLIC source 对应的 IRQ ID |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK |
source 已关闭 |
IM_ERR_INVALID_PARAM |
IRQ 不是普通 PLIC source |
| 其他错误码 | 底层 PLIC 操作失败 |
补充说明:
- 关闭 source 不等于清除外设 pending flag;设备 handler 或设备 HAL 仍需清硬件状态。
- owner sync 下会同步清除当前核的 owner bit。
7.3 sys_irq_set_priority
error_code_t sys_irq_set_priority(uint32_t irq_id,
hal_plic_priority_t priority);
功能说明:
设置 PLIC source 优先级。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
irq_id |
uint32_t |
输入 | PLIC source 对应的 IRQ ID |
priority |
hal_plic_priority_t |
输入 | HAL_PLIC_PRIORITY_0 到 HAL_PLIC_PRIORITY_7 |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK |
优先级设置成功 |
IM_ERR_INVALID_PARAM |
IRQ ID 或 priority 非法 |
| 其他错误码 | 底层 PLIC 操作失败 |
补充说明:
- 数值越大优先级越高;priority 和 source enable 是两个独立控制项。
8. CPU Machine External 接口
8.1 Machine External
error_code_t im_cpu_irq_enable_mexternal(void);
error_code_t im_cpu_irq_disable_mexternal(void);
功能说明:
使能或关闭 CPU Machine External delivery,只控制 CPU mie.MEIE,不控制具体 PLIC source。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
| 无 | — | — | 这两个接口均无参数 |
返回值表:
| 返回值 | 说明 |
|---|---|
| IM_OK | 操作成功 |
| 其他错误码 | CPU IRQ 操作失败 |
补充说明:
- 普通外部 IRQ 通常需要同时满足 sys_irq_enable(irq_id) 和 im_cpu_irq_enable_mexternal()。
- 本接口也不直接打开全局 mstatus.MIE。
9. 分发接口
9.1 sys_irq_dispatch
error_code_t sys_irq_dispatch(uint32_t irq_id);
功能说明:
按 irq_id 查找并调用已注册的软件 handler。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
irq_id |
uint32_t |
输入 | 要分发的 IRQ ID |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK |
handler 调用完成 |
IM_ERR_NOT_READY |
没有注册 handler |
IM_ERR_INVALID_PARAM |
IRQ ID 非法 |
IM_ERR_UNSUPPORTED |
CONFIG_IRQ_SIMPLE_DISPATCH=y 且应用未提供实现 |
补充说明:
- 默认实现调用
handler(irq_id, s_irq_args[irq_id])。 CONFIG_IRQ_SIMPLE_DISPATCH=y时,应用必须自行实现该接口。- handler 运行在 IRQ/trap 上下文,必须短小、非阻塞。
9.2 sys_irq_plic_dispatch
error_code_t sys_irq_plic_dispatch(void);
功能说明:
处理一次普通 PLIC machine external IRQ,并将 pending source 分发到已注册的软件 handler。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
| 无 | — | — | 本接口无参数 |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK |
已完成一次 PLIC IRQ 处理 |
IM_ERR_NOT_READY |
没有可处理的 pending source 或 handler 未准备好 |
| 其他错误码 | PLIC claim、分发或 complete 操作失败 |
补充说明:
- 该接口仅供 machine external trap/ISR 路径使用。
- 普通 ACC 路径不调用该接口;ACC handler 直接按向量进入对应入口。
- handler 仍必须满足 ISR 非阻塞约束。
10. 调试接口
10.1 sys_irq_dump
void sys_irq_dump(void);
功能说明:
输出已注册 IRQ 的调试状态。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
| 无 | — | — | 本接口无参数 |
返回值表:
| 返回值 | 说明 |
|---|---|
| 无 | 本接口无返回值 |
补充说明:
- 只有同时启用
CONFIG_SDK_ENABLE_DEBUG_HELPERS=y和CONFIG_IRQ_ENABLE_DEBUG_HELPERS=y时才输出内容。 - 输出包括 IRQ ID、PLIC source ID、priority、enable 状态、pending 状态和注册名字。
- 未启用调试配置时为空操作。
11. 具体示例
11.1 普通 PLIC 外设 IRQ
#include "im_irq.h"
static void uart_irq_handler(uint32_t irq_id, void *arg)
{
uart_device_t *dev = (uart_device_t *)arg;
(void)irq_id;
uart_handle_irq(dev); /* 读取并清除UART硬件状态 */
}
error_code_t uart_irq_init(uart_device_t *dev)
{
error_code_t ret;
ret = sys_irq_init();
if (ret != IM_OK) {
return ret;
}
ret = sys_irq_request((uint32_t)IRQ_UART0,
uart_irq_handler,
"uart0",
dev);
if (ret != IM_OK) {
return ret;
}
ret = sys_irq_set_priority((uint32_t)IRQ_UART0,
HAL_PLIC_PRIORITY_2);
if (ret != IM_OK) {
sys_irq_release((uint32_t)IRQ_UART0);
return ret;
}
ret = sys_irq_enable((uint32_t)IRQ_UART0);
if (ret != IM_OK) {
sys_irq_release((uint32_t)IRQ_UART0);
return ret;
}
return im_cpu_irq_enable_mexternal();
}
void uart_irq_deinit(void)
{
sys_irq_disable((uint32_t)IRQ_UART0);
sys_irq_release((uint32_t)IRQ_UART0);
}
实际系统通常只需全局调用一次 sys_irq_init()。外设 source、CPU MEIE 和全局中断开关是独立层次。
11.2 V0/V1 IPC owner sync
启用 CONFIG_IRQ_OWNER_SYNC 时,应用一般不需要直接操作 owner API。正常调用:
sys_irq_enable((uint32_t)IRQ_GPIOA);
V0 会发送 enable 通知,V1 更新 owner 表;V1 则直接更新本地 owner 表并处理 V0 通知。应用仍应从架构上保证一个共享外设 IRQ 只由一个核负责。
12. ISR 使用约束
所有 IRQ handler 都在 trap/ISR 上下文运行:
- 不阻塞,不等待互斥锁、信号量或长时间轮询;
- 不执行耗时的协议栈、文件系统或大块内存操作;
- 先读取并清除设备硬件 pending 状态;
- 复杂处理通过队列、事件标志或 task notification 延后到任务上下文;
- FreeRTOS 中只使用允许在 ISR 中调用的
FromISR接口; arg指向对象的生命周期必须覆盖 IRQ 注册到 release 的整个期间;sys_irq_request()/sys_irq_release()建议只在初始化/反初始化阶段串行调用。
13. 常见问题和注意事项
13.1 只调用 sys_irq_enable() 但收不到中断
普通 PLIC IRQ 至少需要:
handler 已注册
PLIC source 已 enable
CPU mie.MEIE 已 enable
全局 mstatus.MIE 已 enable
设备本身的 IRQ 产生位已 enable
13.2 直接 release
sys_irq_release() 不会关闭 PLIC source,必须先调用:
sys_irq_disable(irq_id);
sys_irq_release(irq_id);
13.3 IRQ handler 被重复注册
默认注册表中一个 IRQ 只能有一个 handler;重复调用 sys_irq_request() 返回 IM_ERR_ALREADY_REGISTERED。
13.4 IRQ owner 冲突
V0/V1 同时打开同一个普通 PLIC IRQ 时,owner mask 会变为 IM_IRQ_OWNER_CORE_BOTH 并打印 warning。该机制不会替应用解决设备归属问题。
14. 文件组织
code/include/drivers/imsis/im_irq.h 公共IRQ API
code/drivers/imsis/irq/im_irq.c 注册表、生命周期和分发
code/include/drivers/g32s10/plic/im_irq_port.h PLIC/CPU适配接口
code/drivers/g32s10/plic/im_irq_port.c PLIC/CSR实现
code/include/soc/g32s10/irq_table.def 软件IRQ编号表
code/drivers/g32s10/plic/im_irq_owner.c V0/V1 owner同步
code/soc/g32s10/system/interrupt/ trap、向量和ACC入口
code/soc/g32s10/system/ipc/ IPC doorbell和消息分发
15. 推荐调用模板
15.1 默认软件分发模板
ret = sys_irq_init();
if (ret != IM_OK) {
return ret;
}
ret = sys_irq_request(irq_id, handler, name, arg);
if (ret != IM_OK) {
return ret;
}
ret = sys_irq_set_priority(irq_id, priority); /* 可选 */
if (ret != IM_OK) {
sys_irq_release(irq_id);
return ret;
}
ret = sys_irq_enable(irq_id);
if (ret != IM_OK) {
sys_irq_release(irq_id);
return ret;
}
ret = im_cpu_irq_enable_mexternal();
if (ret != IM_OK) {
sys_irq_disable(irq_id);
sys_irq_release(irq_id);
return ret;
}
/* ... device running ... */
sys_irq_disable(irq_id);
sys_irq_release(irq_id);
15.2 V0 ACC 直达 handler 高级用法模板
本模板仅适用于 V0 裸机 ACC 普通外设 IRQ:启用 CONFIG_IRQ_ACC_MODE=y,不启用 CONFIG_OS_BACKEND_FREERTOS,并保留默认注册表模式(CONFIG_IRQ_SIMPLE_DISPATCH=n)。FreeRTOS ACC 不能直接套用,须遵守 2.3.3 中的入口/退出约束。
默认模式的 sys_irq_enable() 会检查软件注册表,因此本模板保留 sys_irq_request() / sys_irq_release()。注册用于兼容公共 API 的资源管理;实际 ACC 中断仍直接进入应用定义的 IRQ_UART0_handler(),不经过 sys_irq_dispatch() 或注册回调。无需为单个直达 IRQ 切换整个工程的分发模式。
**入口定义:**以下代码放在应用 C 文件的文件作用域,确保编译并链接进 V0 固件。
#include <stddef.h>
#include "im_irq.h"
/* 应用提供同名强符号;不要声明为 static 或 weak。 */
void IRQ_UART0_handler(void)
{
/* 在此直接读取 UART0 状态、处理业务并清除 UART0 的 pending 条件 */
}
/* 应用定义的注册适配回调,不是 SDK API;ACC 硬件入口不经过它。 */
static void uart0_irq_registry_callback(uint32_t irq_id, void *arg)
{
(void)irq_id;
(void)arg;
IRQ_UART0_handler();
}
**初始化片段:**放在上述应用 C 文件中、返回 error_code_t 的初始化函数内。调用前应保持 UART0 设备中断关闭,并完成外设及业务状态准备。
error_code_t ret;
ret = sys_irq_init();
if (ret != IM_OK) {
return ret;
}
/* 满足 sys_irq_enable() 的注册检查,不改变 ACC 直达入口。 */
ret = sys_irq_request(IRQ_UART0, uart0_irq_registry_callback,
"uart0-acc-direct", NULL);
if (ret != IM_OK) {
return ret;
}
/* 可选:request 已设置默认优先级,此处显式选择优先级。 */
ret = sys_irq_set_priority(IRQ_UART0, HAL_PLIC_PRIORITY_1);
if (ret != IM_OK) {
sys_irq_release(IRQ_UART0);
return ret;
}
ret = sys_irq_enable(IRQ_UART0);
if (ret != IM_OK) {
sys_irq_release(IRQ_UART0);
return ret;
}
ret = im_cpu_irq_enable_mexternal();
if (ret != IM_OK) {
sys_irq_disable(IRQ_UART0);
sys_irq_release(IRQ_UART0);
return ret;
}
/* 在此清理 UART0 遗留 pending,再打开 UART0 设备内部中断。 */
/* 系统初始化流程还必须确保全局 mstatus.MIE 已打开。 */
return IM_OK;
运行时,ACC 向量直接跳到 IRQ_UART0_handler();业务代码写在该函数内,无需另行调用分发接口。
**停用片段:**放在返回 error_code_t 的停用函数内,在不再使用 UART0 中断时执行,不要紧接初始化立即执行。
error_code_t ret;
/* 在此关闭 UART0 设备内部中断,并处理遗留 pending。 */
ret = sys_irq_disable(IRQ_UART0);
if (ret != IM_OK) {
return ret;
}
return sys_irq_release(IRQ_UART0);
sys_irq_release() 只释放注册表条目,不会撤销链接时的强符号覆盖,必须先关闭设备中断和 PLIC source。不要为了停用 UART0 而关闭所有外设共享的 CPU machine external 入口。