未验证 提交 d1cb77ef 编写于 作者: O openharmony_ci 提交者: Gitee

!2937 更新快速入门+纯净版【快速入门需要翻译】

Merge pull request !2937 from duangavin123/master
# 驱动使用指南 # 驱动使用指南
- [HDF驱动框架](driver-hdf.md) - HDF驱动框架
- [HDF开发概述](driver-hdf-overview.md) - [HDF开发概述](driver-hdf-overview.md)
- [驱动开发](driver-hdf-development.md) - [驱动开发](driver-hdf-development.md)
- [驱动服务管理](driver-hdf-servicemanage.md) - [驱动服务管理](driver-hdf-servicemanage.md)
- [驱动消息机制管理](driver-hdf-message-management.md) - [驱动消息机制管理](driver-hdf-message-management.md)
- [配置管理](driver-hdf-manage.md) - [配置管理](driver-hdf-manage.md)
- [HDF开发实例](driver-hdf-sample.md) - [HDF开发实例](driver-hdf-sample.md)
- [平台驱动开发](driver-develop.md) - 平台驱动开发
- [ADC](driver-platform-adc-develop.md) - [ADC](driver-platform-adc-develop.md)
- [DAC](driver-platform-dac-develop.md) - [DAC](driver-platform-dac-develop.md)
- [GPIO](driver-platform-gpio-develop.md) - [GPIO](driver-platform-gpio-develop.md)
- [HDMI](driver-platform-hdmi-develop.md) - [HDMI](driver-platform-hdmi-develop.md)
- [I2C](driver-platform-i2c-develop.md) - [I2C](driver-platform-i2c-develop.md)
- [I3C](driver-platform-i3c-develop.md) - [I3C](driver-platform-i3c-develop.md)
- [MIPI-CSI](driver-platform-mipicsi-develop.md) - [MIPI CSI](driver-platform-mipicsi-develop.md)
- [MIPI-DSI](driver-platform-mipidsi-develop.md) - [MIPI DSI](driver-platform-mipidsi-develop.md)
- [MMC](driver-platform-mmc-develop.md) - [MMC](driver-platform-mmc-develop.md)
- [PIN](driver-platform-pin-develop.md) - [PIN](driver-platform-pin-develop.md)
- [PWM](driver-platform-pwm-develop.md) - [PWM](driver-platform-pwm-develop.md)
- [REGULATOR](driver-platform-regulator-develop.md) - [Regulator](driver-platform-regulator-develop.md)
- [RTC](driver-platform-rtc-develop.md) - [RTC](driver-platform-rtc-develop.md)
- [SDIO](driver-platform-sdio-develop.md) - [SDIO](driver-platform-sdio-develop.md)
- [SPI](driver-platform-spi-develop.md) - [SPI](driver-platform-spi-develop.md)
- [UART](driver-platform-uart-develop.md) - [UART](driver-platform-uart-develop.md)
- [WatchDog](driver-platform-watchdog-develop.md) - [WatchDog](driver-platform-watchdog-develop.md)
- [平台驱动使用](driver-platform.md) - 平台驱动使用
- [ADC](driver-platform-adc-des.md) - [ADC](driver-platform-adc-des.md)
- [DAC](driver-platform-dac-des.md) - [DAC](driver-platform-dac-des.md)
- [GPIO](driver-platform-gpio-des.md) - [GPIO](driver-platform-gpio-des.md)
- [HDMI](driver-platform-hdmi-des.md) - [HDMI](driver-platform-hdmi-des.md)
- [I2C](driver-platform-i2c-des.md) - [I2C](driver-platform-i2c-des.md)
- [I3C](driver-platform-i3c-des.md) - [I3C](driver-platform-i3c-des.md)
- [MIPI-CSI](driver-platform-mipicsi-des.md) - [MIPI CSI](driver-platform-mipicsi-des.md)
- [MIPI-DSI](driver-platform-mipidsi-des.md) - [MIPI DSI](driver-platform-mipidsi-des.md)
- [PIN](driver-platform-pin-des.md) - [PIN](driver-platform-pin-des.md)
- [PWM](driver-platform-pwm-des.md) - [PWM](driver-platform-pwm-des.md)
- [REGULATOR](driver-platform-regulator-des.md) - [Regulator](driver-platform-regulator-des.md)
- [RTC](driver-platform-rtc-des.md) - [RTC](driver-platform-rtc-des.md)
- [SDIO](driver-platform-sdio-des.md) - [SDIO](driver-platform-sdio-des.md)
- [SPI](driver-platform-spi-des.md) - [SPI](driver-platform-spi-des.md)
- [UART](driver-platform-uart-des.md) - [UART](driver-platform-uart-des.md)
- [WATCHDOG](driver-platform-watchdog-des.md) - [WatchDog](driver-platform-watchdog-des.md)
- [外设驱动使用](driver-peripherals.md) - 外设驱动使用
- [LCD](driver-peripherals-lcd-des.md) - [LCD](driver-peripherals-lcd-des.md)
- [TOUCHSCREEN](driver-peripherals-touch-des.md) - [Touchscreen](driver-peripherals-touch-des.md)
- [SENSOR](driver-peripherals-sensor-des.md) - [Sensor](driver-peripherals-sensor-des.md)
- [WLAN](driver-peripherals-external-des.md) - [WLAN](driver-peripherals-external-des.md)
- [AUDIO](driver-peripherals-audio-des.md) - [Audio](driver-peripherals-audio-des.md)
- [USB](driver-peripherals-usb-des.md) - [USB](driver-peripherals-usb-des.md)
- [CAMERA](driver-peripherals-camera-des.md) - [Camera](driver-peripherals-camera-des.md)
- [VIBRATOR](driver-peripherals-vibrator-des.md) - [Vibrator](driver-peripherals-vibrator-des.md)
- [LIGHT](driver-peripherals-light-des.md) - [Light](driver-peripherals-light-des.md)
\ No newline at end of file
# 平台驱动开发<a name="ZH-CN_TOPIC_0000001160769576"></a> # 平台驱动开发
- **[ADC](driver-platform-adc-develop.md)**
- **[DAC](driver-platform-dac-develop.md)**
- **[GPIO](driver-platform-gpio-develop.md)** - **[ADC](driver-platform-adc-develop.md)**
- **[HDMI](driver-platform-hdmi-develop.md)** - **[GPIO](driver-platform-gpio-develop.md)**
- **[I2C](driver-platform-i2c-develop.md)** - **[I2C](driver-platform-i2c-develop.md)**
- **[I3C](driver-platform-i3c-develop.md)** - **[MIPI DSI](driver-platform-mipidsi-develop.md)**
- **[MIPI-CSI](driver-platform-mipicsi-develop.md)**
- **[MIPI-DSI](driver-platform-mipidsi-develop.md)**
- **[MMC](driver-platform-mmc-develop.md)** - **[MMC](driver-platform-mmc-develop.md)**
......
# 驱动开发<a name="ZH-CN_TOPIC_0000001051930361"></a> # 驱动开发
- [驱动模型介绍](#section157425168112)
- [驱动开发步骤](#section1969312275533)
## 驱动模型介绍<a name="section157425168112"></a> ## 驱动模型介绍
HDF框架以组件化的驱动模型作为核心设计思路,为开发者提供更精细化的驱动管理,让驱动开发和部署更加规范。HDF框架将一类设备驱动放在同一个host里面,开发者也可以将驱动功能分层独立开发和部署,支持一个驱动多个node,HDF驱动模型如下图所示: HDF框架以组件化的驱动模型作为核心设计思路,为开发者提供更精细化的驱动管理,让驱动开发和部署更加规范。HDF框架将一类设备驱动放在同一个host里面,开发者也可以将驱动功能分层独立开发和部署,支持一个驱动多个node,HDF驱动模型如下图所示:
**图 1** HDF驱动模型<a name="fig3580184214210"></a> **图1** HDF驱动模型
![](figures/HDF驱动模型.png "HDF驱动模型")
## 驱动开发步骤<a name="section1969312275533"></a> ![zh-cn_image_0000001153947412](figures/zh-cn_image_0000001153947412.png)
基于HDF框架进行驱动的开发主要分为两个部分,驱动实现和驱动配置,详细开发流程如下所示:
1. <a name="li35182436435"></a>驱动实现 ## 驱动开发步骤
基于HDF框架进行驱动的开发主要分为两个部分,驱动实现和驱动配置,详细开发流程如下所示:
1. 驱动实现
驱动实现包含驱动业务代码和驱动入口注册,具体写法如下: 驱动实现包含驱动业务代码和驱动入口注册,具体写法如下:
- 驱动业务代码 - 驱动业务代码
``` ```
#include "hdf_device_desc.h" // HDF框架对驱动开放相关能力接口的头文件 #include "hdf_device_desc.h" // HDF框架对驱动开发相关能力接口的头文件
#include "hdf_log.h" // HDF 框架提供的日志接口头文件 #include "hdf_log.h" // HDF 框架提供的日志接口头文件
#define HDF_LOG_TAG "sample_driver" // 打印日志所包含的标签,如果不定义则用默认定义的HDF_TAG标签 #define HDF_LOG_TAG "sample_driver" // 打印日志所包含的标签,如果不定义则用默认定义的HDF_TAG标签
...@@ -47,7 +46,6 @@ HDF框架以组件化的驱动模型作为核心设计思路,为开发者提 ...@@ -47,7 +46,6 @@ HDF框架以组件化的驱动模型作为核心设计思路,为开发者提
return; return;
} }
``` ```
- 驱动入口注册到HDF框架 - 驱动入口注册到HDF框架
``` ```
...@@ -65,15 +63,13 @@ HDF框架以组件化的驱动模型作为核心设计思路,为开发者提 ...@@ -65,15 +63,13 @@ HDF框架以组件化的驱动模型作为核心设计思路,为开发者提
``` ```
2. 驱动编译 2. 驱动编译
- liteos - liteos
涉及makefile和BUILD.gn修改:
涉及makefile和BUILD.gn修改: - makefile部分:
* makefile部分:
驱动代码的编译必须要使用HDF框架提供的Makefile模板进行编译。 驱动代码的编译必须要使用HDF框架提供的Makefile模板进行编译。
``` ```
include $(LITEOSTOPDIR)/../../drivers/adapter/khdf/liteos/lite.mk #导入hdf预定义内容,必需 include $(LITEOSTOPDIR)/../../drivers/adapter/khdf/liteos/lite.mk #导入hdf预定义内容,必需
MODULE_NAME := #生成的结果文件 MODULE_NAME := #生成的结果文件
...@@ -85,15 +81,16 @@ HDF框架以组件化的驱动模型作为核心设计思路,为开发者提 ...@@ -85,15 +81,16 @@ HDF框架以组件化的驱动模型作为核心设计思路,为开发者提
编译结果文件链接到内核镜像,添加到drivers/adapter/khdf/liteos目录下的hdf_lite.mk里面,示例如下: 编译结果文件链接到内核镜像,添加到drivers/adapter/khdf/liteos目录下的hdf_lite.mk里面,示例如下:
``` ```
LITEOS_BASELIB += -lxxx #链接生成的静态库 LITEOS_BASELIB += -lxxx #链接生成的静态库
LIB_SUBDIRS += #驱动代码Makefile的目录 LIB_SUBDIRS += #驱动代码Makefile的目录
``` ```
* BUILD.gn部分: - BUILD.gn部分:
添加模块BUILD.gn参考定义如下内容: 添加模块BUILD.gn参考定义如下内容:
``` ```
import("//build/lite/config/component/lite_component.gni") import("//build/lite/config/component/lite_component.gni")
import("//drivers/adapter/khdf/liteos/hdf.gni") import("//drivers/adapter/khdf/liteos/hdf.gni")
...@@ -114,6 +111,7 @@ HDF框架以组件化的驱动模型作为核心设计思路,为开发者提 ...@@ -114,6 +111,7 @@ HDF框架以组件化的驱动模型作为核心设计思路,为开发者提
把新增模块的BUILD.gn所在的目录添加到/drivers/adapter/khdf/liteos/BUILD.gn里面: 把新增模块的BUILD.gn所在的目录添加到/drivers/adapter/khdf/liteos/BUILD.gn里面:
``` ```
group("liteos") { group("liteos") {
public_deps = [ ":$module_name" ] public_deps = [ ":$module_name" ]
...@@ -122,39 +120,36 @@ HDF框架以组件化的驱动模型作为核心设计思路,为开发者提 ...@@ -122,39 +120,36 @@ HDF框架以组件化的驱动模型作为核心设计思路,为开发者提
] ]
} }
``` ```
- linux - linux
如果需要定义模块控制宏,需要在模块目录xxx里面添加Kconfig文件,并把Kconfig文件路径添加到drivers/adapter/khdf/linux/Kconfig里面: 如果需要定义模块控制宏,需要在模块目录xxx里面添加Kconfig文件,并把Kconfig文件路径添加到drivers/adapter/khdf/linux/Kconfig里面:
``` ```
source "drivers/hdf/khdf/xxx/Kconfig" #目录为hdf模块软链接到kernel里面的目录 source "drivers/hdf/khdf/xxx/Kconfig" #目录为hdf模块软链接到kernel里面的目录
``` ```
添加模块目录到drivers/adapter/khdf/linux/Makefile: 添加模块目录到drivers/adapter/khdf/linux/Makefile:
``` ```
obj-$(CONFIG_DRIVERS_HDF) += xxx/ obj-$(CONFIG_DRIVERS_HDF) += xxx/
``` ```
在模块目录xxx里面添加Makefile文件,在Makefile文件里面添加模块代码编译规则: 在模块目录xxx里面添加Makefile文件,在Makefile文件里面添加模块代码编译规则:
``` ```
obj-y += xxx.o obj-y += xxx.o
``` ```
3. 驱动配置 3. 驱动配置
HDF使用HCS作为配置描述源码,HCS详细介绍参考[配置管理](../driver/driver-hdf-manage.md)介绍。
HDF使用HCS作为配置描述源码,HCS详细介绍参考[配置管理](driver-hdf-manage.md)介绍。
驱动配置包含两部分,HDF框架定义的驱动设备描述和驱动的私有配置信息,具体写法如下: 驱动配置包含两部分,HDF框架定义的驱动设备描述和驱动的私有配置信息,具体写法如下:
- 驱动设备描述(必选) - 驱动设备描述(必选)
HDF框架加载驱动所需要的信息来源于HDF框架定义的驱动设备描述,因此基于HDF框架开发的驱动必须要在HDF框架定义的device_info.hcs配置文件中添加对应的设备描述,驱动的设备描述填写如下所示:
HDF框架加载驱动所需要的信息来源于HDF框架定义的驱动设备描述,因此基于HDF框架开发的驱动必须要在HDF框架定义的device\_info.hcs配置文件中添加对应的设备描述,驱动的设备描述填写如下所示:
``` ```
root { root {
...@@ -193,10 +188,9 @@ HDF框架以组件化的驱动模型作为核心设计思路,为开发者提 ...@@ -193,10 +188,9 @@ HDF框架以组件化的驱动模型作为核心设计思路,为开发者提
} }
} }
``` ```
- 驱动私有配置信息(可选) - 驱动私有配置信息(可选)
如果驱动有私有配置,则可以添加一个驱动的配置文件,用来填写一些驱动的默认配置信息,HDF框架在加载驱动的时候,会将对应的配置信息获取并保存在HdfDeviceObject 中的property里面,通过Bind和Init(参考步骤1)传递给驱动,驱动的配置信息示例如下:
如果驱动有私有配置,则可以添加一个驱动的配置文件,用来填写一些驱动的默认配置信息,HDF框架在加载驱动的时候,会将对应的配置信息获取并保存在HdfDeviceObject 中的property里面,通过Bind和Init(参考[驱动开发](#li35182436435))传递给驱动,驱动的配置信息示例如下:
``` ```
root { root {
...@@ -210,35 +204,18 @@ HDF框架以组件化的驱动模型作为核心设计思路,为开发者提 ...@@ -210,35 +204,18 @@ HDF框架以组件化的驱动模型作为核心设计思路,为开发者提
配置信息定义之后,需要将该配置文件添加到板级配置入口文件hdf.hcs(这一块可以通过OpenHarmony驱动子系统在DevEco集成驱动开发套件工具一键式配置,具体使用方法参考驱动开发套件中的介绍),示例如下: 配置信息定义之后,需要将该配置文件添加到板级配置入口文件hdf.hcs(这一块可以通过OpenHarmony驱动子系统在DevEco集成驱动开发套件工具一键式配置,具体使用方法参考驱动开发套件中的介绍),示例如下:
``` ```
#include "device_info/device_info.hcs" #include "device_info/device_info.hcs"
#include "sample/sample_config.hcs" #include "sample/sample_config.hcs"
``` ```
4. 用户态驱动服务启动配置
用户态需要把驱动服务配置到文件drivers/adapter/uhdf2/host/hdf_devhostmusl.cfg中,如下: > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 驱动加载方式支持按需加载和按序加载两种方式,具体使用方法如下:
``` >
{ > - 按需加载
"name" : "sample_host", //驱动服务进程名字,和device_info.hcs中配置的hostName对应 >
"dynamic" : true, //动态加载,目前驱动服务只支持动态加载,即由hdf_devmgr在初始化时调用init模块接口启动
"path" : ["/vendor/bin/hdf_devhost"],//hdf_devhost所在的目录
"uid" : "sample_host",//进程的用户ID
"gid" : ["sample_host"],//进程的组ID
"caps" : ["DAC_OVERRIDE", "DAC_READ_SEARCH"]//进程的Linux capabilities配置
}
```
进程的用户ID在文件base/startup/init_lite/services/etc/passwd中配置,进程的组ID在文件base/startup/init_lite/services/etc/group中配置,进程用户ID和组ID配置参考:[系统服务用户组添加方法](https://gitee.com/openharmony/startup_init_lite/wikis)
>![](../public_sys-resources/icon-note.gif) **说明:**
>驱动加载方式支持按需加载和按序加载两种方式,具体使用方法如下:
>- 按需加载
> ``` > ```
> typedef enum { > typedef enum {
> DEVICE_PRELOAD_ENABLE = 0, > DEVICE_PRELOAD_ENABLE = 0,
...@@ -247,7 +224,8 @@ HDF框架以组件化的驱动模型作为核心设计思路,为开发者提 ...@@ -247,7 +224,8 @@ HDF框架以组件化的驱动模型作为核心设计思路,为开发者提
> DEVICE_PRELOAD_INVALID > DEVICE_PRELOAD_INVALID
> } DevicePreload; > } DevicePreload;
> ``` > ```
> 配置文件中preload 字段配成 0 (DEVICE\_PRELOAD\_ENABLE ),则系统启动过程中默认加载;配成1(DEVICE\_PRELOAD\_ENABLE\_STEP2),当系统支持快启的时候,则在系统完成之后再加载这一类驱动,否则和DEVICE\_PRELOAD\_ENABLE 含义相同;配成2(DEVICE\_PRELOAD\_DISABLE),则系统启动过程中默认不加载,支持后续动态加载,当用户态获取驱动服务(参考[消息机制](driver-hdf-message-management.md))时,如果驱动服务不存在时,HDF框架会尝试动态加载该驱动。 >
>- 按序加载(需要驱动为默认加载) > 配置文件中preload 字段配成 0(DEVICE_PRELOAD_ENABLE),则系统启动过程中默认加载;配成1(DEVICE_PRELOAD_ENABLE_STEP2),当系统支持快启的时候,则在系统完成之后再加载这一类驱动,否则和DEVICE_PRELOAD_ENABLE含义相同;配成2(DEVICE_PRELOAD_DISABLE),则系统启动过程中默认不加载,支持后续动态加载,当用户态获取驱动服务(参考[消息机制](../driver/driver-hdf-message-management.md))时,如果驱动服务不存在,HDF框架会尝试动态加载该驱动。
>
> - 按序加载(需要驱动为默认加载)
> 配置文件中的priority(取值范围为整数0到200)是用来表示host和驱动的优先级,不同的host内的驱动,host的priority值越小,驱动加载优先级越高;同一个host内驱动的priority值越小,加载优先级越高。 > 配置文件中的priority(取值范围为整数0到200)是用来表示host和驱动的优先级,不同的host内的驱动,host的priority值越小,驱动加载优先级越高;同一个host内驱动的priority值越小,加载优先级越高。
# 配置管理<a name="ZH-CN_TOPIC_0000001053493462"></a> # 配置管理
- [配置概述](#section59914284576)
- [配置语法](#section533713333580)
- [关键字](#section4522107333)
- [基本结构](#section853042911312)
- [数据类型](#section177001259134)
- [预处理](#section14867121641)
- [注释](#section1323412417)
- [引用修改](#section193708571145)
- [节点复制](#section1487792020513)
- [删除](#section1096515391155)
- [属性引用](#section20271317611)
- [模板](#section958819191063)
- [配置生成](#section106152531919) ## 配置概述
- [hc-gen介绍](#section359734416616)
HCS(HDF Configuration Source)是HDF驱动框架的配置描述源码,内容以Key-Value为主要形式。它实现了配置代码与驱动代码解耦,便于开发者进行配置管理。
## 配置概述<a name="section59914284576"></a> HC-GEN(HDF Configuration Generator)是HCS配置转换工具,可以将HDF配置文件转换为软件可读取的文件格式:
HCS\(**H**DF **C**onfiguration **S**ource\)是HDF驱动框架的配置描述源码,内容以Key-Value为主要形式。它实现了配置代码与驱动代码解耦,便于开发者进行配置管理。
HC-GEN**\(H**DF **C**onfiguration **G**enerator**\)**是HCS配置转换工具,可以将HDF配置文件转换为软件可读取的文件格式:
- 在弱性能环境中,转换为配置树源码或配置树宏定义,驱动可直接调用C代码或宏式APIs获取配置。 - 在弱性能环境中,转换为配置树源码或配置树宏定义,驱动可直接调用C代码或宏式APIs获取配置。
- 在高性能环境中,转换为HCB\(**H**DF **C**onfiguration **B**inary\)二进制文件,驱动可使用HDF框架提供的配置解析接口获取配置。
- 在高性能环境中,转换为HCB(HDF Configuration Binary)二进制文件,驱动可使用HDF框架提供的配置解析接口获取配置。
以下是使用HCB模式的典型应用场景: 以下是使用HCB模式的典型应用场景:
**图 1** 配置使用流程图<a name="fig772653312159"></a> **图1** 配置使用流程图
![](figures/配置使用流程图.png "配置使用流程图")
![zh-cn_image_0000001154105768](figures/zh-cn_image_0000001154105768.png)
HCS经过HC-GEN编译生成HCB文件,HDF驱动框架中的HCS Parser模块会从HCB文件中重建配置树,HDF驱动模块使用HCS Parser提供的配置读取接口获取配置内容。 HCS经过HC-GEN编译生成HCB文件,HDF驱动框架中的HCS Parser模块会从HCB文件中重建配置树,HDF驱动模块使用HCS Parser提供的配置读取接口获取配置内容。
## 配置语法<a name="section533713333580"></a>
## 配置语法
HCS的语法介绍如下: HCS的语法介绍如下:
### 关键字<a name="section4522107333"></a>
### 关键字
HCS配置语法保留了以下关键字。 HCS配置语法保留了以下关键字。
**表 1** HCS配置语法保留关键字 **表1** HCS配置语法保留关键字
<a name="table197619515016"></a> | 关键字 | 用途 | 说明 |
<table><thead align="left"><tr id="row107621651103"><th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.1"><p id="p0745257902"><a name="p0745257902"></a><a name="p0745257902"></a>关键字</p> | -------- | -------- | -------- |
</th> | root | 配置根节点 | - |
<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.2"><p id="p1974510571305"><a name="p1974510571305"></a><a name="p1974510571305"></a>用途</p> | include | 引用其他HCS配置文件 | - |
</th> | delete | 删除节点或属性 | 只能用于操作include导入的配置树 |
<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.3"><p id="p10745175720020"><a name="p10745175720020"></a><a name="p10745175720020"></a>说明</p> | template | 定义模板节点 | - |
</th> | match_attr | 用于标记节点的匹配查找属性 | 解析配置时可以使用该属性的值查找到对应节点 |
</tr>
</thead>
<tbody><tr id="row77624515014"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p8745657307"><a name="p8745657307"></a><a name="p8745657307"></a>root</p> ### 基本结构
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p074525719015"><a name="p074525719015"></a><a name="p074525719015"></a>配置根节点</p> HCS主要分为属性(Attribute)和节点(Node)两种结构。
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p1174515575018"><a name="p1174515575018"></a><a name="p1174515575018"></a>-</p>
</td>
</tr>
<tr id="row18762175115012"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p11745175710019"><a name="p11745175710019"></a><a name="p11745175710019"></a>include</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p167458577016"><a name="p167458577016"></a><a name="p167458577016"></a>引用其他HCS配置文件</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p9745135718012"><a name="p9745135718012"></a><a name="p9745135718012"></a>-</p>
</td>
</tr>
<tr id="row20762251608"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p16745105712015"><a name="p16745105712015"></a><a name="p16745105712015"></a>delete</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p774585716016"><a name="p774585716016"></a><a name="p774585716016"></a>删除节点或属性</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p974514571102"><a name="p974514571102"></a><a name="p974514571102"></a>只能用于操作include导入的配置树</p>
</td>
</tr>
<tr id="row18762751509"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p174617571907"><a name="p174617571907"></a><a name="p174617571907"></a>template</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p1874610571705"><a name="p1874610571705"></a><a name="p1874610571705"></a>定义模板节点</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p774617571019"><a name="p774617571019"></a><a name="p774617571019"></a>-</p>
</td>
</tr>
<tr id="row376320511903"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p3746557501"><a name="p3746557501"></a><a name="p3746557501"></a>match_attr</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p1174635712015"><a name="p1174635712015"></a><a name="p1174635712015"></a>用于标记节点的匹配查找属性</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p1774615571508"><a name="p1774615571508"></a><a name="p1774615571508"></a>解析配置时可以使用该属性的值查找到对应节点</p>
</td>
</tr>
</tbody>
</table>
### 基本结构<a name="section853042911312"></a>
HCS主要分为属性\(Attribute\)和节点\(Node\)两种结构。
**属性** **属性**
属性即最小的配置单元,是一个独立的配置项。语法如下: 属性即最小的配置单元,是一个独立的配置项。语法如下:
``` ```
attribute_name = value; attribute_name = value;
``` ```
- attribute\_name 是**字母、数字、下划线**的组合且必须以字母或下划线开头,字母区分大小写。 - attribute_name 是**字母、数字、下划线**的组合且必须以字母或下划线开头,字母区分大小写。
- value的可用格式如下: - value的可用格式如下:
- 数字常量,支持二进制、八进制、十进制、十六进制数,具体参考数据类型节。 - 数字常量,支持二进制、八进制、十进制、十六进制数,具体参考数据类型节。
- 字符串,内容使用双引号("")引用。
- 字符串,内容使用双引号\(""\)引用。
- 节点引用。 - 节点引用。
- attribute 必须以分号(;)结束且必须属于一个node。
- attribute 必须以分号\(;\)结束且必须属于一个node。
**节点** **节点**
节点是一组属性的集合,语法如下: 节点是一组属性的集合,语法如下:
``` ```
node_name { node_name {
module = "sample"; module = "sample";
...@@ -127,7 +75,7 @@ HCS主要分为属性\(Attribute\)和节点\(Node\)两种结构。 ...@@ -127,7 +75,7 @@ HCS主要分为属性\(Attribute\)和节点\(Node\)两种结构。
} }
``` ```
- node\_name 是**字母、数字、下划线**的组合且必须以字母或下划线开头,字母区分大小写。 - node_name 是**字母、数字、下划线**的组合且必须以字母或下划线开头,字母区分大小写。
- 大括号后无需添加结束符“;”。 - 大括号后无需添加结束符“;”。
...@@ -135,31 +83,32 @@ HCS主要分为属性\(Attribute\)和节点\(Node\)两种结构。 ...@@ -135,31 +83,32 @@ HCS主要分为属性\(Attribute\)和节点\(Node\)两种结构。
- root节点中必须包含module属性,其值应该为一个字符串,用于表征该配置所属模块。 - root节点中必须包含module属性,其值应该为一个字符串,用于表征该配置所属模块。
- 节点中可以增加match\_attr属性,其值为一个全局唯一的字符串。在解析配置时可以调用查找接口以该属性的值查找到包含该属性的节点。 - 节点中可以增加match_attr属性,其值为一个全局唯一的字符串。在解析配置时可以调用查找接口以该属性的值查找到包含该属性的节点。
### 数据类型<a name="section177001259134"></a>
### 数据类型
在属性定义中使用自动数据类型,不显式指定类型,属性支持的数据类型如下: 在属性定义中使用自动数据类型,不显式指定类型,属性支持的数据类型如下:
**整型** **整型**
整型长度自动推断,根据实际数据长度给与最小空间占用的类型。 整型长度自动推断,根据实际数据长度给与最小空间占用的类型。
- 二进制,0b前缀,示例:0b1010。 - 二进制,0b前缀,示例:0b1010。
- 八进制,0前缀,示例:0664。 - 八进制,0前缀,示例:0664。
- 十进制 ,无前缀,且支持有符号与无符号,示例:1024,+1024均合法。负值在读取时注意使用有符号数读取接口。 - 十进制 ,无前缀,且支持有符号与无符号,示例:1024,+1024均合法。负值在读取时注意使用有符号数读取接口。
- 十六进制,0x前缀,示例:0xff00、0xFF。 - 十六进制,0x前缀,示例:0xff00、0xFF。
**字符串** **字符串**
字符串使用双引号\(""\)表示。 字符串使用双引号("")表示。
**数组** **数组**
数组元素支持整型、字符串,不支持混合类型。整型数组中uint32\_t uint64\_t混用会向上转型为uint64\_t 数组。整型数组与字符串数组示例如下: 数组元素支持整型、字符串,不支持混合类型。整型数组中uint32_t uint64_t混用会向上转型为uint64_t 数组。整型数组与字符串数组示例如下:
``` ```
attr_foo = [0x01, 0x02, 0x03, 0x04]; attr_foo = [0x01, 0x02, 0x03, 0x04];
...@@ -170,51 +119,58 @@ attr_bar = ["hello", "world"]; ...@@ -170,51 +119,58 @@ attr_bar = ["hello", "world"];
bool类型中**true**表示真,**false**表示假。 bool类型中**true**表示真,**false**表示假。
### 预处理<a name="section14867121641"></a>
### 预处理
**include** **include**
用于导入其他HCS文件。语法示例如下: 用于导入其他HCS文件。语法示例如下:
``` ```
#include "foo.hcs" #include "foo.hcs"
#include "../bar.hcs" #include "../bar.hcs"
``` ```
- 文件名必须使用双引号\(""\),不在同一目录使用相对路径引用。被include文件也必须是合法的HCS文件。 - 文件名必须使用双引号(""),不在同一目录使用相对路径引用。被include文件也必须是合法的HCS文件。
- 多个include,如果存在相同的节点,后者覆盖前者,其余的节点依次展开。 - 多个include,如果存在相同的节点,后者覆盖前者,其余的节点依次展开。
### 注释<a name="section1323412417"></a>
### 注释
支持两种注释风格。 支持两种注释风格。
- 单行注释。 - 单行注释。
``` ```
// comment // comment
``` ```
- 多行注释。 - 多行注释。
``` ```
/* /*
comment comment
*/ */
``` ```
>![](../public_sys-resources/icon-note.gif) **说明:** > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
>多行注释不支持嵌套。 > 多行注释不支持嵌套。
### 引用修改<a name="section193708571145"></a> ### 引用修改
引用修改可以实现修改另外任意一个节点的内容,语法为: 引用修改可以实现修改另外任意一个节点的内容,语法为:
``` ```
node :& source_node node :& source_node
``` ```
上述语句表示node中的内容是对source\_node节点内容的修改。示例如下: 上述语句表示node中的内容是对source_node节点内容的修改。示例如下:
``` ```
root { root {
...@@ -239,6 +195,7 @@ root { ...@@ -239,6 +195,7 @@ root {
最终生成配置树为: 最终生成配置树为:
``` ```
root { root {
module = "sample"; module = "sample";
...@@ -253,20 +210,24 @@ root { ...@@ -253,20 +210,24 @@ root {
} }
``` ```
在以上示例中,可以看到foo.foo\_节点通过引用将bar.attr属性的值修改为了"foo",foo.foo1节点通过引用将foo.foo2.attr属性的值修改为了0x2。foo.foo\_以及foo.foo1节点表示对目标节点内容的修改,其自身并不会存在最终生成的配置树中。 在以上示例中,可以看到foo.foo_节点通过引用将bar.attr属性的值修改为了"foo",foo.foo1节点通过引用将foo.foo2.attr属性的值修改为了0x2。foo.foo_以及foo.foo1节点表示对目标节点内容的修改,其自身并不会存在最终生成的配置树中。
- 引用同级node,可以直接使用node名称,否则被引用的节点必须使用绝对路径,节点间使用“.”分隔,root表示根节点,格式为root开始的节点路径序列,例如root.foo.bar即为一个合法的绝对路径。 - 引用同级node,可以直接使用node名称,否则被引用的节点必须使用绝对路径,节点间使用“.”分隔,root表示根节点,格式为root开始的节点路径序列,例如root.foo.bar即为一个合法的绝对路径。
- 如果出现修改冲突(即多处修改同一个属性),编译器将提示warning,因为这种情况下只会生效某一个修改而导致最终结果不确定。 - 如果出现修改冲突(即多处修改同一个属性),编译器将提示warning,因为这种情况下只会生效某一个修改而导致最终结果不确定。
### 节点复制<a name="section1487792020513"></a>
### 节点复制
节点复制可以实现在节点定义时从另一个节点先复制内容,用于定义内容相似的节点。语法为: 节点复制可以实现在节点定义时从另一个节点先复制内容,用于定义内容相似的节点。语法为:
``` ```
node : source_node node : source_node
``` ```
上述语句表示在定义"node"节点时将另一个节点"source\_node"的属性复制过来。示例如下: 上述语句表示在定义"node"节点时将另一个节点"source_node"的属性复制过来。示例如下:
``` ```
root { root {
...@@ -282,6 +243,7 @@ root { ...@@ -282,6 +243,7 @@ root {
上述代码的最终生成配置树为: 上述代码的最终生成配置树为:
``` ```
root { root {
module = "sample"; module = "sample";
...@@ -295,13 +257,15 @@ root { ...@@ -295,13 +257,15 @@ root {
} }
``` ```
在上述示例中,编译后bar节点即包含attr\_0属性也包含attr\_1属性,在bar中对attr\_0的修改不会影响到foo。 在上述示例中,编译后bar节点即包含attr_0属性也包含attr_1属性,在bar中对attr_0的修改不会影响到foo。
在foo和bar在同级node中可不指定foo的路径,否则需要使用绝对路径引用,参考[引用修改](#section193708571145) 在foo和bar在同级node中可不指定foo的路径,否则需要使用绝对路径引用,参考[引用修改](#引用修改)
### 删除<a name="section1096515391155"></a>
要对include导入的base配置树中不需要的节点或属性进行删除,可以使用delete关键字。下面的举例中sample1.hcs通过include导入了sample2.hcs中的配置内容,并使用delete删除了sample2.hcs中的attribute2属性和foo\_2节点,示例如下: ### 删除
要对include导入的base配置树中不需要的节点或属性进行删除,可以使用delete关键字。下面的举例中sample1.hcs通过include导入了sample2.hcs中的配置内容,并使用delete删除了sample2.hcs中的attribute2属性和foo_2节点,示例如下:
``` ```
// sample2.hcs // sample2.hcs
...@@ -322,7 +286,8 @@ root { ...@@ -322,7 +286,8 @@ root {
} }
``` ```
上述代码在生成过程中将会删除root.foo\_2节点与attr\_2,最终生成配置树为: 上述代码在生成过程中将会删除root.foo_2节点与attr_2,最终生成配置树为:
``` ```
root { root {
...@@ -330,19 +295,22 @@ root { ...@@ -330,19 +295,22 @@ root {
} }
``` ```
>![](../public_sys-resources/icon-note.gif) **说明:** > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
>在同一个HCS文件中不允许使用delete,建议直接删除不需要的属性。 > 在同一个HCS文件中不允许使用delete,建议直接删除不需要的属性。
### 属性引用<a name="section20271317611"></a>
### 属性引用
为了在解析配置时快速定位到关联的节点,可以把节点作为属性的右值,通过读取属性查找到对应节点。语法为: 为了在解析配置时快速定位到关联的节点,可以把节点作为属性的右值,通过读取属性查找到对应节点。语法为:
``` ```
attribute = &node; attribute = &node;
``` ```
上述语句表示attribute的值是一个节点node的引用,在解析时可以用这个attribute快速定位到node,便于关联和查询其他node。示例如下: 上述语句表示attribute的值是一个节点node的引用,在解析时可以用这个attribute快速定位到node,便于关联和查询其他node。示例如下:
``` ```
node1 { node1 {
attributes; attributes;
...@@ -351,8 +319,10 @@ node2 { ...@@ -351,8 +319,10 @@ node2 {
attr_1 = &root.node1; attr_1 = &root.node1;
} }
``` ```
``` ```
node2 { node2 {
node1 { node1 {
...@@ -362,12 +332,14 @@ node2 { ...@@ -362,12 +332,14 @@ node2 {
} }
``` ```
### 模板<a name="section958819191063"></a>
### 模板
模板的用途在于生成严格一致的node结构,以便对同类型node进行遍历和管理。 模板的用途在于生成严格一致的node结构,以便对同类型node进行遍历和管理。
使用template关键字定义模板node,子node通过双冒号“::”声明继承关系。子节点可以改写但不能新增和删除template中的属性,子节点中没有定义的属性将使用template中的定义作为默认值。示例如下: 使用template关键字定义模板node,子node通过双冒号“::”声明继承关系。子节点可以改写但不能新增和删除template中的属性,子节点中没有定义的属性将使用template中的定义作为默认值。示例如下:
``` ```
root { root {
module = "sample"; module = "sample";
...@@ -387,6 +359,7 @@ root { ...@@ -387,6 +359,7 @@ root {
生成配置树如下: 生成配置树如下:
``` ```
root { root {
module = "sample"; module = "sample";
...@@ -401,16 +374,19 @@ root { ...@@ -401,16 +374,19 @@ root {
} }
``` ```
在上述示例中,bar和bar\_1节点继承了foo节点,生成配置树节点结构与foo保持了完全一致,只是属性的值不同。 在上述示例中,bar和bar_1节点继承了foo节点,生成配置树节点结构与foo保持了完全一致,只是属性的值不同。
## 配置生成<a name="section106152531919"></a> ## 配置生成
hc-gen是配置生成的工具,可以对HCS配置语法进行检查并把HCS源文件转化成HCB二进制文件。 hc-gen是配置生成的工具,可以对HCS配置语法进行检查并把HCS源文件转化成HCB二进制文件。
### hc-gen介绍<a name="section359734416616"></a>
### hc-gen介绍
hc-gen参数说明: hc-gen参数说明:
``` ```
Usage: hc-gen [Options] [File] Usage: hc-gen [Options] [File]
options: options:
...@@ -418,7 +394,6 @@ options: ...@@ -418,7 +394,6 @@ options:
-a hcb align with four bytes -a hcb align with four bytes
-b output binary output, default enable -b output binary output, default enable
-t output config in C language source file style -t output config in C language source file style
-m output config in macro source file style
-i output binary hex dump in C language source file style -i output binary hex dump in C language source file style
-p <prefix> prefix of generated symbol name -p <prefix> prefix of generated symbol name
-d decompile hcb to hcs -d decompile hcb to hcs
...@@ -429,25 +404,28 @@ options: ...@@ -429,25 +404,28 @@ options:
生成.c/.h 配置文件方法: 生成.c/.h 配置文件方法:
``` ```
hc-gen -o [OutputCFileName] -t [SourceHcsFileName] hc-gen -o [OutputCFileName] -t [SourceHcsFileName]
``` ```
生成HCB 配置文件方法: 生成HCB 配置文件方法:
``` ```
hc-gen -o [OutputHcbFileName] -b [SourceHcsFileName] hc-gen -o [OutputHcbFileName] -b [SourceHcsFileName]
``` ```
生成宏定义配置文件方法: 生成宏定义配置文件方法:
``` ```
hc-gen -o [OutputMacroFileName] -m [SourceHcsFileName] hc-gen -o [OutputMacroFileName] -m [SourceHcsFileName]
``` ```
反编译HCB文件为HCS方法: 反编译HCB文件为HCS方法:
``` ```
hc-gen -o [OutputHcsFileName] -d [SourceHcbFileName] hc-gen -o [OutputHcsFileName] -d [SourceHcbFileName]
``` ```
# 驱动消息机制管理<a name="ZH-CN_TOPIC_0000001052657065"></a> # 驱动消息机制管理
- [使用场景](#section33014541954)
- [接口说明](#section538852311616)
- [开发步骤](#section946912121153)
## 使用场景<a name="section33014541954"></a> ## 使用场景
当用户态应用和内核态驱动需要交互时,可以使用HDF框架的消息机制来实现。 当用户态应用和内核态驱动需要交互时,可以使用HDF框架的消息机制来实现。
## 接口说明<a name="section538852311616"></a>
## 接口说明
消息机制的功能主要有以下两种: 消息机制的功能主要有以下两种:
1. 用户态应用发送消息到驱动。 1. 用户态应用发送消息到驱动。
2. 用户态应用接收驱动主动上报事件。 2. 用户态应用接收驱动主动上报事件。
**表 1** 消息机制接口 **表1** 消息机制接口
<a name="table208212674114"></a> | 方法 | 描述 |
<table><thead align="left"><tr id="row08282618416"><th class="cellrowborder" valign="top" width="46.379999999999995%" id="mcps1.2.3.1.1"><p id="p382132664112"><a name="p382132664112"></a><a name="p382132664112"></a>方法</p> | -------- | -------- |
</th> | struct&nbsp;HdfIoService&nbsp;\*HdfIoServiceBind(const&nbsp;char&nbsp;\*serviceName); | 用户态获取驱动的服务,获取该服务之后通过服务中的Dispatch方法向驱动发送消息。 |
<th class="cellrowborder" valign="top" width="53.620000000000005%" id="mcps1.2.3.1.2"><p id="p4826264419"><a name="p4826264419"></a><a name="p4826264419"></a>描述</p> | void&nbsp;HdfIoServiceRecycle(struct&nbsp;HdfIoService&nbsp;\*service); | 释放驱动服务。 |
</th> | int&nbsp;HdfDeviceRegisterEventListener(struct&nbsp;HdfIoService&nbsp;\*target,&nbsp;struct&nbsp;HdfDevEventlistener&nbsp;\*listener); | 用户态程序注册接收驱动上报事件的操作方法。 |
</tr> | int&nbsp;HdfDeviceSendEvent(struct&nbsp;HdfDeviceObject&nbsp;\*deviceObject,&nbsp;uint32_t&nbsp;id,&nbsp;struct&nbsp;HdfSBuf&nbsp;\*data); | 驱动主动上报事件接口。 |
</thead>
<tbody><tr id="row1582426174114"><td class="cellrowborder" valign="top" width="46.379999999999995%" headers="mcps1.2.3.1.1 "><p id="p182341916144420"><a name="p182341916144420"></a><a name="p182341916144420"></a>struct HdfIoService *HdfIoServiceBind(const char *serviceName)</p>
</td> ## 开发步骤
<td class="cellrowborder" valign="top" width="53.620000000000005%" headers="mcps1.2.3.1.2 "><p id="p58272614113"><a name="p58272614113"></a><a name="p58272614113"></a>用户态获取驱动的服务,获取该服务之后通过服务中的Dispatch方法向驱动发送消息。</p>
</td> 1. 将驱动配置信息中服务策略policy字段设置为2(SERVICE_POLICY_CAPACITY,参考[policy定义](../driver/driver-hdf-servicemanage.md))。
</tr>
<tr id="row578565084913"><td class="cellrowborder" valign="top" width="46.379999999999995%" headers="mcps1.2.3.1.1 "><p id="p15786185024918"><a name="p15786185024918"></a><a name="p15786185024918"></a>void HdfIoServiceRecycle(struct HdfIoService *service);</p>
</td>
<td class="cellrowborder" valign="top" width="53.620000000000005%" headers="mcps1.2.3.1.2 "><p id="p47861750154912"><a name="p47861750154912"></a><a name="p47861750154912"></a>释放驱动服务。</p>
</td>
</tr>
<tr id="row1382112617413"><td class="cellrowborder" valign="top" width="46.379999999999995%" headers="mcps1.2.3.1.1 "><p id="p482182611415"><a name="p482182611415"></a><a name="p482182611415"></a>int HdfDeviceRegisterEventListener(struct HdfIoService *target, struct HdfDevEventlistener *listener);</p>
</td>
<td class="cellrowborder" valign="top" width="53.620000000000005%" headers="mcps1.2.3.1.2 "><p id="p18825261412"><a name="p18825261412"></a><a name="p18825261412"></a>用户态程序注册接收驱动上报事件的操作方法。</p>
</td>
</tr>
<tr id="row498956124019"><td class="cellrowborder" valign="top" width="46.379999999999995%" headers="mcps1.2.3.1.1 "><p id="p6412911184019"><a name="p6412911184019"></a><a name="p6412911184019"></a>int HdfDeviceSendEvent(struct HdfDeviceObject *deviceObject, uint32_t id, struct HdfSBuf *data);</p>
</td>
<td class="cellrowborder" valign="top" width="53.620000000000005%" headers="mcps1.2.3.1.2 "><p id="p1698915634018"><a name="p1698915634018"></a><a name="p1698915634018"></a>驱动主动上报事件接口。</p>
</td>
</tr>
</tbody>
</table>
## 开发步骤<a name="section946912121153"></a>
1. 将驱动配置信息中服务策略policy字段设置为2(SERVICE\_POLICY\_CAPACITY,参考[policy定义](driver-hdf-servicemanage.md))。
``` ```
device_sample :: Device { device_sample :: Device {
...@@ -59,6 +36,7 @@ ...@@ -59,6 +36,7 @@
``` ```
2. 配置驱动信息中的服务设备节点权限(permission字段)是框架给驱动创建设备节点的权限,默认是0666,驱动开发者根据驱动的实际使用场景配置驱动设备节点的权限。 2. 配置驱动信息中的服务设备节点权限(permission字段)是框架给驱动创建设备节点的权限,默认是0666,驱动开发者根据驱动的实际使用场景配置驱动设备节点的权限。
3. 在服务实现过程中,实现服务基类成员IDeviceIoService中的Dispatch方法。 3. 在服务实现过程中,实现服务基类成员IDeviceIoService中的Dispatch方法。
``` ```
...@@ -153,7 +131,6 @@ ...@@ -153,7 +131,6 @@
return 0; return 0;
} }
``` ```
2. 用户态注册接收驱动上报消息的操作方法。 2. 用户态注册接收驱动上报消息的操作方法。
``` ```
...@@ -178,7 +155,6 @@ ...@@ -178,7 +155,6 @@
return 0; return 0;
} }
``` ```
3. 驱动上报事件。 3. 驱动上报事件。
``` ```
...@@ -188,6 +164,3 @@ ...@@ -188,6 +164,3 @@
return HdfDeviceSendEvent(deviceObject, cmdCode, data); return HdfDeviceSendEvent(deviceObject, cmdCode, data);
} }
``` ```
# HDF开发概述<a name="ZH-CN_TOPIC_0000001051611604"></a> # HDF开发概述
- [简介](#section0649162112376)
- [驱动加载](#section68701942154319)
- [驱动服务管理](#section12453133414412)
- [驱动消息机制](#section129410710451)
## 简介<a name="section0649162112376"></a> ## 简介
HDF(Hardware Driver Foundation)驱动框架,为驱动开发者提供驱动框架能力,包括驱动加载、驱动服务管理和驱动消息机制。旨在构建统一的驱动架构平台,为驱动开发者提供更精准、更高效的开发环境,力求做到一次开发,多系统部署。 HDF(Hardware Driver Foundation)驱动框架,为驱动开发者提供驱动框架能力,包括驱动加载、驱动服务管理和驱动消息机制。旨在构建统一的驱动架构平台,为驱动开发者提供更精准、更高效的开发环境,力求做到一次开发,多系统部署。
## 驱动加载<a name="section68701942154319"></a>
## 驱动加载
HDF驱动加载包括按需加载和按序加载。 HDF驱动加载包括按需加载和按序加载。
- 按需加载 - 按需加载
HDF框架支持驱动在系统启动过程中默认加载,或者在系统启动之后动态加载。 HDF框架支持驱动在系统启动过程中默认加载,或者在系统启动之后动态加载。
- 按序加载 - 按序加载
HDF框架支持驱动在系统启动的过程中按照驱动的优先级进行加载。 HDF框架支持驱动在系统启动的过程中按照驱动的优先级进行加载。
## 驱动服务管理<a name="section12453133414412"></a> ## 驱动服务管理
HDF框架可以集中管理驱动服务,开发者可直接通过HDF框架对外提供的能力接口获取驱动相关的服务。 HDF框架可以集中管理驱动服务,开发者可直接通过HDF框架对外提供的能力接口获取驱动相关的服务。
## 驱动消息机制<a name="section129410710451"></a>
HDF框架提供统一的驱动消息机制,支持用户态应用向内核态驱动发送消息,也支持内核态驱动向用户态应用发送消息。 ## 驱动消息机制
HDF框架提供统一的驱动消息机制,支持用户态应用向内核态驱动发送消息,也支持内核态驱动向用户态应用发送消息。
# HDF开发实例<a name="ZH-CN_TOPIC_0000001052451677"></a> # HDF开发实例
- [添加配置](#section27261067111)
- [编写驱动代码](#section177988005)
- [编写用户程序和驱动交互代码](#section6205173816412)
下面基于HDF框架,提供一个完整的样例,包含配置文件的添加,驱动代码的实现以及用户态程序和驱动交互的流程。 下面基于HDF框架,提供一个完整的样例,包含配置文件的添加,驱动代码的实现以及用户态程序和驱动交互的流程。
## 添加配置<a name="section27261067111"></a>
在HDF框架的配置文件(例如vendor/hisilicon/xxx/hdf_config/device\_info)中添加该驱动的配置信息,如下所示: ## 添加配置
在HDF框架的配置文件(例如vendor/hisilicon/xxx/hdf_config/device_info)中添加该驱动的配置信息,如下所示:
``` ```
root { root {
...@@ -46,9 +45,11 @@ root { ...@@ -46,9 +45,11 @@ root {
} }
``` ```
## 编写驱动代码<a name="section177988005"></a>
基于HDF框架编写的sample驱动代码如下(编译参考 [驱动开发](driver-hdf-development.md)): ## 编写驱动代码
基于HDF框架编写的sample驱动代码如下(编译参考[驱动开发](../driver/driver-hdf-development.md)):
``` ```
#include <fcntl.h> #include <fcntl.h>
...@@ -118,9 +119,11 @@ struct HdfDriverEntry g_sampleDriverEntry = { ...@@ -118,9 +119,11 @@ struct HdfDriverEntry g_sampleDriverEntry = {
HDF_INIT(g_sampleDriverEntry); HDF_INIT(g_sampleDriverEntry);
``` ```
## 编写用户程序和驱动交互代码<a name="section6205173816412"></a>
基于HDF框架编写的用户态程序和驱动交互的代码如下(代码可以放在目录drivers/adapter/uhdf下面编译,build.gn可以参考drivers/framework/sample/platform/uart/dev/build.gn): ## 编写用户程序和驱动交互代码
基于HDF框架编写的用户态程序和驱动交互的代码如下(代码可以放在目录drivers/adapter/uhdf下面编译,build.gn可以参考drivers/framework/sample/platform/uart/dev/build.gn):
``` ```
#include <fcntl.h> #include <fcntl.h>
...@@ -229,10 +232,13 @@ int main() ...@@ -229,10 +232,13 @@ int main()
} }
``` ```
>![](../public_sys-resources/icon-note.gif) **说明:** > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
>用户态应用程序使用了HDF框架中的消息发送接口,因此在编译用户态程序的过程中需要依赖HDF框架对外提供的hdf\_core和osal的动态库,在gn编译文件中添加如下依赖项: > 用户态应用程序使用了HDF框架中的消息发送接口,因此在编译用户态程序的过程中需要依赖HDF框架对外提供的hdf_core和osal的动态库,在gn编译文件中添加如下依赖项:
>deps = \[ >
>"//drivers/adapter/uhdf/manager:hdf\_core", > deps = [
>"//drivers/adapter/uhdf/posix:hdf\_posix\_osal", >
>\] > "//drivers/adapter/uhdf/manager:hdf_core",
>
> "//drivers/adapter/uhdf/posix:hdf_posix_osal",
>
> ]
# 驱动服务管理<a name="ZH-CN_TOPIC_0000001052777057"></a> # 驱动服务管理
- [使用场景](#section14244270117)
- [接口说明](#section1432412561722)
- [开发步骤](#section393515164416)
驱动服务是HDF驱动设备对外提供能力的对象,由HDF框架统一管理。驱动服务管理主要包含驱动服务的发布和获取。 驱动服务是HDF驱动设备对外提供能力的对象,由HDF框架统一管理。驱动服务管理主要包含驱动服务的发布和获取。
HDF框架定义了驱动对外发布服务的策略,是由配置文件中的policy字段来控制,policy字段的取值范围以及含义如下: HDF框架定义了驱动对外发布服务的策略,是由配置文件中的policy字段来控制,policy字段的取值范围以及含义如下:
``` ```
typedef enum { typedef enum {
/* 驱动不提供服务 */ /* 驱动不提供服务 */
...@@ -25,43 +25,26 @@ typedef enum { ...@@ -25,43 +25,26 @@ typedef enum {
} ServicePolicy; } ServicePolicy;
``` ```
## 使用场景<a name="section14244270117"></a>
## 使用场景
当驱动以接口的形式对外提供能力时,可以使用HDF框架的驱动服务管理能力。 当驱动以接口的形式对外提供能力时,可以使用HDF框架的驱动服务管理能力。
## 接口说明<a name="section1432412561722"></a>
## 接口说明
针对驱动服务管理功能,HDF框架开放了以下接口供开发者调用,如下表所示: 针对驱动服务管理功能,HDF框架开放了以下接口供开发者调用,如下表所示:
**表 1** 服务管理接口 **表1** 服务管理接口
<a name="table8431122013592"></a> | 方法 | 描述 |
<table><thead align="left"><tr id="row13431820135919"><th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.1"><p id="p1670132714592"><a name="p1670132714592"></a><a name="p1670132714592"></a>方法</p> | -------- | -------- |
</th> | int32_t&nbsp;(\*Bind)(struct&nbsp;HdfDeviceObject&nbsp;\*deviceObject); | 需要驱动开发者实现Bind函数,将自己的服务接口绑定到HDF框架中。 |
<th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.2"><p id="p770172785910"><a name="p770172785910"></a><a name="p770172785910"></a>描述</p> | const&nbsp;struct&nbsp;HdfObject&nbsp;\*DevSvcManagerClntGetService(const&nbsp;char&nbsp;\*svcName); | 获取驱动的服务。 |
</th> | int&nbsp;HdfDeviceSubscribeService(<br/>struct&nbsp;HdfDeviceObject&nbsp;\*deviceObject,&nbsp;const&nbsp;char&nbsp;\*serviceName,&nbsp;struct&nbsp;SubscriberCallback&nbsp;callback); | 订阅驱动的服务。 |
</tr>
</thead>
<tbody><tr id="row1743112017594"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p18601333135911"><a name="p18601333135911"></a><a name="p18601333135911"></a>int32_t (*Bind)(struct HdfDeviceObject *deviceObject);</p> ## 开发步骤
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p46015332591"><a name="p46015332591"></a><a name="p46015332591"></a>需要驱动开发者实现Bind函数,将自己的服务接口绑定到HDF框架中。</p>
</td>
</tr>
<tr id="row1543212045914"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p19601163314590"><a name="p19601163314590"></a><a name="p19601163314590"></a>const struct HdfObject *DevSvcManagerClntGetService(const char *svcName);</p>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p1601123318598"><a name="p1601123318598"></a><a name="p1601123318598"></a>获取驱动的服务。</p>
</td>
</tr>
<tr id="row20432162019594"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p960173310590"><a name="p960173310590"></a><a name="p960173310590"></a>int HdfDeviceSubscribeService(</p>
<p id="p126021533165915"><a name="p126021533165915"></a><a name="p126021533165915"></a>struct HdfDeviceObject *deviceObject, const char *serviceName, struct SubscriberCallback callback);</p>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p06029334597"><a name="p06029334597"></a><a name="p06029334597"></a>订阅驱动的服务。</p>
</td>
</tr>
</tbody>
</table>
## 开发步骤<a name="section393515164416"></a>
驱动服务管理的开发包括驱动服务的编写、绑定、获取或者订阅,详细步骤如下。 驱动服务管理的开发包括驱动服务的编写、绑定、获取或者订阅,详细步骤如下。
...@@ -109,13 +92,12 @@ typedef enum { ...@@ -109,13 +92,12 @@ typedef enum {
``` ```
3. 驱动服务获取。 3. 驱动服务获取。
驱动服务的获取有两种方式,HDF框架提供接口直接获取和HDF框架提供订阅机制获取。 驱动服务的获取有两种方式,HDF框架提供接口直接获取和HDF框架提供订阅机制获取。
- 通过HDF接口直接获取 - 通过HDF接口直接获取
当明确驱动已经加载完成时,获取该驱动的服务可以通过HDF框架提供的能力接口直接获取,如下所示: 当明确驱动已经加载完成时,获取该驱动的服务可以通过HDF框架提供的能力接口直接获取,如下所示:
``` ```
const struct ISampleDriverService *sampleService = const struct ISampleDriverService *sampleService =
(const struct ISampleDriverService *)DevSvcManagerClntGetService("sample_driver"); (const struct ISampleDriverService *)DevSvcManagerClntGetService("sample_driver");
...@@ -125,11 +107,10 @@ typedef enum { ...@@ -125,11 +107,10 @@ typedef enum {
sampleService->ServiceA(); sampleService->ServiceA();
sampleService->ServiceB(5); sampleService->ServiceB(5);
``` ```
- 通过HDF提供的订阅机制获取 - 通过HDF提供的订阅机制获取
当内核态对驱动(同一个host)加载的时机不感知时,可以通过HDF框架提供的订阅机制来订阅该驱动,当该驱动加载完成时,HDF框架会将被订阅的驱动服务发布给订阅者,实现方式如下所示: 当内核态对驱动(同一个host)加载的时机不感知时,可以通过HDF框架提供的订阅机制来订阅该驱动,当该驱动加载完成时,HDF框架会将被订阅的驱动服务发布给订阅者,实现方式如下所示:
``` ```
// 订阅回调函数的编写,当被订阅的驱动加载完成后,HDF框架会将被订阅驱动的服务发布给订阅者,通过这个回调函数给订阅者使用 // 订阅回调函数的编写,当被订阅的驱动加载完成后,HDF框架会将被订阅驱动的服务发布给订阅者,通过这个回调函数给订阅者使用
// object为订阅者的私有数据,service为被订阅的服务对象 // object为订阅者的私有数据,service为被订阅的服务对象
...@@ -160,6 +141,3 @@ typedef enum { ...@@ -160,6 +141,3 @@ typedef enum {
return ret; return ret;
} }
``` ```
# HDF驱动框架<a name="ZH-CN_TOPIC_0000001157319419"></a> # HDF驱动框架
- **[HDF开发概述](driver-hdf-overview.md)** - **[HDF开发概述](driver-hdf-overview.md)**
...@@ -11,5 +13,3 @@ ...@@ -11,5 +13,3 @@
- **[配置管理](driver-hdf-manage.md)** - **[配置管理](driver-hdf-manage.md)**
- **[HDF开发实例](driver-hdf-sample.md)** - **[HDF开发实例](driver-hdf-sample.md)**
\ No newline at end of file
# LCD<a name="ZH-CN_TOPIC_0000001052857284"></a> # LCD
## 概述<a name="section141575391542"></a> ## 概述
LCD(Liquid Crystal Display)液晶显示驱动,对LCD进行上电,并通过接口初始化LCD内部寄存器,使LCD正常工作。Display驱动模型基于HDF( Hardware Driver Foundation)[驱动框架](driver-hdf-overview.md)开发,实现跨OS、跨平台,为LCD硬件提供上下电功能、发送初始化序列功能,使LCD进入正常的工作模式,显示芯片平台侧的图像数据,基于HDF驱动框架的Display驱动模型如[图1](#fig69138814229) LCD(Liquid Crystal Display)液晶显示驱动,对LCD进行上电,并通过接口初始化LCD内部寄存器,使LCD正常工作。Display驱动模型基于HDF( Hardware Driver Foundation)[驱动框架](../driver/driver-hdf-overview.md)开发,实现跨OS、跨平台为LCD硬件提供上下电功能、发送初始化序列功能,使LCD进入正常的工作模式,显示芯片平台侧的图像数据。基于HDF驱动框架的Display驱动模型如下所示
**图 1** 基于HDF驱动框架的Display驱动模型<a name="fig69138814229"></a> **图1** 基于HDF驱动框架的Display驱动模型
![](figures/基于HDF驱动框架的Display驱动模型.png "基于HDF驱动框架的Display驱动模型")
**Display驱动模型介绍** ![zh-cn_image_0000001170262223](figures/zh-cn_image_0000001170262223.png)
Display驱动模型主要由平台驱动层、芯片平台适配层、LCD器件驱动层三部分组成。驱动模型基于HDF驱动框架开发,通过Platform层和OSAL层提供的接口,屏蔽内核形态的差异,使得器件驱动可以便利的迁移到不同OS及芯片平台。模型向上对接Display公共hal层,支撑HDI(Hardware Display Interface)接口的实现,通过Display-HDI对图形服务提供各类驱动能力接口。
- Display平台驱动层:通过HDF提供的IOService数据通道,与公共Hal层对接,集中接收并处理各类上层调用指令。
- SOC平台驱动适配层:借助此SOC适配层,实现Display驱动和SOC侧驱动解耦,主要完成芯片平台相关的参数配置,并传递平台驱动层的调用到器件驱动层。 Display驱动模型主要由平台驱动层、芯片平台适配层、LCD器件驱动层三部分组成。驱动模型基于HDF驱动框架开发,通过Platform层和OSAL层提供的接口,屏蔽内核形态的差异,使得器件驱动可以便利的迁移到不同OS及芯片平台。模型向上对接Display公共HAL层,支撑HDI(Hardware Display Interface)接口的实现,通过Display-HDI对图形服务提供各类驱动能力接口。
- Display平台驱动层:通过HDF提供的IOService数据通道,与公共HAL层对接,集中接收并处理各类上层调用指令。
- SoC平台驱动适配层:借助此SoC适配层,实现Display驱动和SoC侧驱动解耦,主要完成芯片平台相关的参数配置,并传递平台驱动层的调用到器件驱动层。
- LCD器件驱动层:在器件驱动层中,主要实现和器件自身强相关的驱动适配接口,例如发送初始化序列、上下电、背光设置等。 - LCD器件驱动层:在器件驱动层中,主要实现和器件自身强相关的驱动适配接口,例如发送初始化序列、上下电、背光设置等。
基于Display驱动模型开发LCD驱动,可以借助平台提供的各种能力及接口,较大程度的降低器件驱动的开发周期和难度,提升开发效率。 基于Display驱动模型开发LCD驱动,可以借助平台提供的各种能力及接口,较大程度的降低器件驱动的开发周期和难度,提升开发效率。
## 接口说明<a name="section53793327396"></a>
## 接口说明
LCD接口通常可分为MIPI DSI接口、TTL接口和LVDS接口,常用的是MIPI DSI接口和TTL接口,下面对常用的MIPI DSI接口和TTL接口作简要介绍。 LCD接口通常可分为MIPI DSI接口、TTL接口和LVDS接口,常用的是MIPI DSI接口和TTL接口,下面对常用的MIPI DSI接口和TTL接口作简要介绍。
- MIPI DSI接口 - MIPI DSI接口
**图 2** MIPI DSI接口<a name="fig6936451331"></a> **图2** MIPI DSI接口
![](figures/MIPI-DSI接口.png "MIPI-DSI接口")
![zh-cn_image_0000001147040198](figures/zh-cn_image_0000001147040198.png)
MIPI DSI接口是MIPI(Mobile Industry Processor Interface)联盟定义的显示接口,主要用于移动终端显示屏接口,接口数据传输遵循MIPI协议,MIPI DSI接口为数据接口,传输图像数据,通常情况下MIPI DSI接口的控制信息以MIPI包形式通过MIPI DSI接口发送到对端IC,不需要额外的外设接口。 MIPI DSI接口是MIPI(Mobile Industry Processor Interface)联盟定义的显示接口,主要用于移动终端显示屏接口,接口数据传输遵循MIPI协议,MIPI DSI接口为数据接口,传输图像数据,通常情况下MIPI DSI接口的控制信息以MIPI包形式通过MIPI DSI接口发送到对端IC,不需要额外的外设接口。
- TTL接口 - TTL接口
**图 3** TTL接口<a name="fig141611855635"></a> **图3** TTL接口
![](figures/TTL接口.png "TTL接口")
![zh-cn_image_0000001192960023](figures/zh-cn_image_0000001192960023.png)
TTL(Transistor Transistor Logic)即晶体管-晶体管逻辑,TTL电平信号由TTL器件产生,TTL器件是数字集成电路的一大门类,它采用双极型工艺制造,具有高速度、低功耗和品种多等特点。 TTL(Transistor Transistor Logic)即晶体管-晶体管逻辑,TTL电平信号由TTL器件产生,TTL器件是数字集成电路的一大门类,它采用双极型工艺制造,具有高速度、低功耗和品种多等特点。
TTL接口是并行方式传输数据的接口,有数据信号、时钟信号和控制信号(行同步、帧同步、数据有效信号等),在控制信号控制下完成数据传输。通常TTL接口的LCD,内部寄存器读写需要额外的外设接口,比如SPI接口、I2C接口等。 TTL接口是并行方式传输数据的接口,有数据信号、时钟信号和控制信号(行同步、帧同步、数据有效信号等),在控制信号控制下完成数据传输。通常TTL接口的LCD,内部寄存器读写需要额外的外设接口,比如SPI接口、I2C接口等。
## 开发步骤<a name="section12394223125615"></a> ## 开发步骤
Display驱动模型基于HDF驱动框架、Platform接口及OSAL接口开发,可以做到不区分OS(LiteOS、Linux)和芯片平台(Hi35xx、Hi38xx、V3S等),为LCD器件提供统一的驱动模型。开发步骤如下:
Display驱动模型基于HDF驱动框架、Platform接口及OSAL接口开发,可以做到不区分OS(LiteOS、Linux)和芯片平台(Hi35xx、Hi38xx、V3S等),为LCD器件提供统一的驱动模型。
1. 添加LCD驱动相关的设备描述配置。 1. 添加LCD驱动相关的设备描述配置。
2. 在SOC平台驱动适配层中适配对应的芯片平台驱动。
2. 在SoC平台驱动适配层中适配对应的芯片平台驱动。
3. 添加器件驱动,并在驱动入口函数Init中注册Panel驱动数据,驱动数据接口主要包括如下接口: 3. 添加器件驱动,并在驱动入口函数Init中注册Panel驱动数据,驱动数据接口主要包括如下接口:
- LCD上下电 - LCD上下电
根据LCD硬件连接,使用Platform接口层提供的GPIO操作接口操作对应LCD管脚,例如复位管脚、IOVCC管脚,上电时序参考LCD供应商提供的SPEC。 根据LCD硬件连接,使用Platform接口层提供的GPIO操作接口操作对应LCD管脚,例如复位管脚、IOVCC管脚,上电时序参考LCD供应商提供的SPEC。
- 发送初始化序列 - 发送初始化序列
根据LCD硬件接口,使用Platform接口层提供的I2C、SPI、MIPI等接口,下载LCD初始化序列,初始化参数序列可以参考LCD供应商提供的SPEC。 根据LCD硬件接口,使用Platform接口层提供的I2C、SPI、MIPI等接口,下载LCD初始化序列,初始化参数序列可以参考LCD供应商提供的SPEC。
4. 根据需求实现HDF框架其他接口,比如Release接口。 4. 根据需求实现HDF框架其他接口,比如Release接口。
5. 根据需求使用HDF框架可创建其他设备节点,用于业务逻辑或者调试功能。 5. 根据需求使用HDF框架可创建其他设备节点,用于业务逻辑或者调试功能。
## 开发实例<a name="section7441155155813"></a>
## 开发实例
添加设备描述配置: 添加设备描述配置:
``` ```
/* Display驱动相关的设备描述配置 */ /* Display驱动相关的设备描述配置 */
display :: host { display :: host {
...@@ -75,7 +84,7 @@ display :: host { ...@@ -75,7 +84,7 @@ display :: host {
serviceName = "hdf_disp"; serviceName = "hdf_disp";
} }
} }
/* SOC适配层驱动设备描述 */ /* SoC适配层驱动设备描述 */
device_hi35xx_disp :: device { device_hi35xx_disp :: device {
device0 :: deviceNode { device0 :: deviceNode {
policy = 0; policy = 0;
...@@ -103,6 +112,7 @@ display :: host { ...@@ -103,6 +112,7 @@ display :: host {
SOC适配层驱动,以Hi35xx系列芯片为例,需要在本层驱动中适配MIPI等和芯片平台相关的配置,示例如下: SOC适配层驱动,以Hi35xx系列芯片为例,需要在本层驱动中适配MIPI等和芯片平台相关的配置,示例如下:
``` ```
static int32_t MipiDsiInit(struct PanelInfo *info) static int32_t MipiDsiInit(struct PanelInfo *info)
{ {
...@@ -145,6 +155,7 @@ static int32_t MipiDsiInit(struct PanelInfo *info) ...@@ -145,6 +155,7 @@ static int32_t MipiDsiInit(struct PanelInfo *info)
LCD器件驱动示例如下: LCD器件驱动示例如下:
``` ```
#define RESET_GPIO 5 #define RESET_GPIO 5
#define MIPI_DSI0 0 #define MIPI_DSI0 0
...@@ -347,4 +358,3 @@ struct HdfDriverEntry g_sampleDevEntry = { ...@@ -347,4 +358,3 @@ struct HdfDriverEntry g_sampleDevEntry = {
HDF_INIT(g_sampleDevEntry); HDF_INIT(g_sampleDevEntry);
``` ```
# TOUCHSCREEN<a name="ZH-CN_TOPIC_0000001052857350"></a> # Touchscreen
- [概述](#section175431838101617)
- [接口说明](#section105459441659)
- [开发步骤](#section65745222184)
- [开发实例](#section263714411191)
- [设备描述配置](#section18249155619195)
- [板级配置及器件私有配置](#section3571192072014)
- [添加器件驱动](#section6356758162015)
## 概述
## 概述<a name="section175431838101617"></a>
- **Touchscreen驱动主要任务** - **Touchscreen驱动主要任务**
Touchscreen驱动用于驱动触摸屏使其正常工作,该驱动主要完成如下工作:对触摸屏驱动IC进行上电、配置硬件管脚并初始化其状态、注册中断、配置通信接口(I2C或SPI)、设定Input相关配置、下载及更新固件等操作。 Touchscreen驱动用于驱动触摸屏使其正常工作,该驱动主要完成如下工作:对触摸屏驱动IC进行上电、配置硬件管脚并初始化其状态、注册中断、配置通信接口(I2C或SPI)、设定Input相关配置、下载及更新固件等操作。
- **Touchscreen驱动模型说明**
本节主要介绍基于Input驱动模型开发Touchscreen器件驱动,Input模型整体的框架如下图所示。
- **Touchscreen驱动层次说明** Input驱动模型基于HDF驱动框架、Platform接口、OSAL接口进行开发,向上对接规范化的驱动接口HDI(Hardware Driver Interface)层,通过Input-HDI层对外提供硬件能力,即上层Input Service可以通过HDI接口层获取相应的驱动能力,进而操控Touchscreen等输入设备。
本节主要介绍基于Input驱动模型开发touchscreen器件驱动,Input模型整体的框架如[图1](#fig6251184817261)。
Input驱动模型基于HDF驱动框架、Platform接口、OSAL接口进行开发,向上对接规范化的驱动接口HDI(Hardware Driver Interface)层,通过Input-HDI层对外提供硬件能力,即上层Input service可以通过HDI接口层获取相应的驱动能力,进而操控touchscreen等输入设备。 **图1** 基于HDF驱动框架的Input驱动模型
![zh-cn_image_0000001123742904](figures/zh-cn_image_0000001123742904.png)
**图 1** 基于HDF驱动框架的Input驱动模型<a name="fig6251184817261"></a>
![](figures/基于HDF驱动框架的input驱动模型.png "基于HDF驱动框架的input驱动模型")
- **Input驱动模型介绍** - **Input驱动模型介绍**
Input驱动模型核心部分由设备管理层、公共驱动层、器件驱动层组成。器件产生的数据借助平台数据通道能力从内核传递到用户态,驱动模型通过配置文件适配不同器件及硬件平台,提高开发者的器件驱动开发效率。如下部分为模型各部分的说明: Input驱动模型核心部分由设备管理层、公共驱动层、器件驱动层组成。器件产生的数据借助平台数据通道能力从内核传递到用户态,驱动模型通过配置文件适配不同器件及硬件平台,提高开发者的器件驱动开发效率。如下部分为模型各部分的说明:
- Input设备管理:为各类输入设备驱动提供Input设备的注册、注销接口,同时统一管理Input设备列表。 - Input设备管理:为各类输入设备驱动提供Input设备的注册、注销接口,同时统一管理Input设备列表。
- Input平台驱动:指各类Input设备的公共抽象驱动(例如触摸屏的公共驱动),负责对板级硬件进行初始化、硬件中断处理、向manager注册Input设备等。 - Input平台驱动:指各类Input设备的公共抽象驱动(例如触摸屏的公共驱动),负责对板级硬件进行初始化、硬件中断处理、向manager注册Input设备等。
- Input器件驱动:指各器件厂家的差异化驱动,通过适配平台驱动预留的差异化接口,实现器件驱动开发量最小化。 - Input器件驱动:指各器件厂家的差异化驱动,通过适配平台驱动预留的差异化接口,实现器件驱动开发量最小化。
- Input数据通道:提供一套通用的数据上报通道,各类别的Input设备驱动均可用此通道上报Input事件。 - Input数据通道:提供一套通用的数据上报通道,各类别的Input设备驱动均可用此通道上报Input事件。
- Input配置解析:负责对Input设备的板级配置及器件私有配置进行解析及管理。 - Input配置解析:负责对Input设备的板级配置及器件私有配置进行解析及管理。
- **基于HDF驱动框架开发器件驱动的优势** - **基于HDF驱动框架开发器件驱动的优势**
在HDF(Hardware Driver Foundation)[驱动管理框架](driver-hdf-development.md)的基础上,Input驱动模型调用OSAL接口层和Platfom接口层提供的基础接口进行开发,包括bus通信接口、操作系统原生接口(memory、lock、thread、timer等)。由于OSAL接口和Platform接口屏蔽了芯片平台差异,所以基于Input驱动模型实现的touchscreen驱动可以进行跨平台、跨OS迁移,以便逐步实现驱动的一次开发,多端部署。 在HDF(Hardware Driver Foundation)[驱动管理框架](../driver/driver-hdf-development.md)的基础上,Input驱动模型调用OSAL接口层和Platform接口层提供的基础接口进行开发,包括bus通信接口、操作系统原生接口(memory、lock、thread、timer等)。由于OSAL接口和Platform接口屏蔽了芯片平台差异,所以基于Input驱动模型实现的Touchscreen驱动可以进行跨平台、跨OS迁移,以便逐步实现驱动的一次开发,多端部署。
## 接口说明<a name="section105459441659"></a> ## 接口说明
Touchscreen器件的硬件接口相对简单,根据PIN脚的属性,可以简单分为如下三类: Touchscreen器件的硬件接口相对简单,根据PIN脚的属性,可以简单分为如下三类:
- 电源接口 - 电源接口
- IO控制接口 - IO控制接口
- 通信接口 - 通信接口
**图 2** Touchscreen器件常用管脚<a name="fig1290384314416"></a> **图2** Touchscreen器件常用管脚
![](figures/Touchscreen器件常用管脚.png "Touchscreen器件常用管脚")
![zh-cn_image_0000001192846991](figures/zh-cn_image_0000001192846991.png)
如上图所示的三类接口,分别做简要说明如下: 如上图所示的三类接口,分别做简要说明如下:
1. **电源接口** 1. **电源接口**
- LDO\_1P8:1.8V数字电路 - LDO_1P8:1.8V数字电路
- LDO\_3P3:3.3V模拟电路 - LDO_3P3:3.3V模拟电路
通常情况下,Touchscreenreen驱动IC和LCD驱动IC是相互分离的,这种情况下,Touchscreen驱动IC一般同时需要1.8V和3.3V两路供电。随着芯片演进,业内已有Touchscreen驱动IC和LCD驱动IC集成在一颗IC中的芯片案例,对Touchscreen而言,只需要关注1.8V供电即可,其内部需要的3.3V电源,会在驱动IC内部从LCD的VSP电源(典型值5.5V)中分出来。
通常情况下,touchscreen驱动IC和LCD驱动IC是相互分离的,这种情况下,touchscreen驱动IC一般同时需要1.8V和3.3V两路供电。随着芯片演进,业内已有touchscreen驱动IC和LCD驱动IC集成在一颗IC中的芯片案例,对touchscreen而言,只需要关注1.8V供电即可,其内部需要的3.3V电源,会在驱动IC内部从LCD的VSP电源(典型值5.5V)中分出来。
2. **IO控制接口** 2. **IO控制接口**
- Reset:reset管脚,用于在系统休眠、唤醒时,由主机侧对驱动IC进行复位操作。 - Reset:reset管脚,用于在系统休眠、唤醒时,由主机侧对驱动IC进行复位操作。
- INT:中断管脚,需要在驱动初始化时,配置为输入上拉状态。在驱动IC检测到外部触摸信号后,通过操作中断管脚来触发中断,器件驱动则会在中断处理函数中进行报点数据读取等操作。 - INT:中断管脚,需要在驱动初始化时,配置为输入上拉状态。在驱动IC检测到外部触摸信号后,通过操作中断管脚来触发中断,器件驱动则会在中断处理函数中进行报点数据读取等操作。
3. **通信接口** 3. **通信接口**
- I2C:由于touchscreen的报点数据量相对较少,所以一般选用I2C方式传输数据。I2C的具体协议及对应操作接口,可以参考Platform接口层中的[“I2C”使用指南](driver-platform-i2c-des.md#section5361140416) - I2C:由于Touchscreen的报点数据量相对较少,所以一般选用I2C方式传输数据。I2C的具体协议及对应操作接口,可以参考Platform接口层中的[“I2C”使用指南](../driver/driver-platform-i2c-des.md#概述)
- SPI:部分厂商,由于需要传递的数据不止报点坐标,而是需要获取基础容值,数据量较大,所以会选用SPI通信方式。SPI的具体协议及对应操作接口,可以参考Platform接口层中的[“SPI” 使用指南](driver-platform-spi-des.md#section193356154511) - SPI:部分厂商,由于需要传递的数据不止报点坐标,而是需要获取基础容值,数据量较大,所以会选用SPI通信方式。SPI的具体协议及对应操作接口,可以参考Platform接口层中的[“SPI” 使用指南](../driver/driver-platform-spi-des.md#概述)
## 开发步骤<a name="section65745222184"></a> ## 开发步骤
Input驱动模型是基于HDF框架、Platform接口和OSAL接口开发,不区分操作系统和芯片平台,为touchscreen等输入器件提供统一的驱动开发架构。 Input驱动模型是基于HDF框架、Platform接口和OSAL接口开发,不区分操作系统和芯片平台,为Touchscreen等输入器件提供统一的驱动开发架构。
如下以touchscreen器件驱动为例,说明Input驱动模型的完整加载流程: 如下以Touchscreen器件驱动为例,说明Input驱动模型的完整加载流程:
(1)设备描述配置:由开发者参考已有模板进行设备描述配置,包括驱动加载顺序、板级硬件信息、器件私有数据信息等。 (1)设备描述配置:由开发者参考已有模板进行设备描述配置,包括驱动加载顺序、板级硬件信息、器件私有数据信息等。
...@@ -95,25 +81,24 @@ Input驱动模型是基于HDF框架、Platform接口和OSAL接口开发,不区 ...@@ -95,25 +81,24 @@ Input驱动模型是基于HDF框架、Platform接口和OSAL接口开发,不区
请参考如下相关步骤: 请参考如下相关步骤:
1. 设备描述配置 1. 设备描述配置
目前Input驱动基于HDF驱动框架编写,驱动的加载启动由HDF驱动管理框架统一处理。首先需要在对应的配置文件中,将驱动信息注册进去,如是否加载、加载优先级,此后HDF驱动框架会逐一启动注册过的驱动模块。驱动的相关配置请参考[HDF驱动框架配置指导](../driver/driver-hdf-development.md#驱动开发步骤)
目前Input驱动基于HDF驱动框架编写,驱动的加载启动由HDF驱动管理框架统一处理。首先需要在对应的配置文件中,将驱动信息注册进去,如是否加载、加载优先级,此后HDF驱动框架会逐一启动注册过的驱动模块。驱动的相关配置请参考[HDF驱动框架配置指导](driver-hdf-development.md#section1969312275533)。
2. 板级配置及Touchscreen器件私有配置 2. 板级配置及Touchscreen器件私有配置
配置对应的IO管脚功能,例如对单板上为Touchscreen设计预留的I2C Pin脚,需设置对应的寄存器,使其选择I2C的通信功能。
配置对应的IO管脚功能,例如对单板上为touchscreen设计预留的I2C Pin脚,需设置对应的寄存器,使其选择I2C的通信功能。
3. 实现器件差异化适配接口 3. 实现器件差异化适配接口
根据硬件单板设计的通信接口,使用Platform接口层提供的管脚操作接口配置对应的复位管脚、中断管脚以及电源操作,对于GPIO的操作,可参考[GPIO操作接口指导](../driver/driver-platform-gpio-des.md#概述)
根据硬件单板设计的通信接口,使用Platform接口层提供的管脚操作接口配置对应的复位管脚、中断管脚以及电源操作,对于GPIO的操作,可参考[GPIO操作接口指导](driver-platform-gpio-des.md#section1635911016188) ## 开发实例
本实例提供Touchscreen驱动开发示例,并简要对具体关键点进行开发说明。
## 开发实例<a name="section263714411191"></a>
本实例提供touchscreen驱动开发示例,并简要对具体关键点进行开发说明。 ### 设备描述配置
### 设备描述配置<a name="section18249155619195"></a> 如下配置主要包含Input驱动模型各模块层级信息,具体原理可参考[HDF驱动开发指南](../driver/driver-hdf-development.md),HDF框架依据该配置信息实现对Input模型各模块的依次加载等。
如下配置主要包含Input驱动模型各模块层级信息,具体原理可参考[HDF驱动开发指南](driver-hdf-development.md),HDF框架依据该配置信息实现对Input模型各模块的依次加载等。
``` ```
input :: host { input :: host {
...@@ -156,10 +141,12 @@ input :: host { ...@@ -156,10 +141,12 @@ input :: host {
} }
``` ```
### 板级配置及器件私有配置<a name="section3571192072014"></a>
### 板级配置及器件私有配置
如下配置包含板级硬件配置及器件私有数据配置,实际业务开发时,可根据具体需求增删及修改如下配置文件信息。 如下配置包含板级硬件配置及器件私有数据配置,实际业务开发时,可根据具体需求增删及修改如下配置文件信息。
``` ```
root { root {
input_config { input_config {
...@@ -245,10 +232,12 @@ root { ...@@ -245,10 +232,12 @@ root {
} }
``` ```
### 添加器件驱动<a name="section6356758162015"></a>
### 添加器件驱动
在器件驱动中,主要实现了平台预留的差异化接口,以器件数据获取及解析进行示例说明。具体开发过程,需要根据实际使用的单板及器件进行适配。 在器件驱动中,主要实现了平台预留的差异化接口,以器件数据获取及解析进行示例说明。具体开发过程,需要根据实际使用的单板及器件进行适配。
``` ```
/* 将从器件中读取到的报点数据解析为坐标 */ /* 将从器件中读取到的报点数据解析为坐标 */
static void ParsePointData(ChipDevice *device, FrameData *frame, uint8_t *buf, uint8_t pointNum) static void ParsePointData(ChipDevice *device, FrameData *frame, uint8_t *buf, uint8_t pointNum)
...@@ -402,4 +391,3 @@ struct HdfDriverEntry g_touchSampleChipEntry = { ...@@ -402,4 +391,3 @@ struct HdfDriverEntry g_touchSampleChipEntry = {
HDF_INIT(g_touchSampleChipEntry); HDF_INIT(g_touchSampleChipEntry);
``` ```
# 外设驱动使用<a name="ZH-CN_TOPIC_0000001157319411"></a> # 外设驱动使用
- **[LCD](driver-peripherals-lcd-des.md)** - **[LCD](driver-peripherals-lcd-des.md)**
- **[TOUCHSCREEN](driver-peripherals-touch-des.md)** - **[Touchscreen](driver-peripherals-touch-des.md)**
- **[SENSOR](driver-peripherals-sensor-des.md)** - **[SENSOR](driver-peripherals-sensor-des.md)**
- **[WLAN](driver-peripherals-external-des.md)** - **[WLAN](driver-peripherals-external-des.md)**
- **[AUDIO](driver-peripherals-audio-des.md)** - **[USB](driver-peripherals-usb-des.md)**
\ No newline at end of file \ No newline at end of file
# I2C<a name="ZH-CN_TOPIC_0000001206171515"></a> # I2C
- [概述](#section5361140416)
- [接口说明](#section545869122317)
- [使用指导](#section1695201514281)
- [使用流程](#section1338373417288)
- [打开I2C控制器](#section13751110132914)
- [进行I2C通信](#section9202183372916)
- [关闭I2C控制器](#section19481164133018)
- [使用实例](#section5302202015300) ## 概述
## 概述<a name="section5361140416"></a> - I2C(Inter Integrated Circuit)总线是由Philips公司开发的一种简单、双向二线制同步串行总线。
- I2C\(Inter Integrated Circuit\)总线是由Philips公司开发的一种简单、双向二线制同步串行总线。 - I2C以主从方式工作,通常有一个主设备和一个或者多个从设备,主从设备通过SDA(SerialData)串行数据线以及SCL(SerialClock)串行时钟线两根线相连,如图1所示。
- I2C以主从方式工作,通常有一个主设备和一个或者多个从设备,主从设备通过SDA\(SerialData\)串行数据线以及SCL\(SerialClock\)串行时钟线两根线相连,如[图1 ](#fig1135561232714)所示。
- I2C数据的传输必须以一个起始信号作为开始条件,以一个结束信号作为传输的停止条件。数据传输以字节为单位,高位在前,逐个bit进行传输。 - I2C数据的传输必须以一个起始信号作为开始条件,以一个结束信号作为传输的停止条件。数据传输以字节为单位,高位在前,逐个bit进行传输。
- I2C总线上的每一个设备都可以作为主设备或者从设备,而且每一个设备都会对应一个唯一的地址,当主设备需要和某一个从设备通信时,通过广播的方式,将从设备地址写到总线上,如果某个从设备符合此地址,将会发出应答信号,建立传输。 - I2C总线上的每一个设备都可以作为主设备或者从设备,而且每一个设备都会对应一个唯一的地址,当主设备需要和某一个从设备通信时,通过广播的方式,将从设备地址写到总线上,如果某个从设备符合此地址,将会发出应答信号,建立传输。
- I2C接口定义了完成I2C传输的通用方法集合,包括: - I2C接口定义了完成I2C传输的通用方法集合,包括:
- I2C控制器管理: 打开或关闭I2C控制器 - I2C控制器管理: 打开或关闭I2C控制器
- I2C消息传输:通过消息传输结构体数组进行自定义传输 - I2C消息传输:通过消息传输结构体数组进行自定义传输
**图 1** I2C物理连线示意图<a name="fig1135561232714"></a> **图1** I2C物理连线示意图
![](figures/I2C物理连线示意图.png "I2C物理连线示意图")
![zh-cn_image_0000001160653004](figures/zh-cn_image_0000001160653004.png)
## 接口说明<a name="section545869122317"></a>
## 接口说明
**表 1** I2C驱动API接口功能介绍
**表1** I2C驱动API接口功能介绍
<a name="table1731550155318"></a>
<table><thead align="left"><tr id="row4419501537"><th class="cellrowborder" valign="top" width="18.63%" id="mcps1.2.4.1.1"><p id="p641050105320"><a name="p641050105320"></a><a name="p641050105320"></a>功能分类</p> | 功能分类 | 接口描述 |
</th> | -------- | -------- |
<th class="cellrowborder" valign="top" width="28.03%" id="mcps1.2.4.1.2"><p id="p54150165315"><a name="p54150165315"></a><a name="p54150165315"></a>接口名</p> | I2C控制器管理接口 | -&nbsp;I2cOpen:打开I2C控制器<br/>-&nbsp;I2cClose:关闭I2C控制器 |
</th> | I2C消息传输接口 | I2cTransfer:自定义传输 |
<th class="cellrowborder" valign="top" width="53.339999999999996%" id="mcps1.2.4.1.3"><p id="p941150145313"><a name="p941150145313"></a><a name="p941150145313"></a>描述</p>
</th> > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
</tr> > 本文涉及的所有接口,仅限内核态使用,不支持在用户态使用。
</thead>
<tbody><tr id="row34145016535"><td class="cellrowborder" rowspan="2" valign="top" width="18.63%" headers="mcps1.2.4.1.1 "><p id="p229610227124"><a name="p229610227124"></a><a name="p229610227124"></a>I2C控制器管理接口</p>
</td> ## 使用指导
<td class="cellrowborder" valign="top" width="28.03%" headers="mcps1.2.4.1.2 "><p id="p19389143041518"><a name="p19389143041518"></a><a name="p19389143041518"></a>I2cOpen</p>
</td>
<td class="cellrowborder" valign="top" width="53.339999999999996%" headers="mcps1.2.4.1.3 "><p id="p8738101941716"><a name="p8738101941716"></a><a name="p8738101941716"></a>打开I2C控制器</p> ### 使用流程
</td>
</tr> 使用I2C设备的一般流程如下图所示。
<tr id="row5632152611414"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p143890309153"><a name="p143890309153"></a><a name="p143890309153"></a>I2cClose</p>
</td> **图2** I2C设备使用流程图
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p573815197171"><a name="p573815197171"></a><a name="p573815197171"></a>关闭I2C控制器</p>
</td> ![zh-cn_image_0000001206291495](figures/zh-cn_image_0000001206291495.png)
</tr>
<tr id="row15108165391412"><td class="cellrowborder" valign="top" width="18.63%" headers="mcps1.2.4.1.1 "><p id="p91084533141"><a name="p91084533141"></a><a name="p91084533141"></a>I2c消息传输接口</p>
</td> ### 打开I2C控制器
<td class="cellrowborder" valign="top" width="28.03%" headers="mcps1.2.4.1.2 "><p id="p13901730101511"><a name="p13901730101511"></a><a name="p13901730101511"></a>I2cTransfer</p>
</td>
<td class="cellrowborder" valign="top" width="53.339999999999996%" headers="mcps1.2.4.1.3 "><p id="p12738111912171"><a name="p12738111912171"></a><a name="p12738111912171"></a>自定义传输</p>
</td>
</tr>
</tbody>
</table>
>![](../public_sys-resources/icon-note.gif) **说明:**
>本文涉及的所有接口,仅限内核态使用,不支持在用户态使用。
## 使用指导<a name="section1695201514281"></a>
### 使用流程<a name="section1338373417288"></a>
使用I2C设备的一般流程如[图2](#fig183017194234)所示。
**图 2** I2C设备使用流程图<a name="fig183017194234"></a>
![](figures/I2C设备使用流程图.png "I2C设备使用流程图")
### 打开I2C控制器<a name="section13751110132914"></a>
在进行I2C通信前,首先要调用I2cOpen打开I2C控制器。 在进行I2C通信前,首先要调用I2cOpen打开I2C控制器。
DevHandle I2cOpen\(int16\_t number\); DevHandle I2cOpen(int16_t number);
**表 2** I2cOpen参数和返回值描述 **表2** I2cOpen参数和返回值描述
<a name="table7603619123820"></a> | **参数** | **参数描述** |
<table><thead align="left"><tr id="row1060351914386"><th class="cellrowborder" valign="top" width="20.66%" id="mcps1.2.3.1.1"><p id="p14603181917382"><a name="p14603181917382"></a><a name="p14603181917382"></a><strong id="b16510829133012"><a name="b16510829133012"></a><a name="b16510829133012"></a>参数</strong></p> | -------- | -------- |
</th> | number | I2C控制器号 |
<th class="cellrowborder" valign="top" width="79.34%" id="mcps1.2.3.1.2"><p id="p36031519183819"><a name="p36031519183819"></a><a name="p36031519183819"></a><strong id="b65222293309"><a name="b65222293309"></a><a name="b65222293309"></a>参数描述</strong></p> | **返回值** | **返回值描述** |
</th> | NULL | 打开I2C控制器失败 |
</tr> | 设备句柄 | 打开的I2C控制器设备句柄 |
</thead>
<tbody><tr id="row1960431983813"><td class="cellrowborder" valign="top" width="20.66%" headers="mcps1.2.3.1.1 "><p id="p3604719123817"><a name="p3604719123817"></a><a name="p3604719123817"></a>number</p>
</td>
<td class="cellrowborder" valign="top" width="79.34%" headers="mcps1.2.3.1.2 "><p id="p221392414442"><a name="p221392414442"></a><a name="p221392414442"></a>I2C控制器号</p>
</td>
</tr>
<tr id="row11410612183019"><td class="cellrowborder" valign="top" width="20.66%" headers="mcps1.2.3.1.1 "><p id="p460381915385"><a name="p460381915385"></a><a name="p460381915385"></a><strong id="b4349113243013"><a name="b4349113243013"></a><a name="b4349113243013"></a>返回值</strong></p>
</td>
<td class="cellrowborder" valign="top" width="79.34%" headers="mcps1.2.3.1.2 "><p id="p96031619153812"><a name="p96031619153812"></a><a name="p96031619153812"></a><strong id="b63502322308"><a name="b63502322308"></a><a name="b63502322308"></a>返回值描述</strong></p>
</td>
</tr>
<tr id="row15410111273017"><td class="cellrowborder" valign="top" width="20.66%" headers="mcps1.2.3.1.1 "><p id="p1060418195389"><a name="p1060418195389"></a><a name="p1060418195389"></a>NULL</p>
</td>
<td class="cellrowborder" valign="top" width="79.34%" headers="mcps1.2.3.1.2 "><p id="p760471912388"><a name="p760471912388"></a><a name="p760471912388"></a>打开I2C控制器失败</p>
</td>
</tr>
<tr id="row1241081213303"><td class="cellrowborder" valign="top" width="20.66%" headers="mcps1.2.3.1.1 "><p id="p5604719133811"><a name="p5604719133811"></a><a name="p5604719133811"></a>设备句柄</p>
</td>
<td class="cellrowborder" valign="top" width="79.34%" headers="mcps1.2.3.1.2 "><p id="p3604181933818"><a name="p3604181933818"></a><a name="p3604181933818"></a>打开的I2C控制器设备句柄</p>
</td>
</tr>
</tbody>
</table>
假设系统中存在8个I2C控制器,编号从0到7,那么我们现在获取3号控制器 假设系统中存在8个I2C控制器,编号从0到7,那么我们现在获取3号控制器
``` ```
DevHandle i2cHandle = NULL; /* I2C控制器句柄 / DevHandle i2cHandle = NULL; /* I2C控制器句柄 /
...@@ -125,56 +74,27 @@ if (i2cHandle == NULL) { ...@@ -125,56 +74,27 @@ if (i2cHandle == NULL) {
} }
``` ```
### 进行I2C通信<a name="section9202183372916"></a>
### 进行I2C通信
消息传输 消息传输
int32\_t I2cTransfer\(DevHandle handle, struct I2cMsg \*msgs, int16\_t count\); int32_t I2cTransfer(DevHandle handle, struct I2cMsg \*msgs, int16_t count);
**表 3** I2cTransfer参数和返回值描述 **表3** I2cTransfer参数和返回值描述
<a name="table1934414174212"></a> | **参数** | **参数描述** |
<table><thead align="left"><tr id="row1134415176216"><th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.1"><p id="p13295152320217"><a name="p13295152320217"></a><a name="p13295152320217"></a><strong id="b17389641205115"><a name="b17389641205115"></a><a name="b17389641205115"></a>参数</strong></p> | -------- | -------- |
</th> | handle | I2C控制器设备句柄 |
<th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.2"><p id="p1295112352115"><a name="p1295112352115"></a><a name="p1295112352115"></a><strong id="b19401541175118"><a name="b19401541175118"></a><a name="b19401541175118"></a>参数描述</strong></p> | msgs | 待传输数据的消息结构体数组 |
</th> | count | 消息数组长度 |
</tr> | **返回值** | **返回值描述** |
</thead> | 正整数 | 成功传输的消息结构体数目 |
<tbody><tr id="row5344101702113"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p19295132382111"><a name="p19295132382111"></a><a name="p19295132382111"></a>handle</p> | 负数 | 执行失败 |
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p1051172572919"><a name="p1051172572919"></a><a name="p1051172572919"></a>I2C控制器设备句柄</p>
</td>
</tr>
<tr id="row17344171722117"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p9295122332113"><a name="p9295122332113"></a><a name="p9295122332113"></a>msgs</p>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p202951238218"><a name="p202951238218"></a><a name="p202951238218"></a>待传输数据的消息结构体数组</p>
</td>
</tr>
<tr id="row45812466213"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p1659246112117"><a name="p1659246112117"></a><a name="p1659246112117"></a>count</p>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p259124622119"><a name="p259124622119"></a><a name="p259124622119"></a>消息数组长度</p>
</td>
</tr>
<tr id="row04701426105110"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p17295142322113"><a name="p17295142322113"></a><a name="p17295142322113"></a><strong id="b2159044145115"><a name="b2159044145115"></a><a name="b2159044145115"></a>返回值</strong></p>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p142959232211"><a name="p142959232211"></a><a name="p142959232211"></a><strong id="b16160044135114"><a name="b16160044135114"></a><a name="b16160044135114"></a>返回值描述</strong></p>
</td>
</tr>
<tr id="row74701226125110"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p929532313211"><a name="p929532313211"></a><a name="p929532313211"></a>正整数</p>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p829512237217"><a name="p829512237217"></a><a name="p829512237217"></a>成功传输的消息结构体数目</p>
</td>
</tr>
<tr id="row204701126195115"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p12958234217"><a name="p12958234217"></a><a name="p12958234217"></a>负数</p>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p1295192312112"><a name="p1295192312112"></a><a name="p1295192312112"></a>执行失败</p>
</td>
</tr>
</tbody>
</table>
I2C传输消息类型为I2cMsg,每个传输消息结构体表示一次读或写,通过一个消息数组,可以执行若干次的读写组合操作。 I2C传输消息类型为I2cMsg,每个传输消息结构体表示一次读或写,通过一个消息数组,可以执行若干次的读写组合操作。
``` ```
int32_t ret; int32_t ret;
uint8_t wbuff[2] = { 0x12, 0x13 }; uint8_t wbuff[2] = { 0x12, 0x13 };
...@@ -196,40 +116,35 @@ if (ret != 2) { ...@@ -196,40 +116,35 @@ if (ret != 2) {
} }
``` ```
>![](../public_sys-resources/icon-caution.gif) **注意:** > ![icon-caution.gif](public_sys-resources/icon-caution.gif) **注意:**
>- I2cMsg结构体中的设备地址不包含读写标志位,读写信息由flags成员变量的读写控制位传递。 > - I2cMsg结构体中的设备地址不包含读写标志位,读写信息由flags成员变量的读写控制位传递。
>- 本函数不对消息结构体个数count做限制,其最大个数度由具体I2C控制器决定。 >
>- 本函数也不对每个消息结构体中的数据长度做限制,同样由具体I2C控制器决定。 > - 本函数不对消息结构体个数count做限制,其最大个数度由具体I2C控制器决定。
>- 本函数可能会引起系统休眠,不允许在中断上下文调用 >
> - 本函数也不对每个消息结构体中的数据长度做限制,同样由具体I2C控制器决定。
>
> - 本函数可能会引起系统休眠,不允许在中断上下文调用
### 关闭I2C控制器<a name="section19481164133018"></a>
### 关闭I2C控制器
I2C通信完成之后,需要关闭I2C控制器,关闭函数如下所示: I2C通信完成之后,需要关闭I2C控制器,关闭函数如下所示:
void I2cClose\(DevHandle handle\); void I2cClose(DevHandle handle);
**表 4** I2cClose参数和返回值描述 **表4** I2cClose参数和返回值描述
<a name="table72517953115"></a> | 参数 | 参数描述 |
<table><thead align="left"><tr id="row1525793312"><th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.1"><p id="p115402031153111"><a name="p115402031153111"></a><a name="p115402031153111"></a>参数</p> | -------- | -------- |
</th> | handle | I2C控制器设备句柄 |
<th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.2"><p id="p65406313319"><a name="p65406313319"></a><a name="p65406313319"></a>参数描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row1926109193116"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p105419317318"><a name="p105419317318"></a><a name="p105419317318"></a>handle</p>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p1213245577"><a name="p1213245577"></a><a name="p1213245577"></a>I2C控制器设备句柄</p>
</td>
</tr>
</tbody>
</table>
``` ```
I2cClose(i2cHandle); /* 关闭I2C控制器 */ I2cClose(i2cHandle); /* 关闭I2C控制器 */
``` ```
## 使用实例<a name="section5302202015300"></a>
## 使用实例
本例程以操作开发板上的I2C设备为例,详细展示I2C接口的完整使用流程。 本例程以操作开发板上的I2C设备为例,详细展示I2C接口的完整使用流程。
...@@ -243,11 +158,12 @@ I2cClose(i2cHandle); /* 关闭I2C控制器 */ ...@@ -243,11 +158,12 @@ I2cClose(i2cHandle); /* 关闭I2C控制器 */
本例程首先对Touch IC进行复位操作(开发板上电默认会给TouchIC供电,本例程不考虑供电),然后对其内部寄存器进行随机读写,测试I2C通路是否正常。 本例程首先对Touch IC进行复位操作(开发板上电默认会给TouchIC供电,本例程不考虑供电),然后对其内部寄存器进行随机读写,测试I2C通路是否正常。
>![](../public_sys-resources/icon-note.gif) **说明:** > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
>本例程重点在于展示I2C设备访问流程,并验证I2C通路,所以对于设备寄存器读写值不做关注,读写寄存器导致的行为由设备自身决定。 > 本例程重点在于展示I2C设备访问流程,并验证I2C通路,所以对于设备寄存器读写值不做关注,读写寄存器导致的行为由设备自身决定。
示例如下: 示例如下:
``` ```
#include "i2c_if.h" /* I2C标准接口头文件 */ #include "i2c_if.h" /* I2C标准接口头文件 */
#include "gpio_if.h" /* GPIO标准接口头文件 */ #include "gpio_if.h" /* GPIO标准接口头文件 */
...@@ -420,4 +336,3 @@ static int32_t TestCaseI2c(void) ...@@ -420,4 +336,3 @@ static int32_t TestCaseI2c(void)
return ret; return ret;
} }
``` ```
# I2C<a name="ZH-CN_TOPIC_0000001176922456"></a> # I2C
- [概述](#section2040078630114257)
- [接口说明](#section752964871810)
- [开发步骤](#section1085786591114257)
- [开发实例](#section1773332551114257)
## 概述<a name="section2040078630114257"></a> ## 概述
I2C(Inter Integrated Circuit)总线是由Philips公司开发的一种简单、双向二线制同步串行总线在HDF框架中,I2C模块接口适配模式采用统一服务模式,这需要一个设备服务来作为I2C模块的管理器,统一处理外部访问,这会在配置文件中有所体现。统一服务模式适合于同类型设备对象较多的情况,如I2C可能同时具备十几个控制器,采用独立服务模式需要配置更多的设备节点,且服务会占据内存资源。 I2C(Inter Integrated Circuit)总线是由Philips公司开发的一种简单、双向二线制同步串行总线,在HDF框架中,I2C模块接口适配模式采用统一服务模式,这需要一个设备服务来作为I2C模块的管理器,统一处理外部访问,这会在配置文件中有所体现。统一服务模式适合于同类型设备对象较多的情况,如I2C可能同时具备十几个控制器,采用独立服务模式需要配置更多的设备节点,且服务会占据内存资源。
**图 1** I2C统一服务模式结构图<a name="fig17640124912440"></a> **图1** I2C统一服务模式结构图
![](figures/统一服务模式结构图.png "I2C统一服务模式结构图")
## 接口说明<a name="section752964871810"></a> ![zh-cn_image_0000001177082394](figures/zh-cn_image_0000001177082394.png)
## 接口说明
I2cMethod和I2cLockMethod定义: I2cMethod和I2cLockMethod定义:
``` ```
struct I2cMethod { struct I2cMethod {
int32_t (*transfer)(struct I2cCntlr *cntlr, struct I2cMsg *msgs, int16_t count); int32_t (*transfer)(struct I2cCntlr *cntlr, struct I2cMsg *msgs, int16_t count);
...@@ -26,66 +25,40 @@ struct I2cLockMethod {//锁机制操作结构体 ...@@ -26,66 +25,40 @@ struct I2cLockMethod {//锁机制操作结构体
}; };
``` ```
**表 1** I2cMethod结构体成员的回调函数功能说明 **表1** I2cMethod结构体成员的回调函数功能说明
<a name="table139121605913"></a> | 函数成员 | 入参 | 出参 | 返回值 | 功能 |
<table><thead align="left"><tr id="row1391101625915"><th class="cellrowborder" valign="top" width="20%" id="mcps1.2.6.1.1"><p id="p11391151619599"><a name="p11391151619599"></a><a name="p11391151619599"></a>函数成员</p> | -------- | -------- | -------- | -------- | -------- |
</th> | transfer | cntlr:结构体指针,核心层I2C控制器。<br>msgs:结构体指针,用户消息。<br>count:uint16_t,消息数量。 | 无 | HDF_STATUS相关状态 | 传递用户消息 |
<th class="cellrowborder" valign="top" width="20%" id="mcps1.2.6.1.2"><p id="p1539261618596"><a name="p1539261618596"></a><a name="p1539261618596"></a>入参</p>
</th>
<th class="cellrowborder" valign="top" width="20%" id="mcps1.2.6.1.3"><p id="p2392416175914"><a name="p2392416175914"></a><a name="p2392416175914"></a>出参</p> ## 开发步骤
</th>
<th class="cellrowborder" valign="top" width="20%" id="mcps1.2.6.1.4"><p id="p103926169598"><a name="p103926169598"></a><a name="p103926169598"></a>返回值</p>
</th>
<th class="cellrowborder" valign="top" width="20%" id="mcps1.2.6.1.5"><p id="p163921316175917"><a name="p163921316175917"></a><a name="p163921316175917"></a>功能</p>
</th>
</tr>
</thead>
<tbody><tr id="row339221695916"><td class="cellrowborder" valign="top" width="20%" headers="mcps1.2.6.1.1 "><p id="p1392716195914"><a name="p1392716195914"></a><a name="p1392716195914"></a>transfer</p>
</td>
<td class="cellrowborder" valign="top" width="20%" headers="mcps1.2.6.1.2 "><p id="p193923162593"><a name="p193923162593"></a><a name="p193923162593"></a>cntlr:结构体指针,核心层I2C控制器;msgs:结构体指针,用户消息 ;count:uint16_t,消息数量</p>
</td>
<td class="cellrowborder" valign="top" width="20%" headers="mcps1.2.6.1.3 "><p id="p1539212165594"><a name="p1539212165594"></a><a name="p1539212165594"></a></p>
</td>
<td class="cellrowborder" valign="top" width="20%" headers="mcps1.2.6.1.4 "><p id="p139291617594"><a name="p139291617594"></a><a name="p139291617594"></a>HDF_STATUS相关状态</p>
</td>
<td class="cellrowborder" valign="top" width="20%" headers="mcps1.2.6.1.5 "><p id="p6392121655919"><a name="p6392121655919"></a><a name="p6392121655919"></a>传递用户消息</p>
</td>
</tr>
</tbody>
</table>
## 开发步骤<a name="section1085786591114257"></a>
I2C模块适配的三个环节是配置属性文件,实例化驱动入口,以及实例化核心层接口函数。 I2C模块适配的三个环节是配置属性文件,实例化驱动入口,以及实例化核心层接口函数。
1. **实例化驱动入口:** 1. **实例化驱动入口:**
- 实例化HdfDriverEntry结构体成员。 - 实例化HdfDriverEntry结构体成员。
- 调用HDF\_INIT将HdfDriverEntry实例化对象注册到HDF框架中。 - 调用HDF_INIT将HdfDriverEntry实例化对象注册到HDF框架中。
2. **配置属性文件:** 2. **配置属性文件:**
- 在device\_info.hcs文件中添加deviceNode描述。 - 在device_info.hcs文件中添加deviceNode描述。
- 【可选】添加i2c\_config.hcs器件属性文件。 - 【可选】添加i2c_config.hcs器件属性文件。
3. **实例化I2C控制器对象:** 3. **实例化I2C控制器对象:**
- 初始化I2cCntlr成员。 - 初始化I2cCntlr成员。
- 实例化I2cCntlr成员I2cMethod和I2cLockMethod。 - 实例化I2cCntlr成员I2cMethod和I2cLockMethod。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
>![](../public_sys-resources/icon-note.gif) **说明:** > 实例化I2cCntlr成员I2cMethod和I2cLockMethod,详见[接口说明](#接口说明)。
>实例化I2cCntlr成员I2cMethod和I2cLockMethod,详见[接口说明](#section752964871810)。
4. **驱动调试:** 4. **驱动调试:**
【可选】针对新增驱动程序,建议验证驱动基本功能,例如挂载后的信息反馈,消息传输的成功与否等。 【可选】针对新增驱动程序,建议验证驱动基本功能,例如挂载后的信息反馈,消息传输的成功与否等。
## 开发实例<a name="section1773332551114257"></a> ## 开发实例
下方将以i2c\_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。 下方将以i2c_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。
1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf\_device\_desc.h 中定义)类型的全局变量,且moduleName要和device\_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。
1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf_device_desc.h 中定义)类型的全局变量,且moduleName要和device_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。
一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
I2C驱动入口参考: I2C驱动入口参考:
...@@ -94,6 +67,7 @@ I2C模块适配的三个环节是配置属性文件,实例化驱动入口, ...@@ -94,6 +67,7 @@ I2C模块适配的三个环节是配置属性文件,实例化驱动入口,
I2C管理器服务的驱动由核心层实现,厂商不需要关注这部分内容的实现,这个但在实现Init函数的时候需要调用核心层的I2cCntlrAdd函数,它会实现相应功能。 I2C管理器服务的驱动由核心层实现,厂商不需要关注这部分内容的实现,这个但在实现Init函数的时候需要调用核心层的I2cCntlrAdd函数,它会实现相应功能。
``` ```
struct HdfDriverEntry g_i2cDriverEntry = { struct HdfDriverEntry g_i2cDriverEntry = {
.moduleVersion = 1, .moduleVersion = 1,
...@@ -114,45 +88,21 @@ I2C模块适配的三个环节是配置属性文件,实例化驱动入口, ...@@ -114,45 +88,21 @@ I2C模块适配的三个环节是配置属性文件,实例化驱动入口,
HDF_INIT(g_i2cManagerEntry); HDF_INIT(g_i2cManagerEntry);
``` ```
2. 完成驱动入口注册之后,下一步请在device\_info.hcs文件中添加deviceNode信息,并在i2c\_config.hcs中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值对于厂商驱动的实现以及核心层I2cCntlr相关成员的默认值或限制范围有密切关系。 2. 完成驱动入口注册之后,下一步请在device_info.hcs文件中添加deviceNode信息,并在i2c_config.hcs中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值对于厂商驱动的实现以及核心层I2cCntlr相关成员的默认值或限制范围有密切关系。
统一服务模式的特点是device_info文件中第一个设备节点必须为I2C管理器,其各项参数必须如表2设置:
统一服务模式的特点是device\_info文件中第一个设备节点必须为I2C管理器,其各项参数必须如[表2](#table96651915911)设置:
**表2** 统一服务模式的特点
**表 2** 统一服务模式的特点
| 成员名 | 值 |
<a name="table96651915911"></a> | -------- | -------- |
<table><thead align="left"><tr id="row96618194915"><th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.1"><p id="p1066119790"><a name="p1066119790"></a><a name="p1066119790"></a>成员名</p> | moduleName | 固定为HDF_PLATFORM_I2C_MANAGER |
</th> | serviceName | 固定为HDF_PLATFORM_I2C_MANAGER |
<th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.2"><p id="p8674191494"><a name="p8674191494"></a><a name="p8674191494"></a>值</p> | policy | 具体配置为1或2取决于是否对用户态可见 |
</th> | deviceMatchAttr | 没有使用,可忽略 |
</tr>
</thead> 从第二个节点开始配置具体I2C控制器信息,此节点并不表示某一路I2C控制器,而是代表一个资源性质设备,用于描述一类I2C控制器的信息。多个控制器之间相互区分的参数是busID和reg_pbase,这在i2c_config文件中有所体现。
<tbody><tr id="row767111916914"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p46714196920"><a name="p46714196920"></a><a name="p46714196920"></a>moduleName</p> - device_info.hcs 配置参考。
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p36717191292"><a name="p36717191292"></a><a name="p36717191292"></a>固定为 HDF_PLATFORM_I2C_MANAGER</p>
</td>
</tr>
<tr id="row16671119392"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p11671019699"><a name="p11671019699"></a><a name="p11671019699"></a>serviceName</p>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p86716195912"><a name="p86716195912"></a><a name="p86716195912"></a>固定为 HDF_PLATFORM_I2C_MANAGER</p>
</td>
</tr>
<tr id="row17673191911"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p5673191898"><a name="p5673191898"></a><a name="p5673191898"></a>policy</p>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p18677191699"><a name="p18677191699"></a><a name="p18677191699"></a>具体配置为1或2取决于是否对用户态可见</p>
</td>
</tr>
<tr id="row8675191894"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p12677191913"><a name="p12677191913"></a><a name="p12677191913"></a>deviceMatchAttr</p>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p1567171918915"><a name="p1567171918915"></a><a name="p1567171918915"></a>没有使用,可忽略</p>
</td>
</tr>
</tbody>
</table>
从第二个节点开始配置具体I2C控制器信息,此节点并不表示某一路I2C控制器,而是代表一个资源性质设备,用于描述一类I2C控制器的信息。多个控制器之间相互区分的参数是busID和reg\_pbase,这在i2c\_config文件中有所体现。
- device\_info.hcs 配置参考。
``` ```
root { root {
...@@ -181,7 +131,8 @@ I2C模块适配的三个环节是配置属性文件,实例化驱动入口, ...@@ -181,7 +131,8 @@ I2C模块适配的三个环节是配置属性文件,实例化驱动入口,
} }
``` ```
- i2c\_config.hcs 配置参考。 - i2c_config.hcs 配置参考。
``` ```
root { root {
...@@ -212,7 +163,8 @@ I2C模块适配的三个环节是配置属性文件,实例化驱动入口, ...@@ -212,7 +163,8 @@ I2C模块适配的三个环节是配置属性文件,实例化驱动入口,
3. 完成驱动入口注册之后,最后一步就是以核心层I2cCntlr对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化I2cCntlr成员I2cMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。 3. 完成驱动入口注册之后,最后一步就是以核心层I2cCntlr对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化I2cCntlr成员I2cMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。
- 自定义结构体参考 - 自定义结构体参考
从驱动的角度看,自定义结构体是参数和数据的载体,而且i2c\_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,其中一些重要数值也会传递给核心层I2cCntlr对象,例如设备号、总线号等。 从驱动的角度看,自定义结构体是参数和数据的载体,而且i2c_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,其中一些重要数值也会传递给核心层I2cCntlr对象,例如设备号、总线号等。
``` ```
// 厂商自定义功能结构体 // 厂商自定义功能结构体
...@@ -238,9 +190,9 @@ I2C模块适配的三个环节是配置属性文件,实例化驱动入口, ...@@ -238,9 +190,9 @@ I2C模块适配的三个环节是配置属性文件,实例化驱动入口,
const struct I2cLockMethod *lockOps; const struct I2cLockMethod *lockOps;
}; };
``` ```
- I2cCntlr成员回调函数结构体I2cMethod的实例化,和锁机制回调函数结构体I2cLockMethod实例化,其他成员在Init函数中初始化。 - I2cCntlr成员回调函数结构体I2cMethod的实例化,和锁机制回调函数结构体I2cLockMethod实例化,其他成员在Init函数中初始化。
``` ```
// i2c_hi35xx.c 中的示例 // i2c_hi35xx.c 中的示例
static const struct I2cMethod g_method = { static const struct I2cMethod g_method = {
...@@ -252,8 +204,7 @@ I2C模块适配的三个环节是配置属性文件,实例化驱动入口, ...@@ -252,8 +204,7 @@ I2C模块适配的三个环节是配置属性文件,实例化驱动入口,
.unlock = Hi35xxI2cUnlock,//解锁函数 .unlock = Hi35xxI2cUnlock,//解锁函数
}; };
``` ```
- Init函数参考
- init函数参考
入参: 入参:
...@@ -261,54 +212,24 @@ I2C模块适配的三个环节是配置属性文件,实例化驱动入口, ...@@ -261,54 +212,24 @@ I2C模块适配的三个环节是配置属性文件,实例化驱动入口,
返回值: 返回值:
HDF\_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf\_base.h中HDF\_STATUS 定义)。 HDF_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf_base.h中HDF_STATUS 定义)。
**表 3** init函数入参及返回值参考 **表3** Init函数入参及返回值参考
<a name="table1743073181511"></a> | 状态(值) | 问题描述 |
<table><thead align="left"><tr id="row443033171513"><th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.1"><p id="p34306341517"><a name="p34306341517"></a><a name="p34306341517"></a>状态(值)</p> | -------- | -------- |
</th> | HDF_ERR_INVALID_OBJECT | 控制器对象非法 |
<th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.2"><p id="p1243123101510"><a name="p1243123101510"></a><a name="p1243123101510"></a>问题描述</p> | HDF_ERR_INVALID_PARAM | 参数非法 |
</th> | HDF_ERR_MALLOC_FAIL | 内存分配失败 |
</tr> | HDF_ERR_IO | I/O&nbsp;错误 |
</thead> | HDF_SUCCESS | 传输成功 |
<tbody><tr id="row5431638151"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p1043114319156"><a name="p1043114319156"></a><a name="p1043114319156"></a>HDF_ERR_INVALID_OBJECT</p> | HDF_FAILURE | 传输失败 |
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p343173101513"><a name="p343173101513"></a><a name="p343173101513"></a>控制器对象非法</p>
</td>
</tr>
<tr id="row1243143181516"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p1443118317154"><a name="p1443118317154"></a><a name="p1443118317154"></a>HDF_ERR_INVALID_PARAM</p>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p343113341515"><a name="p343113341515"></a><a name="p343113341515"></a>参数非法</p>
</td>
</tr>
<tr id="row1943115391516"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p1843143171511"><a name="p1843143171511"></a><a name="p1843143171511"></a>HDF_ERR_MALLOC_FAIL</p>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p943114391515"><a name="p943114391515"></a><a name="p943114391515"></a>内存分配失败</p>
</td>
</tr>
<tr id="row1443183101514"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p54311031157"><a name="p54311031157"></a><a name="p54311031157"></a>HDF_ERR_IO</p>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p74315311158"><a name="p74315311158"></a><a name="p74315311158"></a>I/O 错误</p>
</td>
</tr>
<tr id="row3431437158"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p8432332158"><a name="p8432332158"></a><a name="p8432332158"></a>HDF_SUCCESS</p>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p104329391519"><a name="p104329391519"></a><a name="p104329391519"></a>传输成功</p>
</td>
</tr>
<tr id="row34321136152"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p184325391517"><a name="p184325391517"></a><a name="p184325391517"></a>HDF_FAILURE</p>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p1343220319154"><a name="p1343220319154"></a><a name="p1343220319154"></a>传输失败</p>
</td>
</tr>
</tbody>
</table>
函数说明: 函数说明:
初始化自定义结构体对象,初始化I2cCntlr成员,调用核心层I2cCntlrAdd函数,【可选】接入VFS。 初始化自定义结构体对象,初始化I2cCntlr成员,调用核心层I2cCntlrAdd函数,【可选】接入VFS。
``` ```
static int32_t Hi35xxI2cInit(struct HdfDeviceObject *device) static int32_t Hi35xxI2cInit(struct HdfDeviceObject *device)
{ {
...@@ -354,7 +275,6 @@ I2C模块适配的三个环节是配置属性文件,实例化驱动入口, ...@@ -354,7 +275,6 @@ I2C模块适配的三个环节是配置属性文件,实例化驱动入口,
return ret; return ret;
} }
``` ```
- Release 函数参考 - Release 函数参考
入参: 入参:
...@@ -369,6 +289,7 @@ I2C模块适配的三个环节是配置属性文件,实例化驱动入口, ...@@ -369,6 +289,7 @@ I2C模块适配的三个环节是配置属性文件,实例化驱动入口,
释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源。 释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源。
``` ```
static void Hi35xxI2cRelease(struct HdfDeviceObject *device) static void Hi35xxI2cRelease(struct HdfDeviceObject *device)
{ {
...@@ -396,6 +317,3 @@ I2C模块适配的三个环节是配置属性文件,实例化驱动入口, ...@@ -396,6 +317,3 @@ I2C模块适配的三个环节是配置属性文件,实例化驱动入口,
return; return;
} }
``` ```
# MIPI-CSI<a name="title_MIPI_CSIDes"></a> # MIPI CSI<a name="title_MIPI_CSIDes"></a>
- [概述](#section1_MIPI_CSIDes)
- [ComboDevAttr结构体](#section1.1_MIPI_CSIDes)
- [ExtDataType结构体](#section1.2_MIPI_CSIDes)
- [接口说明](#section1.3_MIPI_CSIDes)
- [使用指导](#section2_MIPI_CSIDes)
- [使用流程](#section2.1_MIPI_CSIDes)
- [获取MIPI-CSI控制器操作句柄](#section2.2_MIPI_CSIDes)
- [MIPI-CSI相应配置](#section2.3_MIPI_CSIDes)
- [复位/撤销复位sensor](#section2.4_MIPI_CSIDes)
- [复位/撤销复位MIPI RX](#section2.5_MIPI_CSIDes)
- [使能/关闭MIPI的时钟](#section2.6_MIPI_CSIDes)
- [使能/关闭MIPI上的sensor时钟](#section2.7_MIPI_CSIDes)
- [释放MIPI-CSI控制器操作句柄](#section2.8_MIPI_CSIDes)
- [使用实例](#section3_MIPI_CSIDes)
## 概述<a name="section1_MIPI_CSIDes"></a> ## 概述<a name="section1_MIPI_CSIDes"></a>
...@@ -57,14 +42,14 @@ ...@@ -57,14 +42,14 @@
### 接口说明<a name="section1.3_MIPI_CSIDes"></a> ### 接口说明<a name="section1.3_MIPI_CSIDes"></a>
**表 3** MIPI-CSI API接口功能介绍 **表 3** MIPI CSI API接口功能介绍
<a name="table3_MIPI_CSIDes"></a> <a name="table3_MIPI_CSIDes"></a>
| 功能分类 | 接口名 | | 功能分类 | 接口名 |
| -------- | -------- | | -------- | -------- |
| 获取/释放MIPI-CSI控制器操作句柄 | MipiCsiOpen:获取MIPI-CSI控制器操作句柄<br/>MipiCsiClose:释放MIPI-CSI控制器操作句柄 | | 获取/释放MIPI CSI控制器操作句柄 | MipiCsiOpen:获取MIPI CSI控制器操作句柄<br/>MipiCsiClose:释放MIPI CSI控制器操作句柄 |
| MIPI-CSI相应配置 | MipiCsiSetComboDevAttr:设置MIPI,CMOS或者LVDS相机的参数给控制器,参数包括工作模式,图像区域,图像深度,数据速率和物理通道等<br/>MipiCsiSetExtDataType(可选):设置YUV和RAW数据格式和位深<br/>MipiCsiSetHsMode:设置MIPI&nbsp;RX的Lane分布。根据硬件连接的形式选择具体的mode<br/>MipiCsiSetPhyCmvmode:设置共模电压模式 | | MIPI CSI相应配置 | MipiCsiSetComboDevAttr:设置MIPI,CMOS或者LVDS相机的参数给控制器,参数包括工作模式,图像区域,图像深度,数据速率和物理通道等<br/>MipiCsiSetExtDataType(可选):设置YUV和RAW数据格式和位深<br/>MipiCsiSetHsMode:设置MIPI&nbsp;RX的Lane分布。根据硬件连接的形式选择具体的mode<br/>MipiCsiSetPhyCmvmode:设置共模电压模式 |
| 复位/撤销复位Sensor | MipiCsiResetSensor:复位Sensor<br/>MipiCsiUnresetSensor:撤销复位Sensor | | 复位/撤销复位Sensor | MipiCsiResetSensor:复位Sensor<br/>MipiCsiUnresetSensor:撤销复位Sensor |
| 复位/撤销复位MIPI&nbsp;RX | MipiCsiResetRx:复位MIPI&nbsp;RX。不同的s32WorkingViNum有不同的enSnsType<br/>MipiCsiUnresetRx:撤销复位MIPI&nbsp;RX | | 复位/撤销复位MIPI&nbsp;RX | MipiCsiResetRx:复位MIPI&nbsp;RX。不同的s32WorkingViNum有不同的enSnsType<br/>MipiCsiUnresetRx:撤销复位MIPI&nbsp;RX |
| 使能/关闭MIPI的时钟 | MipiCsiEnableClock:使能MIPI的时钟。根据上层函数电泳传递的enSnsType参数决定是用MIPI还是LVDS<br/>MipiCsiDisableClock:关闭MIPI设备的时钟 | | 使能/关闭MIPI的时钟 | MipiCsiEnableClock:使能MIPI的时钟。根据上层函数电泳传递的enSnsType参数决定是用MIPI还是LVDS<br/>MipiCsiDisableClock:关闭MIPI设备的时钟 |
...@@ -75,16 +60,16 @@ ...@@ -75,16 +60,16 @@
### 使用流程<a name="section2.1_MIPI_CSIDes"></a> ### 使用流程<a name="section2.1_MIPI_CSIDes"></a>
使用MIPI-CSI的一般流程如[图2](#fig2_MIPI_CSIDes)所示。 使用MIPI CSI的一般流程如图2所示。
**图 2** MIPI-CSI使用流程图<a name="fig2_MIPI_CSIDes"></a> **图 2** MIPI CSI使用流程图<a name="fig2_MIPI_CSIDes"></a>
![](figures/MIPI-CSI使用流程图.png) ![](figures/MIPI-CSI使用流程图.png)
### 获取MIPI-CSI控制器操作句柄<a name="section2.2_MIPI_CSIDes"></a> ### 获取MIPI CSI控制器操作句柄<a name="section2.2_MIPI_CSIDes"></a>
在进行MIPI-CSI进行通信前,首先要调用MipiCsiOpen获取控制器操作句柄,该函数会返回指定通道ID的控制器操作句柄。 在进行MIPI CSI进行通信前,首先要调用MipiCsiOpen获取控制器操作句柄,该函数会返回指定通道ID的控制器操作句柄。
```c ```c
DevHandle MipiCsiOpen(uint8_t id); DevHandle MipiCsiOpen(uint8_t id);
...@@ -101,11 +86,11 @@ DevHandle MipiCsiOpen(uint8_t id); ...@@ -101,11 +86,11 @@ DevHandle MipiCsiOpen(uint8_t id);
| NULL | 获取失败 | | NULL | 获取失败 |
| 设备句柄 | 获取到指令通道的控制器操作句柄,类型为DevHandle | | 设备句柄 | 获取到指令通道的控制器操作句柄,类型为DevHandle |
假设系统中的MIPI-CSI通道为0,获取该通道控制器操作句柄的示例如下: 假设系统中的MIPI CSI通道为0,获取该通道控制器操作句柄的示例如下:
```c ```c
DevHandle MipiCsiHandle = NULL; /* 设备句柄 */ DevHandle MipiCsiHandle = NULL; /* 设备句柄 */
id = 0; /* MiPi-Csi通道ID */ id = 0; /* MIPI CSI通道ID */
/* 获取控制器操作句柄 */ /* 获取控制器操作句柄 */
MipiCsiHandle = MipiCsiOpen(id); MipiCsiHandle = MipiCsiOpen(id);
...@@ -115,9 +100,9 @@ if (MipiCsiHandle == NULL) { ...@@ -115,9 +100,9 @@ if (MipiCsiHandle == NULL) {
} }
``` ```
### MIPI-CSI相应配置<a name="section2.3_MIPI_CSIDes"></a> ### MIPI CSI相应配置<a name="section2.3_MIPI_CSIDes"></a>
- 写入MIPI-CSI配置 - 写入MIPI CSI配置
```c ```c
int32_t MipiCsiSetComboDevAttr(DevHandle handle, ComboDevAttr *pAttr); int32_t MipiCsiSetComboDevAttr(DevHandle handle, ComboDevAttr *pAttr);
...@@ -130,7 +115,7 @@ if (MipiCsiHandle == NULL) { ...@@ -130,7 +115,7 @@ if (MipiCsiHandle == NULL) {
| 参数 | 参数描述 | | 参数 | 参数描述 |
| ---------- | -------------------------- | | ---------- | -------------------------- |
| handle | 控制器操作句柄 | | handle | 控制器操作句柄 |
| pAttr | MIPI-CSI相应配置结构体指针 | | pAttr | MIPI CSI相应配置结构体指针 |
| **返回值** | **返回值描述** | | **返回值** | **返回值描述** |
| 0 | 设置成功 | | 0 | 设置成功 |
| 负数 | 设置失败 | | 负数 | 设置失败 |
...@@ -528,9 +513,9 @@ if (MipiCsiHandle == NULL) { ...@@ -528,9 +513,9 @@ if (MipiCsiHandle == NULL) {
} }
``` ```
### 释放MIPI-CSI控制器操作句柄<a name="section2.8_MIPI_CSIDes"></a> ### 释放MIPI CSI控制器操作句柄<a name="section2.8_MIPI_CSIDes"></a>
MIPI-CSI使用完成之后,需要释放控制器操作句柄,释放句柄的函数如下所示: MIPI CSI使用完成之后,需要释放控制器操作句柄,释放句柄的函数如下所示:
```c ```c
void MipiCsiClose(DevHandle handle); void MipiCsiClose(DevHandle handle);
...@@ -544,15 +529,15 @@ void MipiCsiClose(DevHandle handle); ...@@ -544,15 +529,15 @@ void MipiCsiClose(DevHandle handle);
| 参数 | 参数描述 | | 参数 | 参数描述 |
| ------------ | ------------------------------------------------ | | ------------ | ------------------------------------------------ |
| handle | MIPI-CSI控制器操作句柄 | | handle | MIPI CSI控制器操作句柄 |
```c ```c
MipiCsiClose(MIPIHandle); /* 释放掉MIPI-CSI控制器操作句柄 */ MipiCsiClose(MIPIHandle); /* 释放掉MIPI CSI控制器操作句柄 */
``` ```
## 使用实例<a name="section3_MIPI_CSIDes"></a> ## 使用实例<a name="section3_MIPI_CSIDes"></a>
MIPI-CSI完整的使用示例如下所示: MIPI CSI完整的使用示例如下所示:
```c ```c
#include "hdf.h" #include "hdf.h"
......
# MIPI-CSI<a name="title_MIPI_CSIDevelop"></a> # MIPI CSI
- [概述](#section1_MIPI_CSIDevelop)
- [接口说明](#section2_MIPI_CSIDevelop)
- [开发步骤](#section3_MIPI_CSIDevelop)
- [开发实例](#section4_MIPI_CSIDevelop)
## 概述 <a name="section1_MIPI_CSIDevelop"></a> ## 概述 <a name="section1_MIPI_CSIDevelop"></a>
CSI(Camera Serial Interface)是由MIPI(Mobile Industry Processor Interface )联盟下Camera工作组指定的接口标准。在HDF框架中,MIPI-CSI的接口适配模式采用无服务模式,用于不需要在用户态提供API的设备类型,或者没有用户态和内核区分的OS系统,MIPI-CSI的接口关联方式是DevHandle直接指向设备对象内核态地址(DevHandle是一个void类型指针)。 CSI(Camera Serial Interface)是由MIPI(Mobile Industry Processor Interface )联盟下Camera工作组指定的接口标准。在HDF框架中,MIPI CSI的接口适配模式采用无服务模式,用于不需要在用户态提供API的设备类型,或者没有用户态和内核区分的OS系统,MIPI CSI的接口关联方式是DevHandle直接指向设备对象内核态地址(DevHandle是一个void类型指针)。
图 1 无服务模式结构图 图 1 无服务模式结构图
![image1](figures/无服务模式结构图.png) ![image1](figures/无服务模式结构图.png)
## 接口说明 <a name="section2_MIPI_CSIDevelop"></a> ## 接口说明 <a name="section2_MIPI_CSIDevelop"></a>
...@@ -35,7 +31,7 @@ struct MipiCsiCntlrMethod { ...@@ -35,7 +31,7 @@ struct MipiCsiCntlrMethod {
表1 MipiCsiCntlrMethod成员的回调函数功能说明 表1 MipiCsiCntlrMethod成员的回调函数功能说明
| 成员函数 | 入参 | 出参 | 返回状态 | 功能 | | 成员函数 | 入参 | 出参 | 返回状态 | 功能 |
| ------------------ | ------------------------------------------------------------ | ---- | ------------------ | -------------------------- | | ------------------ | ------------------------------------------------------------ | ---- | ------------------ | -------------------------- |
| setComboDevAttr | **cntlr**:结构体指针,MipiCsi控制器 ;<br>**pAttr**:结构体指针,MIPI-CSI相应配置结构体指针 | 无 | HDF_STATUS相关状态 | 写入MIPI-CSI配置 | | setComboDevAttr | **cntlr**:结构体指针,MipiCsi控制器 ;<br>**pAttr**:结构体指针,MIPI CSI相应配置结构体指针 | 无 | HDF_STATUS相关状态 | 写入MIPI CSI配置 |
| setPhyCmvmode | **cntlr**:结构体指针,MipiCsi控制器 ;<br>**devno**:uint8_t,设备编号;<br>**cmvMode**:枚举类型,共模电压模式参数 | 无 | HDF_STATUS相关状态 | 设置共模电压模式 | | setPhyCmvmode | **cntlr**:结构体指针,MipiCsi控制器 ;<br>**devno**:uint8_t,设备编号;<br>**cmvMode**:枚举类型,共模电压模式参数 | 无 | HDF_STATUS相关状态 | 设置共模电压模式 |
| setExtDataType | **cntlr**:结构体指针,MipiCsi控制器 ;<br>**dataType**:结构体指针,定义YUV和原始数据格式以及位深度 | 无 | HDF_STATUS相关状态 | 设置YUV和RAW数据格式和位深 | | setExtDataType | **cntlr**:结构体指针,MipiCsi控制器 ;<br>**dataType**:结构体指针,定义YUV和原始数据格式以及位深度 | 无 | HDF_STATUS相关状态 | 设置YUV和RAW数据格式和位深 |
| setHsMode | **cntlr**:结构体指针,MipiCsi控制器 ;<br>**laneDivideMode**:枚举类型,lane模式参数 | 无 | HDF_STATUS相关状态 | 设置MIPI RX的Lane分布 | | setHsMode | **cntlr**:结构体指针,MipiCsi控制器 ;<br>**laneDivideMode**:枚举类型,lane模式参数 | 无 | HDF_STATUS相关状态 | 设置MIPI RX的Lane分布 |
...@@ -50,7 +46,7 @@ struct MipiCsiCntlrMethod { ...@@ -50,7 +46,7 @@ struct MipiCsiCntlrMethod {
## 开发步骤 <a name="section3_MIPI_CSIDevelop"></a> ## 开发步骤 <a name="section3_MIPI_CSIDevelop"></a>
MIPI-CSI模块适配的三个环节是配置属性文件、实例化驱动入、以及实例化核心层接口函数。 MIPI CSI模块适配的三个环节是配置属性文件、实例化驱动入、以及实例化核心层接口函数。
1. **实例化驱动入口:** 1. **实例化驱动入口:**
- 实例化HdfDriverEntry结构体成员。 - 实例化HdfDriverEntry结构体成员。
...@@ -107,7 +103,7 @@ MIPI-CSI模块适配的三个环节是配置属性文件、实例化驱动入、 ...@@ -107,7 +103,7 @@ MIPI-CSI模块适配的三个环节是配置属性文件、实例化驱动入、
一般在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 一般在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
- MIPI-CSI驱动入口参考 - MIPI CSI驱动入口参考
```c ```c
struct HdfDriverEntry g_mipiCsiDriverEntry = { struct HdfDriverEntry g_mipiCsiDriverEntry = {
...@@ -123,7 +119,7 @@ MIPI-CSI模块适配的三个环节是配置属性文件、实例化驱动入、 ...@@ -123,7 +119,7 @@ MIPI-CSI模块适配的三个环节是配置属性文件、实例化驱动入、
- 自定义结构体参考 - 自定义结构体参考
> 从驱动的角度看,自定义结构体是参数和数据的载体,一般来说,config文件中的数值也会用来初始化结构体成员,本例的mipicsi器件属性在源文件中,故基本成员结构与MipiCsiCntlr无太大差异。 从驱动的角度看,自定义结构体是参数和数据的载体,一般来说,config文件中的数值也会用来初始化结构体成员,本例的mipicsi器件属性在源文件中,故基本成员结构与MipiCsiCntlr无太大差异。
```c ```c
typedef struct { typedef struct {
...@@ -199,23 +195,25 @@ MIPI-CSI模块适配的三个环节是配置属性文件、实例化驱动入、 ...@@ -199,23 +195,25 @@ MIPI-CSI模块适配的三个环节是配置属性文件、实例化驱动入、
- **Init函数参考** - **Init函数参考**
> **入参:** **入参:**
> HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息 HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息
>
> **返回值:** **返回值:**
> HDF_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf_base.h中HDF_STATUS 定义) HDF_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf_base.h中HDF_STATUS 定义)
>
> | 状态(值) | 问题描述 |
> | :--------------------- | :----------: | | 状态(值) | 问题描述 |
> | HDF_ERR_INVALID_OBJECT | 无效对象 | | :--------------------- | :----------: |
> | HDF_ERR_MALLOC_FAIL | 内存分配失败 | | HDF_ERR_INVALID_OBJECT | 无效对象 |
> | HDF_ERR_INVALID_PARAM | 无效参数 | | HDF_ERR_MALLOC_FAIL | 内存分配失败 |
> | HDF_ERR_IO | I/O 错误 | | HDF_ERR_INVALID_PARAM | 无效参数 |
> | HDF_SUCCESS | 执行成功 | | HDF_ERR_IO | I/O 错误 |
> | HDF_FAILURE | 执行失败 | | HDF_SUCCESS | 执行成功 |
> | HDF_FAILURE | 执行失败 |
> **函数说明:**
> MipiCsiCntlrMethod的实例化对象的挂载,调用MipiCsiRegisterCntlr,以及其他厂商自定义初始化操作。 **函数说明:**
MipiCsiCntlrMethod的实例化对象的挂载,调用MipiCsiRegisterCntlr,以及其他厂商自定义初始化操作。
```c ```c
static int32_t Hi35xxMipiCsiInit(struct HdfDeviceObject *device) static int32_t Hi35xxMipiCsiInit(struct HdfDeviceObject *device)
...@@ -282,14 +280,14 @@ MIPI-CSI模块适配的三个环节是配置属性文件、实例化驱动入、 ...@@ -282,14 +280,14 @@ MIPI-CSI模块适配的三个环节是配置属性文件、实例化驱动入、
- **Release函数参考** - **Release函数参考**
> **入参:** **入参:**
> HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。
>
> **返回值:** **返回值:**
>
>
> **函数说明:** **函数说明:**
> 该函数需要在驱动入口结构体中赋值给Release接口,当HDF框架调用Init函数初始化驱动失败时,可以调用Release释放驱动资源,该函数中需包含释放内存和删除控制器等操作。所有强制转换获取相应对象的操作**前提**是在Init函数中具备对应赋值的操作。 该函数需要在驱动入口结构体中赋值给Release接口,当HDF框架调用Init函数初始化驱动失败时,可以调用Release释放驱动资源,该函数中需包含释放内存和删除控制器等操作。所有强制转换获取相应对象的操作**前提**是在Init函数中具备对应赋值的操作。
```c ```c
static void Hi35xxMipiCsiRelease(struct HdfDeviceObject *device) static void Hi35xxMipiCsiRelease(struct HdfDeviceObject *device)
......
# MIPI-DSI<a name="ZH-CN_TOPIC_0000001222082237"></a> # MIPI DSI
- [概述](#section1266787503161538)
- [接口说明](#section752964871810)
- [开发步骤](#section545182932161538)
- [开发实例](#section1167576616161538)
## 概述<a name="section1266787503161538"></a> ## 概述
DSI(Display Serial Interface)是由移动行业处理器接口联盟(Mobile Industry Processor Interface \(MIPI\) Alliance)制定的规范。在HDF框架中,MIPI-DSI的接口适配模式采用无服务模式,用于不需要在用户态提供API的设备类型,或者没有用户态和内核区分的OS系统,其关联方式是DevHandle直接指向设备对象内核态地址(DevHandle是一个void类型指针)。 DSI(Display Serial Interface)是由移动行业处理器接口联盟(Mobile Industry Processor Interface (MIPI) Alliance)制定的规范。在HDF框架中,MIPI DSI的接口适配模式采用无服务模式,用于不需要在用户态提供API的设备类型,或者没有用户态和内核区分的OS系统,其关联方式是DevHandle直接指向设备对象内核态地址(DevHandle是一个void类型指针)。
**图 1** DSI无服务模式结构图<a name="fig207610236189"></a> **图1** DSI无服务模式结构图
![](figures/无服务模式结构图.png "DSI无服务模式结构图")
## 接口说明<a name="section752964871810"></a> ![zh-cn_image_0000001176603960](figures/zh-cn_image_0000001176603960.png)
## 接口说明
MipiDsiCntlrMethod定义: MipiDsiCntlrMethod定义:
``` ```
struct MipiDsiCntlrMethod { // 核心层结构体的成员函数 struct MipiDsiCntlrMethod { // 核心层结构体的成员函数
int32_t (*setCntlrCfg)(struct MipiDsiCntlr *cntlr); int32_t (*setCntlrCfg)(struct MipiDsiCntlr *cntlr);
...@@ -30,113 +29,48 @@ struct MipiDsiCntlrMethod { // 核心层结构体的成员函数 ...@@ -30,113 +29,48 @@ struct MipiDsiCntlrMethod { // 核心层结构体的成员函数
}; };
``` ```
**表 1** MipiDsiCntlrMethod成员的回调函数功能说明 **表1** MipiDsiCntlrMethod成员的回调函数功能说明
<a name="table49321701800"></a> | 成员函数 | 入参 | 出参 | 返回状态 | 功能 |
<table><thead align="left"><tr id="row129321407019"><th class="cellrowborder" valign="top" width="20%" id="mcps1.2.6.1.1"><p id="p1793219014017"><a name="p1793219014017"></a><a name="p1793219014017"></a>成员函数</p> | -------- | -------- | -------- | -------- | -------- |
</th> | setCntlrCfg | cntlr:结构体指针,MipiDsi控制器&nbsp; | 无 | HDF_STATUS相关状态 | 设置控制器参数 |
<th class="cellrowborder" valign="top" width="20%" id="mcps1.2.6.1.2"><p id="p11932130705"><a name="p11932130705"></a><a name="p11932130705"></a>入参</p> | setCmd | cntlr:结构体指针,MipiDsi控制器;<br>cmd:结构体指针,指令传入值; | 无 | HDF_STATUS相关状态 | 向显示设备发送指令 |
</th> | getCmd | cntlr:结构体指针,MipiDsi控制器;<br>cmd:传入的命令描述结构体指针;<br>readLen:读取的数据大小; | out:结构体指针,用于存储读取的数据。 | HDF_STATUS相关状态 | 通过发送指令读取数据 |
<th class="cellrowborder" valign="top" width="20%" id="mcps1.2.6.1.3"><p id="p1493216019019"><a name="p1493216019019"></a><a name="p1493216019019"></a>出参</p> | toHs | cntlr:&nbsp;结构体指针,MipiDsi控制器&nbsp;; | 无 | HDF_STATUS相关状态 | 设置为高速模式 |
</th> | toLp | cntlr:&nbsp;结构体指针,MipiDsi控制器&nbsp;; | 无 | HDF_STATUS相关状态 | 设置为低电模式 |
<th class="cellrowborder" valign="top" width="20%" id="mcps1.2.6.1.4"><p id="p12932400019"><a name="p12932400019"></a><a name="p12932400019"></a>返回状态</p>
</th>
<th class="cellrowborder" valign="top" width="20%" id="mcps1.2.6.1.5"><p id="p89322010019"><a name="p89322010019"></a><a name="p89322010019"></a>功能</p> ## 开发步骤
</th>
</tr> MIPI DSI模块适配的三个环节是配置属性文件,实例化驱动入口,以及实例化核心层接口函数。
</thead>
<tbody><tr id="row093219016016"><td class="cellrowborder" valign="top" width="20%" headers="mcps1.2.6.1.1 "><p id="p9932209019"><a name="p9932209019"></a><a name="p9932209019"></a>setCntlrCfg</p>
</td>
<td class="cellrowborder" valign="top" width="20%" headers="mcps1.2.6.1.2 "><p id="p199321001705"><a name="p199321001705"></a><a name="p199321001705"></a>cntlr: 结构体指针,MipiDsi控制器 ;</p>
</td>
<td class="cellrowborder" valign="top" width="20%" headers="mcps1.2.6.1.3 "><p id="p093210106"><a name="p093210106"></a><a name="p093210106"></a></p>
</td>
<td class="cellrowborder" valign="top" width="20%" headers="mcps1.2.6.1.4 "><p id="p16932701709"><a name="p16932701709"></a><a name="p16932701709"></a>HDF_STATUS相关状态</p>
</td>
<td class="cellrowborder" valign="top" width="20%" headers="mcps1.2.6.1.5 "><p id="p3932130702"><a name="p3932130702"></a><a name="p3932130702"></a>设置控制器参数</p>
</td>
</tr>
<tr id="row593211015010"><td class="cellrowborder" valign="top" width="20%" headers="mcps1.2.6.1.1 "><p id="p169331101014"><a name="p169331101014"></a><a name="p169331101014"></a>setCmd</p>
</td>
<td class="cellrowborder" valign="top" width="20%" headers="mcps1.2.6.1.2 "><p id="p189338015011"><a name="p189338015011"></a><a name="p189338015011"></a>cntlr: 结构体指针,MipiDsi控制器 ;cmd: 结构体指针,指令传入值</p>
</td>
<td class="cellrowborder" valign="top" width="20%" headers="mcps1.2.6.1.3 "><p id="p493300204"><a name="p493300204"></a><a name="p493300204"></a></p>
</td>
<td class="cellrowborder" valign="top" width="20%" headers="mcps1.2.6.1.4 "><p id="p49332011019"><a name="p49332011019"></a><a name="p49332011019"></a>HDF_STATUS相关状态</p>
</td>
<td class="cellrowborder" valign="top" width="20%" headers="mcps1.2.6.1.5 "><p id="p17933801808"><a name="p17933801808"></a><a name="p17933801808"></a>向显示设备发送指令</p>
</td>
</tr>
<tr id="row793312013010"><td class="cellrowborder" valign="top" width="20%" headers="mcps1.2.6.1.1 "><p id="p13933120708"><a name="p13933120708"></a><a name="p13933120708"></a>getCmd</p>
</td>
<td class="cellrowborder" valign="top" width="20%" headers="mcps1.2.6.1.2 "><p id="p199331906010"><a name="p199331906010"></a><a name="p199331906010"></a>cntlr: 结构体指针,MipiDsi控制器 ;</p>
</td>
<td class="cellrowborder" valign="top" width="20%" headers="mcps1.2.6.1.3 "><p id="p139331001602"><a name="p139331001602"></a><a name="p139331001602"></a>cmd: 结构体指针,用于传出指令值;</p>
</td>
<td class="cellrowborder" valign="top" width="20%" headers="mcps1.2.6.1.4 "><p id="p993390900"><a name="p993390900"></a><a name="p993390900"></a>HDF_STATUS相关状态</p>
</td>
<td class="cellrowborder" valign="top" width="20%" headers="mcps1.2.6.1.5 "><p id="p1933901007"><a name="p1933901007"></a><a name="p1933901007"></a>从显示设备读取信息指令</p>
</td>
</tr>
<tr id="row10933004013"><td class="cellrowborder" valign="top" width="20%" headers="mcps1.2.6.1.1 "><p id="p493311019014"><a name="p493311019014"></a><a name="p493311019014"></a>toHs</p>
</td>
<td class="cellrowborder" valign="top" width="20%" headers="mcps1.2.6.1.2 "><p id="p189330016013"><a name="p189330016013"></a><a name="p189330016013"></a>cntlr: 结构体指针,MipiDsi控制器 ;</p>
</td>
<td class="cellrowborder" valign="top" width="20%" headers="mcps1.2.6.1.3 "><p id="p149338013010"><a name="p149338013010"></a><a name="p149338013010"></a></p>
</td>
<td class="cellrowborder" valign="top" width="20%" headers="mcps1.2.6.1.4 "><p id="p2933309015"><a name="p2933309015"></a><a name="p2933309015"></a>HDF_STATUS相关状态</p>
</td>
<td class="cellrowborder" valign="top" width="20%" headers="mcps1.2.6.1.5 "><p id="p8933709019"><a name="p8933709019"></a><a name="p8933709019"></a>设置为高速模式</p>
</td>
</tr>
<tr id="row99331502001"><td class="cellrowborder" valign="top" width="20%" headers="mcps1.2.6.1.1 "><p id="p993311018016"><a name="p993311018016"></a><a name="p993311018016"></a>toLp</p>
</td>
<td class="cellrowborder" valign="top" width="20%" headers="mcps1.2.6.1.2 "><p id="p79337011013"><a name="p79337011013"></a><a name="p79337011013"></a>cntlr: 结构体指针,MipiDsi控制器 ;</p>
</td>
<td class="cellrowborder" valign="top" width="20%" headers="mcps1.2.6.1.3 "><p id="p169331301201"><a name="p169331301201"></a><a name="p169331301201"></a></p>
</td>
<td class="cellrowborder" valign="top" width="20%" headers="mcps1.2.6.1.4 "><p id="p39331407020"><a name="p39331407020"></a><a name="p39331407020"></a>HDF_STATUS相关状态</p>
</td>
<td class="cellrowborder" valign="top" width="20%" headers="mcps1.2.6.1.5 "><p id="p19933190507"><a name="p19933190507"></a><a name="p19933190507"></a>设置为低电模式</p>
</td>
</tr>
</tbody>
</table>
## 开发步骤<a name="section545182932161538"></a>
MIPI-DSI模块适配的三个环节是配置属性文件,实例化驱动入口,以及实例化核心层接口函数。
1. **实例化驱动入口:** 1. **实例化驱动入口:**
- 实例化HdfDriverEntry结构体成员。 - 实例化HdfDriverEntry结构体成员。
- 调用HDF\_INIT将HdfDriverEntry实例化对象注册到HDF框架中。 - 调用HDF_INIT将HdfDriverEntry实例化对象注册到HDF框架中。
2. **配置属性文件:** 2. **配置属性文件:**
- 在device\_info.hcs文件中添加deviceNode描述。 - 在device_info.hcs文件中添加deviceNode描述。
- 【可选】添加mipidsi\_config.hcs器件属性文件。 - 【可选】添加mipidsi_config.hcs器件属性文件。
3. **实例化MIPIDSI控制器对象:** 3. **实例化MIPIDSI控制器对象:**
- 初始化MipiDsiCntlr成员。 - 初始化MipiDsiCntlr成员。
- 实例化MipiDsiCntlr成员MipiDsiCntlrMethod。 - 实例化MipiDsiCntlr成员MipiDsiCntlrMethod。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
>![](../public_sys-resources/icon-note.gif) **说明:** > 实例化MipiDsiCntlr成员MipiDsiCntlrMethod,其定义和成员说明见[接口说明](#接口说明)。
>实例化MipiDsiCntlr成员MipiDsiCntlrMethod,其定义和成员说明见[接口说明](#section752964871810)。
4. **驱动调试:** 4. **驱动调试:**
【可选】针对新增驱动程序,建议验证驱动基本功能,例如挂载后的信息反馈,数据传输的成功与否等。 【可选】针对新增驱动程序,建议验证驱动基本功能,例如挂载后的信息反馈,数据传输的成功与否等。
## 开发实例<a name="section1167576616161538"></a> ## 开发实例
下方将以mipi\_tx\_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。 下方将以mipi_tx_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。
1. 一般来说,驱动开发首先需要在 xx\_config.hcs 中配置器件属性,并在device\_info.hcs文件中添加deviceNode描述。器件属性值与核心层MipiDsiCntlr 成员的默认值或限制范围有密切关系,deviceNode信息与驱动入口注册相关。 1. 一般来说,驱动开发首先需要在 xx_config.hcs 中配置器件属性,并在device_info.hcs文件中添加deviceNode描述。器件属性值与核心层MipiDsiCntlr 成员的默认值或限制范围有密切关系,deviceNode信息与驱动入口注册相关。
但本例中MIPI控制器无需配置额外属性,如有厂商需要,则需要在device\_info文件的deviceNode增加deviceMatchAttr信息,以及增加mipidsi\_config文件。 但本例中MIPI控制器无需配置额外属性,如有厂商需要,则需要在device_info文件的deviceNode增加deviceMatchAttr信息,以及增加mipidsi_config文件。
device\_info.hcs 配置参考: device_info.hcs 配置参考:
``` ```
root { root {
...@@ -159,11 +93,10 @@ MIPI-DSI模块适配的三个环节是配置属性文件,实例化驱动入口 ...@@ -159,11 +93,10 @@ MIPI-DSI模块适配的三个环节是配置属性文件,实例化驱动入口
} }
``` ```
2. 完成器件属性文件的配置之后,下一步请实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf\_device\_desc.h 中定义)类型的全局变量,且moduleName要和device\_info.hcs中保持一致。HdfDriverEntry结构体的函数指针成员会被厂商操作函数填充,HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组,方便调用。 2. 完成器件属性文件的配置之后,下一步请实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf_device_desc.h 中定义)类型的全局变量,且moduleName要和device_info.hcs中保持一致。HdfDriverEntry结构体的函数指针成员会被厂商操作函数填充,HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组,方便调用。
一般在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 一般在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
- MIPI-DSI驱动入口参考。 - MIPI DSI驱动入口参考。
``` ```
struct HdfDriverEntry g_mipiTxDriverEntry = { struct HdfDriverEntry g_mipiTxDriverEntry = {
...@@ -180,6 +113,7 @@ MIPI-DSI模块适配的三个环节是配置属性文件,实例化驱动入口 ...@@ -180,6 +113,7 @@ MIPI-DSI模块适配的三个环节是配置属性文件,实例化驱动入口
从驱动的角度看,自定义结构体是参数和数据的载体,一般来说,config文件中的数值也会用来初始化结构体成员,但本例的mipidsi无器件属性文件,故基本成员结构与MipiDsiCntlr无太大差异。 从驱动的角度看,自定义结构体是参数和数据的载体,一般来说,config文件中的数值也会用来初始化结构体成员,但本例的mipidsi无器件属性文件,故基本成员结构与MipiDsiCntlr无太大差异。
``` ```
typedef struct { typedef struct {
unsigned int devno; // 设备号 unsigned int devno; // 设备号
...@@ -203,9 +137,9 @@ MIPI-DSI模块适配的三个环节是配置属性文件,实例化驱动入口 ...@@ -203,9 +137,9 @@ MIPI-DSI模块适配的三个环节是配置属性文件,实例化驱动入口
void *priv; void *priv;
}; };
``` ```
- MipiDsiCntlr成员回调函数结构体MipiDsiCntlrMethod的实例化,其他成员在Init函数中初始化。 - MipiDsiCntlr成员回调函数结构体MipiDsiCntlrMethod的实例化,其他成员在Init函数中初始化。
``` ```
static struct MipiDsiCntlrMethod g_method = { static struct MipiDsiCntlrMethod g_method = {
.setCntlrCfg = Hi35xxSetCntlrCfg, .setCntlrCfg = Hi35xxSetCntlrCfg,
...@@ -215,7 +149,6 @@ MIPI-DSI模块适配的三个环节是配置属性文件,实例化驱动入口 ...@@ -215,7 +149,6 @@ MIPI-DSI模块适配的三个环节是配置属性文件,实例化驱动入口
.toLp = Hi35xxToLp, .toLp = Hi35xxToLp,
}; };
``` ```
- Init函数参考 - Init函数参考
入参: 入参:
...@@ -224,52 +157,23 @@ MIPI-DSI模块适配的三个环节是配置属性文件,实例化驱动入口 ...@@ -224,52 +157,23 @@ MIPI-DSI模块适配的三个环节是配置属性文件,实例化驱动入口
返回值: 返回值:
HDF\_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf\_base.h中HDF\_STATUS 定义)。 HDF_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf_base.h中HDF_STATUS 定义)。
<a name="table344041707161538"></a>
<table><thead align="left"><tr id="row1205250994161538"><th class="cellrowborder" valign="top" width="50%" id="mcps1.1.3.1.1"><p id="entry1646623665161538p0"><a name="entry1646623665161538p0"></a><a name="entry1646623665161538p0"></a>状态(值)</p> | 状态(值) | 问题描述 |
</th> | -------- | -------- |
<th class="cellrowborder" valign="top" width="50%" id="mcps1.1.3.1.2"><p id="entry36551796161538p0"><a name="entry36551796161538p0"></a><a name="entry36551796161538p0"></a>问题描述</p> | HDF_ERR_INVALID_OBJECT | 无效对象 |
</th> | HDF_ERR_MALLOC_FAIL | 内存分配失败 |
</tr> | HDF_ERR_INVALID_PARAM | 无效参数 |
</thead> | HDF_ERR_IO | I/O&nbsp;错误 |
<tbody><tr id="row1245832689161538"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.1 "><p id="entry635453137161538p0"><a name="entry635453137161538p0"></a><a name="entry635453137161538p0"></a>HDF_ERR_INVALID_OBJECT</p> | HDF_SUCCESS | 执行成功 |
</td> | HDF_FAILURE | 执行失败 |
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.2 "><p id="entry1681554112161538p0"><a name="entry1681554112161538p0"></a><a name="entry1681554112161538p0"></a>无效对象</p>
</td>
</tr>
<tr id="row86233502161538"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.1 "><p id="entry2128705324161538p0"><a name="entry2128705324161538p0"></a><a name="entry2128705324161538p0"></a>HDF_ERR_MALLOC_FAIL</p>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.2 "><p id="entry1664050443161538p0"><a name="entry1664050443161538p0"></a><a name="entry1664050443161538p0"></a>内存分配失败</p>
</td>
</tr>
<tr id="row230078441161538"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.1 "><p id="entry325107899161538p0"><a name="entry325107899161538p0"></a><a name="entry325107899161538p0"></a>HDF_ERR_INVALID_PARAM</p>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.2 "><p id="entry754791216161538p0"><a name="entry754791216161538p0"></a><a name="entry754791216161538p0"></a>无效参数</p>
</td>
</tr>
<tr id="row20758403161538"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.1 "><p id="entry1970333605161538p0"><a name="entry1970333605161538p0"></a><a name="entry1970333605161538p0"></a>HDF_ERR_IO</p>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.2 "><p id="entry1122658595161538p0"><a name="entry1122658595161538p0"></a><a name="entry1122658595161538p0"></a>I/O 错误</p>
</td>
</tr>
<tr id="row1425117417161538"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.1 "><p id="entry1844298129161538p0"><a name="entry1844298129161538p0"></a><a name="entry1844298129161538p0"></a>HDF_SUCCESS</p>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.2 "><p id="entry712326009161538p0"><a name="entry712326009161538p0"></a><a name="entry712326009161538p0"></a>执行成功</p>
</td>
</tr>
<tr id="row1899574933161538"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.1 "><p id="entry1964112434161538p0"><a name="entry1964112434161538p0"></a><a name="entry1964112434161538p0"></a>HDF_FAILURE</p>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.2 "><p id="entry1481231483161538p0"><a name="entry1481231483161538p0"></a><a name="entry1481231483161538p0"></a>执行失败</p>
</td>
</tr>
</tbody>
</table>
函数说明: 函数说明:
MipiDsiCntlrMethod的实例化对象的挂载,调用MipiDsiRegisterCntlr,以及其他厂商自定义初始化操作。 MipiDsiCntlrMethod的实例化对象的挂载,调用MipiDsiRegisterCntlr,以及其他厂商自定义初始化操作。
``` ```
static int32_t Hi35xxMipiTxInit(struct HdfDeviceObject *device) static int32_t Hi35xxMipiTxInit(struct HdfDeviceObject *device)
{ {
...@@ -305,7 +209,6 @@ MIPI-DSI模块适配的三个环节是配置属性文件,实例化驱动入口 ...@@ -305,7 +209,6 @@ MIPI-DSI模块适配的三个环节是配置属性文件,实例化驱动入口
return HDF_FAILURE; return HDF_FAILURE;
} }
``` ```
- Release函数参考 - Release函数参考
入参: 入参:
...@@ -320,6 +223,7 @@ MIPI-DSI模块适配的三个环节是配置属性文件,实例化驱动入口 ...@@ -320,6 +223,7 @@ MIPI-DSI模块适配的三个环节是配置属性文件,实例化驱动入口
该函数需要在驱动入口结构体中赋值给 Release 接口, 当 HDF 框架调用 Init 函数初始化驱动失败时,可以调用 Release 释放驱动资源, 该函数中需包含释放内存和删除控制器等操作。所有强制转换获取相应对象的操作前提是在Init函数中具备对应赋值的操作。 该函数需要在驱动入口结构体中赋值给 Release 接口, 当 HDF 框架调用 Init 函数初始化驱动失败时,可以调用 Release 释放驱动资源, 该函数中需包含释放内存和删除控制器等操作。所有强制转换获取相应对象的操作前提是在Init函数中具备对应赋值的操作。
``` ```
static void Hi35xxMipiTxRelease(struct HdfDeviceObject *device) static void Hi35xxMipiTxRelease(struct HdfDeviceObject *device)
{ {
...@@ -334,6 +238,3 @@ MIPI-DSI模块适配的三个环节是配置属性文件,实例化驱动入口 ...@@ -334,6 +238,3 @@ MIPI-DSI模块适配的三个环节是配置属性文件,实例化驱动入口
HDF_LOGI("%s: unload mipi_tx driver 1212!", __func__); HDF_LOGI("%s: unload mipi_tx driver 1212!", __func__);
} }
``` ```
# PWM<a name="ZH-CN_TOPIC_0000001222082217"></a> # PWM
- [概述](#section1591602238164144)
- [接口说明](#section752964871810)
- [开发步骤](#section967396342164144)
- [开发实例](#section1883877829164144)
## 概述<a name="section1591602238164144"></a> ## 概述
PWM(Pulse Width Modulator)即脉冲宽度调节器,在HDF框架中,PWM的接口适配模式采用独立服务模式,在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。独立服务模式可以直接借助HDFDeviceManager的服务管理能力,但需要为每个设备单独配置设备节点,增加内存占用。 PWM(Pulse Width Modulator)即脉冲宽度调节器,在HDF框架中,PWM的接口适配模式采用独立服务模式,在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。独立服务模式可以直接借助HDFDeviceManager的服务管理能力,但需要为每个设备单独配置设备节点,增加内存占用。
**图 1** PWM独立服务模式结构图<a name="fig983655084219"></a> **图1** PWM独立服务模式结构图
![](figures/独立服务模式结构图.png "PWM独立服务模式结构图") ![zh-cn_image_0000001176603944](figures/zh-cn_image_0000001176603944.png)
## 接口说明<a name="section752964871810"></a>
## 接口说明
PwmMethod定义: PwmMethod定义:
``` ```
struct PwmMethod { struct PwmMethod {
int32_t (*setConfig)(struct PwmDev *pwm, struct PwmConfig *config); int32_t (*setConfig)(struct PwmDev *pwm, struct PwmConfig *config);
...@@ -24,80 +22,42 @@ struct PwmMethod { ...@@ -24,80 +22,42 @@ struct PwmMethod {
}; };
``` ```
**表 1** PwmMethod结构体成员的回调函数功能说明 **表1** PwmMethod结构体成员的回调函数功能说明
<a name="table11173154124311"></a> | 成员函数 | 入参 | 返回值 | 功能 |
<table><thead align="left"><tr id="row2173441164311"><th class="cellrowborder" valign="top" width="25%" id="mcps1.2.5.1.1"><p id="p17174144144310"><a name="p17174144144310"></a><a name="p17174144144310"></a>成员函数</p> | -------- | -------- | -------- | -------- |
</th> | setConfig | **pwm**:&nbsp;&nbsp;结构体指针,核心层PWM控制器;<br/>**config**:&nbsp;&nbsp;结构体指针,属性传入值; | HDF_STATUS相关状态 | 配置属性 |
<th class="cellrowborder" valign="top" width="25%" id="mcps1.2.5.1.2"><p id="p21751441154318"><a name="p21751441154318"></a><a name="p21751441154318"></a>入参</p> | open | **pwm**:&nbsp;&nbsp;结构体指针,核心层PWM控制器; | HDF_STATUS相关状态 | 打开设备 |
</th> | close | **pwm**:&nbsp;&nbsp;结构体指针,核心层PWM控制器; | HDF_STATUS相关状态 | 关闭设备 |
<th class="cellrowborder" valign="top" width="25%" id="mcps1.2.5.1.3"><p id="p191751741144313"><a name="p191751741144313"></a><a name="p191751741144313"></a>返回值</p>
</th>
<th class="cellrowborder" valign="top" width="25%" id="mcps1.2.5.1.4"><p id="p5175641154315"><a name="p5175641154315"></a><a name="p5175641154315"></a>功能</p> ## 开发步骤
</th>
</tr>
</thead>
<tbody><tr id="row7175154144311"><td class="cellrowborder" valign="top" width="25%" headers="mcps1.2.5.1.1 "><p id="p3900552134317"><a name="p3900552134317"></a><a name="p3900552134317"></a>setConfig</p>
</td>
<td class="cellrowborder" valign="top" width="25%" headers="mcps1.2.5.1.2 "><p id="p422655084417"><a name="p422655084417"></a><a name="p422655084417"></a><strong id="b10227650134413"><a name="b10227650134413"></a><a name="b10227650134413"></a>pwm</strong>: 结构体指针,核心层PWM控制器;</p>
<p id="p02275502443"><a name="p02275502443"></a><a name="p02275502443"></a><strong id="b322719508445"><a name="b322719508445"></a><a name="b322719508445"></a>config</strong>: 结构体指针,属性传入值;</p>
</td>
<td class="cellrowborder" valign="top" width="25%" headers="mcps1.2.5.1.3 "><p id="p18176184112433"><a name="p18176184112433"></a><a name="p18176184112433"></a>HDF_STATUS相关状态</p>
</td>
<td class="cellrowborder" valign="top" width="25%" headers="mcps1.2.5.1.4 "><p id="p5176124164314"><a name="p5176124164314"></a><a name="p5176124164314"></a>配置属性</p>
</td>
</tr>
<tr id="row217654124312"><td class="cellrowborder" valign="top" width="25%" headers="mcps1.2.5.1.1 "><p id="p121761041144314"><a name="p121761041144314"></a><a name="p121761041144314"></a>open</p>
</td>
<td class="cellrowborder" valign="top" width="25%" headers="mcps1.2.5.1.2 "><p id="p2176941144314"><a name="p2176941144314"></a><a name="p2176941144314"></a><strong id="b137308954516"><a name="b137308954516"></a><a name="b137308954516"></a>pwm</strong>: 结构体指针,核心层PWM控制器;</p>
</td>
<td class="cellrowborder" valign="top" width="25%" headers="mcps1.2.5.1.3 "><p id="p1317694119435"><a name="p1317694119435"></a><a name="p1317694119435"></a>HDF_STATUS相关状态</p>
</td>
<td class="cellrowborder" valign="top" width="25%" headers="mcps1.2.5.1.4 "><p id="p376133118453"><a name="p376133118453"></a><a name="p376133118453"></a>打开设备</p>
</td>
</tr>
<tr id="row8176174110439"><td class="cellrowborder" valign="top" width="25%" headers="mcps1.2.5.1.1 "><p id="p017684174314"><a name="p017684174314"></a><a name="p017684174314"></a>close</p>
</td>
<td class="cellrowborder" valign="top" width="25%" headers="mcps1.2.5.1.2 "><p id="p1217694118437"><a name="p1217694118437"></a><a name="p1217694118437"></a><strong id="b44731616124513"><a name="b44731616124513"></a><a name="b44731616124513"></a>pwm</strong>: 结构体指针,核心层PWM控制器;</p>
</td>
<td class="cellrowborder" valign="top" width="25%" headers="mcps1.2.5.1.3 "><p id="p16176104115437"><a name="p16176104115437"></a><a name="p16176104115437"></a>HDF_STATUS相关状态</p>
</td>
<td class="cellrowborder" valign="top" width="25%" headers="mcps1.2.5.1.4 "><p id="p10893332114514"><a name="p10893332114514"></a><a name="p10893332114514"></a>关闭设备</p>
</td>
</tr>
</tbody>
</table>
## 开发步骤<a name="section967396342164144"></a>
PWM模块适配HDF框架的三个环节是配置属性文件,实例化驱动入口,以及填充核心层接口函数。 PWM模块适配HDF框架的三个环节是配置属性文件,实例化驱动入口,以及填充核心层接口函数。
1. **实例化驱动入口:** 1. **实例化驱动入口:**
- 实例化HdfDriverEntry结构体成员。 - 实例化HdfDriverEntry结构体成员。
- 调用HDF\_INIT将HdfDriverEntry实例化对象注册到HDF框架中。 - 调用HDF_INIT将HdfDriverEntry实例化对象注册到HDF框架中。
2. **配置属性文件:** 2. **配置属性文件:**
- 在device\_info.hcs文件中添加deviceNode描述。 - 在device_info.hcs文件中添加deviceNode描述。
- 【可选】添加pwm\_config.hcs器件属性文件。 - 【可选】添加pwm_config.hcs器件属性文件。
3. **实例化PWM控制器对象:** 3. **实例化PWM控制器对象:**
- 初始化PwmDev成员。 - 初始化PwmDev成员。
- 实例化PwmDev成员PwmMethod。 - 实例化PwmDev成员PwmMethod。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
>![](../public_sys-resources/icon-note.gif) **说明:** > 实例化PwmDev成员PwmMethod,其定义和成员说明见[接口说明](#接口说明)。
>实例化PwmDev成员PwmMethod,其定义和成员说明见[接口说明](#section752964871810)。
4. **驱动调试:** 4. **驱动调试:**
【可选】针对新增驱动程序,建议验证驱动基本功能,例如PWM控制状态,中断响应情况等。 【可选】针对新增驱动程序,建议验证驱动基本功能,例如PWM控制状态,中断响应情况等。
## 开发实例<a name="section1883877829164144"></a> ## 开发实例
下方将以pwm\_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。 下方将以pwm_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。
1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf\_device\_desc.h 中定义)类型的全局变量,且moduleName要和device\_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。 1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf_device_desc.h 中定义)类型的全局变量,且moduleName要和device_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。
一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
...@@ -115,8 +75,9 @@ PWM模块适配HDF框架的三个环节是配置属性文件,实例化驱动 ...@@ -115,8 +75,9 @@ PWM模块适配HDF框架的三个环节是配置属性文件,实例化驱动
HDF_INIT(g_hdfPwm); HDF_INIT(g_hdfPwm);
``` ```
2. 完成驱动入口注册之后,下一步请在device\_info.hcs文件中添加deviceNode信息,并在 pwm\_config.hcs 中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值与核心层PwmDev成员的默认值或限制范围有密切关系。 如有更多个器件信息,则需要在device\_info文件增加deviceNode信息,以及在pwm\_config文件中增加对应的器件属性**。** 2. 完成驱动入口注册之后,下一步请在device_info.hcs文件中添加deviceNode信息,并在 pwm_config.hcs 中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值与核心层PwmDev成员的默认值或限制范围有密切关系。 如有更多个器件信息,则需要在device_info文件增加deviceNode信息,以及在pwm_config文件中增加对应的器件属性**。**
- device\_info.hcs 配置参考。 - device_info.hcs 配置参考。
``` ```
root { root {
...@@ -147,8 +108,8 @@ PWM模块适配HDF框架的三个环节是配置属性文件,实例化驱动 ...@@ -147,8 +108,8 @@ PWM模块适配HDF框架的三个环节是配置属性文件,实例化驱动
} }
} }
``` ```
- pwm_config.hcs 配置参考。
- pwm\_config.hcs 配置参考。
``` ```
root { root {
...@@ -176,7 +137,8 @@ PWM模块适配HDF框架的三个环节是配置属性文件,实例化驱动 ...@@ -176,7 +137,8 @@ PWM模块适配HDF框架的三个环节是配置属性文件,实例化驱动
3. 完成驱动入口注册之后,最后一步就是以核心层PwmDev对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化PwmDev成员PwmMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。 3. 完成驱动入口注册之后,最后一步就是以核心层PwmDev对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化PwmDev成员PwmMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。
- 自定义结构体参考。 - 自定义结构体参考。
从驱动的角度看,自定义结构体是参数和数据的载体,而且pwm\_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,一些重要数值也会传递给核心层对象,例如设备号等。 从驱动的角度看,自定义结构体是参数和数据的载体,而且pwm_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,一些重要数值也会传递给核心层对象,例如设备号等。
``` ```
struct HiPwm { struct HiPwm {
...@@ -215,13 +177,13 @@ PWM模块适配HDF框架的三个环节是配置属性文件,实例化驱动 ...@@ -215,13 +177,13 @@ PWM模块适配HDF框架的三个环节是配置属性文件,实例化驱动
- PwmDev成员回调函数结构体PwmMethod的实例化,其他成员在Init函数中初始化。 - PwmDev成员回调函数结构体PwmMethod的实例化,其他成员在Init函数中初始化。
``` ```
// pwm_hi35xx.c 中的示例:钩子函数的填充 // pwm_hi35xx.c 中的示例:钩子函数的填充
struct PwmMethod g_pwmOps = { struct PwmMethod g_pwmOps = {
.setConfig = HiPwmSetConfig,//配置属性 .setConfig = HiPwmSetConfig,//配置属性
}; };
``` ```
- Init函数参考 - Init函数参考
入参: 入参:
...@@ -230,52 +192,22 @@ PWM模块适配HDF框架的三个环节是配置属性文件,实例化驱动 ...@@ -230,52 +192,22 @@ PWM模块适配HDF框架的三个环节是配置属性文件,实例化驱动
返回值: 返回值:
HDF\_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf\_base.h中HDF\_STATUS 定义)。 HDF_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf_base.h中HDF_STATUS 定义)。
<a name="table1057438215164144"></a> | 状态(值) | 问题描述 |
<table><thead align="left"><tr id="row31521027164144"><th class="cellrowborder" valign="top" width="50%" id="mcps1.1.3.1.1"><p id="entry1990732428164144p0"><a name="entry1990732428164144p0"></a><a name="entry1990732428164144p0"></a>状态(值)</p> | -------- | -------- |
</th> | HDF_ERR_INVALID_OBJECT | 控制器对象非法 |
<th class="cellrowborder" valign="top" width="50%" id="mcps1.1.3.1.2"><p id="entry2123581292164144p0"><a name="entry2123581292164144p0"></a><a name="entry2123581292164144p0"></a>问题描述</p> | HDF_ERR_MALLOC_FAIL | 内存分配失败 |
</th> | HDF_ERR_INVALID_PARAM | 参数非法 |
</tr> | HDF_ERR_IO | I/O&nbsp;错误 |
</thead> | HDF_SUCCESS | 初始化成功 |
<tbody><tr id="row1749271383164144"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.1 "><p id="entry202330388164144p0"><a name="entry202330388164144p0"></a><a name="entry202330388164144p0"></a>HDF_ERR_INVALID_OBJECT</p> | HDF_FAILURE | 初始化失败 |
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.2 "><p id="entry1717598064164144p0"><a name="entry1717598064164144p0"></a><a name="entry1717598064164144p0"></a>控制器对象非法</p>
</td>
</tr>
<tr id="row1715354988164144"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.1 "><p id="entry450625221164144p0"><a name="entry450625221164144p0"></a><a name="entry450625221164144p0"></a>HDF_ERR_MALLOC_FAIL</p>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.2 "><p id="entry361497788164144p0"><a name="entry361497788164144p0"></a><a name="entry361497788164144p0"></a>内存分配失败</p>
</td>
</tr>
<tr id="row1202091366164144"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.1 "><p id="entry370837906164144p0"><a name="entry370837906164144p0"></a><a name="entry370837906164144p0"></a>HDF_ERR_INVALID_PARAM</p>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.2 "><p id="entry353311523164144p0"><a name="entry353311523164144p0"></a><a name="entry353311523164144p0"></a>参数非法</p>
</td>
</tr>
<tr id="row602018308164144"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.1 "><p id="entry1984036607164144p0"><a name="entry1984036607164144p0"></a><a name="entry1984036607164144p0"></a>HDF_ERR_IO</p>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.2 "><p id="entry1221756048164144p0"><a name="entry1221756048164144p0"></a><a name="entry1221756048164144p0"></a>I/O 错误</p>
</td>
</tr>
<tr id="row47997479164144"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.1 "><p id="entry1220816374164144p0"><a name="entry1220816374164144p0"></a><a name="entry1220816374164144p0"></a>HDF_SUCCESS</p>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.2 "><p id="entry1903499126164144p0"><a name="entry1903499126164144p0"></a><a name="entry1903499126164144p0"></a>初始化成功</p>
</td>
</tr>
<tr id="row2031856197164144"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.1 "><p id="entry463793674164144p0"><a name="entry463793674164144p0"></a><a name="entry463793674164144p0"></a>HDF_FAILURE</p>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.2 "><p id="entry516362874164144p0"><a name="entry516362874164144p0"></a><a name="entry516362874164144p0"></a>初始化失败</p>
</td>
</tr>
</tbody>
</table>
函数说明: 函数说明:
初始化自定义结构体对象,初始化PwmDev成员,调用核心层PwmDeviceAdd函数。 初始化自定义结构体对象,初始化PwmDev成员,调用核心层PwmDeviceAdd函数。
``` ```
//此处bind函数为空函数,可与init函数结合,也可根据厂商需要实现相关操作 //此处bind函数为空函数,可与init函数结合,也可根据厂商需要实现相关操作
static int32_t HdfPwmBind(struct HdfDeviceObject *obj) static int32_t HdfPwmBind(struct HdfDeviceObject *obj)
...@@ -320,7 +252,6 @@ PWM模块适配HDF框架的三个环节是配置属性文件,实例化驱动 ...@@ -320,7 +252,6 @@ PWM模块适配HDF框架的三个环节是配置属性文件,实例化驱动
return HDF_SUCCESS; return HDF_SUCCESS;
} }
``` ```
- Release 函数参考 - Release 函数参考
入参: 入参:
...@@ -335,6 +266,7 @@ PWM模块适配HDF框架的三个环节是配置属性文件,实例化驱动 ...@@ -335,6 +266,7 @@ PWM模块适配HDF框架的三个环节是配置属性文件,实例化驱动
释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源。 释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源。
``` ```
static void HdfPwmRelease(struct HdfDeviceObject *obj) static void HdfPwmRelease(struct HdfDeviceObject *obj)
{ {
...@@ -346,6 +278,3 @@ PWM模块适配HDF框架的三个环节是配置属性文件,实例化驱动 ...@@ -346,6 +278,3 @@ PWM模块适配HDF框架的三个环节是配置属性文件,实例化驱动
HiPwmRemove(hp); //释放HiPwm HiPwmRemove(hp); //释放HiPwm
} }
``` ```
# 平台驱动使用<a name="ZH-CN_TOPIC_0000001111199424"></a> # 平台驱动使用
- **[ADC](driver-platform-adc-des.md)**
- **[DAC](driver-platform-dac-des.md)**
- **[GPIO](driver-platform-gpio-des.md)** - **[GPIO](driver-platform-gpio-des.md)**
- **[HDMI](driver-platform-hdmi-des.md)**
- **[I2C](driver-platform-i2c-des.md)** - **[I2C](driver-platform-i2c-des.md)**
- **[I3C](driver-platform-i3c-des.md)**
- **[MIPI-CSI](driver-platform-mipicsi-des.md)**
- **[MIPI-DSI](driver-platform-mipidsi-des.md)**
- **[PIN](driver-platform-pin-des.md)**
- **[PWM](driver-platform-pwm-des.md)**
- **[RTC](driver-platform-rtc-des.md)** - **[RTC](driver-platform-rtc-des.md)**
- **[SDIO](driver-platform-sdio-des.md)** - **[SDIO](driver-platform-sdio-des.md)**
...@@ -28,4 +14,8 @@ ...@@ -28,4 +14,8 @@
- **[UART](driver-platform-uart-des.md)** - **[UART](driver-platform-uart-des.md)**
- **[WATCHDOG](driver-platform-watchdog-des.md)** - **[Watchdog](driver-platform-watchdog-des.md)**
- **[MIPI DSI](driver-platform-mipidsi-des.md)**
- **[PWM](driver-platform-pwm-des.md)**
\ No newline at end of file
# 驱动<a name="ZH-CN_TOPIC_0000001111039544"></a> # 驱动
- **[HDF驱动框架](driver-hdf.md)** - **[HDF驱动框架](driver-hdf.md)**
...@@ -7,5 +9,3 @@ ...@@ -7,5 +9,3 @@
- **[平台驱动使用](driver-platform.md)** - **[平台驱动使用](driver-platform.md)**
- **[外设驱动使用](driver-peripherals.md)** - **[外设驱动使用](driver-peripherals.md)**
\ No newline at end of file
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册