188 lines
6.9 KiB
Markdown
Raw Normal View History

2025-04-10 17:31:33 +08:00
# openHAL
openHAL对硬件资源统一管理对上层提供统一的硬件层API接口对底层芯片层API如CMSIS进行二次封装提供类Android Things、PikaPython、linux等风格接口。
* 提供可靠且稳定的标准化接口,统一管理外设,实现资源的灵活复用;
* 提供和主流软件平台兼容或适配的操作层,例如各种开源工程及系统;
* openHAL和openAPP、openDDK构建open开发框架可用于对接各类SDK
![功能单元](./assets/openhal.png)
![调用关系](./assets/api.png)
# 开发准则
* 暴露的接口尽量统一,用户可用的接口尽量全面,参数尽量封装在内部
* 时间测量接口,初始化对应时间数组,每次调用会计时,通过导出数据可以分析时间消耗
# 功能矩阵
| HAL | startup | create/delete | open/close | read/write | ioctl/pmctl | query |
| ------ | ----- | ------ | ---- | ----- | ----- | ------ |
| [PAD](#pad) | √ | √ | √ | √ | √ | √ |
| [GPIO](#gpio) | √ | √ | √ | √ | √ | √ |
| [UART](#uart) | √ | √ | √ | √ | √ | √ |
| [I2C](#i2c) | √ | √ | √ | √ | √ | √ |
| [KPC](#kpc) | - | - | - | - | - | - |
| [SCR](#screen)| - | - | - | - | - | - |
* EC7XX系列PAD类比传统MCU的GPIO具有唯一标识作为其余外设的依赖
* 除依赖IO的还有DMA/TIM等不依赖IO的IP
## 接口分类
| OPEN API | param[in] | param[out] | return | brief |
| ------- | ------- | ------- | ------- | ------- |
| api_xxx_startup | - | - | - | 上电初始化
| api_xxx_default | - | - | - | 数据解析
| api_xxx_query | √ | - | enum | 查询接口
| api_xxx_create | √ | | √ | 创建设备,动态表更新
| api_xxx_open | timeout | inf | enum | 开启,回调,系统通知
| api_xxx_apply | func | cnf | enum | 预注册
| api_xxx_ioctl | enum | | | 配置设备
| api_xxx_pmctl | enum | | | 配置设备功耗/模式
| api_xxx_write | √ | - | | 写操作
| api_xxx_read | - | √ | | 读操作
| api_xxx_close | func | - | enum | 关闭,回调,系统通知
| api_xxx_delete | √ | - | enum | 删除设备,动态表更新
| api_test_xxx | | | | 测试接口
基本功能接口(兼容接口):
* 获取/释放资源create()/delete()
* 针对状态的查询接口 query()
* 针对设备的操作和配置 ioctl()
* startup()用于执行上电初始化相关数据可配置传入或读特定区域flash
* default()用于解析对应数据存储到该模块的flash区域结构化数据读取
调用类接口:
* create兼容传统api参数实现对资源初始化和delete接口都会更新设备列表
* open接口获取操作接口超时返回和close接口组合实现实现分时复用
* apply接口预申请资源注册预配置接口在预申请资源被释放同时执行
* ioctl是一个多功能可扩展接口可配置硬件参数直接操作底层设备
释放类接口:
* close接口用于释放设备占用可传入执行函数用于配置在idle状态的执行内容
* delete将还原设备状态发送系统通知之后设备可以被重新create和apply
单元测试:
* 通过api_test_xxx()执行所有接口调用遍历,通过返回值确认执行情况
## 参考
### Android Things
```bash
gpio.setEdgeTriggerType(Gpio.EDGE_BOTH);
gpio.registerGpioCallback(mGpioCallback);
gpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_HIGH);// 低电平有效
gpio.setActiveType(Gpio.ACTIVE_LOW);... // 将值切换为LOW
gpio.setValue(true);
```
### Pika Python
采用类linux的设计所有类型的设备操作有且仅有类似于文件的5个标准APIopen()、close()、write()、read()、ioctl()
```bash
pika_dev* pika_hal_open(PIKA_HAL_DEV_TYPE dev_type, char* name);
int pika_hal_close(pika_dev* dev);
int pika_hal_ioctl(pika_dev* dev, PIKA_HAL_IOCTL_CMD cmd, ...);
int pika_hal_read(pika_dev* dev, void* buf, size_t len);
int pika_hal_write(pika_dev* dev, void* buf, size_t len);
```
---
# 使用方式
```bash
SUBSYS_OPENHAL_ENABLE = y
```
配置文件通过CSV表格打包烧录内部文件系统更新方式包括
* 在工程路径下,通过编译打包直接烧录
* 通过Python脚本上传文件到文件系统
转存逻辑从文件中提取配置信息生成响应数据结构体再将对应的RAM结构体数据备份到指定区域开机加载指定区域校验后写入硬件配置。
相较于devicemanage的目标芯片属性openHAL支持更多外设资源扩展可以作为驱动标准件。
## pad
| API | param[in] | param[out] | return | brief |
| ------- | ------- | ------- | ------- | ------- |
| [api_pad_startup](#api_pad_startup) | - | √ | √ | 加载默认配置
| [api_pad_default](#api_pad_default) | | - | enum |
| [api_pad_create](#api_pad_create) | paddr | config | enum | 申请接口
| [api_pad_open](#api_pad_open) | timeout | | enum | 申请接口
| [api_pad_apply](#api_pad_apply) | cb | | - | 申请接口
| api_pad_query | paddr/usrId | - | enum | 查询接口
| api_pad_ioctl | | | | 配置接口
| api_pad_pmctl | | | | 运行状态/功耗模式
| api_pad_close | usrId | | enum | 关闭接口
| api_pad_delete | usrId | | enum | 删除接口
| api_test_pad | usrId | | | 测试接口
* 如果其他虚拟设备占用了IO需要从所有可用IO列表中删除对应IO避免再分配
### api_pad_startup
默认配置数据导出加载pad默认配置并初始化配置文件存储区域固定存储内容可通过文件升级方式更新
### api_pad_default
默认配置数据的解析导入
### api_pad_create
### api_pad_open
系统级接口和close接口成对使用会malloc相应任务堆栈依赖freeRTOS消息机制管理状态和超时。
```bash
api_ret_t api_pad_open(uint32_t usrId,PadConfig_t *config,uint32_t timeout);
```
* 如果在超时时间内申请的usrId是free状态则获取成功并以传入的config参数初始化;
* 如果在超时时间内申请的usrId是close状态则获取成功pad的配置参数以config传出;
* 超时未获取成功通过open_hal_ack_t枚举返回状态;
### api_pad_apply
系统级接口非阻塞获取pad成功后回调可用于共用外设端口情况
```bash
int api_pad_apply(uint32_t usrId,void *cb);
```
## gpio
* 当前实现是基于单IO为单位所以不需要bit操作如果以port为单位可以进行16bit组合封装
## uart
## i2c
## kpc
```bash
KpcConfig_t kpcConfig;
KPC_getDefaultConfig(&kpcConfig);
kpcConfig.validRowMask = KPC_ROW_3 | KPC_ROW_2 | KPC_ROW_1 | KPC_ROW_0;
kpcConfig.validColumnMask = KPC_COLUMN_2 | KPC_COLUMN_1 | KPC_COLUMN_0;
// 480ms (12*40ms) autorepeat delay
kpcConfig.autoRepeat.delay = 12;
KPC_init(&kpcConfig, KPC_callback);
KPC_eventQueueInit();
KPC_startScan();
```