API REFERENCE / CONVENTIONS
API 约定
本文介绍 SDK 应用编程接口(API)中常见的约定和假设,包括接口构成、分层依赖、命名与参数、错误处理、配置结构体、私有接口以及 API 稳定性。阅读各模块 API 参考前,建议先了解这些约定,以便正确理解接口的分层位置、调用语义和兼容性范围。
OVERVIEW
接口构成
SDK 提供以下几类编程接口:
各模块公共头文件中声明的 C 函数、结构体、枚举、类型定义和宏,按
LL / HAL / middleware分层组织,对外头文件集中在code/include/。构建系统接口:
imde命令、CMake 函数、Kconfig 选项,详见「SDK文档 / SDK编译」。主机工具及其命令行参数,集中在
tools/目录。
SDK 由多个模块组成,其中既有为芯片专门编写的代码,也有第三方组件(位于 code/third_party/)。部分第三方组件由 SDK 提供包装接口,部分直接呈现底层库的原始 API,使用前请确认所用接口属于哪一类。
LAYERING
分层与依赖方向
SDK 逻辑分层自下而上为 ll → hal → middleware → app,依赖方向只能向下,禁止反向依赖和跨层绕过:
| 层级 | 面向 | 核心约束 |
|---|---|---|
ll | 寄存器、外设实例、中断、DMA | 不含业务语义;不依赖 middleware;默认不动态分配内存。 |
hal | 设备能力(UART、I2C、SPI、Flash、Timer) | 不承载业务流程;可依赖 ll 和通用 core/utils;对外不暴露寄存器细节。 |
middleware | 能力与流程编排(升级、日志、存储) | 不直接访问寄存器;所有硬件访问必须经过 hal。 |
应用和上层业务不应绕过 hal 直接调用 ll;确需底层操作时,应先评估是否应在 hal 中补充能力接口。
NAMING
命名与参数
公共函数按 命名,例如 ll_gpio_init、hal_uart_write、mid_upgrade_start。常用动词模板:
| 层级 | 典型接口 |
|---|---|
| LL | init / deinit / enable / disable / set_xxx / get_xxx / irq_handler |
| HAL | open / close / read / write / ioctl / register_callback |
| Middleware | init / start / stop / execute / get_state / set_xxx |
类型统一使用小写蛇形加后缀:_t(类型)、_config_t(配置)、_handle_t(句柄)、_event_t(事件)、_state_t(状态)。宏和枚举值使用全大写下划线并带层级或模块前缀:LL 层用 LL_,HAL 层用 HAL_,Middleware 和 SDK 公共基础宏用 IM_。带物理或时间单位的参数必须在名称中体现单位,如 timeout_ms、clock_hz、voltage_mv。
参数顺序统一为:句柄或实例 → 输入数据 → 输入长度 → 输出参数 → 超时或选项。输出参数使用 _out 后缀:
error_code_t hal_flash_read(hal_flash_handle_t *handle, uint32 address, uint8 *buffer_out, size_t buffer_size, size_t *read_len_out);
ERRORS
错误处理
可能失败的操作型公共 API 优先返回 error_code_t,错误码统一定义在 error_code.h,命名使用 ERR_ 前缀,参数错误、超时、忙、未初始化、IO 错误等均有标准定义。不会发生错误的查询、判断、转换接口,或返回值本身具有明确业务语义的接口,可以返回 bool、数值、枚举或指针:
bool hal_gpio_is_pin_valid(const gpio_regs_t *gpiox, uint32 pin_mask); uint32 ll_gpio_read(uint32 base); error_code_t hal_gpio_read_pin(const gpio_regs_t *gpiox, uint32 pin_mask, hal_gpio_pin_state_t *pin_state_out);
公共 API 必须校验关键输入参数,校验顺序统一为空指针、长度、状态。断言只用于发现开发期错误,可恢复错误必须通过返回值处理,不允许用断言代替对外接口的参数检查。
CONFIG
配置结构体
初始化和配置函数(通常以 _init、_config、_open 命名)需要一个指向配置结构体的指针作为参数。初始化函数不会保存该指针,因此在栈上分配结构体是安全的。推荐使用 C99 指定初始化器,将关心的字段显式赋值,其余字段初始化为零:
const hal_gpio_config_t gpio_config = {
.gpiox = gpioa,
.pin_mask = GPIO_PIN_MASK_ALL,
.default_state = HAL_GPIO_PIN_RESET,
/* 其余字段(若有)初始化为零 */
};
error_code_t ret = hal_gpio_init(&gpio_config);错误示例:只给部分字段赋值而直接使用未初始化的局部结构体,未赋值字段的内容是不确定的。C++ 同样支持指定初始化器,但初始化器必须遵循字段声明顺序;若需兼容更早的 C++ 标准,可以先整体清零再逐个赋值:
hal_uart_config_t uart_config = {}; /* 所有字段初始化为零 */
uart_config.baudrate = 115200;
uart_config.timeout_ms = 1000;当模块提供默认配置初始化函数或宏时,优先使用它,再按需覆盖个别字段。
SEMANTICS
调用语义与生命周期
阻塞接口必须显式提供
timeout_ms或注明「永久阻塞」语义;异步接口命名需体现异步性质,如_start、_async。回调统一通过
user_ctx传入用户上下文;中断回调、线程回调的运行上下文必须在接口注释中标明。资源生命周期动作统一使用
init/deinit、open/close、start/stop、create/destroy,同一类资源只选一组主语义。LL 和 HAL 默认禁止动态内存分配;middleware 若使用动态内存,必须明确申请与释放的所有权。
PRIVATE
私有接口与内部实现
SDK 中部分头文件仅限内部使用,不支持在应用程序中调用。此类头文件命名为 *_internal.h 或位于 internal/ 目录;寄存器映射结构体(struct)属于 LL 或 SoC 寄存器头文件,HAL 公共头文件不得直接展开其字段定义。
私有接口可能在次要或补丁版本之间以不兼容方式被删除或更改。应用程序不应依赖:
*_internal.h与internal/下的任何声明。HAL 公共接口中的寄存器位、寄存器偏移、IRQ 号、DMA 通道等底层细节。
通过
extern暴露的全局变量或寄存器实例;跨文件访问状态必须使用get_xxx()、set_xxx()接口。
EXAMPLES
示例代码
code/examples/ 提供演示各模块用法的示例工程。示例中的通用辅助组件是为减少重复而抽取的,不属于 SDK API 范畴,不同版本之间可能存在显著变化。不建议在自定义项目中直接引用这些组件;基于示例开始新项目时,应将所需公共组件复制出来并视为项目的一部分。示例组件针对演示场景编写,可能不包括生产应用所需的完整错误处理,使用前请阅读代码确认适用性。
STABILITY
API 稳定性
对外暴露的公共头文件、类型、函数名一经发布,即遵守源代码级别兼容性:应用程序无需修改即可在新版本 SDK 上重新编译。扩展优先新增接口或新增结构体字段,避免修改旧接口语义。
SDK 不保证版本间的二进制兼容性。以下更改可以保持源代码兼容,但基于旧版本预编译的库可能失效:
更改枚举成员的数值。
新增结构体成员或调整成员顺序。
用具有相同签名的
static inline函数替换extern函数,或反之。
以下内容不在兼容性保证范围内:私有接口与内部实现、示例代码及其公共组件、明确标记为 beta/preview/experimental 的功能、为修复安全问题或替换不安全默认行为所做的更改,以及 Kconfig 选项在菜单中的位置和示例工程的位置与名称。