驱动开发规范

API 规范

头文件

每一个外设驱动与 API 相关的头文件有三个:

  • bk_api_xxx.h 定义 xxx 外设的 API。

  • bk_api_xxx_types.h 定义 xxx 外设的公开数据类型与宏。外部组件与驱动层可直接访问,HAL 层与 SOC 层禁止访问。

  • xxx_types.h 定义 xxx 外设的公开数据类型与宏。外部组件,驱动层,HAL 层,SOC 层都可访问。

API 头文件中的接口,数据类型,宏应该是稳定的,抽象的,与具体的硬件无关。

备注

xxx_types.h 不应该包含内部数据类型,而应该放到内部头文件中:

  • 如果是驱动层私有数据类型,则放到 xxx_driver.h 中。

  • 如果是 HAL 层私有数据类型,则放到 xxx_hal.h 中。

  • 如果是 SOC 层私有数据类型,则放到 xxx_ll.h 中。

设备 ID 从 0 开始

像 DMA/ADC/GPIO 等多通道外设,其通道号,或者标识号从 0 开始。

错误码

每个驱动都应该定义自己的错误码,错误码偏移在 bk_err.h 中定义。

可重入

Armino 驱动 API 默认可实现为不可重入,对于某些具有并行访问要求的外设,如,两个不同 任务可能同时竞争访问同一 ADC 通道时,需要在驱动层使用加锁的方式保证可重入。驱动 API 可重入性需要在 API 文档中说明。

文档

文档要求如下:

  • 所有驱动 API 需要有 API 文档

  • 对于复杂驱动 API,需要增加 API 使用指南

示例

对于使用复杂的驱动,需要在 project/examples/periperial 下增加相应的示例程序。

CLI 命令

每一个驱动 API 均需要在增加一组 CLI 命令,用于对驱动进行测试。

驱动层规范

芯片无关性

驱动层代码与具体芯片无关,不应该出现像 CONFIG_SOC_xxx 包起来的代码。 具体芯片相关的实现应该放在 HAL 层。

寄存器无关

驱动层代码不应该直接操作寄存器,必须通过 HAL/LL 层接口操作寄存器。

低功耗要求

请充分考虑外设的低功耗设计需求:

  • 当外设操作需要等硬件状态时,在事务开始前需要投票阻止 CPU 进入``低压休眠模式``,在事务结束后再投赞成票。

  • 在外设 API 在实现时,操作前打开时钟,在操作结束之后关闭时钟。

传输模式

建议实现下述外设读写模式:

模式

读/写

描述

轮询

读/写

不使用中断机制,使用``忙等待``的方式等待传输结束后返回。

中断 + 接收缓存

驱动层定义一个接收缓存,缓存长度可配置。

在中断中将收到的数据存接收缓存。

API 从接收缓存中取数据,支持阻塞与非阻塞方式, 阻塞方式可设置阻塞的超时时间。

中断 + 0-copy

中断中直接使用用户传入的数据指针进行写操作。

API 支持阻塞与非阻塞方式,阻塞方式可设置 超时时间。

使用``非阻塞``方式时有独立的 API 可以等外设传输完成。

接口完整性

实现具体驱动时,建议参考 CMSIS/FreeRTOS_IO 以及典型操作系统外设驱动在适配时的要求, 确保驱动外设已经实现了最常见的功能,方便后续驱动适配。

驱动层通用 API

Driver 层通常要求实现如下标准 API, 在实现 API 时即要充分考虑未来扩充的可能性, 同时也要考虑尽量降低驱动开发复杂度。

Driver API

功能描述

bk_xxx_driver_init

  1. 驱动框架相关数据结构初始化

  2. 驱动全局配置,对于多通道设备, 通用配置 可以这里进行配置

bk_xxx_driver_deinit

驱动框架卸载,释放所有软/硬件资源

bk_xxx_init

  1. 多通道设备, 使用这个 API 初始化特定通道

  2. 初始化软件资源, 如申请通道控制结构等

  3. 初始化硬件, 如设备上电,配置时钟源等

  4. 初始化通道正常运行相关配置

bk_xxx_deinit

  1. 重置通道硬件配置到默认值

  2. 关闭通道硬件

  3. 关闭通道硬件时钟, 电源等

  4. 释放通道软件资源

bk_xxx_start

启动设备, start 之后设备正常工作

bk_xxx_stop

关闭设备, 不会复位硬件中已有配置

HAL/LL/SOC 层规范

软/硬件寄存器定义一致性

驱动软件寄存器命名与芯片寄存器定义中名字保持一致,建议通过脚本生成相关代码:

  • SoC 层 xxx_reg.h/xxx_struct.h 由脚本依据寄存器定义生成

  • LL 层 xxx_ll.h 由脚本依据寄存器定义生成

寄存器访问

通过结构体访问寄存器

为保证代码可读性,驱动代码中应该优先使用 xxx_struct.h 中定义的结构体字段访问寄存器。

通过宏访问寄存器

对于某些多通道位操作,或者某些对性能敏感的操作可选择使用寄存器宏操作。

最常用的寄存器位操作宏如下,不般不建议自己另外定义一套寄存器访问宏,请 优先使用下述宏访问寄存器。

宏名

描述

REG_WRITE(r, b)

写 32 位寄存器

REG_READ(r)

读 32 位寄存器

REG_SET_BIT(r, b)

写一位或者多位, mask 为 0xffffffff

REG_CLR_BIT(r, b)

清一位或者多位, mask 为 0xffffffff

REG_SET_BITS(r, b, m)

写一位或者多位, mask 为 m

REG_SET_FIELD(r, f, v)

写指定多位, mask 为 _S & _v

REG_GET_FIELD(r, f, v)

读指定多位, mask 为 _S & _v