diff --git a/zh-cn/device-dev/driver/Readme-CN.md b/zh-cn/device-dev/driver/Readme-CN.md index 652a8c588ef50fd0c118b2c931661162cd779b6c..0a3ef42249ef30a21979b2d1611b4a8f502b41fd 100755 --- a/zh-cn/device-dev/driver/Readme-CN.md +++ b/zh-cn/device-dev/driver/Readme-CN.md @@ -1,55 +1,54 @@ # 驱动使用指南 -- [HDF驱动框架](driver-hdf.md) +- HDF驱动框架 - [HDF开发概述](driver-hdf-overview.md) - [驱动开发](driver-hdf-development.md) - [驱动服务管理](driver-hdf-servicemanage.md) - [驱动消息机制管理](driver-hdf-message-management.md) - [配置管理](driver-hdf-manage.md) - [HDF开发实例](driver-hdf-sample.md) -- [平台驱动开发](driver-develop.md) +- 平台驱动开发 - [ADC](driver-platform-adc-develop.md) - [DAC](driver-platform-dac-develop.md) - [GPIO](driver-platform-gpio-develop.md) - [HDMI](driver-platform-hdmi-develop.md) - [I2C](driver-platform-i2c-develop.md) - [I3C](driver-platform-i3c-develop.md) - - [MIPI-CSI](driver-platform-mipicsi-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) - [PIN](driver-platform-pin-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) - [SDIO](driver-platform-sdio-develop.md) - [SPI](driver-platform-spi-develop.md) - [UART](driver-platform-uart-develop.md) - [WatchDog](driver-platform-watchdog-develop.md) -- [平台驱动使用](driver-platform.md) +- 平台驱动使用 - [ADC](driver-platform-adc-des.md) - [DAC](driver-platform-dac-des.md) - [GPIO](driver-platform-gpio-des.md) - [HDMI](driver-platform-hdmi-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) + - [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) - - [REGULATOR](driver-platform-regulator-des.md) + - [Regulator](driver-platform-regulator-des.md) - [RTC](driver-platform-rtc-des.md) - [SDIO](driver-platform-sdio-des.md) - [SPI](driver-platform-spi-des.md) - [UART](driver-platform-uart-des.md) - - [WATCHDOG](driver-platform-watchdog-des.md) -- [外设驱动使用](driver-peripherals.md) + - [WatchDog](driver-platform-watchdog-des.md) +- 外设驱动使用 - [LCD](driver-peripherals-lcd-des.md) - - [TOUCHSCREEN](driver-peripherals-touch-des.md) - - [SENSOR](driver-peripherals-sensor-des.md) + - [Touchscreen](driver-peripherals-touch-des.md) + - [Sensor](driver-peripherals-sensor-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) - - [CAMERA](driver-peripherals-camera-des.md) - - [VIBRATOR](driver-peripherals-vibrator-des.md) - - [LIGHT](driver-peripherals-light-des.md) - + - [Camera](driver-peripherals-camera-des.md) + - [Vibrator](driver-peripherals-vibrator-des.md) + - [Light](driver-peripherals-light-des.md) \ No newline at end of file diff --git a/zh-cn/device-dev/driver/driver-develop.md b/zh-cn/device-dev/driver/driver-develop.md index bb2cff55133ce0f076a67d747ce13db2c2c2ee3b..4bfb18822cfb09d7e6bcc9eba7dabcc2d5924286 100644 --- a/zh-cn/device-dev/driver/driver-develop.md +++ b/zh-cn/device-dev/driver/driver-develop.md @@ -1,31 +1,25 @@ -# 平台驱动开发 +# 平台驱动开发 -- **[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)** +- **[MMC](driver-platform-mmc-develop.md)** -- **[MIPI-DSI](driver-platform-mipidsi-develop.md)** +- **[PWM](driver-platform-pwm-develop.md)** -- **[MMC](driver-platform-mmc-develop.md)** +- **[RTC](driver-platform-rtc-develop.md)** -- **[PWM](driver-platform-pwm-develop.md)** +- **[SDIO](driver-platform-sdio-develop.md)** -- **[RTC](driver-platform-rtc-develop.md)** +- **[SPI](driver-platform-spi-develop.md)** -- **[SDIO](driver-platform-sdio-develop.md)** +- **[UART](driver-platform-uart-develop.md)** -- **[SPI](driver-platform-spi-develop.md)** - -- **[UART](driver-platform-uart-develop.md)** - -- **[WatchDog](driver-platform-watchdog-develop.md)** +- **[WatchDog](driver-platform-watchdog-develop.md)** \ No newline at end of file diff --git a/zh-cn/device-dev/driver/driver-hdf-development.md b/zh-cn/device-dev/driver/driver-hdf-development.md index f5ed1cc265b9c66adb0a668bea64b002dec0ea39..08b088a444793c24a1a2a4a0dbeed817a7ac7d90 100755 --- a/zh-cn/device-dev/driver/driver-hdf-development.md +++ b/zh-cn/device-dev/driver/driver-hdf-development.md @@ -1,253 +1,231 @@ -# 驱动开发 +# 驱动开发 -- [驱动模型介绍](#section157425168112) -- [驱动开发步骤](#section1969312275533) -## 驱动模型介绍 +## 驱动模型介绍 HDF框架以组件化的驱动模型作为核心设计思路,为开发者提供更精细化的驱动管理,让驱动开发和部署更加规范。HDF框架将一类设备驱动放在同一个host里面,开发者也可以将驱动功能分层独立开发和部署,支持一个驱动多个node,HDF驱动模型如下图所示: -**图 1** HDF驱动模型 -![](figures/HDF驱动模型.png "HDF驱动模型") + **图1** HDF驱动模型 -## 驱动开发步骤 + ![zh-cn_image_0000001153947412](figures/zh-cn_image_0000001153947412.png) -基于HDF框架进行驱动的开发主要分为两个部分,驱动实现和驱动配置,详细开发流程如下所示: -1. 驱动实现 +## 驱动开发步骤 - 驱动实现包含驱动业务代码和驱动入口注册,具体写法如下: +基于HDF框架进行驱动的开发主要分为两个部分,驱动实现和驱动配置,详细开发流程如下所示: - - 驱动业务代码 +1. 驱动实现 + 驱动实现包含驱动业务代码和驱动入口注册,具体写法如下: - ``` - #include "hdf_device_desc.h" // HDF框架对驱动开放相关能力接口的头文件 - #include "hdf_log.h" // HDF 框架提供的日志接口头文件 - - #define HDF_LOG_TAG "sample_driver" // 打印日志所包含的标签,如果不定义则用默认定义的HDF_TAG标签 - - //驱动对外提供的服务能力,将相关的服务接口绑定到HDF框架 - int32_t HdfSampleDriverBind(struct HdfDeviceObject *deviceObject) - { - HDF_LOGD("Sample driver bind success"); - return 0; - } - - // 驱动自身业务初始的接口 - int32_t HdfSampleDriverInit(struct HdfDeviceObject *deviceObject) - { - HDF_LOGD("Sample driver Init success"); - return 0; - } + - 驱动业务代码 - // 驱动资源释放的接口 - void HdfSampleDriverRelease(struct HdfDeviceObject *deviceObject) - { - HDF_LOGD("Sample driver release success"); - return; - } - ``` - - - 驱动入口注册到HDF框架 - - ``` - // 定义驱动入口的对象,必须为HdfDriverEntry(在hdf_device_desc.h中定义)类型的全局变量 - struct HdfDriverEntry g_sampleDriverEntry = { - .moduleVersion = 1, - .moduleName = "sample_driver", - .Bind = HdfSampleDriverBind, - .Init = HdfSampleDriverInit, - .Release = HdfSampleDriverRelease, - }; + ``` + #include "hdf_device_desc.h" // HDF框架对驱动开发相关能力接口的头文件 + #include "hdf_log.h" // HDF 框架提供的日志接口头文件 + + #define HDF_LOG_TAG "sample_driver" // 打印日志所包含的标签,如果不定义则用默认定义的HDF_TAG标签 + + //驱动对外提供的服务能力,将相关的服务接口绑定到HDF框架 + int32_t HdfSampleDriverBind(struct HdfDeviceObject *deviceObject) + { + HDF_LOGD("Sample driver bind success"); + return 0; + } + + // 驱动自身业务初始的接口 + int32_t HdfSampleDriverInit(struct HdfDeviceObject *deviceObject) + { + HDF_LOGD("Sample driver Init success"); + return 0; + } + + // 驱动资源释放的接口 + void HdfSampleDriverRelease(struct HdfDeviceObject *deviceObject) + { + HDF_LOGD("Sample driver release success"); + return; + } + ``` + - 驱动入口注册到HDF框架 - // 调用HDF_INIT将驱动入口注册到HDF框架中,在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动,当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 - HDF_INIT(g_sampleDriverEntry); - ``` + ``` + // 定义驱动入口的对象,必须为HdfDriverEntry(在hdf_device_desc.h中定义)类型的全局变量 + struct HdfDriverEntry g_sampleDriverEntry = { + .moduleVersion = 1, + .moduleName = "sample_driver", + .Bind = HdfSampleDriverBind, + .Init = HdfSampleDriverInit, + .Release = HdfSampleDriverRelease, + }; + + // 调用HDF_INIT将驱动入口注册到HDF框架中,在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动,当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 + HDF_INIT(g_sampleDriverEntry); + ``` 2. 驱动编译 - - liteos + 涉及makefile和BUILD.gn修改: + + - makefile部分: + 驱动代码的编译必须要使用HDF框架提供的Makefile模板进行编译。 + + + ``` + include $(LITEOSTOPDIR)/../../drivers/adapter/khdf/liteos/lite.mk #导入hdf预定义内容,必需 + MODULE_NAME := #生成的结果文件 + LOCAL_INCLUDE := #本驱动的头文件目录 + LOCAL_SRCS := #本驱动的源代码文件 + LOCAL_CFLAGS := #自定义的编译选项 + include $(HDF_DRIVER) #导入模板makefile完成编译 + ``` + + 编译结果文件链接到内核镜像,添加到drivers/adapter/khdf/liteos目录下的hdf_lite.mk里面,示例如下: + + + ``` + LITEOS_BASELIB += -lxxx #链接生成的静态库 + LIB_SUBDIRS += #驱动代码Makefile的目录 + ``` + + - BUILD.gn部分: + 添加模块BUILD.gn参考定义如下内容: + + + ``` + import("//build/lite/config/component/lite_component.gni") + import("//drivers/adapter/khdf/liteos/hdf.gni") + module_switch = defined(LOSCFG_DRIVERS_HDF_xxx) + module_name = "xxx" + hdf_driver(module_name) { + sources = [ + "xxx/xxx/xxx.c", #模块要编译的源码文件 + ] + public_configs = [ ":public" ] #使用依赖的头文件配置 + } + config("public") { #定义依赖的头文件配置 + include_dirs = [ + "xxx/xxx/xxx", #依赖的头文件目录 + ] + } + ``` + + 把新增模块的BUILD.gn所在的目录添加到/drivers/adapter/khdf/liteos/BUILD.gn里面: + + + ``` + group("liteos") { + public_deps = [ ":$module_name" ] + deps = [ + "xxx/xxx", #新增模块BUILD.gn所在的目录,目录结构相对于/drivers/adapter/khdf/liteos + ] + } + ``` + - linux + 如果需要定义模块控制宏,需要在模块目录xxx里面添加Kconfig文件,并把Kconfig文件路径添加到drivers/adapter/khdf/linux/Kconfig里面: - 涉及makefile和BUILD.gn修改: - - * makefile部分: - - 驱动代码的编译必须要使用HDF框架提供的Makefile模板进行编译。 - - ``` - include $(LITEOSTOPDIR)/../../drivers/adapter/khdf/liteos/lite.mk #导入hdf预定义内容,必需 - MODULE_NAME := #生成的结果文件 - LOCAL_INCLUDE := #本驱动的头文件目录 - LOCAL_SRCS := #本驱动的源代码文件 - LOCAL_CFLAGS := #自定义的编译选项 - include $(HDF_DRIVER) #导入模板makefile完成编译 - ``` - - 编译结果文件链接到内核镜像,添加到drivers/adapter/khdf/liteos目录下的hdf_lite.mk里面,示例如下: - - ``` - LITEOS_BASELIB += -lxxx #链接生成的静态库 - LIB_SUBDIRS += #驱动代码Makefile的目录 - ``` - - * BUILD.gn部分: - - 添加模块BUILD.gn参考定义如下内容: - - ``` - import("//build/lite/config/component/lite_component.gni") - import("//drivers/adapter/khdf/liteos/hdf.gni") - module_switch = defined(LOSCFG_DRIVERS_HDF_xxx) - module_name = "xxx" - hdf_driver(module_name) { - sources = [ - "xxx/xxx/xxx.c", #模块要编译的源码文件 - ] - public_configs = [ ":public" ] #使用依赖的头文件配置 - } - config("public") { #定义依赖的头文件配置 - include_dirs = [ - "xxx/xxx/xxx", #依赖的头文件目录 - ] - } - ``` - - 把新增模块的BUILD.gn所在的目录添加到/drivers/adapter/khdf/liteos/BUILD.gn里面: - - ``` - group("liteos") { - public_deps = [ ":$module_name" ] - deps = [ - "xxx/xxx", #新增模块BUILD.gn所在的目录,目录结构相对于/drivers/adapter/khdf/liteos - ] - } - ``` + + ``` + source "drivers/hdf/khdf/xxx/Kconfig" #目录为hdf模块软链接到kernel里面的目录 + ``` - - linux + 添加模块目录到drivers/adapter/khdf/linux/Makefile: - 如果需要定义模块控制宏,需要在模块目录xxx里面添加Kconfig文件,并把Kconfig文件路径添加到drivers/adapter/khdf/linux/Kconfig里面: - - ``` - source "drivers/hdf/khdf/xxx/Kconfig" #目录为hdf模块软链接到kernel里面的目录 - ``` - - 添加模块目录到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. 驱动配置 + HDF使用HCS作为配置描述源码,HCS详细介绍参考[配置管理](../driver/driver-hdf-manage.md)介绍。 + 驱动配置包含两部分,HDF框架定义的驱动设备描述和驱动的私有配置信息,具体写法如下: - - -3. 驱动配置 - - HDF使用HCS作为配置描述源码,HCS详细介绍参考[配置管理](driver-hdf-manage.md)介绍。 - - 驱动配置包含两部分,HDF框架定义的驱动设备描述和驱动的私有配置信息,具体写法如下: - - - 驱动设备描述(必选) - - HDF框架加载驱动所需要的信息来源于HDF框架定义的驱动设备描述,因此基于HDF框架开发的驱动必须要在HDF框架定义的device\_info.hcs配置文件中添加对应的设备描述,驱动的设备描述填写如下所示: - - ``` - root { - device_info { - match_attr = "hdf_manager"; - template host { // host模板,继承该模板的节点(如下sample_host)如果使用模板中的默认值,则节点字段可以缺省 - hostName = ""; - priority = 100; - template device { - template deviceNode { - policy = 0; - priority = 100; - preload = 0; - permission = 0664; - moduleName = ""; - serviceName = ""; - deviceMatchAttr = ""; - } - } - } - sample_host :: host{ - hostName = "host0"; // host名称,host节点是用来存放某一类驱动的容器 - priority = 100; // host启动优先级(0-200),值越大优先级越低,建议默认配100,优先级相同则不保证host的加载顺序 - device_sample :: device { // sample设备节点 - device0 :: deviceNode { // sample驱动的DeviceNode节点 - policy = 1; // policy字段是驱动服务发布的策略,在驱动服务管理章节有详细介绍 - priority = 100; // 驱动启动优先级(0-200),值越大优先级越低,建议默认配100,优先级相同则不保证device的加载顺序 - preload = 0; // 驱动按需加载字段,在本章节最后的说明有详细介绍 - permission = 0664; // 驱动创建设备节点权限 - moduleName = "sample_driver"; // 驱动名称,该字段的值必须和驱动入口结构的moduleName值一致 - serviceName = "sample_service"; // 驱动对外发布服务的名称,必须唯一 - deviceMatchAttr = "sample_config"; // 驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等 - } - } - } - } - } - ``` - - - 驱动私有配置信息(可选) - - 如果驱动有私有配置,则可以添加一个驱动的配置文件,用来填写一些驱动的默认配置信息,HDF框架在加载驱动的时候,会将对应的配置信息获取并保存在HdfDeviceObject 中的property里面,通过Bind和Init(参考[驱动开发](#li35182436435))传递给驱动,驱动的配置信息示例如下: - - ``` - root { - SampleDriverConfig { - sample_version = 1; - sample_bus = "I2C_0"; - match_attr = "sample_config"; //该字段的值必须和device_info.hcs中的deviceMatchAttr值一致 - } - } - ``` - - 配置信息定义之后,需要将该配置文件添加到板级配置入口文件hdf.hcs(这一块可以通过OpenHarmony驱动子系统在DevEco集成驱动开发套件工具一键式配置,具体使用方法参考驱动开发套件中的介绍),示例如下: - - ``` - #include "device_info/device_info.hcs" - #include "sample/sample_config.hcs" - ``` - -4. 用户态驱动服务启动配置 - - 用户态需要把驱动服务配置到文件drivers/adapter/uhdf2/host/hdf_devhostmusl.cfg中,如下: - - ``` - { - "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 { -> DEVICE_PRELOAD_ENABLE = 0, -> DEVICE_PRELOAD_ENABLE_STEP2, -> DEVICE_PRELOAD_DISABLE, -> DEVICE_PRELOAD_INVALID -> } DevicePreload; -> ``` -> 配置文件中preload 字段配成 0 (DEVICE\_PRELOAD\_ENABLE ),则系统启动过程中默认加载;配成1(DEVICE\_PRELOAD\_ENABLE\_STEP2),当系统支持快启的时候,则在系统完成之后再加载这一类驱动,否则和DEVICE\_PRELOAD\_ENABLE 含义相同;配成2(DEVICE\_PRELOAD\_DISABLE),则系统启动过程中默认不加载,支持后续动态加载,当用户态获取驱动服务(参考[消息机制](driver-hdf-message-management.md))时,如果驱动服务不存在时,HDF框架会尝试动态加载该驱动。 ->- 按序加载(需要驱动为默认加载) -> 配置文件中的priority(取值范围为整数0到200)是用来表示host和驱动的优先级,不同的host内的驱动,host的priority值越小,驱动加载优先级越高;同一个host内驱动的priority值越小,加载优先级越高。 - + - 驱动设备描述(必选) + HDF框架加载驱动所需要的信息来源于HDF框架定义的驱动设备描述,因此基于HDF框架开发的驱动必须要在HDF框架定义的device_info.hcs配置文件中添加对应的设备描述,驱动的设备描述填写如下所示: + + + ``` + root { + device_info { + match_attr = "hdf_manager"; + template host { // host模板,继承该模板的节点(如下sample_host)如果使用模板中的默认值,则节点字段可以缺省 + hostName = ""; + priority = 100; + template device { + template deviceNode { + policy = 0; + priority = 100; + preload = 0; + permission = 0664; + moduleName = ""; + serviceName = ""; + deviceMatchAttr = ""; + } + } + } + sample_host :: host{ + hostName = "host0"; // host名称,host节点是用来存放某一类驱动的容器 + priority = 100; // host启动优先级(0-200),值越大优先级越低,建议默认配100,优先级相同则不保证host的加载顺序 + device_sample :: device { // sample设备节点 + device0 :: deviceNode { // sample驱动的DeviceNode节点 + policy = 1; // policy字段是驱动服务发布的策略,在驱动服务管理章节有详细介绍 + priority = 100; // 驱动启动优先级(0-200),值越大优先级越低,建议默认配100,优先级相同则不保证device的加载顺序 + preload = 0; // 驱动按需加载字段,在本章节最后的说明有详细介绍 + permission = 0664; // 驱动创建设备节点权限 + moduleName = "sample_driver"; // 驱动名称,该字段的值必须和驱动入口结构的moduleName值一致 + serviceName = "sample_service"; // 驱动对外发布服务的名称,必须唯一 + deviceMatchAttr = "sample_config"; // 驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等 + } + } + } + } + } + ``` + - 驱动私有配置信息(可选) + 如果驱动有私有配置,则可以添加一个驱动的配置文件,用来填写一些驱动的默认配置信息,HDF框架在加载驱动的时候,会将对应的配置信息获取并保存在HdfDeviceObject 中的property里面,通过Bind和Init(参考步骤1)传递给驱动,驱动的配置信息示例如下: + + + ``` + root { + SampleDriverConfig { + sample_version = 1; + sample_bus = "I2C_0"; + match_attr = "sample_config"; //该字段的值必须和device_info.hcs中的deviceMatchAttr值一致 + } + } + ``` + + 配置信息定义之后,需要将该配置文件添加到板级配置入口文件hdf.hcs(这一块可以通过OpenHarmony驱动子系统在DevEco集成驱动开发套件工具一键式配置,具体使用方法参考驱动开发套件中的介绍),示例如下: + + + ``` + #include "device_info/device_info.hcs" + #include "sample/sample_config.hcs" + ``` + + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> 驱动加载方式支持按需加载和按序加载两种方式,具体使用方法如下: +> +> - 按需加载 +> +> ``` +> typedef enum { +> DEVICE_PRELOAD_ENABLE = 0, +> DEVICE_PRELOAD_ENABLE_STEP2, +> DEVICE_PRELOAD_DISABLE, +> DEVICE_PRELOAD_INVALID +> } DevicePreload; +> ``` +> +> 配置文件中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值越小,加载优先级越高。 diff --git a/zh-cn/device-dev/driver/driver-hdf-manage.md b/zh-cn/device-dev/driver/driver-hdf-manage.md index 9b591965f4bb551eaac376cbc622aa92ef3c4dd1..ffc6f115a4f1f787125410ee355c662d72a29fbf 100644 --- a/zh-cn/device-dev/driver/driver-hdf-manage.md +++ b/zh-cn/device-dev/driver/driver-hdf-manage.md @@ -1,125 +1,73 @@ -# 配置管理 +# 配置管理 -- [配置概述](#section59914284576) -- [配置语法](#section533713333580) - - [关键字](#section4522107333) - - [基本结构](#section853042911312) - - [数据类型](#section177001259134) - - [预处理](#section14867121641) - - [注释](#section1323412417) - - [引用修改](#section193708571145) - - [节点复制](#section1487792020513) - - [删除](#section1096515391155) - - [属性引用](#section20271317611) - - [模板](#section958819191063) -- [配置生成](#section106152531919) - - [hc-gen介绍](#section359734416616) +## 配置概述 +HCS(HDF Configuration Source)是HDF驱动框架的配置描述源码,内容以Key-Value为主要形式。它实现了配置代码与驱动代码解耦,便于开发者进行配置管理。 -## 配置概述 +HC-GEN(HDF Configuration Generator)是HCS配置转换工具,可以将HDF配置文件转换为软件可读取的文件格式: -HCS\(**H**DF **C**onfiguration **S**ource\)是HDF驱动框架的配置描述源码,内容以Key-Value为主要形式。它实现了配置代码与驱动代码解耦,便于开发者进行配置管理。 +- 在弱性能环境中,转换为配置树源码或配置树宏定义,驱动可直接调用C代码或宏式APIs获取配置。 -HC-GEN**\(H**DF **C**onfiguration **G**enerator**\)**是HCS配置转换工具,可以将HDF配置文件转换为软件可读取的文件格式: - -- 在弱性能环境中,转换为配置树源码或配置树宏定义,驱动可直接调用C代码或宏式APIs获取配置。 -- 在高性能环境中,转换为HCB\(**H**DF **C**onfiguration **B**inary\)二进制文件,驱动可使用HDF框架提供的配置解析接口获取配置。 +- 在高性能环境中,转换为HCB(HDF Configuration Binary)二进制文件,驱动可使用HDF框架提供的配置解析接口获取配置。 以下是使用HCB模式的典型应用场景: -**图 1** 配置使用流程图 -![](figures/配置使用流程图.png "配置使用流程图") + **图1** 配置使用流程图 + + ![zh-cn_image_0000001154105768](figures/zh-cn_image_0000001154105768.png) HCS经过HC-GEN编译生成HCB文件,HDF驱动框架中的HCS Parser模块会从HCB文件中重建配置树,HDF驱动模块使用HCS Parser提供的配置读取接口获取配置内容。 -## 配置语法 + +## 配置语法 HCS的语法介绍如下: -### 关键字 + +### 关键字 HCS配置语法保留了以下关键字。 -**表 1** HCS配置语法保留关键字 - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

关键字

-

用途

-

说明

-

root

-

配置根节点

-

-

-

include

-

引用其他HCS配置文件

-

-

-

delete

-

删除节点或属性

-

只能用于操作include导入的配置树

-

template

-

定义模板节点

-

-

-

match_attr

-

用于标记节点的匹配查找属性

-

解析配置时可以使用该属性的值查找到对应节点

-
- -### 基本结构 - -HCS主要分为属性\(Attribute\)和节点\(Node\)两种结构。 + **表1** HCS配置语法保留关键字 + +| 关键字 | 用途 | 说明 | +| -------- | -------- | -------- | +| root | 配置根节点 | - | +| include | 引用其他HCS配置文件 | - | +| delete | 删除节点或属性 | 只能用于操作include导入的配置树 | +| template | 定义模板节点 | - | +| match_attr | 用于标记节点的匹配查找属性 | 解析配置时可以使用该属性的值查找到对应节点 | + + +### 基本结构 + +HCS主要分为属性(Attribute)和节点(Node)两种结构。 **属性** 属性即最小的配置单元,是一个独立的配置项。语法如下: + ``` attribute_name = value; ``` -- attribute\_name 是**字母、数字、下划线**的组合且必须以字母或下划线开头,字母区分大小写。 - -- value的可用格式如下: - - - 数字常量,支持二进制、八进制、十进制、十六进制数,具体参考数据类型节。 - - - 字符串,内容使用双引号\(""\)引用。 +- attribute_name 是**字母、数字、下划线**的组合且必须以字母或下划线开头,字母区分大小写。 - - 节点引用。 +- value的可用格式如下: + - 数字常量,支持二进制、八进制、十进制、十六进制数,具体参考数据类型节。 + - 字符串,内容使用双引号("")引用。 + - 节点引用。 -- attribute 必须以分号\(;\)结束且必须属于一个node。 - +- attribute 必须以分号(;)结束且必须属于一个node。 **节点** 节点是一组属性的集合,语法如下: + ``` node_name { module = "sample"; @@ -127,40 +75,41 @@ HCS主要分为属性\(Attribute\)和节点\(Node\)两种结构。 } ``` -- node\_name 是**字母、数字、下划线**的组合且必须以字母或下划线开头,字母区分大小写。 +- node_name 是**字母、数字、下划线**的组合且必须以字母或下划线开头,字母区分大小写。 + +- 大括号后无需添加结束符“;”。 -- 大括号后无需添加结束符“;”。 +- root为保留关键字,用于声明配置表的根节点。每个配置表必须以root节点开始。 -- root为保留关键字,用于声明配置表的根节点。每个配置表必须以root节点开始。 +- root节点中必须包含module属性,其值应该为一个字符串,用于表征该配置所属模块。 -- root节点中必须包含module属性,其值应该为一个字符串,用于表征该配置所属模块。 +- 节点中可以增加match_attr属性,其值为一个全局唯一的字符串。在解析配置时可以调用查找接口以该属性的值查找到包含该属性的节点。 -- 节点中可以增加match\_attr属性,其值为一个全局唯一的字符串。在解析配置时可以调用查找接口以该属性的值查找到包含该属性的节点。 -### 数据类型 +### 数据类型 在属性定义中使用自动数据类型,不显式指定类型,属性支持的数据类型如下: **整型** -整型长度自动推断,根据实际数据长度给与最小空间占用的类型。 - -- 二进制,0b前缀,示例:0b1010。 + 整型长度自动推断,根据实际数据长度给与最小空间占用的类型。 +- 二进制,0b前缀,示例:0b1010。 -- 八进制,0前缀,示例:0664。 -- 十进制 ,无前缀,且支持有符号与无符号,示例:1024,+1024均合法。负值在读取时注意使用有符号数读取接口。 +- 八进制,0前缀,示例:0664。 -- 十六进制,0x前缀,示例:0xff00、0xFF。 +- 十进制 ,无前缀,且支持有符号与无符号,示例:1024,+1024均合法。负值在读取时注意使用有符号数读取接口。 +- 十六进制,0x前缀,示例:0xff00、0xFF。 **字符串** -字符串使用双引号\(""\)表示。 +字符串使用双引号("")表示。 **数组** -数组元素支持整型、字符串,不支持混合类型。整型数组中uint32\_t uint64\_t混用会向上转型为uint64\_t 数组。整型数组与字符串数组示例如下: +数组元素支持整型、字符串,不支持混合类型。整型数组中uint32_t uint64_t混用会向上转型为uint64_t 数组。整型数组与字符串数组示例如下: + ``` attr_foo = [0x01, 0x02, 0x03, 0x04]; attr_bar = ["hello", "world"]; @@ -170,52 +119,59 @@ attr_bar = ["hello", "world"]; bool类型中**true**表示真,**false**表示假。 -### 预处理 + +### 预处理 **include** 用于导入其他HCS文件。语法示例如下: + ``` #include "foo.hcs" #include "../bar.hcs" ``` -- 文件名必须使用双引号\(""\),不在同一目录使用相对路径引用。被include文件也必须是合法的HCS文件。 -- 多个include,如果存在相同的节点,后者覆盖前者,其余的节点依次展开。 +- 文件名必须使用双引号(""),不在同一目录使用相对路径引用。被include文件也必须是合法的HCS文件。 + +- 多个include,如果存在相同的节点,后者覆盖前者,其余的节点依次展开。 -### 注释 + +### 注释 支持两种注释风格。 -- 单行注释。 +- 单行注释。 - ``` - // comment - ``` + + ``` + // comment + ``` -- 多行注释。 +- 多行注释。 - ``` - /* - comment - */ - ``` + + ``` + /* + comment + */ + ``` - >![](../public_sys-resources/icon-note.gif) **说明:** - >多行注释不支持嵌套。 + > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** + > 多行注释不支持嵌套。 -### 引用修改 +### 引用修改 引用修改可以实现修改另外任意一个节点的内容,语法为: + ``` node :& source_node ``` -上述语句表示node中的内容是对source\_node节点内容的修改。示例如下: - + 上述语句表示node中的内容是对source_node节点内容的修改。示例如下: + ``` root { module = "sample"; @@ -239,6 +195,7 @@ root { 最终生成配置树为: + ``` root { module = "sample"; @@ -253,21 +210,25 @@ 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即为一个合法的绝对路径。 -- 如果出现修改冲突(即多处修改同一个属性),编译器将提示warning,因为这种情况下只会生效某一个修改而导致最终结果不确定。 +- 引用同级node,可以直接使用node名称,否则被引用的节点必须使用绝对路径,节点间使用“.”分隔,root表示根节点,格式为root开始的节点路径序列,例如root.foo.bar即为一个合法的绝对路径。 -### 节点复制 +- 如果出现修改冲突(即多处修改同一个属性),编译器将提示warning,因为这种情况下只会生效某一个修改而导致最终结果不确定。 + + +### 节点复制 节点复制可以实现在节点定义时从另一个节点先复制内容,用于定义内容相似的节点。语法为: + ``` node : source_node ``` -上述语句表示在定义"node"节点时将另一个节点"source\_node"的属性复制过来。示例如下: +上述语句表示在定义"node"节点时将另一个节点"source_node"的属性复制过来。示例如下: + ``` root { module = "sample"; @@ -282,6 +243,7 @@ root { 上述代码的最终生成配置树为: + ``` root { module = "sample"; @@ -295,14 +257,16 @@ root { } ``` -在上述示例中,编译后bar节点即包含attr\_0属性也包含attr\_1属性,在bar中对attr\_0的修改不会影响到foo。 +在上述示例中,编译后bar节点即包含attr_0属性也包含attr_1属性,在bar中对attr_0的修改不会影响到foo。 + +在foo和bar在同级node中可不指定foo的路径,否则需要使用绝对路径引用,参考[引用修改](#引用修改)。 -在foo和bar在同级node中可不指定foo的路径,否则需要使用绝对路径引用,参考[引用修改](#section193708571145)。 -### 删除 +### 删除 -要对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 root { @@ -322,27 +286,31 @@ root { } ``` -上述代码在生成过程中将会删除root.foo\_2节点与attr\_2,最终生成配置树为: +上述代码在生成过程中将会删除root.foo_2节点与attr_2,最终生成配置树为: + ``` root { attr_1 = 0x1; } ``` ->![](../public_sys-resources/icon-note.gif) **说明:** ->在同一个HCS文件中不允许使用delete,建议直接删除不需要的属性。 +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> 在同一个HCS文件中不允许使用delete,建议直接删除不需要的属性。 -### 属性引用 + +### 属性引用 为了在解析配置时快速定位到关联的节点,可以把节点作为属性的右值,通过读取属性查找到对应节点。语法为: + ``` attribute = &node; ``` 上述语句表示attribute的值是一个节点node的引用,在解析时可以用这个attribute快速定位到node,便于关联和查询其他node。示例如下: + ``` node1 { attributes; @@ -351,8 +319,10 @@ node2 { attr_1 = &root.node1; } ``` + 或 + ``` node2 { node1 { @@ -362,12 +332,14 @@ node2 { } ``` -### 模板 + +### 模板 模板的用途在于生成严格一致的node结构,以便对同类型node进行遍历和管理。 使用template关键字定义模板node,子node通过双冒号“::”声明继承关系。子节点可以改写但不能新增和删除template中的属性,子节点中没有定义的属性将使用template中的定义作为默认值。示例如下: + ``` root { module = "sample"; @@ -387,6 +359,7 @@ root { 生成配置树如下: + ``` root { module = "sample"; @@ -401,16 +374,19 @@ root { } ``` -在上述示例中,bar和bar\_1节点继承了foo节点,生成配置树节点结构与foo保持了完全一致,只是属性的值不同。 +在上述示例中,bar和bar_1节点继承了foo节点,生成配置树节点结构与foo保持了完全一致,只是属性的值不同。 -## 配置生成 + +## 配置生成 hc-gen是配置生成的工具,可以对HCS配置语法进行检查并把HCS源文件转化成HCB二进制文件。 -### hc-gen介绍 + +### hc-gen介绍 hc-gen参数说明: + ``` Usage: hc-gen [Options] [File] options: @@ -418,7 +394,6 @@ options: -a hcb align with four bytes -b output binary output, default enable -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 -p prefix of generated symbol name -d decompile hcb to hcs @@ -429,25 +404,28 @@ options: 生成.c/.h 配置文件方法: + ``` hc-gen -o [OutputCFileName] -t [SourceHcsFileName] ``` 生成HCB 配置文件方法: + ``` hc-gen -o [OutputHcbFileName] -b [SourceHcsFileName] ``` 生成宏定义配置文件方法: + ``` hc-gen -o [OutputMacroFileName] -m [SourceHcsFileName] ``` 反编译HCB文件为HCS方法: + ``` hc-gen -o [OutputHcsFileName] -d [SourceHcbFileName] ``` - diff --git a/zh-cn/device-dev/driver/driver-hdf-message-management.md b/zh-cn/device-dev/driver/driver-hdf-message-management.md index a956303a57cca0d1528d5664b4c6798800479f9b..27161c307123ea87643a25f1fafef216b77f989b 100644 --- a/zh-cn/device-dev/driver/driver-hdf-message-management.md +++ b/zh-cn/device-dev/driver/driver-hdf-message-management.md @@ -1,193 +1,166 @@ -# 驱动消息机制管理 +# 驱动消息机制管理 -- [使用场景](#section33014541954) -- [接口说明](#section538852311616) -- [开发步骤](#section946912121153) -## 使用场景 +## 使用场景 当用户态应用和内核态驱动需要交互时,可以使用HDF框架的消息机制来实现。 -## 接口说明 - -消息机制的功能主要有以下两种: - -1. 用户态应用发送消息到驱动。 -2. 用户态应用接收驱动主动上报事件。 - -**表 1** 消息机制接口 - - - - - - - - - - - - - - - - - - - -

方法

-

描述

-

struct HdfIoService *HdfIoServiceBind(const char *serviceName)

-

用户态获取驱动的服务,获取该服务之后通过服务中的Dispatch方法向驱动发送消息。

-

void HdfIoServiceRecycle(struct HdfIoService *service);

-

释放驱动服务。

-

int HdfDeviceRegisterEventListener(struct HdfIoService *target, struct HdfDevEventlistener *listener);

-

用户态程序注册接收驱动上报事件的操作方法。

-

int HdfDeviceSendEvent(struct HdfDeviceObject *deviceObject, uint32_t id, struct HdfSBuf *data);

-

驱动主动上报事件接口。

-
- -## 开发步骤 - -1. 将驱动配置信息中服务策略policy字段设置为2(SERVICE\_POLICY\_CAPACITY,参考[policy定义](driver-hdf-servicemanage.md))。 - - ``` - device_sample :: Device { - policy = 2; - ... - } - ``` - -2. 配置驱动信息中的服务设备节点权限(permission字段)是框架给驱动创建设备节点的权限,默认是0666,驱动开发者根据驱动的实际使用场景配置驱动设备节点的权限。 -3. 在服务实现过程中,实现服务基类成员IDeviceIoService中的Dispatch方法。 - - ``` - // Dispatch是用来处理用户态发下来的消息 - int32_t SampleDriverDispatch(struct HdfDeviceObject *device, int cmdCode, struct HdfSBuf *data, struct HdfSBuf *reply) - { - HDF_LOGE("sample driver lite A dispatch"); - return 0; - } - int32_t SampleDriverBind(struct HdfDeviceObject *device) - { - HDF_LOGE("test for lite os sample driver A Open!"); - if (device == NULL) { - HDF_LOGE("test for lite os sample driver A Open failed!"); - return -1; - } - static struct ISampleDriverService sampleDriverA = { - .ioService.Dispatch = SampleDriverDispatch, - .ServiceA = SampleDriverServiceA, - .ServiceB = SampleDriverServiceB, - }; - device->service = (struct IDeviceIoService *)(&sampleDriverA); - return 0; - } - ``` - -4. 驱动定义消息处理函数中的cmd类型。 - - ``` - #define SAMPLE_WRITE_READ 1 // 读写操作码1 - ``` - -5. 用户态获取服务接口并发送消息到驱动。 - - ``` - int SendMsg(const char *testMsg) - { - if (testMsg == NULL) { - HDF_LOGE("test msg is null"); - return -1; - } - struct HdfIoService *serv = HdfIoServiceBind("sample_driver"); - if (serv == NULL) { - HDF_LOGE("fail to get service"); - return -1; - } - struct HdfSBuf *data = HdfSBufObtainDefaultSize(); - if (data == NULL) { - HDF_LOGE("fail to obtain sbuf data"); - return -1; - } - struct HdfSBuf *reply = HdfSBufObtainDefaultSize(); - if (reply == NULL) { - HDF_LOGE("fail to obtain sbuf reply"); - ret = HDF_DEV_ERR_NO_MEMORY; - goto out; - } - if (!HdfSbufWriteString(data, testMsg)) { - HDF_LOGE("fail to write sbuf"); - ret = HDF_FAILURE; - goto out; - } - int ret = serv->dispatcher->Dispatch(&serv->object, SAMPLE_WRITE_READ, data, reply); - if (ret != HDF_SUCCESS) { - HDF_LOGE("fail to send service call"); - goto out; - } - out: - HdfSBufRecycle(data); - HdfSBufRecycle(reply); - HdfIoServiceRecycle(serv); - return ret; - } - ``` - -6. 用户态接收该驱动上报的消息。 - 1. 用户态编写驱动上报消息的处理函数。 - - ``` - static int OnDevEventReceived(void *priv, uint32_t id, struct HdfSBuf *data) - { - OsalTimespec time; - OsalGetTime(&time); - HDF_LOGE("%s received event at %llu.%llu", (char *)priv, time.sec, time.usec); - - const char *string = HdfSbufReadString(data); - if (string == NULL) { - HDF_LOGE("fail to read string in event data"); - return -1; - } - HDF_LOGE("%s: dev event received: %d %s", (char *)priv, id, string); - return 0; - } - ``` - - 2. 用户态注册接收驱动上报消息的操作方法。 - - ``` - int RegisterListen() - { - struct HdfIoService *serv = HdfIoServiceBind("sample_driver"); - if (serv == NULL) { - HDF_LOGE("fail to get service"); - return -1; - } - static struct HdfDevEventlistener listener = { - .callBack = OnDevEventReceived, - .priv ="Service0" - }; - if (HdfDeviceRegisterEventListener(serv, &listener) != 0) { - HDF_LOGE("fail to register event listener"); - return -1; - } - ...... - HdfDeviceUnregisterEventListener(serv, &listener); - HdfIoServiceRecycle(serv); - return 0; - } - ``` - - 3. 驱动上报事件。 - - ``` - int32_t SampleDriverDispatch(struct HdfDeviceObject *device, int cmdCode, struct HdfSBuf *data, struct HdfSBuf *reply) - { - ... // process api call here - return HdfDeviceSendEvent(deviceObject, cmdCode, data); - } - ``` +## 接口说明 +消息机制的功能主要有以下两种: +1. 用户态应用发送消息到驱动。 + +2. 用户态应用接收驱动主动上报事件。 + + **表1** 消息机制接口 + +| 方法 | 描述 | +| -------- | -------- | +| struct HdfIoService \*HdfIoServiceBind(const char \*serviceName); | 用户态获取驱动的服务,获取该服务之后通过服务中的Dispatch方法向驱动发送消息。 | +| void HdfIoServiceRecycle(struct HdfIoService \*service); | 释放驱动服务。 | +| int HdfDeviceRegisterEventListener(struct HdfIoService \*target, struct HdfDevEventlistener \*listener); | 用户态程序注册接收驱动上报事件的操作方法。 | +| int HdfDeviceSendEvent(struct HdfDeviceObject \*deviceObject, uint32_t id, struct HdfSBuf \*data); | 驱动主动上报事件接口。 | + + +## 开发步骤 + +1. 将驱动配置信息中服务策略policy字段设置为2(SERVICE_POLICY_CAPACITY,参考[policy定义](../driver/driver-hdf-servicemanage.md))。 + + ``` + device_sample :: Device { + policy = 2; + ... + } + ``` + +2. 配置驱动信息中的服务设备节点权限(permission字段)是框架给驱动创建设备节点的权限,默认是0666,驱动开发者根据驱动的实际使用场景配置驱动设备节点的权限。 + +3. 在服务实现过程中,实现服务基类成员IDeviceIoService中的Dispatch方法。 + + ``` + // Dispatch是用来处理用户态发下来的消息 + int32_t SampleDriverDispatch(struct HdfDeviceObject *device, int cmdCode, struct HdfSBuf *data, struct HdfSBuf *reply) + { + HDF_LOGE("sample driver lite A dispatch"); + return 0; + } + int32_t SampleDriverBind(struct HdfDeviceObject *device) + { + HDF_LOGE("test for lite os sample driver A Open!"); + if (device == NULL) { + HDF_LOGE("test for lite os sample driver A Open failed!"); + return -1; + } + static struct ISampleDriverService sampleDriverA = { + .ioService.Dispatch = SampleDriverDispatch, + .ServiceA = SampleDriverServiceA, + .ServiceB = SampleDriverServiceB, + }; + device->service = (struct IDeviceIoService *)(&sampleDriverA); + return 0; + } + ``` + +4. 驱动定义消息处理函数中的cmd类型。 + + ``` + #define SAMPLE_WRITE_READ 1 // 读写操作码1 + ``` + +5. 用户态获取服务接口并发送消息到驱动。 + + ``` + int SendMsg(const char *testMsg) + { + if (testMsg == NULL) { + HDF_LOGE("test msg is null"); + return -1; + } + struct HdfIoService *serv = HdfIoServiceBind("sample_driver"); + if (serv == NULL) { + HDF_LOGE("fail to get service"); + return -1; + } + struct HdfSBuf *data = HdfSBufObtainDefaultSize(); + if (data == NULL) { + HDF_LOGE("fail to obtain sbuf data"); + return -1; + } + struct HdfSBuf *reply = HdfSBufObtainDefaultSize(); + if (reply == NULL) { + HDF_LOGE("fail to obtain sbuf reply"); + ret = HDF_DEV_ERR_NO_MEMORY; + goto out; + } + if (!HdfSbufWriteString(data, testMsg)) { + HDF_LOGE("fail to write sbuf"); + ret = HDF_FAILURE; + goto out; + } + int ret = serv->dispatcher->Dispatch(&serv->object, SAMPLE_WRITE_READ, data, reply); + if (ret != HDF_SUCCESS) { + HDF_LOGE("fail to send service call"); + goto out; + } + out: + HdfSBufRecycle(data); + HdfSBufRecycle(reply); + HdfIoServiceRecycle(serv); + return ret; + } + ``` + +6. 用户态接收该驱动上报的消息。 + 1. 用户态编写驱动上报消息的处理函数。 + + ``` + static int OnDevEventReceived(void *priv, uint32_t id, struct HdfSBuf *data) + { + OsalTimespec time; + OsalGetTime(&time); + HDF_LOGE("%s received event at %llu.%llu", (char *)priv, time.sec, time.usec); + + const char *string = HdfSbufReadString(data); + if (string == NULL) { + HDF_LOGE("fail to read string in event data"); + return -1; + } + HDF_LOGE("%s: dev event received: %d %s", (char *)priv, id, string); + return 0; + } + ``` + 2. 用户态注册接收驱动上报消息的操作方法。 + + ``` + int RegisterListen() + { + struct HdfIoService *serv = HdfIoServiceBind("sample_driver"); + if (serv == NULL) { + HDF_LOGE("fail to get service"); + return -1; + } + static struct HdfDevEventlistener listener = { + .callBack = OnDevEventReceived, + .priv ="Service0" + }; + if (HdfDeviceRegisterEventListener(serv, &listener) != 0) { + HDF_LOGE("fail to register event listener"); + return -1; + } + ...... + HdfDeviceUnregisterEventListener(serv, &listener); + HdfIoServiceRecycle(serv); + return 0; + } + ``` + 3. 驱动上报事件。 + + ``` + int32_t SampleDriverDispatch(struct HdfDeviceObject *device, int cmdCode, struct HdfSBuf *data, struct HdfSBuf *reply) + { + ... // process api call here + return HdfDeviceSendEvent(deviceObject, cmdCode, data); + } + ``` diff --git a/zh-cn/device-dev/driver/driver-hdf-overview.md b/zh-cn/device-dev/driver/driver-hdf-overview.md index d0bbfd27e28aad1beaa861c0182caaa4cace8fa0..601e10ee75cf3617d235f8d6a440edf984eb7b22 100755 --- a/zh-cn/device-dev/driver/driver-hdf-overview.md +++ b/zh-cn/device-dev/driver/driver-hdf-overview.md @@ -1,32 +1,27 @@ -# HDF开发概述 +# HDF开发概述 -- [简介](#section0649162112376) -- [驱动加载](#section68701942154319) -- [驱动服务管理](#section12453133414412) -- [驱动消息机制](#section129410710451) -## 简介 +## 简介 HDF(Hardware Driver Foundation)驱动框架,为驱动开发者提供驱动框架能力,包括驱动加载、驱动服务管理和驱动消息机制。旨在构建统一的驱动架构平台,为驱动开发者提供更精准、更高效的开发环境,力求做到一次开发,多系统部署。 -## 驱动加载 -HDF驱动加载包括按需加载和按序加载。 - -- 按需加载 +## 驱动加载 - HDF框架支持驱动在系统启动过程中默认加载,或者在系统启动之后动态加载。 +HDF驱动加载包括按需加载和按序加载。 -- 按序加载 +- 按需加载 + HDF框架支持驱动在系统启动过程中默认加载,或者在系统启动之后动态加载。 - HDF框架支持驱动在系统启动的过程中按照驱动的优先级进行加载。 +- 按序加载 + HDF框架支持驱动在系统启动的过程中按照驱动的优先级进行加载。 -## 驱动服务管理 +## 驱动服务管理 HDF框架可以集中管理驱动服务,开发者可直接通过HDF框架对外提供的能力接口获取驱动相关的服务。 -## 驱动消息机制 -HDF框架提供统一的驱动消息机制,支持用户态应用向内核态驱动发送消息,也支持内核态驱动向用户态应用发送消息。 +## 驱动消息机制 +HDF框架提供统一的驱动消息机制,支持用户态应用向内核态驱动发送消息,也支持内核态驱动向用户态应用发送消息。 diff --git a/zh-cn/device-dev/driver/driver-hdf-sample.md b/zh-cn/device-dev/driver/driver-hdf-sample.md index 6ddc48cb36248e2c55265b70ea9e9968097b4c6f..a8e78b6998e0d415a2c225566486165783f426ff 100644 --- a/zh-cn/device-dev/driver/driver-hdf-sample.md +++ b/zh-cn/device-dev/driver/driver-hdf-sample.md @@ -1,15 +1,14 @@ -# HDF开发实例 +# HDF开发实例 -- [添加配置](#section27261067111) -- [编写驱动代码](#section177988005) -- [编写用户程序和驱动交互代码](#section6205173816412) 下面基于HDF框架,提供一个完整的样例,包含配置文件的添加,驱动代码的实现以及用户态程序和驱动交互的流程。 -## 添加配置 -在HDF框架的配置文件(例如vendor/hisilicon/xxx/hdf_config/device\_info)中添加该驱动的配置信息,如下所示: +## 添加配置 +在HDF框架的配置文件(例如vendor/hisilicon/xxx/hdf_config/device_info)中添加该驱动的配置信息,如下所示: + + ``` root { device_info { @@ -46,10 +45,12 @@ root { } ``` -## 编写驱动代码 -基于HDF框架编写的sample驱动代码如下(编译参考 [驱动开发](driver-hdf-development.md)): +## 编写驱动代码 + +基于HDF框架编写的sample驱动代码如下(编译参考[驱动开发](../driver/driver-hdf-development.md)): + ``` #include #include @@ -118,10 +119,12 @@ struct HdfDriverEntry g_sampleDriverEntry = { HDF_INIT(g_sampleDriverEntry); ``` -## 编写用户程序和驱动交互代码 -基于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 #include @@ -229,10 +232,13 @@ int main() } ``` ->![](../public_sys-resources/icon-note.gif) **说明:** ->用户态应用程序使用了HDF框架中的消息发送接口,因此在编译用户态程序的过程中需要依赖HDF框架对外提供的hdf\_core和osal的动态库,在gn编译文件中添加如下依赖项: ->deps = \[ ->"//drivers/adapter/uhdf/manager:hdf\_core", ->"//drivers/adapter/uhdf/posix:hdf\_posix\_osal", ->\] - +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> 用户态应用程序使用了HDF框架中的消息发送接口,因此在编译用户态程序的过程中需要依赖HDF框架对外提供的hdf_core和osal的动态库,在gn编译文件中添加如下依赖项: +> +> deps = [ +> +> "//drivers/adapter/uhdf/manager:hdf_core", +> +> "//drivers/adapter/uhdf/posix:hdf_posix_osal", +> +> ] diff --git a/zh-cn/device-dev/driver/driver-hdf-servicemanage.md b/zh-cn/device-dev/driver/driver-hdf-servicemanage.md index 06d76d7042d22a6e73a224ef7179008f1e2c4f9e..66ea6eaa54a3470268f5e1598ae713e343c42334 100755 --- a/zh-cn/device-dev/driver/driver-hdf-servicemanage.md +++ b/zh-cn/device-dev/driver/driver-hdf-servicemanage.md @@ -1,13 +1,13 @@ -# 驱动服务管理 +# 驱动服务管理 -- [使用场景](#section14244270117) -- [接口说明](#section1432412561722) -- [开发步骤](#section393515164416) 驱动服务是HDF驱动设备对外提供能力的对象,由HDF框架统一管理。驱动服务管理主要包含驱动服务的发布和获取。 + HDF框架定义了驱动对外发布服务的策略,是由配置文件中的policy字段来控制,policy字段的取值范围以及含义如下: + + ``` typedef enum { /* 驱动不提供服务 */ @@ -25,141 +25,119 @@ typedef enum { } ServicePolicy; ``` -## 使用场景 + +## 使用场景 当驱动以接口的形式对外提供能力时,可以使用HDF框架的驱动服务管理能力。 -## 接口说明 + +## 接口说明 针对驱动服务管理功能,HDF框架开放了以下接口供开发者调用,如下表所示: -**表 1** 服务管理接口 - - - - - - - - - - - - - - - - -

方法

-

描述

-

int32_t (*Bind)(struct HdfDeviceObject *deviceObject);

-

需要驱动开发者实现Bind函数,将自己的服务接口绑定到HDF框架中。

-

const struct HdfObject *DevSvcManagerClntGetService(const char *svcName);

-

获取驱动的服务。

-

int HdfDeviceSubscribeService(

-

struct HdfDeviceObject *deviceObject, const char *serviceName, struct SubscriberCallback callback);

-

订阅驱动的服务。

-
- -## 开发步骤 + **表1** 服务管理接口 -驱动服务管理的开发包括驱动服务的编写、绑定、获取或者订阅,详细步骤如下。 +| 方法 | 描述 | +| -------- | -------- | +| int32_t (\*Bind)(struct HdfDeviceObject \*deviceObject); | 需要驱动开发者实现Bind函数,将自己的服务接口绑定到HDF框架中。 | +| const struct HdfObject \*DevSvcManagerClntGetService(const char \*svcName); | 获取驱动的服务。 | +| int HdfDeviceSubscribeService(
struct HdfDeviceObject \*deviceObject, const char \*serviceName, struct SubscriberCallback callback); | 订阅驱动的服务。 | -1. 驱动服务发布。 - - ``` - 驱动服务结构的定义 - struct ISampleDriverService { - struct IDeviceIoService ioService; // 服务结构的首个成员必须是IDeviceIoService类型的成员 - int32_t (*ServiceA)(void); // 驱动的第一个服务接口 - int32_t (*ServiceB)(uint32_t inputCode); // 驱动的第二个服务接口,有多个可以依次往下累加 - }; - - 驱动服务接口的实现 - int32_t SampleDriverServiceA(void) - { - // 驱动开发者实现业务逻辑 - return 0; - } - - int32_t SampleDriverServiceB(uint32_t inputCode) - { - // 驱动开发者实现业务逻辑 - return 0; - } - ``` - -2. 驱动服务绑定到HDF框架中,实现HdfDriverEntry中的Bind指针函数。 - - ``` - int32_t SampleDriverBind(struct HdfDeviceObject *deviceObject) - { - // deviceObject为HDF框架给每一个驱动创建的设备对象,用来保存设备相关的私有数据和服务接口 - if (deviceObject == NULL) { - HDF_LOGE("Sample device object is null!"); - return -1; - } - static struct ISampleDriverService sampleDriverA = { - .ServiceA = SampleDriverServiceA, - .ServiceB = SampleDriverServiceB, - }; - deviceObject->service = &sampleDriverA.ioService; - return 0; - } - ``` - -3. 驱动服务获取。 - - 驱动服务的获取有两种方式,HDF框架提供接口直接获取和HDF框架提供订阅机制获取。 - - - 通过HDF接口直接获取 - - 当明确驱动已经加载完成时,获取该驱动的服务可以通过HDF框架提供的能力接口直接获取,如下所示: - - ``` - const struct ISampleDriverService *sampleService = - (const struct ISampleDriverService *)DevSvcManagerClntGetService("sample_driver"); - if (sampleService == NULL) { - return -1; - } - sampleService->ServiceA(); - sampleService->ServiceB(5); - ``` - - - 通过HDF提供的订阅机制获取 - - 当内核态对驱动(同一个host)加载的时机不感知时,可以通过HDF框架提供的订阅机制来订阅该驱动,当该驱动加载完成时,HDF框架会将被订阅的驱动服务发布给订阅者,实现方式如下所示: - - ``` - // 订阅回调函数的编写,当被订阅的驱动加载完成后,HDF框架会将被订阅驱动的服务发布给订阅者,通过这个回调函数给订阅者使用 - // object为订阅者的私有数据,service为被订阅的服务对象 - int32_t TestDriverSubCallBack(struct HdfDeviceObject *deviceObject, const struct HdfObject *service) - { - const struct ISampleDriverService *sampleService = - (const struct ISampleDriverService *)service; - if (sampleService == NULL) { - return -1; - } - sampleService->ServiceA(); - sampleService->ServiceB(5); - } - // 订阅过程的实现 - int32_t TestDriverInit(struct HdfDeviceObject *deviceObject) - { - if (deviceObject == NULL) { - HDF_LOGE("Test driver init failed, deviceObject is null!"); - return -1; - } - struct SubscriberCallback callBack; - callBack.deviceObject = deviceObject; - callBack.OnServiceConnected = TestDriverSubCallBack; - int32_t ret = HdfDeviceSubscribeService(deviceObject, "sample_driver", callBack); - if (ret != 0) { - HDF_LOGE("Test driver subscribe sample driver failed!"); - } - return ret; - } - ``` +## 开发步骤 +驱动服务管理的开发包括驱动服务的编写、绑定、获取或者订阅,详细步骤如下。 +1. 驱动服务发布。 + + ``` + 驱动服务结构的定义 + struct ISampleDriverService { + struct IDeviceIoService ioService; // 服务结构的首个成员必须是IDeviceIoService类型的成员 + int32_t (*ServiceA)(void); // 驱动的第一个服务接口 + int32_t (*ServiceB)(uint32_t inputCode); // 驱动的第二个服务接口,有多个可以依次往下累加 + }; + + 驱动服务接口的实现 + int32_t SampleDriverServiceA(void) + { + // 驱动开发者实现业务逻辑 + return 0; + } + + int32_t SampleDriverServiceB(uint32_t inputCode) + { + // 驱动开发者实现业务逻辑 + return 0; + } + ``` + +2. 驱动服务绑定到HDF框架中,实现HdfDriverEntry中的Bind指针函数。 + + ``` + int32_t SampleDriverBind(struct HdfDeviceObject *deviceObject) + { + // deviceObject为HDF框架给每一个驱动创建的设备对象,用来保存设备相关的私有数据和服务接口 + if (deviceObject == NULL) { + HDF_LOGE("Sample device object is null!"); + return -1; + } + static struct ISampleDriverService sampleDriverA = { + .ServiceA = SampleDriverServiceA, + .ServiceB = SampleDriverServiceB, + }; + deviceObject->service = &sampleDriverA.ioService; + return 0; + } + ``` + +3. 驱动服务获取。 + 驱动服务的获取有两种方式,HDF框架提供接口直接获取和HDF框架提供订阅机制获取。 + + - 通过HDF接口直接获取 + 当明确驱动已经加载完成时,获取该驱动的服务可以通过HDF框架提供的能力接口直接获取,如下所示: + + + ``` + const struct ISampleDriverService *sampleService = + (const struct ISampleDriverService *)DevSvcManagerClntGetService("sample_driver"); + if (sampleService == NULL) { + return -1; + } + sampleService->ServiceA(); + sampleService->ServiceB(5); + ``` + - 通过HDF提供的订阅机制获取 + 当内核态对驱动(同一个host)加载的时机不感知时,可以通过HDF框架提供的订阅机制来订阅该驱动,当该驱动加载完成时,HDF框架会将被订阅的驱动服务发布给订阅者,实现方式如下所示: + + + ``` + // 订阅回调函数的编写,当被订阅的驱动加载完成后,HDF框架会将被订阅驱动的服务发布给订阅者,通过这个回调函数给订阅者使用 + // object为订阅者的私有数据,service为被订阅的服务对象 + int32_t TestDriverSubCallBack(struct HdfDeviceObject *deviceObject, const struct HdfObject *service) + { + const struct ISampleDriverService *sampleService = + (const struct ISampleDriverService *)service; + if (sampleService == NULL) { + return -1; + } + sampleService->ServiceA(); + sampleService->ServiceB(5); + } + // 订阅过程的实现 + int32_t TestDriverInit(struct HdfDeviceObject *deviceObject) + { + if (deviceObject == NULL) { + HDF_LOGE("Test driver init failed, deviceObject is null!"); + return -1; + } + struct SubscriberCallback callBack; + callBack.deviceObject = deviceObject; + callBack.OnServiceConnected = TestDriverSubCallBack; + int32_t ret = HdfDeviceSubscribeService(deviceObject, "sample_driver", callBack); + if (ret != 0) { + HDF_LOGE("Test driver subscribe sample driver failed!"); + } + return ret; + } + ``` diff --git a/zh-cn/device-dev/driver/driver-hdf.md b/zh-cn/device-dev/driver/driver-hdf.md index ab9e53aaec4cbbf64fdc75af82412bc847c742b2..47532afc649f2bdb179cee45588016596c4398ce 100644 --- a/zh-cn/device-dev/driver/driver-hdf.md +++ b/zh-cn/device-dev/driver/driver-hdf.md @@ -1,15 +1,15 @@ -# HDF驱动框架 +# HDF驱动框架 -- **[HDF开发概述](driver-hdf-overview.md)** -- **[驱动开发](driver-hdf-development.md)** -- **[驱动服务管理](driver-hdf-servicemanage.md)** +- **[HDF开发概述](driver-hdf-overview.md)** -- **[驱动消息机制管理](driver-hdf-message-management.md)** +- **[驱动开发](driver-hdf-development.md)** -- **[配置管理](driver-hdf-manage.md)** +- **[驱动服务管理](driver-hdf-servicemanage.md)** -- **[HDF开发实例](driver-hdf-sample.md)** +- **[驱动消息机制管理](driver-hdf-message-management.md)** +- **[配置管理](driver-hdf-manage.md)** +- **[HDF开发实例](driver-hdf-sample.md)** \ No newline at end of file diff --git a/zh-cn/device-dev/driver/driver-peripherals-external-des.md b/zh-cn/device-dev/driver/driver-peripherals-external-des.md index 2c2a6fe9d6e99631e69e1935e9f48de9a09b4117..7bcb11a6eccf16a32a8c4acc3569b438e3b469d6 100644 --- a/zh-cn/device-dev/driver/driver-peripherals-external-des.md +++ b/zh-cn/device-dev/driver/driver-peripherals-external-des.md @@ -1,22 +1,17 @@ -# WLAN +# WLAN -- [概述](#section729758162218) - - [WLAN驱动接口架构](#section178022416377) -- [接口说明](#section7331102018815) -- [开发步骤](#section15957746172412) -- [开发实例](#section1395253612512) +## 概述 -## 概述 +WLAN是基于HDF(Hardware Driver Foundation)驱动框架开发的模块,该模块可实现跨操作系统迁移,自适应器件差异,模块化拼装编译等功能。各WLAN厂商驱动开发人员可根据WLAN模块提供的向下统一接口适配各自的驱动代码,实现如下能力:建立/关闭WLAN热点、扫描、关联WLAN热点等;对HDI层向上提供能力如下:设置MAC地址、设置发射功率、获取设备的MAC地址等。WLAN模块框架图如下: -WLAN是基于HDF(Hardware Driver Foundation)驱动框架开发的模块,该模块可实现跨操作系统迁移,自适应器件差异,模块化拼装编译等功能。各WLAN厂商驱动开发人员可根据WLAN模块提供的向下统一接口适配各自的驱动代码,实现如下能力:建立/关闭WLAN热点、扫描、关联WLAN热点等;对HDI层向上提供能力如下:设置MAC地址、设置发射功率、获取设备的MAC地址等。[WLAN模块框架图](#fig4415112614415)如下: + **图1** WLAN框架 + ![zh-cn_image_0000001200092359](figures/zh-cn_image_0000001200092359.png) -**图 1** WLAN框架 -![](figures/WLAN框架.png "WLAN框架") -### WLAN驱动接口架构 +### WLAN驱动接口架构 -WLAN模块有三部分对外开放的API接口,如[下图2](#fig1492411431166)所示: +WLAN模块有三部分对外开放的API接口,如下图所示: 1. 对HDI层提供的能力接口。 @@ -24,227 +19,105 @@ WLAN模块有三部分对外开放的API接口,如[下图2](#fig1492411431166) 3. 提供给各厂商实现的能力接口。 -**图 2** WLAN模块开放能力分布图 -![](figures/WLAN模块开放能力分布图.png "WLAN模块开放能力分布图") - -## 接口说明 - -WLAN驱动模块提供给驱动开发人员可直接调用的能力接口,主要功能有:创建/释放WifiModule、关联/取消关联、申请/释放NetBuf、lwip的pbuf和NetBuf的相互转换等。提供的部分接口说明如[表1](#table1521573319472)所示: - -**表 1** 可直接调用的接口 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

头文件

-

接口名称

-

功能描述

-

wifi_module.h

-

-

struct WifiModule *WifiModuleCreate(const struct HdfConfigWifiModuleConfig *config);

-

基于HDF开发WLAN驱动时,创建一个WifiModule。

-

void WifiModuleDelete(struct WifiModule *module);

-

基于HDF开发WLAN驱动时,删除并释放WifiModule所有数据。

-

int32_t DelFeature(struct WifiModule *module, uint16_t featureType);

-

基于HDF开发WLAN驱动时,从WifiModule删除一个功能组件。

-

int32_t AddFeature(struct WifiModule *module, uint16_t featureType, struct WifiFeature *featureData);

-

基于HDF开发WLAN驱动时,注册一个功能组件到WifiModule。

-

wifi_mac80211_ops.h

-

int32_t (*startAp)(NetDevice *netDev);

-

启动AP。

-

int32_t (*stopAp)(NetDevice *netDev);

-

停止AP。

-

int32_t (*connect)(NetDevice *netDev, WifiConnectParams *param);

-

开始关联。

-

int32_t (*disconnect)(NetDevice *netDev, uint16_t reasonCode);

-

取消关联。

-

hdf_netbuf.h

-

static inline void NetBufQueueInit(struct NetBufQueue *q);

-

初始化NetBuf队列。

-

struct NetBuf *NetBufAlloc(uint32_t size);

-

申请NetBuf。

-

void NetBufFree(struct NetBuf *nb);

-

释放NetBuf。

-

struct NetBuf *Pbuf2NetBuf(const struct NetDevice *netdev, struct pbuf *lwipBuf);

-

lwip的pbuf转换为NetBuf。

-

struct pbuf *NetBuf2Pbuf(const struct NetBuf *nb);

-

NetBuf转换为lwip的pbuf。

-
- -同时WLAN驱动模块也提供了需要驱动开发人员实现的能力接口,主要功能有:初始化/注销NetDevice、打开/关闭NetDevice、获取NetDevice的状态等。提供的部分接口说明如[表2](#table74613501475)所示: - -**表 2** 需要开发人员实现的接口 - - - - - - - - - - - - - - - - - - - - - - - - - - - -

头文件

-

接口名称

-

功能描述

-

net_device.h

-

int32_t (*init)(struct NetDevice *netDev);

-

初始化NetDevice。

-

struct NetDevStats *(*getStats)(struct NetDevice *netDev);

-

获取NetDevice的状态。

-

int32_t (*setMacAddr)(struct NetDevice *netDev, void *addr);

-

设置Mac地址。

-

void (*deInit)(struct NetDevice *netDev);

-

注销NetDevice。

-

int32_t (*open)(struct NetDevice *netDev);

-

打开NetDevice。

-

int32_t (*stop)(struct NetDevice *netDev);

-

关闭NetDevice。

-
- -WLAN驱动模块对HDI层提供的能力接口,主要功能有:创建/销毁 IWiFi对象、设置MAC地址等。提供的部分接口说明如[表3](#table141076311618)所示: - -**表 3** HAL层对外接口 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

头文件

-

接口名称

-

功能描述

-

wifi_hal.h

-

-

int32_t WifiConstruct(struct IWiFi **wifiInstance);

-

创建IWiFi对象,提供IWiFi基本能力。

-

int32_t WifiDestruct(struct IWiFi **wifiInstance);

-

销毁IWiFi对象。

-

int32_t (*start)(struct IWiFi *);

-

创建HAL和驱动之间的通道及获取驱动支持的网卡信息。

-

int32_t (*stop)(struct IWiFi *);

-

销毁通道。

-

wifi_hal_base_feature.h

-

int32_t (*getFeatureType)(const struct IWiFiBaseFeature *);

-

获取特性的类型。

-

int32_t (*setMacAddress)(const struct IWiFiBaseFeature *, unsigned char *, uint8_t);

-

设置MAC地址。

-

int32_t (*getDeviceMacAddress)(const struct IWiFiBaseFeature *, unsigned char *, uint8_t);

-

获取设备持久化的MAC地址。

-

int32_t (*setTxPower)(const struct IWiFiBaseFeature *, int32_t);

-

设置发射功率。

-
- -## 开发步骤 + **图2** WLAN模块开放能力分布图 + ![zh-cn_image_0000001197807387](figures/zh-cn_image_0000001197807387.png) + + +## 接口说明 + +WLAN驱动模块提供给驱动开发人员可直接调用的能力接口,主要功能有:创建/释放WifiModule、关联/取消关联、申请/释放NetBuf、lwip的pbuf和NetBuf的相互转换等。 + +可直接调用的接口如下: + + **表1** wifi_module.h + +| 接口名称 | 功能描述 | +| -------- | -------- | +| struct WifiModule \*WifiModuleCreate(const struct HdfConfigWifiModuleConfig \*config) | 基于HDF开发WLAN驱动时,创建一个WifiModule。 | +| void WifiModuleDelete(struct WifiModule \*module) | 基于HDF开发WLAN驱动时,删除并释放WifiModule所有数据。 | +| int32_t DelFeature(struct WifiModule \*module, uint16_t featureType) | 基于HDF开发WLAN驱动时,从WifiModule删除一个功能组件。 | +| int32_t AddFeature(struct WifiModule \*module, uint16_t featureType, struct WifiFeature \*featureData) | 基于HDF开发WLAN驱动时,注册一个功能组件到WifiModule。 | + + **表2** wifi_mac80211_ops.h + +| 接口名称 | 功能描述 | +| -------- | -------- | +| int32_t (\*startAp)(NetDevice \*netDev) | 启动AP。 | +| int32_t (\*stopAp)(NetDevice \*netDev) | 停止AP。 | +| int32_t (\*connect)(NetDevice \*netDev, WifiConnectParams \*param) | 开始关联。 | +| int32_t (\*disconnect)(NetDevice \*netDev, uint16_t reasonCode) | 取消关联。 | + + **表3** hdf_netbuf.h + +| 接口名称 | 功能描述 | +| -------- | -------- | +| static inline void NetBufQueueInit(struct NetBufQueue \*q) | 初始化NetBuf队列。 | +| struct NetBuf \*NetBufAlloc(uint32_t size) | 申请NetBuf。 | +| void NetBufFree(struct NetBuf \*nb) | 释放NetBuf | +| struct NetBuf \*Pbuf2NetBuf(const struct NetDevice \*netdev, struct pbuf \*lwipBuf) | lwip的pbuf转换为NetBuf。 | +| struct pbuf \*NetBuf2Pbuf(const struct NetBuf \*nb) | NetBuf转换为lwip的pbuf。 | + +同时WLAN驱动模块也提供了需要驱动开发人员实现的能力接口,主要功能有:初始化/注销NetDevice、打开/关闭NetDevice、获取NetDevice的状态等。提供的部分接口说明如下表所示: + + **表4** net_device.h + +| 接口名称 | 功能描述 | +| -------- | -------- | +| int32_t (\*init)(struct NetDevice \*netDev) | 初始化NetDevice。 | +| struct NetDevStats \*(\*getStats)(struct NetDevice \*netDev) | 获取NetDevice的状态。 | +| int32_t (\*setMacAddr)(struct NetDevice \*netDev, void \*addr) | 设置Mac地址。 | +| void (\*deInit)(struct NetDevice \*netDev) | 注销NetDevice。 | +| int32_t (\*open)(struct NetDevice \*netDev) | 打开NetDevice。 | +| int32_t (\*stop)(struct NetDevice \*netDev) | 关闭NetDevice。 | + +WLAN驱动模块对HDI层提供的能力接口,主要功能有:创建/销毁 IWiFi对象、设置MAC地址等。提供的部分接口说明如下表所示: + + **表5** wifi_hal.h + +| 接口名称 | 功能描述 | +| -------- | -------- | +| int32_t WifiConstruct(struct IWiFi \*\*wifiInstance) | 创建IWiFi对象,提供IWiFi基本能力。 | +| int32_t WifiDestruct(struct IWiFi \*\*wifiInstance) | 销毁IWiFi对象。 | +| int32_t (\*start)(struct IWiFi \*) | 创建HAL和驱动之间的通道及获取驱动支持的网卡信息。 | +| int32_t (\*stop)(struct IWiFi \*) | 销毁通道。 | + + **表6** wifi_hal_base_feature.h + +| 接口名称 | 功能描述 | +| -------- | -------- | +| int32_t (\*getFeatureType)(const struct IWiFiBaseFeature \*) | 获取特性的类型。 | +| int32_t (\*setMacAddress)(const struct IWiFiBaseFeature \*, unsigned char \*, uint8_t) | 设置MAC地址。 | +| int32_t (\*getDeviceMacAddress)(const struct IWiFiBaseFeature \*, unsigned char \*, uint8_t) | 获取设备持久化的MAC地址。 | +| int32_t (\*setTxPower)(const struct IWiFiBaseFeature \*, int32_t) | 设置发射功率。 | + + +## 开发步骤 WLAN驱动基于HDF框架和PLATFORM框架开发,不区分OS和芯片平台,为不同厂商的WLAN模组提供统一的驱动模型,各WLAN模组厂商根据如下指导适配WLAN驱动框架。 -1. 通过wifi\_config.hcs文件,配置硬件参数:module\(不同feature\),芯片等。 -2. 解析配置文件, 生成全量配置的结构体对象。 -3. Module初始化,创建Module。 -4. 挂接chip,初始化chip。 -5. 总线初始化。 -6. 上层wpa业务挂接。 ->![](../public_sys-resources/icon-note.gif) **说明:** ->以上驱动框架适配步骤一部分已经提供(详细见开发实例),待开发人员实现的部分有:1、根据硬件,修改配置参数;2、适配挂接chip;3、测试自验证。 +1. 通过wifi_config.hcs文件,配置硬件参数:module(不同feature),芯片等。 + +2. 解析配置文件, 生成全量配置的结构体对象。 + +3. Module初始化,创建Module。 + +4. 挂接chip,初始化chip。 + +5. 总线初始化。 -## 开发实例 +6. 上层wpa业务挂接。 + + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> 以上驱动框架适配步骤一部分已经提供(详细见开发实例),待开发人员实现的部分有:1、根据硬件,修改配置参数;2、适配挂接chip;3、测试自验证。 + + +## 开发实例 本例程提供WLAN模块初始化过程的完整使用流程。示例如下(以hi3881WLAN芯片为例): -1、根据硬件,修改配置参数。 + 1、根据硬件,修改配置参数。 ``` /* 根据硬件参数,通过wlan_platform.hcs配置相关参数,以下是WLAN平台配置的示例 */ @@ -296,7 +169,7 @@ root { } ``` -2、适配挂接WLAN芯片的初始化和去初始化、WLAN芯片驱动的初始化和去初始化 + 2、适配挂接WLAN芯片的初始化和去初始化、WLAN芯片驱动的初始化和去初始化 ``` /* WLAN初始化挂接流程 */ @@ -416,6 +289,7 @@ struct HdfDriverEntry g_hdfHisiChipEntry = { HDF_INIT(g_hdfHisiChipEntry); ``` + ``` #include "hdf_wifi_product.h" #include "hi_wifi_api.h" @@ -425,7 +299,7 @@ HDF_INIT(g_hdfHisiChipEntry); #endif #include "wifi_mac80211_ops.h" #include "wal_cfg80211.h" -#include "net_adpater.h" +#include "net_adapter.h" #include "hdf_wlan_utils.h" #define HDF_LOG_TAG Hi3881Driver @@ -511,7 +385,7 @@ int32_t Hi3881Deinit(struct HdfChipDriver *chipDriver, struct NetDevice *netDevi } ``` -3、在芯片侧初始化过程中调用netdev的init和add接口进行初始化netdev,并挂接netdev的一些函数指针 + 3、在芯片侧初始化过程中调用netdev的init和add接口进行初始化netdev,并挂接netdev的一些函数指针 ``` hi_s32 wal_init_drv_wlan_netdev(nl80211_iftype_uint8 type, wal_phy_mode mode, hi_char* ifname, hi_u32* len) @@ -562,6 +436,7 @@ hi_s32 wal_init_netif(nl80211_iftype_uint8 type, oal_net_device_stru *netdev, co 4、WifiMac80211Ops中的函数挂接实现。 + ``` /* 挂接mac80211的一些函数指针 */ @@ -611,4 +486,3 @@ hi_void HiMac80211Init(struct HdfChipDriver *chipDriver) chipDriver->apOps = &g_apOps; } ``` - diff --git a/zh-cn/device-dev/driver/driver-peripherals-lcd-des.md b/zh-cn/device-dev/driver/driver-peripherals-lcd-des.md index b07d6c9e3cfd691876810e7ba647a304b4de1c4f..b0dc6ea6e86d05f1f03e013a4b442c039576bab9 100644 --- a/zh-cn/device-dev/driver/driver-peripherals-lcd-des.md +++ b/zh-cn/device-dev/driver/driver-peripherals-lcd-des.md @@ -1,66 +1,75 @@ -# LCD +# LCD -## 概述 +## 概述 -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驱动模型 -![](figures/基于HDF驱动框架的Display驱动模型.png "基于HDF驱动框架的Display驱动模型") + **图1** 基于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侧驱动解耦,主要完成芯片平台相关的参数配置,并传递平台驱动层的调用到器件驱动层。 -- LCD器件驱动层:在器件驱动层中,主要实现和器件自身强相关的驱动适配接口,例如发送初始化序列、上下电、背光设置等。 + +Display驱动模型主要由平台驱动层、芯片平台适配层、LCD器件驱动层三部分组成。驱动模型基于HDF驱动框架开发,通过Platform层和OSAL层提供的接口,屏蔽内核形态的差异,使得器件驱动可以便利的迁移到不同OS及芯片平台。模型向上对接Display公共HAL层,支撑HDI(Hardware Display Interface)接口的实现,通过Display-HDI对图形服务提供各类驱动能力接口。 + +- Display平台驱动层:通过HDF提供的IOService数据通道,与公共HAL层对接,集中接收并处理各类上层调用指令。 + +- SoC平台驱动适配层:借助此SoC适配层,实现Display驱动和SoC侧驱动解耦,主要完成芯片平台相关的参数配置,并传递平台驱动层的调用到器件驱动层。 + +- LCD器件驱动层:在器件驱动层中,主要实现和器件自身强相关的驱动适配接口,例如发送初始化序列、上下电、背光设置等。 基于Display驱动模型开发LCD驱动,可以借助平台提供的各种能力及接口,较大程度的降低器件驱动的开发周期和难度,提升开发效率。 -## 接口说明 + +## 接口说明 LCD接口通常可分为MIPI DSI接口、TTL接口和LVDS接口,常用的是MIPI DSI接口和TTL接口,下面对常用的MIPI DSI接口和TTL接口作简要介绍。 -- MIPI DSI接口 +- MIPI DSI接口 + + **图2** MIPI DSI接口 + + ![zh-cn_image_0000001147040198](figures/zh-cn_image_0000001147040198.png) - **图 2** MIPI DSI接口 - ![](figures/MIPI-DSI接口.png "MIPI-DSI接口") + 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接口 - **图 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接口等。 -## 开发步骤 +## 开发步骤 -Display驱动模型基于HDF驱动框架、Platform接口及OSAL接口开发,可以做到不区分OS(LiteOS、Linux)和芯片平台(Hi35xx、Hi38xx、V3S等),为LCD器件提供统一的驱动模型。 +Display驱动模型基于HDF驱动框架、Platform接口及OSAL接口开发,可以做到不区分OS(LiteOS、Linux)和芯片平台(Hi35xx、Hi38xx、V3S等),为LCD器件提供统一的驱动模型。开发步骤如下: -1. 添加LCD驱动相关的设备描述配置。 -2. 在SOC平台驱动适配层中适配对应的芯片平台驱动。 -3. 添加器件驱动,并在驱动入口函数Init中注册Panel驱动数据,驱动数据接口主要包括如下接口: - - LCD上下电 - 根据LCD硬件连接,使用Platform接口层提供的GPIO操作接口操作对应LCD管脚,例如复位管脚、IOVCC管脚,上电时序参考LCD供应商提供的SPEC。 +1. 添加LCD驱动相关的设备描述配置。 - - 发送初始化序列 +2. 在SoC平台驱动适配层中适配对应的芯片平台驱动。 - 根据LCD硬件接口,使用Platform接口层提供的I2C、SPI、MIPI等接口,下载LCD初始化序列,初始化参数序列可以参考LCD供应商提供的SPEC。 +3. 添加器件驱动,并在驱动入口函数Init中注册Panel驱动数据,驱动数据接口主要包括如下接口: + - LCD上下电 + 根据LCD硬件连接,使用Platform接口层提供的GPIO操作接口操作对应LCD管脚,例如复位管脚、IOVCC管脚,上电时序参考LCD供应商提供的SPEC。 + - 发送初始化序列 + 根据LCD硬件接口,使用Platform接口层提供的I2C、SPI、MIPI等接口,下载LCD初始化序列,初始化参数序列可以参考LCD供应商提供的SPEC。 -4. 根据需求实现HDF框架其他接口,比如Release接口。 -5. 根据需求使用HDF框架可创建其他设备节点,用于业务逻辑或者调试功能。 +4. 根据需求实现HDF框架其他接口,比如Release接口。 -## 开发实例 +5. 根据需求使用HDF框架可创建其他设备节点,用于业务逻辑或者调试功能。 + + +## 开发实例 添加设备描述配置: + ``` /* Display驱动相关的设备描述配置 */ display :: host { @@ -75,7 +84,7 @@ display :: host { serviceName = "hdf_disp"; } } - /* SOC适配层驱动设备描述 */ + /* SoC适配层驱动设备描述 */ device_hi35xx_disp :: device { device0 :: deviceNode { policy = 0; @@ -103,6 +112,7 @@ display :: host { SOC适配层驱动,以Hi35xx系列芯片为例,需要在本层驱动中适配MIPI等和芯片平台相关的配置,示例如下: + ``` static int32_t MipiDsiInit(struct PanelInfo *info) { @@ -145,6 +155,7 @@ static int32_t MipiDsiInit(struct PanelInfo *info) LCD器件驱动示例如下: + ``` #define RESET_GPIO 5 #define MIPI_DSI0 0 @@ -347,4 +358,3 @@ struct HdfDriverEntry g_sampleDevEntry = { HDF_INIT(g_sampleDevEntry); ``` - diff --git a/zh-cn/device-dev/driver/driver-peripherals-light-des.md b/zh-cn/device-dev/driver/driver-peripherals-light-des.md index 39f4114765e5b9d34f85b1929aad087e098918a4..eea5df18f69350273e96ed602b35ce8e764d4d24 100644 --- a/zh-cn/device-dev/driver/driver-peripherals-light-des.md +++ b/zh-cn/device-dev/driver/driver-peripherals-light-des.md @@ -5,7 +5,7 @@ ### 功能简介 -​ Light驱动模型为上层Light硬件服务层提供稳定的灯控制能力接口,包括获取灯类型、配置点灯模式、配置灯闪烁效果、点灯、熄灯等。基于HDF(Hardware Driver Foundation)驱动框架开发的Light驱动模型,实现跨操作系统迁移,器件差异配置等功能。实现Light驱动“一次开发,多系统部署”的目标。Light驱动模型如图1示: +​ Light驱动模型为上层Light硬件服务层提供稳定的灯控制能力接口,包括获取灯类型、配置点灯模式、配置灯闪烁效果、点灯、熄灯等。基于HDF(Hardware Driver Foundation)驱动框架开发的Light驱动模型,实现跨操作系统迁移,器件差异配置等功能。实现Light驱动“一次开发,多系统部署”的目标。Light驱动模型如[图1](#Light驱动模型图)所示: **图 1** Light驱动模型图 @@ -13,7 +13,7 @@ ### 运作机制 -通过介绍Light驱动模型的加载以及运行流程,对模型内部关键组件以及关联组件之间的关系进行了划分,整体加载流程如图2所示: +通过介绍Light驱动模型的加载以及运行流程,对模型内部关键组件以及关联组件之间的关系进行了划分,整体加载流程如[图2](#Light驱动运行图)所示: **图 2** Light驱动运行图 @@ -36,7 +36,7 @@ Light驱动模型以标准系统Hi3516DV300为例,介绍整个驱动加载及 ### 接口说明 -Light驱动模型支持获取系统中所有灯的信息,动态配置闪烁模式和闪烁时间的能力。Light硬件服务调用GetLightInfo获取Light设备的基本信息;调用TurnOnLight接口启动配置的闪烁效果。Light驱动模型对外开放的API接口能力,参考表1。 +Light驱动模型支持获取系统中所有灯的信息,动态配置闪烁模式和闪烁时间的能力。Light硬件服务调用GetLightInfo获取Light设备的基本信息;调用TurnOnLight接口启动配置的闪烁效果。Light驱动模型对外开放的API接口能力,参考[表1](#Light驱动模型对外API接口能力介绍)。 **表1** Light驱动模型对外API接口能力介绍 @@ -148,7 +148,7 @@ Light驱动模型支持获取系统中所有灯的信息,动态配置闪烁模 HdfWorkDestroy(&drvData->work); HdfWorkQueueDestroy(&drvData->workQueue); (void)OsalMutexDestroy(&drvData->mutex); - OsalMemFree(drvData); + (void)OsalMemFree(drvData); g_lightDrvData = NULL; } ``` diff --git a/zh-cn/device-dev/driver/driver-peripherals-touch-des.md b/zh-cn/device-dev/driver/driver-peripherals-touch-des.md index fc3483b3cd316eb8643fd3f48ed617f588b46388..e97781d375b54707c2414beb4d198091801c7a05 100644 --- a/zh-cn/device-dev/driver/driver-peripherals-touch-des.md +++ b/zh-cn/device-dev/driver/driver-peripherals-touch-des.md @@ -1,84 +1,70 @@ -# TOUCHSCREEN +# Touchscreen -- [概述](#section175431838101617) -- [接口说明](#section105459441659) -- [开发步骤](#section65745222184) -- [开发实例](#section263714411191) - - [设备描述配置](#section18249155619195) - - [板级配置及器件私有配置](#section3571192072014) - - [添加器件驱动](#section6356758162015) +## 概述 -## 概述 +- **Touchscreen驱动主要任务** + Touchscreen驱动用于驱动触摸屏使其正常工作,该驱动主要完成如下工作:对触摸屏驱动IC进行上电、配置硬件管脚并初始化其状态、注册中断、配置通信接口(I2C或SPI)、设定Input相关配置、下载及更新固件等操作。 -- **Touchscreen驱动主要任务** +- **Touchscreen驱动模型说明** + 本节主要介绍基于Input驱动模型开发Touchscreen器件驱动,Input模型整体的框架如下图所示。 - Touchscreen驱动用于驱动触摸屏使其正常工作,该驱动主要完成如下工作:对触摸屏驱动IC进行上电、配置硬件管脚并初始化其状态、注册中断、配置通信接口(I2C或SPI)、设定Input相关配置、下载及更新固件等操作。 + Input驱动模型基于HDF驱动框架、Platform接口、OSAL接口进行开发,向上对接规范化的驱动接口HDI(Hardware Driver Interface)层,通过Input-HDI层对外提供硬件能力,即上层Input Service可以通过HDI接口层获取相应的驱动能力,进而操控Touchscreen等输入设备。 + **图1** 基于HDF驱动框架的Input驱动模型 -- **Touchscreen驱动层次说明** + ![zh-cn_image_0000001123742904](figures/zh-cn_image_0000001123742904.png) - 本节主要介绍基于Input驱动模型开发touchscreen器件驱动,Input模型整体的框架如[图1](#fig6251184817261)。 +- **Input驱动模型介绍** - Input驱动模型基于HDF驱动框架、Platform接口、OSAL接口进行开发,向上对接规范化的驱动接口HDI(Hardware Driver Interface)层,通过Input-HDI层对外提供硬件能力,即上层Input service可以通过HDI接口层获取相应的驱动能力,进而操控touchscreen等输入设备。 + Input驱动模型核心部分由设备管理层、公共驱动层、器件驱动层组成。器件产生的数据借助平台数据通道能力从内核传递到用户态,驱动模型通过配置文件适配不同器件及硬件平台,提高开发者的器件驱动开发效率。如下部分为模型各部分的说明: + - Input设备管理:为各类输入设备驱动提供Input设备的注册、注销接口,同时统一管理Input设备列表。 + - Input平台驱动:指各类Input设备的公共抽象驱动(例如触摸屏的公共驱动),负责对板级硬件进行初始化、硬件中断处理、向manager注册Input设备等。 + - Input器件驱动:指各器件厂家的差异化驱动,通过适配平台驱动预留的差异化接口,实现器件驱动开发量最小化。 + - Input数据通道:提供一套通用的数据上报通道,各类别的Input设备驱动均可用此通道上报Input事件。 + - Input配置解析:负责对Input设备的板级配置及器件私有配置进行解析及管理。 -**图 1** 基于HDF驱动框架的Input驱动模型 -![](figures/基于HDF驱动框架的input驱动模型.png "基于HDF驱动框架的input驱动模型") +- **基于HDF驱动框架开发器件驱动的优势** -- **Input驱动模型介绍** + 在HDF(Hardware Driver Foundation)[驱动管理框架](../driver/driver-hdf-development.md)的基础上,Input驱动模型调用OSAL接口层和Platform接口层提供的基础接口进行开发,包括bus通信接口、操作系统原生接口(memory、lock、thread、timer等)。由于OSAL接口和Platform接口屏蔽了芯片平台差异,所以基于Input驱动模型实现的Touchscreen驱动可以进行跨平台、跨OS迁移,以便逐步实现驱动的一次开发,多端部署。 - Input驱动模型核心部分由设备管理层、公共驱动层、器件驱动层组成。器件产生的数据借助平台数据通道能力从内核传递到用户态,驱动模型通过配置文件适配不同器件及硬件平台,提高开发者的器件驱动开发效率。如下部分为模型各部分的说明: - - Input设备管理:为各类输入设备驱动提供Input设备的注册、注销接口,同时统一管理Input设备列表。 +## 接口说明 - - Input平台驱动:指各类Input设备的公共抽象驱动(例如触摸屏的公共驱动),负责对板级硬件进行初始化、硬件中断处理、向manager注册Input设备等。 - - - Input器件驱动:指各器件厂家的差异化驱动,通过适配平台驱动预留的差异化接口,实现器件驱动开发量最小化。 - - - Input数据通道:提供一套通用的数据上报通道,各类别的Input设备驱动均可用此通道上报Input事件。 - - - Input配置解析:负责对Input设备的板级配置及器件私有配置进行解析及管理。 - - -- **基于HDF驱动框架开发器件驱动的优势** - - 在HDF(Hardware Driver Foundation)[驱动管理框架](driver-hdf-development.md)的基础上,Input驱动模型调用OSAL接口层和Platfom接口层提供的基础接口进行开发,包括bus通信接口、操作系统原生接口(memory、lock、thread、timer等)。由于OSAL接口和Platform接口屏蔽了芯片平台差异,所以基于Input驱动模型实现的touchscreen驱动可以进行跨平台、跨OS迁移,以便逐步实现驱动的一次开发,多端部署。 +Touchscreen器件的硬件接口相对简单,根据PIN脚的属性,可以简单分为如下三类: +- 电源接口 -## 接口说明 +- IO控制接口 -Touchscreen器件的硬件接口相对简单,根据PIN脚的属性,可以简单分为如下三类: +- 通信接口 -- 电源接口 -- IO控制接口 -- 通信接口 + **图2** Touchscreen器件常用管脚 -**图 2** Touchscreen器件常用管脚 -![](figures/Touchscreen器件常用管脚.png "Touchscreen器件常用管脚") + ![zh-cn_image_0000001192846991](figures/zh-cn_image_0000001192846991.png) 如上图所示的三类接口,分别做简要说明如下: -1. **电源接口** - - LDO\_1P8:1.8V数字电路 - - LDO\_3P3:3.3V模拟电路 +1. **电源接口** + - LDO_1P8:1.8V数字电路 + - 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控制接口** + - Reset:reset管脚,用于在系统休眠、唤醒时,由主机侧对驱动IC进行复位操作。 + - INT:中断管脚,需要在驱动初始化时,配置为输入上拉状态。在驱动IC检测到外部触摸信号后,通过操作中断管脚来触发中断,器件驱动则会在中断处理函数中进行报点数据读取等操作。 -2. **IO控制接口** - - Reset:reset管脚,用于在系统休眠、唤醒时,由主机侧对驱动IC进行复位操作。 - - INT:中断管脚,需要在驱动初始化时,配置为输入上拉状态。在驱动IC检测到外部触摸信号后,通过操作中断管脚来触发中断,器件驱动则会在中断处理函数中进行报点数据读取等操作。 +3. **通信接口** + - I2C:由于Touchscreen的报点数据量相对较少,所以一般选用I2C方式传输数据。I2C的具体协议及对应操作接口,可以参考Platform接口层中的[“I2C”使用指南](../driver/driver-platform-i2c-des.md#概述)。 + - SPI:部分厂商,由于需要传递的数据不止报点坐标,而是需要获取基础容值,数据量较大,所以会选用SPI通信方式。SPI的具体协议及对应操作接口,可以参考Platform接口层中的[“SPI” 使用指南](../driver/driver-platform-spi-des.md#概述)。 -3. **通信接口** - - I2C:由于touchscreen的报点数据量相对较少,所以一般选用I2C方式传输数据。I2C的具体协议及对应操作接口,可以参考Platform接口层中的[“I2C”使用指南](driver-platform-i2c-des.md#section5361140416)。 - - SPI:部分厂商,由于需要传递的数据不止报点坐标,而是需要获取基础容值,数据量较大,所以会选用SPI通信方式。SPI的具体协议及对应操作接口,可以参考Platform接口层中的[“SPI” 使用指南](driver-platform-spi-des.md#section193356154511)。 +## 开发步骤 -## 开发步骤 +Input驱动模型是基于HDF框架、Platform接口和OSAL接口开发,不区分操作系统和芯片平台,为Touchscreen等输入器件提供统一的驱动开发架构。 -Input驱动模型是基于HDF框架、Platform接口和OSAL接口开发,不区分操作系统和芯片平台,为touchscreen等输入器件提供统一的驱动开发架构。 - -如下以touchscreen器件驱动为例,说明Input驱动模型的完整加载流程: +如下以Touchscreen器件驱动为例,说明Input驱动模型的完整加载流程: (1)设备描述配置:由开发者参考已有模板进行设备描述配置,包括驱动加载顺序、板级硬件信息、器件私有数据信息等。 @@ -94,26 +80,25 @@ Input驱动模型是基于HDF框架、Platform接口和OSAL接口开发,不区 请参考如下相关步骤: -1. 设备描述配置 - - 目前Input驱动基于HDF驱动框架编写,驱动的加载启动由HDF驱动管理框架统一处理。首先需要在对应的配置文件中,将驱动信息注册进去,如是否加载、加载优先级,此后HDF驱动框架会逐一启动注册过的驱动模块。驱动的相关配置请参考[HDF驱动框架配置指导](driver-hdf-development.md#section1969312275533)。 +1. 设备描述配置 + 目前Input驱动基于HDF驱动框架编写,驱动的加载启动由HDF驱动管理框架统一处理。首先需要在对应的配置文件中,将驱动信息注册进去,如是否加载、加载优先级,此后HDF驱动框架会逐一启动注册过的驱动模块。驱动的相关配置请参考[HDF驱动框架配置指导](../driver/driver-hdf-development.md#驱动开发步骤)。 -2. 板级配置及Touchscreen器件私有配置 +2. 板级配置及Touchscreen器件私有配置 + 配置对应的IO管脚功能,例如对单板上为Touchscreen设计预留的I2C Pin脚,需设置对应的寄存器,使其选择I2C的通信功能。 - 配置对应的IO管脚功能,例如对单板上为touchscreen设计预留的I2C Pin脚,需设置对应的寄存器,使其选择I2C的通信功能。 +3. 实现器件差异化适配接口 + 根据硬件单板设计的通信接口,使用Platform接口层提供的管脚操作接口配置对应的复位管脚、中断管脚以及电源操作,对于GPIO的操作,可参考[GPIO操作接口指导](../driver/driver-platform-gpio-des.md#概述) -3. 实现器件差异化适配接口 - 根据硬件单板设计的通信接口,使用Platform接口层提供的管脚操作接口配置对应的复位管脚、中断管脚以及电源操作,对于GPIO的操作,可参考[GPIO操作接口指导](driver-platform-gpio-des.md#section1635911016188) +## 开发实例 +本实例提供Touchscreen驱动开发示例,并简要对具体关键点进行开发说明。 -## 开发实例 -本实例提供touchscreen驱动开发示例,并简要对具体关键点进行开发说明。 +### 设备描述配置 -### 设备描述配置 +如下配置主要包含Input驱动模型各模块层级信息,具体原理可参考[HDF驱动开发指南](../driver/driver-hdf-development.md),HDF框架依据该配置信息实现对Input模型各模块的依次加载等。 -如下配置主要包含Input驱动模型各模块层级信息,具体原理可参考[HDF驱动开发指南](driver-hdf-development.md),HDF框架依据该配置信息实现对Input模型各模块的依次加载等。 ``` input :: host { @@ -156,10 +141,12 @@ input :: host { } ``` -### 板级配置及器件私有配置 + +### 板级配置及器件私有配置 如下配置包含板级硬件配置及器件私有数据配置,实际业务开发时,可根据具体需求增删及修改如下配置文件信息。 + ``` root { input_config { @@ -245,10 +232,12 @@ root { } ``` -### 添加器件驱动 + +### 添加器件驱动 在器件驱动中,主要实现了平台预留的差异化接口,以器件数据获取及解析进行示例说明。具体开发过程,需要根据实际使用的单板及器件进行适配。 + ``` /* 将从器件中读取到的报点数据解析为坐标 */ static void ParsePointData(ChipDevice *device, FrameData *frame, uint8_t *buf, uint8_t pointNum) @@ -402,4 +391,3 @@ struct HdfDriverEntry g_touchSampleChipEntry = { HDF_INIT(g_touchSampleChipEntry); ``` - diff --git a/zh-cn/device-dev/driver/driver-peripherals-usb-des.md b/zh-cn/device-dev/driver/driver-peripherals-usb-des.md index 351e48e5a554bf8918a5bd28727c16e822e04151..b46eb8401db605fccb59c1b751b74c8eff22e45f 100644 --- a/zh-cn/device-dev/driver/driver-peripherals-usb-des.md +++ b/zh-cn/device-dev/driver/driver-peripherals-usb-des.md @@ -1,410 +1,176 @@ -# USB +# USB -- [概述](#section127mcpsimp) - - [接口说明](#section141mcpsimp) -- [开发指导](#section581mcpsimp) - - [Host DDK API驱动开发步骤](#section584mcpsimp) - - [Host RAW API驱动开发步骤](#section594mcpsimp) - - [Device DDK API驱动开发步骤](#section600mcpsimp) - -- [开发实例](#section607mcpsimp) - - [Host DDK API驱动开发](#section609mcpsimp) - - [Host RAW API驱动开发](#section612mcpsimp) - - [Device DDK API驱动开发](#section615mcpsimp) - - -## 概述 +## 概述 USB Host部分,主要包括协议封装、设备管理、驱动安装与卸载等。 USB Device部分,支持USB功能设备的开发,提供USB设备相关功能,主要包括设备管理、配置管理、IO管理,实现USB功能设备创建、配置、数据通信等。 -USB Host驱动模型如下图1所示: + USB Host和Device驱动模型如下图所示: + + **图1** USB Host驱动模型图 -**图 1** USB Host驱动模型图 -![](figures/USB-Host驱动模型图.png "USB-Host驱动模型图") + ![zh-cn_image_0000001183058868](figures/zh-cn_image_0000001183058868.png) -**图 2** USB Device驱动模型图 -![](figures/USB-Device驱动模型图.png "USB-Device驱动模型图") + + **图2** USB Device驱动模型图 + + ![zh-cn_image_0000001183218992](figures/zh-cn_image_0000001183218992.png) USB驱动模型对外开放的API接口能力如下: -- Usb Host DDK提供给用户态可直接调用的驱动能力接口,按照功能分类三大类:DDK初始化类、对interface对象操作类、对request对象操作类,可以提供DDK初始化、interface绑定和释放,打开和关闭操作,request的申请和释放,同步和异步传输等。 -- Usb Deivce DDK提供设备管理、IO管理、配置管理,主要功能有:创建和删除设备、获取和打开接口、同步和异步传输等。 - -### 接口说明 - -USB驱动模型Host侧开放的API接口功能,参考[图1](#fig1649563542917)。 - -**表 1** USB驱动模型Host侧开放的API接口功能介绍 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

头文件

-

接口名称

-

功能描述

-

usb_ddk_interface.h

-

int32_t UsbInitHostSdk(struct UsbSession **session);

-

USB主机端驱动开发工具包初始化

-

int32_t UsbExitHostSdk(const struct UsbSession *session);

-

USB主机端驱动开发工具包退出

-

const struct UsbInterface *UsbClaimInterface(const struct UsbSession *session, uint8_t busNum, uint8_t usbAddr, uint8_t interfaceIndex);

-

获取USB接口对象

-

int UsbReleaseInterface(const struct UsbInterface *interfaceObj);

-

释放USB接口对象

-

int UsbAddOrRemoveInterface(const struct UsbSession *session, uint8_t busNum, uint8_t usbAddr, uint8_t interfaceIndex, UsbInterfaceStatus status);

-

增加移除接口

-

UsbInterfaceHandle *UsbOpenInterface(const struct UsbInterface *interfaceObj);

-

打开USB对象接口

-

int32_t UsbCloseInterface(const UsbInterfaceHandle *interfaceHandle);

-

关闭USB接口对象

-

int32_t UsbSelectInterfaceSetting(const UsbInterfaceHandle *interfaceHandle, uint8_t settingIndex, struct UsbInterface **interfaceObj);

-

设置可选配置

-

int32_t UsbGetPipeInfo(const UsbInterfaceHandle *interfaceHandle, uint8_t settingIndex, uint8_t pipeId, struct UsbPipeInfo *pipeInfo);

-

获取指定可选设置的管道信息

-

int32_t UsbClearInterfaceHalt(const UsbInterfaceHandle *interfaceHandle, uint8_t pipeAddress);

-

清除指定索引的管道状态

-

struct UsbRequest *UsbAllocRequest(const UsbInterfaceHandle *interfaceHandle, int isoPackets, int length);

-

分配请求对象

-

int UsbFreeRequest(const struct UsbRequest *request);

-

释放请求对象

-

int UsbSubmitRequestAsync(const struct UsbRequest *request);

-

发送异步请求

-

int32_t UsbFillRequest(const struct UsbRequest *request, const UsbInterfaceHandle *interfaceHandle, const struct UsbRequestParams *params);

-

填充请求

-

sint UsbCancelRequest(const struct UsbRequest *request);

-

取消异步请求

-

int UsbSubmitRequestSync(const struct UsbRequest *request);

-

发送同步请求

-

usb_raw_api.h

-

int UsbRawInit(struct UsbSession **session);

-

USB驱动开发工具包专家模式初始化

-

int UsbRawExit(const struct UsbSession *session);

-

USB驱动开发工具包专家模式退出

-

UsbRawHandle *UsbRawOpenDevice(const struct UsbSession *session, uint8_t busNum, uint8_t usbAddr);

-

打开USB设备对象

-

int UsbRawCloseDevice(const UsbRawHandle *devHandle);

-

关闭USB设备对象

-

int UsbRawSendControlRequest(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbControlRequestData *requestData);

-

执行同步控制传输

-

int UsbRawSendBulkRequest(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbRequestData *requestData);

-

执行同步批量传输

-

int UsbRawSendInterruptRequest(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbRequestData *requestData);

-

执行同步中断传输

-

int UsbRawGetConfigDescriptor(const UsbRawDevice *rawDev, uint8_t configIndex, struct UsbRawConfigDescriptor **config);

-

获取给定设备指定ID的设备配置描述符

-

void UsbRawFreeConfigDescriptor(const struct UsbRawConfigDescriptor *config);

-

释放配置描述符内存空间

-

int UsbRawGetConfiguration(const UsbRawHandle *devHandle, int *config);

-

获取当前激活配置

-

int UsbRawSetConfiguration(const UsbRawHandle *devHandle, int config);

-

设置当前激活配置

-

int UsbRawGetDescriptor(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbRawDescriptorParam *param, const unsigned char *data);

-

获取描述符信息

-

UsbRawDevice *UsbRawGetDevice(const UsbRawHandle *devHandle);

-

由设备句柄获取设备指针

-

int UsbRawGetDeviceDescriptor(const UsbRawDevice *rawDev, struct UsbDeviceDescriptor *desc);

-

获取给定设备的USB设备描述符

-

int UsbRawClaimInterface(const UsbRawHandle *devHandle, int interfaceNumber);

-

声明给定设备句柄上的接口

-

int UsbRawReleaseInterface(const UsbRawHandle *devHandle, int interfaceNumber);

-

释放之前声明的接口

-

int UsbRawResetDevice(const UsbRawHandle *devHandle);

-

复位设备

-

struct UsbRawRequest *UsbRawAllocRequest(const UsbRawHandle *devHandle, int isoPackets, int length);

-

分配一个带有指定数量的同步包描述符的传输请求

-

int UsbRawFreeRequest(const struct UsbRawRequest *request);

-

释放之前分配的传输请求

-

int UsbRawFillBulkRequest(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbRawFillRequestData *fillData);

-

填充批量传输请求所需信息

-

int UsbRawFillControlSetup(const unsigned char *setup, const struct UsbControlRequestData *requestData);

-

填充控制传输设置包所需信息

-

int UsbRawFillControlRequest(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbRawFillRequestData *fillData);

-

填充控制传输请求所需信息

-

int UsbRawFillInterruptRequest(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbRawFillRequestData *fillData);

-

填充中断传输请求所需信息

-

int UsbRawFillIsoRequest(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbRawFillRequestData *fillData);

-

填充同步传输(Isochronous Transfers)请求所需信息

-

int UsbRawSubmitRequest(const struct UsbRawRequest *request);

-

提交一个传输请求

-

int UsbRawCancelRequest(const struct UsbRawRequest *request);

-

取消一个传输请求

-

int UsbRawHandleRequests(const UsbRawHandle *devHandle);

-

传输请求事件完成处理

-
- -USB驱动模型Device侧开放的API接口功能,参考[图2](#fig8847615103013)。 - -**表 2** USB驱动模型Device侧开放的API接口功能介绍 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

头文件

-

头文件

-

功能描述

-

usbfn_device.h

-

const struct UsbFnDevice *UsbFnCreateDevice(const char *udcName, const struct UsbFnDescriptorData *descriptor);

-

创建Usb设备

-

int UsbFnRemoveDevice(struct UsbFnDevice *fnDevice);

-

删除Usb设备

-

const struct UsbFnDevice *UsbFnGetDevice(const char *udcName);

-

获取Usb设备

-

usbfn_interface.h

-

int UsbFnStartRecvInterfaceEvent(struct UsbFnInterface *interface, uint32_t eventMask, UsbFnEventCallback callback, void *context);

-

开始接受Event事件

-

int UsbFnStopRecvInterfaceEvent(struct UsbFnInterface *interface);

-

停止接受Event事件

-

UsbFnInterfaceHandle UsbFnOpenInterface(struct UsbFnInterface *interface);

-

打开一个接口

-

int UsbFnCloseInterface(UsbFnInterfaceHandle handle);

-

关闭一个接口

-

int UsbFnGetInterfacePipeInfo(struct UsbFnInterface *interface, uint8_t pipeId, struct UsbFnPipeInfo *info);

-

获取管道信息

-

int UsbFnSetInterfaceProp(const struct UsbFnInterface *interface, const char *name, const char *value);

-

设置自定义属性

-

usbfn_request.h

-

struct UsbFnRequest *UsbFnAllocCtrlRequest(UsbFnInterfaceHandle handle, uint32_t len);

-

申请一个控制请求

-

struct UsbFnRequest *UsbFnAllocRequest(UsbFnInterfaceHandle handle, uint8_t pipe, uint32_t len);

-

申请一个数据请求

-

int UsbFnFreeRequest(struct UsbFnRequest *req);

-

释放一个请求

-

int UsbFnSubmitRequestAsync(struct UsbFnRequest *req);

-

发送异步请求

-

int UsbFnSubmitRequestSync(struct UsbFnRequest *req, uint32_t timeout);

-

发送同步请求

-

int UsbFnCancelRequest(struct UsbFnRequest *req);

-

取消请求

-
- -## 开发指导 +- Usb Host DDK提供给用户态可直接调用的驱动能力接口,按照功能分类三大类:DDK初始化类、对interface对象操作类、对request对象操作类,可以提供DDK初始化、interface绑定和释放,打开和关闭操作,request的申请和释放,同步和异步传输等。 + +- Usb Device DDK提供设备管理、IO管理、配置管理,主要功能有:创建和删除设备、获取和打开接口、同步和异步传输等。 + + +### 接口说明 + +USB驱动模型Host侧开放的API接口功能,参考USB Host驱动模型图。 + + **表1** usb_ddk_interface.h + +| 接口名称 | 功能描述 | +| -------- | -------- | +| int32_t UsbInitHostSdk(struct UsbSession \*\*session); | USB主机端驱动开发工具包初始化 | +| int32_t UsbExitHostSdk(const struct UsbSession
\*session); | USB主机端驱动开发工具包退出 | +| const struct UsbInterface \*UsbClaimInterface(const
struct UsbSession \*session, uint8_t busNum, uint8_t
usbAddr, uint8_t interfaceIndex); | 获取USB接口对象 | +| int UsbReleaseInterface(const struct UsbInterface
\*interfaceObj); | 释放USB接口对象 | +| int UsbAddOrRemoveInterface(const struct UsbSession
\*session, uint8_t busNum, uint8_t usbAddr, uint8_t
interfaceIndex, UsbInterfaceStatus status); | 增加移除接口 | +| UsbInterfaceHandle \*UsbOpenInterface(const struct
UsbInterface \*interfaceObj); | 打开USB对象接口 | +| int32_t UsbCloseInterface(const UsbInterfaceHandle
\*interfaceHandle); | 关闭USB接口对象 | +| int32_t UsbSelectInterfaceSetting(const
UsbInterfaceHandle \*interfaceHandle, uint8_t
settingIndex, struct UsbInterface \*\*interfaceObj); | 设置可选配置 | +| int32_t UsbGetPipeInfo(const UsbInterfaceHandle
\*interfaceHandle, uint8_t settingIndex, uint8_t pipeId,
struct UsbPipeInfo \*pipeInfo); | 获取指定可选设置的管道信息 | +| int32_t UsbClearInterfaceHalt(const
UsbInterfaceHandle \*interfaceHandle, uint8_t
pipeAddress); | 清除指定索引的管道状态 | +| struct UsbRequest \*UsbAllocRequest(const
UsbInterfaceHandle \*interfaceHandle, int isoPackets
, int length); | 分配请求对象 | +| int UsbFreeRequest(const struct UsbRequest
\*request); | 释放请求对象 | +| int UsbSubmitRequestAsync(const struct UsbRequest
\*request); | 发送异步请求 | +| int32_t UsbFillRequest(const struct UsbRequest
\*request, const UsbInterfaceHandle \*interfaceHandle,
const struct UsbRequestParams \*params); | 填充请求 | +| sint UsbCancelRequest(const struct UsbRequest
\*request); | 取消异步请求 | +| int UsbSubmitRequestSync(const struct UsbRequest
\*request); | 发送同步请求 | + + **表2** usb_raw_api.h + +| 接口名称 | 功能描述 | +| -------- | -------- | +| int UsbRawInit(struct UsbSession \*\*session); | USB驱动开发工具包专家模式初始化 | +| int UsbRawExit(const struct UsbSession \*session); | USB驱动开发工具包专家模式退出 | +| UsbRawHandle \*UsbRawOpenDevice(const struct
UsbSession \*session, uint8_t busNum, uint8_t
usbAddr); | 打开USB设备对象 | +| int UsbRawCloseDevice(const UsbRawHandle
\*devHandle); | 关闭USB设备对象 | +| int UsbRawSendControlRequest(const struct
UsbRawRequest \*request, const UsbRawHandle
\*devHandle, const struct UsbControlRequestData
\*requestData); | 执行同步控制传输 | +| int UsbRawSendBulkRequest(const struct
UsbRawRequest \*request, const UsbRawHandle
\*devHandle, const struct UsbRequestData
\*requestData); | 执行同步批量传输 | +| int UsbRawSendInterruptRequest(const struct
UsbRawRequest \*request, const UsbRawHandle
\*devHandle, const struct UsbRequestData
\*requestData); | 执行同步中断传输 | +| int UsbRawGetConfigDescriptor(const UsbRawDevice
\*rawDev, uint8_t configIndex, struct
UsbRawConfigDescriptor \*\*config); | 获取给定设备指定ID的设备配置描述符 | +| void UsbRawFreeConfigDescriptor(const struct
UsbRawConfigDescriptor \*config); | 释放配置描述符内存空间 | +| int UsbRawGetConfiguration(const UsbRawHandle
\*devHandle, int \*config); | 获取当前激活配置 | +| int UsbRawSetConfiguration(const UsbRawHandle
\*devHandle, int config); | 设置当前激活配置 | +| int UsbRawGetDescriptor(const struct UsbRawRequest
\*request, const UsbRawHandle \*devHandle, const struct
UsbRawDescriptorParam \*param, const unsigned char
\*data); | 获取描述符信息 | +| UsbRawDevice \*UsbRawGetDevice(const UsbRawHandle
\*devHandle); | 由设备句柄获取设备指针 | +| int UsbRawGetDeviceDescriptor(const UsbRawDevice
\*rawDev, struct
UsbDeviceDescriptor \*desc); | 获取给定设备的USB设备描述符 | +| int UsbRawClaimInterface(const UsbRawHandle
\*devHandle, int
interfaceNumber); | 声明给定设备句柄上的接口 | +| int UsbRawReleaseInterface(const UsbRawHandle
\*devHandle, in
t interfaceNumber); | 释放之前声明的接口 | +| int UsbRawResetDevice(const UsbRawHandle
\*devHandle); | 复位设备 | +| struct UsbRawRequest \*UsbRawAllocRequest(const
UsbRawHandle
\*devHandle, int isoPackets, int length); | 分配一个带有指定数量的同步包描述符的传输请求 | +| int UsbRawFreeRequest(const struct UsbRawRequest
\*request); | 释放之前分配的传输请求 | +| int UsbRawFillBulkRequest(const struct UsbRawRequest
\*request, const UsbRawHandle \*devHandle, const struct
UsbRawFillRequestData \*fillData); | 填充批量传输请求所需信息 | +| int UsbRawFillControlSetup(const unsigned char \*setup,
const struct UsbControlRequestData \*requestData); | 填充控制传输设置包所需信息 | +| int UsbRawFillControlRequest(const struct UsbRawRequest
\*request, const UsbRawHandle \*devHandle, const struct
UsbRawFillRequestData \*fillData); | 填充控制传输请求所需信息 | +| int UsbRawFillInterruptRequest(const struct UsbRawRequest
\*request, const UsbRawHandle \*devHandle, const struct
UsbRawFillRequestData \*fillData); | 填充中断传输请求所需信息 | +| int UsbRawFillIsoRequest(const struct UsbRawRequest
\*request, const UsbRawHandle \*devHandle, const struct
UsbRawFillRequestData \*fillData); | 填充同步传输(Isochronous Transfers)请求所需信息 | +| int UsbRawSubmitRequest(const struct UsbRawRequest
\*request); | 提交一个传输请求 | +| int UsbRawCancelRequest(const struct UsbRawRequest
\*request); | 取消一个传输请求 | +| int UsbRawHandleRequests(const UsbRawHandle
\*devHandle); | 传输请求事件完成处理 | + +USB驱动模型Device侧开放的API接口功能,参考USB Device驱动模型图。 + + **表3** usbfn_device.h + +| 接口名称 | 功能描述 | +| -------- | -------- | +| const struct UsbFnDevice \*UsbFnCreateDevice(const
char \*udcName, const struct UsbFnDescriptorData
\*descriptor); | 创建Usb设备 | +| int UsbFnRemoveDevice(struct UsbFnDevice
\*fnDevice); | 删除Usb设备 | +| const struct UsbFnDevice \*UsbFnGetDevice(const char
\*udcName); | 获取Usb设备 | + + **表4** usbfn_interface.h + +| 接口名称 | 功能描述 | +| -------- | -------- | +| int UsbFnStartRecvInterfaceEvent(struct
UsbFnInterface \*interface, uint32_t eventMask,
UsbFnEventCallback callback, void \*context); | 开始接受Event事件 | +| int UsbFnStopRecvInterfaceEvent(struct
UsbFnInterface \*interface); | 停止接受Event事件 | +| UsbFnInterfaceHandle UsbFnOpenInterface(struct UsbFnInterface \*interface); | 打开一个接口 | +| int UsbFnCloseInterface(UsbFnInterfaceHandle handle); | 关闭一个接口 | +| int UsbFnGetInterfacePipeInfo(struct UsbFnInterface
\*interface, uint8_t pipeId, struct UsbFnPipeInfo \*info); | 获取管道信息 | +| int UsbFnSetInterfaceProp(const struct UsbFnInterface
\*interface, const char \*name, const char \*value); | 设置自定义属性 | + + **表5** usbfn_request.h + +| 接口名称 | 功能描述 | +| -------- | -------- | +| struct UsbFnRequest
\*UsbFnAllocCtrlRequest(UsbFnInterfaceHandle handle,
uint32_t len); | 申请一个控制请求 | +| struct UsbFnRequest \*UsbFnAllocRequest(UsbFnInterfaceHandle handle,
uint8_t pipe, uint32_t len); | 申请一个数据请求 | +| int UsbFnFreeRequest(struct UsbFnRequest \*req); | 释放一个请求 | +| int UsbFnSubmitRequestAsync(struct UsbFnRequest
\*req); | 发送异步请求 | +| int UsbFnSubmitRequestSync(struct UsbFnRequest
\*req, uint32_t timeout); | 发送同步请求 | +| int UsbFnCancelRequest(struct UsbFnRequest \*req); | 取消请求 | + + +## 开发步骤 USB驱动是基于HDF框架、PLATFORM和OSAL基础接口进行开发,不区分操作系统和芯片平台,为不同USB器件提供统一的驱动模型。本篇开发指导以串口为例,分别介绍USB Host和USB Device驱动开发。 -### 开发步骤 -### Host DDK API驱动开发步骤 +### Host DDK API驱动开发步骤 + +1. 驱动匹配表配置。 + +2. 初始化Host DDK。 + +3. 待步骤2初始化完后获取UsbInterface接口对象。 + +4. 打开步骤3获取到的UsbInterface接口对象,获取相应接口的UsbInterfaceHandle对象。 + +5. 根据步骤4获取到的UsbInterfaceHandle对象,获取指定索引为pipeIndex的pipeInfo信息。 + +6. 为步骤4获取到的UsbInterfaceHandle预先分配待发送的IO Request对象。 + +7. 根据输入参数params填充步骤6预先分配的IO Request。 + +8. 提交IO Request对象,可以选择同步或异步两种模式。 -1. 驱动匹配表配置。 -2. 初始化Host DDK。 -3. 待步骤2初始化完后获取UsbInterface接口对象。 -4. 打开步骤3获取到的UsbInterface接口对象,获取相应接口的UsbInterfaceHandle对象。 -5. 根据步骤4获取到的UsbInterfaceHandle对象,获取指定索引为pipeIndex的pipeInfo信息。 -6. 为步骤4获取到的UsbInterfaceHandle预先分配待发送的IO Request对象。 -7. 根据输入参数params填充步骤6预先分配的IO Request。 -8. 提交IO Request对象,可以选择同步或异步两种模式。 -### Host RAW API驱动开发步骤 +### Host RAW API驱动开发步骤 -1. 驱动匹配表配置。 -2. 初始化Host RAW,并打开USB设备,然后获取描述符,通过描述符获取接口、端点信息。 -3. 分配Request,并根据传输类型使用相应接口对Request进行填充。 -4. 提交IO Request对象,可以选择同步或异步两种模式。 +1. 驱动匹配表配置。 -### Device DDK API驱动开发步骤 +2. 初始化Host RAW,并打开USB设备,然后获取描述符,通过描述符获取接口、端点信息。 -1. 构造描述符。 -2. 创建设备,使用步骤1构造的描述符实例化一个USB设备。 -3. 根据创建的设备获取接口(UsbFnDeviceGetInterface),获取Pipe信息(UsbFnInterfaceGetPipeInfo),打开接口获取Handle(UsbFnInterfaceOpen),根据Handle和Pipe号获取Request(UsbFnRequestAlloc)。 -4. 接收Event事件(UsbFnInterfaceStartRecvEvent)如Enable、Setup等事件,回调函数(UsbFnEventCallback)中对Event事件做出响应。 -5. 收发数据,可以选择同步异步发送模式。 +3. 分配Request,并根据传输类型使用相应接口对Request进行填充。 -## 开发实例 +4. 提交IO Request对象,可以选择同步或异步两种模式。 + + +### Device DDK API驱动开发步骤 + +1. 构造描述符。 + +2. 创建设备,使用步骤1构造的描述符实例化一个USB设备。 + +3. 根据创建的设备获取接口(UsbFnDeviceGetInterface),获取Pipe信息(UsbFnInterfaceGetPipeInfo),打开接口获取Handle(UsbFnInterfaceOpen),根据Handle和Pipe号获取Request(UsbFnRequestAlloc)。 + +4. 接收Event事件(UsbFnInterfaceStartRecvEvent)如Enable、Setup等事件,回调函数(UsbFnEventCallback)中对Event事件做出响应。 + +5. 收发数据,可以选择同步异步发送模式。 + + +## 开发实例 本实例提供USB串口驱动开发示例,并简要对具体关键点进行开发说明。 -### Host DDK API驱动开发 +### Host DDK API驱动开发 + + ``` root { module = "usb_pnp_device"; @@ -492,7 +258,7 @@ static int SerialCtrlMsg(struct AcmDevice *acm, uint8_t request, controlParams.request = request; controlParams.target = USB_REQUEST_TARGET_INTERFACE; controlParams.reqType = USB_REQUEST_TYPE_CLASS; - controlParams.directon = USB_REQUEST_DIR_TO_DEVICE; + controlParams.direction = USB_REQUEST_DIR_TO_DEVICE; controlParams.value = value; controlParams.index = index; controlParams.data = buf; @@ -660,7 +426,7 @@ static int AcmAllocReadRequests(struct AcmDevice *acm) readParams.requestType = USB_REQUEST_PARAMS_DATA_TYPE; readParams.timeout = USB_CTRL_SET_TIMEOUT; readParams.dataReq.numIsoPackets = 0; - readParams.dataReq.directon = (acm->dataInPipe->pipeDirection >> USB_PIPE_DIR_OFFSET) & 0x1; + readParams.dataReq.direction = (acm->dataInPipe->pipeDirection >> USB_PIPE_DIR_OFFSET) & 0x1; readParams.dataReq.length = acm->readSize; ret = UsbFillRequest(acm->readReq[i], InterfaceIdToHandle(acm, acm->dataInPipe->interfaceId), &readParams); //填充待发送的readReq对象 if (HDF_SUCCESS != ret) { @@ -692,7 +458,7 @@ static int AcmAllocNotifyRequest(struct AcmDevice *acm) intParams.requestType = USB_REQUEST_PARAMS_DATA_TYPE; intParams.timeout = USB_CTRL_SET_TIMEOUT; intParams.dataReq.numIsoPackets = 0; - intParams.dataReq.directon = (acm->intPipe->pipeDirection >> USB_PIPE_DIR_OFFSET) & DIRECTION_MASK; + intParams.dataReq.direction = (acm->intPipe->pipeDirection >> USB_PIPE_DIR_OFFSET) & DIRECTION_MASK; intParams.dataReq.length = acm->intSize; ret = UsbFillRequest(acm->notifyReq, InterfaceIdToHandle(acm, acm->intPipe->interfaceId), &intParams); //填充预先分配的中断IO Request if (HDF_SUCCESS != ret) { @@ -1019,8 +785,10 @@ struct HdfDriverEntry g_usbSerialDriverEntry = { HDF_INIT(g_usbSerialDriverEntry); ``` -### Host RAW API驱动开发 +### Host RAW API驱动开发 + + ``` root { module = "usb_pnp_device"; @@ -1453,10 +1221,12 @@ struct HdfDriverEntry g_usbSerialRawDriverEntry = { HDF_INIT(g_usbSerialRawDriverEntry); ``` -### Device DDK API驱动开发 -USB ACM设备核心代码路径为drivers/peripheral/usb/gadget/function/acm/cdcacm.c,其使用示例如下所示,首先根据描述符创建设备,然后获取接口,打开接口,获取Pipe信息,接收Event事件,接着进行USB通信(读写等),设备卸载时候,关闭接口,停止Event接收,删除设备。 +### Device DDK API驱动开发 + +USB ACM设备核心代码路径为drivers\peripheral\usb\gadget\function\acm\cdcacm.c,其使用示例如下所示,首先根据描述符创建设备,然后获取接口,打开接口,获取Pipe信息,接收Event事件,接着进行USB通信(读写等),设备卸载时候,关闭接口,停止Event接收,删除设备。 + ``` 1、创建设备 static int32_t AcmCreateFuncDevice(struct UsbAcmDevice *acm, @@ -1548,4 +1318,3 @@ int32_t ret; return ret; } ``` - diff --git a/zh-cn/device-dev/driver/driver-peripherals.md b/zh-cn/device-dev/driver/driver-peripherals.md index 23a04b3ffcebab1ab05464ed91917db05d9b470e..c7c28e00ed985dd9f44a9a900e9583e1acdec586 100644 --- a/zh-cn/device-dev/driver/driver-peripherals.md +++ b/zh-cn/device-dev/driver/driver-peripherals.md @@ -1,11 +1,13 @@ -# 外设驱动使用 +# 外设驱动使用 -- **[LCD](driver-peripherals-lcd-des.md)** -- **[TOUCHSCREEN](driver-peripherals-touch-des.md)** -- **[SENSOR](driver-peripherals-sensor-des.md)** +- **[LCD](driver-peripherals-lcd-des.md)** -- **[WLAN](driver-peripherals-external-des.md)** +- **[Touchscreen](driver-peripherals-touch-des.md)** -- **[AUDIO](driver-peripherals-audio-des.md)** \ No newline at end of file +- **[SENSOR](driver-peripherals-sensor-des.md)** + +- **[WLAN](driver-peripherals-external-des.md)** + +- **[USB](driver-peripherals-usb-des.md)** \ No newline at end of file diff --git a/zh-cn/device-dev/driver/driver-platform-adc-develop.md b/zh-cn/device-dev/driver/driver-platform-adc-develop.md index c4df774eeec3aeee3722baf645db8c5ecb3a545f..bbbf280282bc618ae7ee76a8ecda686af55ac5c2 100755 --- a/zh-cn/device-dev/driver/driver-platform-adc-develop.md +++ b/zh-cn/device-dev/driver/driver-platform-adc-develop.md @@ -1,21 +1,19 @@ -# ADC +# ADC -- [概述](#section268031773165048) -- [接口说明](#section752964871810) -- [开发步骤](#section100579767165048) -- [开发实例](#section1745221471165048) -## 概述 +## 概述 ADC(Analog to Digital Converter),即模拟-数字转换器,是一种将模拟信号转换成对应数字信号的设备,在HDF框架中,ADC模块接口适配模式采用统一服务模式,这需要一个设备服务来作为ADC模块的管理器,统一处理外部访问,这会在配置文件中有所体现。统一服务模式适合于同类型设备对象较多的情况,如ADC可能同时具备十几个控制器,采用独立服务模式需要配置更多的设备节点,且服务会占据内存资源。 -**图 1** ADC统一服务模式 -![](figures/统一服务模式结构图.png "ADC统一服务模式") + **图1** ADC统一服务 + ![zh-cn_image_0000001177082414](figures/zh-cn_image_0000001177082414.png) -## 接口说明 + +## 接口说明 AdcMethod定义: + ``` struct AdcMethod { int32_t (*read)(struct AdcDevice *device, uint32_t channel, uint32_t *val); @@ -24,401 +22,298 @@ struct AdcMethod { }; ``` -**表 1** AdcMethod结构体成员的回调函数功能说明 - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

函数成员

-

入参

-

出参

-

返回值

-

功能

-

read

-

device: 结构体指针,核心层ADC控制器;channel:uint32_t,传入的通道号;

-

val:uint32_t指针,要传出的信号数据;

-

HDF_STATUS相关状态

-

读取ADC采样的信号数据

-

stop

-

device: 结构体指针,核心层ADC控制器;

-

-

HDF_STATUS相关状态

-

关闭ADC设备

-

start

-

device: 结构体指针,核心层ADC控制器;

-

-

HDF_STATUS相关状态

-

开启ADC设备

-
- -## 开发步骤 - -ADC模块适配的三个环节是配置属性文件,实例化驱动入口,以及实例化核心层接口函数。 - -1. **实例化驱动入口:** - - 实例化HdfDriverEntry结构体成员。 - - 调用HDF\_INIT将HdfDriverEntry实例化对象注册到HDF框架中。 - -2. **配置属性文件:** - - 在device\_info.hcs文件中添加deviceNode描述。 - - 【可选】添加adc\_config.hcs器件属性文件。 - -3. **实例化ADC控制器对象:** - - 初始化AdcDevice成员。 - - 实例化AdcDevice成员AdcMethod。 - - >![](../public_sys-resources/icon-note.gif) **说明:** - >实例化AdcDevice成员AdcMethod,其定义和成员说明见[接口说明](#section752964871810)。 - - -4. **驱动调试:** - - 【可选】针对新增驱动程序,建议验证驱动基本功能,例如挂载后的信息反馈,信号采集的成功与否等。 - - -## 开发实例 - -接下来以 adc\_hi35xx.c 为示例, 展示需要厂商提供哪些内容来完整实现设备功能。 - -1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf\_device\_desc.h 中定义)类型的全局变量,且moduleName要和device\_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。 - - 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 - - ADC驱动入口参考: - - ADC模块这种类型的控制器会出现很多个设备挂接的情况,因而在HDF框架中首先会为这类型的设备创建一个管理器对象。这样,需要打开某个设备时,管理器对象会根据指定参数查找到指定设备。 - - ADC管理器的驱动由核心层实现,厂商不需要关注这部分内容的实现,这个但在实现Init函数的时候需要调用核心层的AdcDeviceAdd函数,它会实现相应功能。 - - ``` - static struct HdfDriverEntry g_hi35xxAdcDriverEntry = { - .moduleVersion = 1, - .Init = Hi35xxAdcInit, - .Release = Hi35xxAdcRelease, - .moduleName = "hi35xx_adc_driver",//【必要且与HCS文件里面的名字匹配】 - }; - HDF_INIT(g_hi35xxAdcDriverEntry); //调用HDF_INIT将驱动入口注册到HDF框架中 - - //核心层adc_core.c管理器服务的驱动入口 - struct HdfDriverEntry g_adcManagerEntry = { - .moduleVersion = 1, - .Init = AdcManagerInit, - .Release = AdcManagerRelease, - .moduleName = "HDF_PLATFORM_ADC_MANAGER",//这与device_info文件中device0对应 - }; - HDF_INIT(g_adcManagerEntry); - ``` - -2. 完成驱动入口注册之后,下一步请在device\_info.hcs文件中添加deviceNode信息,并在adc\_config.hcs中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值对于厂商驱动的实现以及核心层AdcDevice相关成员的默认值或限制范围有密切关系。 - - 统一服务模式的特点是device\_info文件中第一个设备节点必须为ADC管理器,其各项参数必须如下设置: - - - - - - - - - - - - - - - - - - - -

成员名

-

-

moduleName

-

固定为 HDF_PLATFORM_ADC_MANAGER

-

serviceName

-

-

policy

-

具体配置为0,不发布服务

-

deviceMatchAttr

-

没有使用,可忽略

-
- - 从第二个节点开始配置具体ADC控制器信息,此节点并不表示某一路ADC控制器,而是代表一个资源性质设备,用于描述一类ADC控制器的信息。本例只有一个ADC设备,如有多个设备,则需要在device\_info文件增加deviceNode信息,以及在adc\_config文件中增加对应的器件属性。 - - - device\_info.hcs 配置参考。 - - ``` - root { - device_info { - platform :: host { - device_adc :: device { - device0 :: deviceNode { - policy = 0; - priority = 50; - permission = 0644; - moduleName = "HDF_PLATFORM_ADC_MANAGER"; - serviceName = "HDF_PLATFORM_ADC_MANAGER"; - } - device1 :: deviceNode { - policy = 0; // 等于0,不需要发布服务 - priority = 55; // 驱动启动优先级 - permission = 0644; // 驱动创建设备节点权限 - moduleName = "hi35xx_adc_driver"; //【必要】用于指定驱动名称,需要与期望的驱动Entry中的moduleName一致; - serviceName = "HI35XX_ADC_DRIVER"; //【必要】驱动对外发布服务的名称,必须唯一 - deviceMatchAttr = "hisilicon_hi35xx_adc";//【必要】用于配置控制器私有数据,要与adc_config.hcs中对应控制器保持一致 - } // 具体的控制器信息在 adc_config.hcs 中 - } - } - } - } - ``` - - - adc\_config.hcs 配置参考。 - - ``` - root { - platform { - adc_config_hi35xx { - match_attr = "hisilicon_hi35xx_adc"; - template adc_device { - regBasePhy = 0x120e0000;//寄存器物理基地址 - regSize = 0x34; //寄存器位宽 - deviceNum = 0; //设备号 - validChannel = 0x1; //有效通道 - dataWidth = 10; //信号接收的数据位宽 - scanMode = 1; //扫描模式 - delta = 0; //delta参数 - deglitch = 0; - glitchSample = 5000; - rate = 20000; - } - device_0 :: adc_device { - deviceNum = 0; - validChannel = 0x2; - } - } - } - } - ``` - -3. 完成驱动入口注册之后,最后一步就是以核心层AdcDevice对象的初始化为核心,包括初始化厂商自定义结构体(传递参数和数据),实例化AdcDevice成员AdcMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。 - - 自定义结构体参考。 - - 从驱动的角度看,自定义结构体是参数和数据的载体,而且adc\_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,其中一些重要数值也会传递给核心层AdcDevice对象,例如设备号、总线号等。 - - ``` - struct Hi35xxAdcDevice { - struct AdcDevice device;//【必要】是核心层控制对象,具体描述见下面 - volatile unsigned char *regBase;//【必要】寄存器基地址 - volatile unsigned char *pinCtrlBase; - uint32_t regBasePhy; //【必要】寄存器物理基地址 - uint32_t regSize; //【必要】寄存器位宽 - uint32_t deviceNum; //【必要】设备号 - uint32_t dataWidth; //【必要】信号接收的数据位宽 - uint32_t validChannel; //【必要】有效通道 - uint32_t scanMode; //【必要】扫描模式 - uint32_t delta; - uint32_t deglitch; - uint32_t glitchSample; - uint32_t rate; //【必要】采样率 - }; - - //AdcDevice是核心层控制器结构体,其中的成员在Init函数中会被赋值 - struct AdcDevice { - const struct AdcMethod *ops; - OsalSpinlock spin; - uint32_t devNum; - uint32_t chanNum; - const struct AdcLockMethod *lockOps; - void *priv; - }; - ``` - - - AdcDevice成员回调函数结构体AdcMethod的实例化,AdcLockMethod回调函数结构体本例未实现,若要实例化,可参考I2C驱动开发,其他成员在Init函数中初始化。 - - ``` - static const struct AdcMethod g_method = { - .read = Hi35xxAdcRead, - .stop = Hi35xxAdcStop, - .start = Hi35xxAdcStart, - }; - ``` - - - init函数参考 - - 入参: - - HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 - - 返回值: - - HDF\_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf\_base.h中HDF\_STATUS 定义)。 - - - - - - - - - - - - - - - - - - - - - - - - - -

状态(值)

-

问题描述

-

HDF_ERR_INVALID_OBJECT

-

控制器对象非法

-

HDF_ERR_INVALID_PARAM

-

参数非法

-

HDF_ERR_MALLOC_FAIL

-

内存分配失败

-

HDF_ERR_IO

-

I/O 错误

-

HDF_SUCCESS

-

传输成功

-

HDF_FAILURE

-

传输失败

-
- - 函数说明: - - 初始化自定义结构体对象,初始化AdcDevice成员,并调用核心层AdcDeviceAdd函数。 - - ``` - static int32_t Hi35xxAdcInit(struct HdfDeviceObject *device) - { - int32_t ret; - struct DeviceResourceNode *childNode = NULL; - ... - //遍历、解析adc_config.hcs中的所有配置节点,并分别调用Hi35xxAdcParseInit函数来初始化device - DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) { - ret = Hi35xxAdcParseInit(device, childNode);//函数定义见下 - ... - } - return ret; - } - - static int32_t Hi35xxAdcParseInit(struct HdfDeviceObject *device, struct DeviceResourceNode *node) - { - int32_t ret; - struct Hi35xxAdcDevice *hi35xx = NULL; //【必要】自定义结构体对象 - (void)device; - - hi35xx = (struct Hi35xxAdcDevice *)OsalMemCalloc(sizeof(*hi35xx)); //【必要】内存分配 - ... - ret = Hi35xxAdcReadDrs(hi35xx, node); //【必要】将adc_config文件的默认值填充到结构体中 - ... - hi35xx->regBase = OsalIoRemap(hi35xx->regBasePhy, hi35xx->regSize);//【必要】地址映射 - ... - hi35xx->pinCtrlBase = OsalIoRemap(HI35XX_ADC_IO_CONFIG_BASE, HI35XX_ADC_IO_CONFIG_SIZE); - ... - Hi35xxAdcDeviceInit(hi35xx); //【必要】ADC设备的初始化 - hi35xx->device.priv = (void *)node; //【必要】存储设备属性 - hi35xx->device.devNum = hi35xx->deviceNum;//【必要】初始化AdcDevice成员 - hi35xx->device.ops = &g_method; //【必要】AdcMethod的实例化对象的挂载 - ret = AdcDeviceAdd(&hi35xx->device); //【必要且重要】调用此函数填充核心层结构体,返回成功信号后驱动才完全接入平台核心层 - ... - return HDF_SUCCESS; - - __ERR__: - if (hi35xx != NULL) { //不成功的话,需要反向执行初始化相关函数 - if (hi35xx->regBase != NULL) { - OsalIoUnmap((void *)hi35xx->regBase); - hi35xx->regBase = NULL; - } - AdcDeviceRemove(&hi35xx->device); - OsalMemFree(hi35xx); - } - return ret; - } - ``` - - - Release 函数参考 - - 入参: + **表1** AdcMethod结构体成员的回调函数功能说明 - HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 +| 函数成员 | 入参 | 出参 | 返回值 | 功能 | +| -------- | -------- | -------- | -------- | -------- | +| read | device: 结构体指针,核心层ADC控制器;
channel:uint32_t,传入的通道号; | val:uint32_t指针,要传出的信号数据; | HDF_STATUS相关状态 | 读取ADC采样的信号数据 | +| stop | device: 结构体指针,核心层ADC控制器; | 无 | HDF_STATUS相关状态 | 关闭ADC设备 | +| start | device: 结构体指针,核心层ADC控制器; | 无 | HDF_STATUS相关状态 | 开启ADC设备 | - 返回值: - 无。 +## 开发步骤 - 函数说明: - - 释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源。所有强制转换获取相应对象的操作**前提**是在Init函数中具备对应赋值的操作。 +ADC模块适配的三个环节是配置属性文件,实例化驱动入口,以及实例化核心层接口函数。 - ``` - static void Hi35xxAdcRelease(struct HdfDeviceObject *device) - { - const struct DeviceResourceNode *childNode = NULL; - ... - //遍历、解析adc_config.hcs中的所有配置节点,并分别进行release操作 - DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) { - Hi35xxAdcRemoveByNode(childNode);//函数定义见下 - } - } - - static void Hi35xxAdcRemoveByNode(const struct DeviceResourceNode *node) - { - int32_t ret; - int32_t deviceNum; - struct AdcDevice *device = NULL; - struct Hi35xxAdcDevice *hi35xx = NULL; - struct DeviceResourceIface *drsOps = NULL; - - drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE); - ... - ret = drsOps->GetUint32(node, "deviceNum", (uint32_t *)&deviceNum, 0); - ... - //可以调用AdcDeviceGet函数通过设备的deviceNum获取AdcDevice对象, 以及调用AdcDeviceRemove函数来释放AdcDevice对象的内容 - device = AdcDeviceGet(deviceNum); - if (device != NULL && device->priv == node) { - AdcDevicePut(device); - AdcDeviceRemove(device); //【必要】主要是从管理器驱动那边移除AdcDevice对象 - hi35xx = (struct Hi35xxAdcDevice *)device;//【必要】通过强制转换获取自定义的对象并进行release操作 - OsalIoUnmap((void *)hi35xx->regBase); - OsalMemFree(hi35xx); +1. **实例化驱动入口:** + - 实例化HdfDriverEntry结构体成员。 + - 调用HDF_INIT将HdfDriverEntry实例化对象注册到HDF框架中。 + +2. **配置属性文件:** + - 在device_info.hcs文件中添加deviceNode描述。 + - 【可选】添加adc_config.hcs器件属性文件。 + +3. **实例化ADC控制器对象:** + - 初始化AdcDevice成员。 + - 实例化AdcDevice成员AdcMethod。 + > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** + > 实例化AdcDevice成员AdcMethod,其定义和成员说明见[接口说明](#接口说明)。 + +4. **驱动调试:** + 【可选】针对新增驱动程序,建议验证驱动基本功能,例如挂载后的信息反馈,信号采集的成功与否等。 + + +## 开发实例 + + 接下来以 adc_hi35xx.c 为示例, 展示需要厂商提供哪些内容来完整实现设备功能。 +1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf_device_desc.h 中定义)类型的全局变量,且moduleName要和device_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。 + 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 + + ADC驱动入口参考: + + ADC模块这种类型的控制器会出现很多个设备挂接的情况,因而在HDF框架中首先会为这类型的设备创建一个管理器对象。这样,需要打开某个设备时,管理器对象会根据指定参数查找到指定设备。 + + ADC管理器的驱动由核心层实现,厂商不需要关注这部分内容的实现,这个但在实现Init函数的时候需要调用核心层的AdcDeviceAdd函数,它会实现相应功能。 + + + ``` + static struct HdfDriverEntry g_hi35xxAdcDriverEntry = { + .moduleVersion = 1, + .Init = Hi35xxAdcInit, + .Release = Hi35xxAdcRelease, + .moduleName = "hi35xx_adc_driver",//【必要且与HCS文件里面的名字匹配】 + }; + HDF_INIT(g_hi35xxAdcDriverEntry); //调用HDF_INIT将驱动入口注册到HDF框架中 + + //核心层adc_core.c管理器服务的驱动入口 + struct HdfDriverEntry g_adcManagerEntry = { + .moduleVersion = 1, + .Init = AdcManagerInit, + .Release = AdcManagerRelease, + .moduleName = "HDF_PLATFORM_ADC_MANAGER",//这与device_info文件中device0对应 + }; + HDF_INIT(g_adcManagerEntry); + ``` + +2. 完成驱动入口注册之后,下一步请在device_info.hcs文件中添加deviceNode信息,并在adc_config.hcs中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值对于厂商驱动的实现以及核心层AdcDevice相关成员的默认值或限制范围有密切关系。 + 统一服务模式的特点是device_info文件中第一个设备节点必须为ADC管理器,其各项参数必须如下设置: + | 成员名 | 值 | + | -------- | -------- | + | moduleName | 固定为 HDF_PLATFORM_ADC_MANAGER | + | serviceName | 无 | + | policy | 具体配置为0,不发布服务 | + | deviceMatchAttr | 没有使用,可忽略 | + + 从第二个节点开始配置具体ADC控制器信息,此节点并不表示某一路ADC控制器,而是代表一个资源性质设备,用于描述一类ADC控制器的信息。本例只有一个ADC设备,如有多个设备,则需要在device_info文件增加deviceNode信息,以及在adc_config文件中增加对应的器件属性。 + + - device_info.hcs 配置参考。 + + + ``` + root { + device_info { + platform :: host { + device_adc :: device { + device0 :: deviceNode { + policy = 0; + priority = 50; + permission = 0644; + moduleName = "HDF_PLATFORM_ADC_MANAGER"; + serviceName = "HDF_PLATFORM_ADC_MANAGER"; + } + device1 :: deviceNode { + policy = 0; // 等于0,不需要发布服务 + priority = 55; // 驱动启动优先级 + permission = 0644; // 驱动创建设备节点权限 + moduleName = "hi35xx_adc_driver"; //【必要】用于指定驱动名称,需要与期望的驱动Entry中的moduleName一致; + serviceName = "HI35XX_ADC_DRIVER"; //【必要】驱动对外发布服务的名称,必须唯一 + deviceMatchAttr = "hisilicon_hi35xx_adc";//【必要】用于配置控制器私有数据,要与adc_config.hcs中对应控制器保持一致 + } // 具体的控制器信息在 adc_config.hcs 中 + } + } } - return - ``` - - - + } + ``` + - adc_config.hcs 配置参考。 + + + ``` + root { + platform { + adc_config_hi35xx { + match_attr = "hisilicon_hi35xx_adc"; + template adc_device { + regBasePhy = 0x120e0000;//寄存器物理基地址 + regSize = 0x34; //寄存器位宽 + deviceNum = 0; //设备号 + validChannel = 0x1; //有效通道 + dataWidth = 10; //信号接收的数据位宽 + scanMode = 1; //扫描模式 + delta = 0; //delta参数 + deglitch = 0; + glitchSample = 5000; + rate = 20000; + } + device_0 :: adc_device { + deviceNum = 0; + validChannel = 0x2; + } + } + } + } + ``` + +3. 完成驱动入口注册之后,最后一步就是以核心层AdcDevice对象的初始化为核心,包括初始化厂商自定义结构体(传递参数和数据),实例化AdcDevice成员AdcMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。 + - 自定义结构体参考。 + + 从驱动的角度看,自定义结构体是参数和数据的载体,而且adc_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,其中一些重要数值也会传递给核心层AdcDevice对象,例如设备号、总线号等。 + + + ``` + struct Hi35xxAdcDevice { + struct AdcDevice device;//【必要】是核心层控制对象,具体描述见下面 + volatile unsigned char *regBase;//【必要】寄存器基地址 + volatile unsigned char *pinCtrlBase; + uint32_t regBasePhy; //【必要】寄存器物理基地址 + uint32_t regSize; //【必要】寄存器位宽 + uint32_t deviceNum; //【必要】设备号 + uint32_t dataWidth; //【必要】信号接收的数据位宽 + uint32_t validChannel; //【必要】有效通道 + uint32_t scanMode; //【必要】扫描模式 + uint32_t delta; + uint32_t deglitch; + uint32_t glitchSample; + uint32_t rate; //【必要】采样率 + }; + + //AdcDevice是核心层控制器结构体,其中的成员在Init函数中会被赋值 + struct AdcDevice { + const struct AdcMethod *ops; + OsalSpinlock spin; + uint32_t devNum; + uint32_t chanNum; + const struct AdcLockMethod *lockOps; + void *priv; + }; + ``` + + - AdcDevice成员回调函数结构体AdcMethod的实例化,AdcLockMethod回调函数结构体本例未实现,若要实例化,可参考I2C驱动开发,其他成员在Init函数中初始化。 + + + ``` + static const struct AdcMethod g_method = { + .read = Hi35xxAdcRead, + .stop = Hi35xxAdcStop, + .start = Hi35xxAdcStart, + }; + ``` + - Init函数参考 + + 入参: + + HdfDeviceObject是整个驱动对外暴露的接口参数,具备HCS配置文件的信息。 + + 返回值: + + HDF_STATUS相关状态(下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf_base.h中HDF_STATUS 定义)。 + + | 状态(值) | 问题描述 | + | -------- | -------- | + | HDF_ERR_INVALID_OBJECT | 控制器对象非法 | + | HDF_ERR_INVALID_PARAM | 参数非法 | + | HDF_ERR_MALLOC_FAIL | 内存分配失败 | + | HDF_ERR_IO | I/O 错误 | + | HDF_SUCCESS | 传输成功 | + | HDF_FAILURE | 传输失败 | + + 函数说明: + + 初始化自定义结构体对象,初始化AdcDevice成员,并调用核心层AdcDeviceAdd函数。 + + ``` + static int32_t Hi35xxAdcInit(struct HdfDeviceObject *device) + { + int32_t ret; + struct DeviceResourceNode *childNode = NULL; + ... + //遍历、解析adc_config.hcs中的所有配置节点,并分别调用Hi35xxAdcParseInit函数来初始化device + DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) { + ret = Hi35xxAdcParseInit(device, childNode);//函数定义见下 + ... + } + return ret; + } + + static int32_t Hi35xxAdcParseInit(struct HdfDeviceObject *device, struct DeviceResourceNode *node) + { + int32_t ret; + struct Hi35xxAdcDevice *hi35xx = NULL; //【必要】自定义结构体对象 + (void)device; + + hi35xx = (struct Hi35xxAdcDevice *)OsalMemCalloc(sizeof(*hi35xx)); //【必要】内存分配 + ... + ret = Hi35xxAdcReadDrs(hi35xx, node); //【必要】将adc_config文件的默认值填充到结构体中 + ... + hi35xx->regBase = OsalIoRemap(hi35xx->regBasePhy, hi35xx->regSize);//【必要】地址映射 + ... + hi35xx->pinCtrlBase = OsalIoRemap(HI35XX_ADC_IO_CONFIG_BASE, HI35XX_ADC_IO_CONFIG_SIZE); + ... + Hi35xxAdcDeviceInit(hi35xx); //【必要】ADC设备的初始化 + hi35xx->device.priv = (void *)node; //【必要】存储设备属性 + hi35xx->device.devNum = hi35xx->deviceNum;//【必要】初始化AdcDevice成员 + hi35xx->device.ops = &g_method; //【必要】AdcMethod的实例化对象的挂载 + ret = AdcDeviceAdd(&hi35xx->device); //【必要且重要】调用此函数填充核心层结构体,返回成功信号后驱动才完全接入平台核心层 + ... + return HDF_SUCCESS; + + __ERR__: + if (hi35xx != NULL) { //不成功的话,需要反向执行初始化相关函数 + if (hi35xx->regBase != NULL) { + OsalIoUnmap((void *)hi35xx->regBase); + hi35xx->regBase = NULL; + } + AdcDeviceRemove(&hi35xx->device); + OsalMemFree(hi35xx); + } + return ret; + } + ``` + - Release 函数参考 + + 入参: + + HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 + + 返回值: + + 无。 + + 函数说明: + + 释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源。所有强制转换获取相应对象的操作**前提**是在Init函数中具备对应赋值的操作。 + + + ``` + static void Hi35xxAdcRelease(struct HdfDeviceObject *device) + { + const struct DeviceResourceNode *childNode = NULL; + ... + //遍历、解析adc_config.hcs中的所有配置节点,并分别进行release操作 + DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) { + Hi35xxAdcRemoveByNode(childNode);//函数定义见下 + } + } + + static void Hi35xxAdcRemoveByNode(const struct DeviceResourceNode *node) + { + int32_t ret; + int32_t deviceNum; + struct AdcDevice *device = NULL; + struct Hi35xxAdcDevice *hi35xx = NULL; + struct DeviceResourceIface *drsOps = NULL; + + drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE); + ... + ret = drsOps->GetUint32(node, "deviceNum", (uint32_t *)&deviceNum, 0); + ... + //可以调用AdcDeviceGet函数通过设备的deviceNum获取AdcDevice对象, 以及调用AdcDeviceRemove函数来释放AdcDevice对象的内容 + device = AdcDeviceGet(deviceNum); + if (device != NULL && device->priv == node) { + AdcDevicePut(device); + AdcDeviceRemove(device); //【必要】主要是从管理器驱动那边移除AdcDevice对象 + hi35xx = (struct Hi35xxAdcDevice *)device;//【必要】通过强制转换获取自定义的对象并进行release操作 + OsalIoUnmap((void *)hi35xx->regBase); + OsalMemFree(hi35xx); + } + return + ``` diff --git a/zh-cn/device-dev/driver/driver-platform-gpio-des.md b/zh-cn/device-dev/driver/driver-platform-gpio-des.md index 28cc26f4f695d821cc92e153a7c18c65e95fda4b..18da1fa126642838b1c1fe87ec038fdbb0d48ed7 100644 --- a/zh-cn/device-dev/driver/driver-platform-gpio-des.md +++ b/zh-cn/device-dev/driver/driver-platform-gpio-des.md @@ -1,489 +1,254 @@ -# GPIO +# GPIO -- [概述](#section1635911016188) -- [接口说明](#section589913442203) -- [使用指导](#section259614242196) - - [使用流程](#section103477714216) - - [确定GPIO管脚号](#section370083272117) - - [使用API操作GPIO管脚](#section13604050132118) -- [使用实例](#section25941262111) - -## 概述 +## 概述 GPIO(General-purpose input/output)即通用型输入输出。通常,GPIO控制器通过分组的方式管理所有GPIO管脚,每组GPIO有一个或多个寄存器与之关联,通过读写寄存器完成对GPIO管脚的操作。 GPIO接口定义了操作GPIO管脚的标准方法集合,包括: -- 设置管脚方向: 方向可以是输入或者输出\(暂不支持高阻态\) - -- 读写管脚电平值: 电平值可以是低电平或高电平 -- 设置管脚中断服务函数:设置一个管脚的中断响应函数,以及中断触发方式 -- 使能和禁止管脚中断:禁止或使能管脚中断 - -## 接口说明 - -**表 1** GPIO驱动API接口功能介绍 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

功能分类

-

接口名

-

描述

-

GPIO读写

-

GpioRead

-

读管脚电平值

-

GpioWrite

-

写管脚电平值

-

GPIO配置

-

GpioSetDir

-

设置管脚方向

-

GpioGetDir

-

获取管脚方向

-

GPIO中断设置

-

GpioSetIrq

-

设置管脚对应的中断服务函数

-

GpioUnSetIrq

-

取消管脚对应的中断服务函数

-

GpioEnableIrq

-

使能管脚中断

-

GpioDisableIrq

-

禁止管脚中断

-
- ->![](../public_sys-resources/icon-note.gif) **说明:** ->本文涉及的所有接口,仅限内核态使用,不支持在用户态使用。 - -## 使用指导 - -### 使用流程 - -GPIO标准API通过GPIO管脚号来操作指定管脚,使用GPIO的一般流程如[图1](#fig16151101653713)所示。 - -**图 1** GPIO使用流程图 -![](figures/GPIO使用流程图.png "GPIO使用流程图") - -### 确定GPIO管脚号 +- 设置管脚方向:方向可以是输入或者输出(暂不支持高阻态) + +- 读写管脚电平值:电平值可以是低电平或高电平 + +- 设置管脚中断服务函数:设置一个管脚的中断响应函数,以及中断触发方式 + +- 使能和禁止管脚中断:禁止或使能管脚中断 + + +## 接口说明 + + **表1** GPIO驱动API接口功能介绍 + +| 功能分类 | 接口描述 | +| -------- | -------- | +| GPIO读写 | - GpioRead:读管脚电平值
- GpioWrite:写管脚电平值 | +| GPIO配置 | - GpioSetDir:设置管脚方向
- GpioGetDir:获取管脚方向 | +| GPIO中断设置 | - GpioSetIrq:设置管脚对应的中断服务函数
- GpioUnSetIrq:取消管脚对应的中断服务函数
- GpioEnableIrq:使能管脚中断
- GpioDisableIrq:禁止管脚中断 | + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> 本文涉及的所有接口,仅限内核态使用,不支持在用户态使用。 + + +## 使用指导 + + +### 使用流程 + +GPIO标准API通过GPIO管脚号来操作指定管脚,使用GPIO的一般流程如下图所示。 + + **图1** GPIO使用流程图 + + ![zh-cn_image_0000001206291109](figures/zh-cn_image_0000001206291109.png) + + +### 确定GPIO管脚号 不同SOC芯片由于其GPIO控制器型号、参数、以及控制器驱动的不同,GPIO管脚号的换算方式不一样。 -- Hi3516DV300 - - 控制器管理12组GPIO管脚,每组8个。 - - GPIO号 = GPIO组索引 \(0\~11\) \* 每组GPIO管脚数\(8\) + 组内偏移 - - 举例:GPIO10\_3的GPIO号 = 10 \* 8 + 3 = 83 - -- Hi3518EV300 - - 控制器管理10组GPIO管脚,每组10个。 - - GPIO号 = GPIO组索引 \(0\~9\) \* 每组GPIO管脚数\(10\) + 组内偏移 - - 举例:GPIO7\_3的GPIO管脚号 = 7 \* 10 + 3 = 73 - - -### 使用API操作GPIO管脚 - -- 设置GPIO管脚方向 - - 在进行GPIO管脚读写前,需要先通过如下函数设置GPIO管脚方向: - - int32\_t GpioSetDir\(uint16\_t gpio, uint16\_t dir\); - - **表 2** GpioSetDir参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

gpio

-

待设置的GPIO管脚号

-

dir

-

待设置的方向值

-

返回值

-

返回值描述

-

0

-

设置成功

-

负数

-

设置失败

-
- - -- 读写GPIO管脚 - - 如果要读取一个GPIO管脚电平,通过以下函数完成: - - int32\_t GpioRead\(uint16\_t gpio, uint16\_t \*val\); - - **表 3** GpioRead参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

gpio

-

待读取的GPIO管脚号

-

val

-

接收读取电平值的指针

-

返回值

-

返回值描述

-

0

-

读取成功

-

负数

-

读取失败

-
- - 如果要向GPIO管脚写入电平值,通过以下函数完成: - - int32\_t GpioWrite\(uint16\_t gpio, uint16\_t val\); - - **表 4** GpioWrite参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

gpio

-

待写入的GPIO管脚号

-

val

-

待写入的电平值

-

返回值

-

返回值描述

-

0

-

写入成功

-

负数

-

写入失败

-
- - 示例代码: - - ``` - int32_t ret; - uint16_t val; - /* 将3号GPIO管脚配置为输出 */ - ret = GpioSetDir(3, GPIO_DIR_OUT); - if (ret != 0) { - HDF_LOGE("GpioSerDir: failed, ret %d\n", ret); - return; - } - /* 向3号GPIO管脚写入低电平GPIO_VAL_LOW */ - ret = GpioWrite(3, GPIO_VAL_LOW); - if (ret != 0) { - HDF_LOGE("GpioWrite: failed, ret %d\n", ret); - return; - } - /* 将6号GPIO管脚配置为输入 */ - ret = GpioSetDir(6, GPIO_DIR_IN); - if (ret != 0) { - HDF_LOGE("GpioSetDir: failed, ret %d\n", ret); - return; - } - /* 读取6号GPIO管脚的电平值 */ - ret = GpioRead(6, &val); - ``` - - -- 设置GPIO中断 - - 如果要为一个GPIO管脚设置中断响应程序,使用如下函数: - - int32\_t GpioSetIrq\(uint16\_t gpio, uint16\_t mode, GpioIrqFunc func, void \*arg\); - - **表 5** GpioSetIrq参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

gpio

-

GPIO管脚号

-

mode

-

中断触发模式

-

func

-

中断服务程序

-

arg

-

传递给中断服务程序的入参

-

返回值

-

返回值描述

-

0

-

设置成功

-

负数

-

设置失败

-
- - >![](../public_sys-resources/icon-caution.gif) **注意:** - >同一时间,只能为某个GPIO管脚设置一个中断服务函数,如果重复调用GpioSetIrq函数,则之前设置的中断服务函数会被取代。 - - 当不再需要响应中断服务函数时,使用如下函数取消中断设置: - - int32\_t GpioUnSetIrq\(uint16\_t gpio\); - - **表 6** GpioUnSetIrq参数和返回值描述 - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

gpio

-

GPIO管脚号

-

返回值

-

返回值描述

-

0

-

取消成功

-

负数

-

取消失败

-
- - 在中断服务程序设置完成后,还需要先通过如下函数使能GPIO管脚的中断: - - int32\_t GpioEnableIrq\(uint16\_t gpio\); - - **表 7** GpioEnableIrq参数和返回值描述 - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

gpio

-

GPIO管脚号

-

返回值

-

返回值描述

-

0

-

使能成功

-

负数

-

使能失败

-
- - >![](../public_sys-resources/icon-caution.gif) **注意:** - >必须通过此函数使能管脚中断,之前设置的中断服务函数才能被正确响应。 - - 如果要临时屏蔽此中断,可以通过如下函数禁止GPIO管脚中断: - - int32\_t GpioDisableIrq\(uint16\_t gpio\); - - **表 8** GpioDisableIrq参数和返回值描述 - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

gpio

-

GPIO管脚号

-

返回值

-

返回值描述

-

0

-

禁止成功

-

负数

-

禁止失败

-
- - 示例代码: - - ``` - /* 中断服务函数 - */ - int32_t MyCallBackFunc(uint16_t gpio, void *data) - { - HDF_LOGI("%s: gpio:%u interrupt service in! data=%p\n", __func__, gpio, data); - return 0; - } - - int32_t ret; - /* 设置中断服务程序为MyCallBackFunc,入参为NULL,中断触发模式为上升沿触发 */ - ret = GpioSetIrq(3, OSAL_IRQF_TRIGGER_RISING, MyCallBackFunc, NULL); - if (ret != 0) { - HDF_LOGE("GpioSetIrq: failed, ret %d\n", ret); - return; - } - - /* 使能3号GPIO管脚中断 */ - ret = GpioEnableIrq(3); - if (ret != 0) { - HDF_LOGE("GpioEnableIrq: failed, ret %d\n", ret); - return; - } - - /* 禁止3号GPIO管脚中断 */ - ret = GpioDisableIrq(3); - if (ret != 0) { - HDF_LOGE("GpioDisableIrq: failed, ret %d\n", ret); - return; - } - - /* 取消3号GPIO管脚中断服务程序 */ - ret = GpioUnSetIrq(3); - if (ret != 0) { - HDF_LOGE("GpioUnSetIrq: failed, ret %d\n", ret); - return; - } - ``` +- Hi3516DV300 + 控制器管理12组GPIO管脚,每组8个。 + GPIO号 = GPIO组索引 (0~11) \* 每组GPIO管脚数(8) + 组内偏移 -## 使用实例 + 举例:GPIO10_3的GPIO号 = 10 \* 8 + 3 = 83 -本实例程序中,我们将测试一个GPIO管脚的中断触发:为管脚设置中断服务函数,触发方式为边沿触发,然后通过交替写高低电平到管脚,产生电平波动,制造触发条件,观察中断服务函数的执行。 +- Hi3518EV300 + 控制器管理10组GPIO管脚,每组10个。 + + GPIO号 = GPIO组索引 (0~9) \* 每组GPIO管脚数(10) + 组内偏移 + + 举例:GPIO7_3的GPIO管脚号 = 7 \* 10 + 3 = 73 + + +### 使用API操作GPIO管脚 + +- 设置GPIO管脚方向 + 在进行GPIO管脚读写前,需要先通过如下函数设置GPIO管脚方向: + + int32_t GpioSetDir(uint16_t gpio, uint16_t dir); + + **表2** GpioSetDir参数和返回值描述 + + | **参数**| **参数描述** | + | -------- | -------- | + | gpio | 待设置的GPIO管脚号 | + | dir | 待设置的方向值 | + | **返回值** | **返回值描述** | + | 0 | 设置成功 | + | 负数 | 设置失败 | + +- 读写GPIO管脚 -首先需要选取一个空闲的GPIO管脚,本例程基于Hi3516DV300某开发板,GPIO管脚选择GPIO10\_3,换算成GPIO号为83。 + 如果要读取一个GPIO管脚电平,通过以下函数完成: -读者可以根据自己使用的开发板,参考其原理图,选择一个空闲的GPIO管脚即可。 + int32_t GpioRead(uint16_t gpio, uint16_t \*val); + **表3** GpioRead参数和返回值描述 + + | **参数** | **参数描述** | + | -------- | -------- | + | gpio | 待读取的GPIO管脚号 | + | val | 接收读取电平值的指针 | + | **返回值** | **返回值描述** | + | 0 | 读取成功 | + | 负数 | 读取失败 | + + 如果要向GPIO管脚写入电平值,通过以下函数完成: + + int32_t GpioWrite(uint16_t gpio, uint16_t val); + + **表4** GpioWrite参数和返回值描述 + + | **参数** | **参数描述** | + | -------- | -------- | + | gpio | 待写入的GPIO管脚号 | + | val | 待写入的电平值 | + | **返回值** | **返回值描述** | + | 0 | 写入成功 | + | 负数 | 写入失败 | + + 示例代码: + + + ``` + int32_t ret; + uint16_t val; + /* 将3号GPIO管脚配置为输出 */ + ret = GpioSetDir(3, GPIO_DIR_OUT); + if (ret != 0) { + HDF_LOGE("GpioSerDir: failed, ret %d\n", ret); + return; + } + /* 向3号GPIO管脚写入低电平GPIO_VAL_LOW */ + ret = GpioWrite(3, GPIO_VAL_LOW); + if (ret != 0) { + HDF_LOGE("GpioWrite: failed, ret %d\n", ret); + return; + } + /* 将6号GPIO管脚配置为输入 */ + ret = GpioSetDir(6, GPIO_DIR_IN); + if (ret != 0) { + HDF_LOGE("GpioSetDir: failed, ret %d\n", ret); + return; + } + /* 读取6号GPIO管脚的电平值 */ + ret = GpioRead(6, &val); + ``` + +- 设置GPIO中断 + + 如果要为一个GPIO管脚设置中断响应程序,使用如下函数: + + int32_t GpioSetIrq(uint16_t gpio, uint16_t mode, GpioIrqFunc func, void \*arg); + + **表5** GpioSetIrq参数和返回值描述 + + | **参数** | **参数描述** | + | -------- | -------- | + | gpio | GPIO管脚号 | + | mode | 中断触发模式 | + | func | 中断服务程序 | + | arg | 传递给中断服务程序的入参 | + | **返回值** | **返回值描述** | + | 0 | 设置成功 | + | 负数 | 设置失败 | + + > ![icon-caution.gif](public_sys-resources/icon-caution.gif) **注意:** + > 同一时间,只能为某个GPIO管脚设置一个中断服务函数,如果重复调用GpioSetIrq函数,则之前设置的中断服务函数会被取代。 + + 当不再需要响应中断服务函数时,使用如下函数取消中断设置: + + int32_t GpioUnSetIrq(uint16_t gpio); + + **表6** GpioUnSetIrq参数和返回值描述 + + | **参数** | **参数描述** | + | -------- | -------- | + | gpio | GPIO管脚号 | + | **返回值** | **返回值描述** | + | 0 | 取消成功 | + | 负数 | 取消失败 | + + 在中断服务程序设置完成后,还需要先通过如下函数使能GPIO管脚的中断: + + int32_t GpioEnableIrq(uint16_t gpio); + + **表7** GpioEnableIrq参数和返回值描述 + + | **参数** | **参数描述** | + | -------- | -------- | + | gpio | GPIO管脚号 | + | **返回值** | **返回值描述** | + | 0 | 使能成功 | + | 负数 | 使能失败 | + + > ![icon-caution.gif](public_sys-resources/icon-caution.gif) **注意:** + > 必须通过此函数使能管脚中断,之前设置的中断服务函数才能被正确响应。 + + 如果要临时屏蔽此中断,可以通过如下函数禁止GPIO管脚中断: + + int32_t GpioDisableIrq(uint16_t gpio); + + **表8** GpioDisableIrq参数和返回值描述 + + | **参数** | **参数描述** | + | -------- | -------- | + | gpio | GPIO管脚号 | + | **返回值** | **返回值描述** | + | 0 | 禁止成功 | + | 负数 | 禁止失败 | + + 示例代码: + + + ``` + /* 中断服务函数*/ + int32_t MyCallBackFunc(uint16_t gpio, void *data) + { + HDF_LOGI("%s: gpio:%u interrupt service in! data=%p\n", __func__, gpio, data); + return 0; + } + + int32_t ret; + /* 设置中断服务程序为MyCallBackFunc,入参为NULL,中断触发模式为上升沿触发 */ + ret = GpioSetIrq(3, OSAL_IRQF_TRIGGER_RISING, MyCallBackFunc, NULL); + if (ret != 0) { + HDF_LOGE("GpioSetIrq: failed, ret %d\n", ret); + return; + } + + /* 使能3号GPIO管脚中断 */ + ret = GpioEnableIrq(3); + if (ret != 0) { + HDF_LOGE("GpioEnableIrq: failed, ret %d\n", ret); + return; + } + + /* 禁止3号GPIO管脚中断 */ + ret = GpioDisableIrq(3); + if (ret != 0) { + HDF_LOGE("GpioDisableIrq: failed, ret %d\n", ret); + return; + } + + /* 取消3号GPIO管脚中断服务程序 */ + ret = GpioUnSetIrq(3); + if (ret != 0) { + HDF_LOGE("GpioUnSetIrq: failed, ret %d\n", ret); + return; + } + ``` + + +## 使用实例 + +本实例程序中,我们将测试一个GPIO管脚的中断触发:为管脚设置中断服务函数,触发方式为边沿触发,然后通过交替写高低电平到管脚,产生电平波动,制造触发条件,观察中断服务函数的执行。 + +首先需要选取一个空闲的GPIO管脚,本例程基于Hi3516DV300某开发板,GPIO管脚选择GPIO10_3,换算成GPIO号为83。 + + 读者可以根据自己使用的开发板,参考其原理图,选择一个空闲的GPIO管脚即可。 + ``` #include "gpio_if.h" #include "hdf_log.h" @@ -554,4 +319,3 @@ static int32_t TestCaseGpioIrqEdge(void) return (g_irqCnt > 0) ? HDF_SUCCESS : HDF_FAILURE; } ``` - diff --git a/zh-cn/device-dev/driver/driver-platform-gpio-develop.md b/zh-cn/device-dev/driver/driver-platform-gpio-develop.md index 4df1de196e9bda0c906b9e20ff38d500b43d79c9..a7c7c0ce06971278329faabc630b7ef74c38d605 100755 --- a/zh-cn/device-dev/driver/driver-platform-gpio-develop.md +++ b/zh-cn/device-dev/driver/driver-platform-gpio-develop.md @@ -1,21 +1,21 @@ -# GPIO +# GPIO -- [概述](#section1826197354103451) -- [接口说明](#section752964871810) -- [开发步骤](#section731175315103451) -- [开发实例](#section800425816103451) -## 概述 +## 概述 -GPIO(General-purpose input/output)即通用型输入输出,在HDF框架中,GPIO的接口适配模式采用无服务模式,用于不需要在用户态提供API的设备类型,或者没有用户态和内核区分的OS系统,其关联方式是DevHandle直接指向设备对象内核态地址(DevHandle是一个void类型指针)。 +GPIO(General-purpose input/output)即通用型输入输出,在HDF框架中, -**图 1** GPIO无服务模式结构图 -![](figures/无服务模式结构图.png "GPIO无服务模式结构图") +GPIO的接口适配模式采用无服务模式,用于不需要在用户态提供API的设备类型,或者没有用户态和内核区分的OS系统,其关联方式是DevHandle直接指向设备对象内核态地址(DevHandle是一个void类型指针)。 -## 接口说明 + **图1** GPIO无服务模式结构图 + ![zh-cn_image_0000001176603952](figures/zh-cn_image_0000001176603952.png) + + +## 接口说明 GpioMethod定义: + ``` struct GpioMethod { int32_t (*request)(struct GpioCntlr *cntlr, uint16_t local);// 【预留】 @@ -32,385 +32,255 @@ struct GpioMethod { } ``` -**表 1** GpioMethod结构体成员的回调函数功能说明 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

函数成员

-

入参

-

出参

-

返回值

-

功能

-

write

-

cntlr:结构体指针,核心层GPIO控制器;
local:uint16_t,GPIO端口标识号;
val:uint16_t,电平传入值;

-

-

HDF_STATUS相关状态

-

GPIO引脚写入电平值

-

read

-

cntlr:结构体指针,核心层GPIO控制器;
local:uint16_t,GPIO端口标识;

-

val:uint16_t 指针,用于传出电平值;

-

HDF_STATUS相关状态

-

GPIO引脚读取电平值

-

setDir

-

cntlr:结构体指针,核心层GPIO控制器;
local:uint16_t,GPIO端口标识号;
dir:uint16_t,管脚方向传入值;

-

-

HDF_STATUS相关状态

-

设置GPIO引脚输入/输出方向

-

getDir

-

cntlr:结构体指针,核心层GPIO控制器;
local:uint16_t,GPIO端口标识号;

-

dir:uint16_t 指针,用于传出管脚方向值;

-

HDF_STATUS相关状态

-

读GPIO引脚输入/输出方向

-

setIrq

-

cntlr:结构体指针,核心层GPIO控制器;
local:uint16_t,GPIO端口标识号;
mode:uint16_t,表示触发模式(边沿或电平);
func:函数指针,中断服务程序;
arg:void指针,中断服务程序入参;

-

-

HDF_STATUS相关状态

-

将GPIO引脚设置为中断模式

-

unsetIrq

-

cntlr:结构体指针,核心层GPIO控制器;
local:uint16_t,GPIO端口标识号;

-

-

HDF_STATUS相关状态

-

取消GPIO中断设置

-

enableIrq

-

cntlr:结构体指针,核心层GPIO控制器;
local:uint16_t,GPIO端口标识号;

-

-

HDF_STATUS相关状态

-

使能GPIO管脚中断

-

disableIrq

-

cntlr:结构体指针,核心层GPIO控制器;
local:uint16_t,GPIO端口标识号;

-

-

HDF_STATUS相关状态

-

禁止GPIO管脚中断

-
- -## 开发步骤 - -GPIO模块适配的三个环节是配置属性文件,实例化驱动入口,以及实例化核心层接口函数。GPIO控制器分组管理所有管脚,相关参数会在属性文件中有所体现;驱动入口和接口函数的实例化环节是厂商驱动接入HDF的核心环节。 - -1. **实例化驱动入口:** - - 实例化HdfDriverEntry结构体成员。 - - 调用HDF\_INIT将HdfDriverEntry实例化对象注册到HDF框架中。 - -2. **配置属性文件:** - - 在device\_info.hcs文件中添加deviceNode描述。 - - 【可选】添加gpio\_config.hcs器件属性文件。 + **表1** GpioMethod结构体成员的回调函数功能说明 -3. **实例化GPIO控制器对象:** - - 初始化GpioCntlr成员。 - - 实例化GpioCntlr成员GpioMethod。 +| 函数成员 | 入参 | 出参 | 返回值 | 功能 | +| -------- | -------- | -------- | -------- | -------- | +| write | cntlr:结构体指针,核心层GPIO控制器;
local:uint16_t,GPIO端口标识号 ;
val:uint16_t,电平传入值; | 无 | HDF_STATUS相关状态 | GPIO引脚写入电平值 | +| read | cntlr:结构体指针,核心层GPIO控制器;
local:uint16_t,GPIO端口标识; | val:uint16_t 指针,用于传出电平值。 | HDF_STATUS相关状态 | GPIO引脚读取电平值 | +| setDir | cntlr:结构体指针,核心层GPIO控制器;
local:uint16_t,GPIO端口标识号 ;
dir:uint16_t,管脚方向传入值; | 无 | HDF_STATUS相关状态 | 设置GPIO引脚输入/输出方向 | +| getDir | cntlr:结构体指针,核心层GPIO控制器;
local:uint16_t,GPIO端口标识号; | dir:uint16_t 指针,用于传出管脚方向值。 | HDF_STATUS相关状态 | 读GPIO引脚输入/输出方向 | +| setIrq | cntlr:结构体指针,核心层GPIO控制器;
local:uint16_t,GPIO端口标识号;
mode:uint16_t,表示触发模式(边沿或电平);
func:函数指针,中断服务程序;
arg:void指针,中断服务程序入参; | 无 | HDF_STATUS相关状态 | 将GPIO引脚设置为中断模式 | +| unsetIrq | cntlr:结构体指针,核心层GPIO控制器;
local:uint16_t,GPIO端口标识号; | 无 | HDF_STATUS相关状态 | 取消GPIO中断设置 | +| enableIrq | cntlr:结构体指针,核心层GPIO控制器;
local:uint16_t,GPIO端口标识号; | 无 | HDF_STATUS相关状态 | 使能GPIO管脚中断 | +| disableIrq | cntlr:结构体指针,核心层GPIO控制器;
local:uint16_t,GPIO端口标识号; | 无 | HDF_STATUS相关状态 | 禁止GPIO管脚中断 | - >![](../public_sys-resources/icon-note.gif) **说明:** - >实例化GpioCntlr成员GpioMethod,详见[接口说明](#section752964871810)。 +## 开发步骤 -4. **驱动调试:** - - 【可选】针对新增驱动程序,建议验证驱动基本功能,例如GPIO控制状态,中断响应情况等。 +GPIO模块适配的三个环节是配置属性文件,实例化驱动入口,以及实例化核心层接口函数。GPIO控制器分组管理所有管脚,相关参数会在属性文件中有所体现;驱动入口和接口函数的实例化环节是厂商驱动接入HDF的核心环节。 +1. **实例化驱动入口:** + - 实例化HdfDriverEntry结构体成员。 + - 调用HDF_INIT将HdfDriverEntry实例化对象注册到HDF框架中。 -## 开发实例 +2. **配置属性文件:** + - 在device_info.hcs文件中添加deviceNode描述。 + - 【可选】添加gpio_config.hcs器件属性文件。 -下方将以gpio\_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。 +3. **实例化GPIO控制器对象:** + - 初始化GpioCntlr成员。 + - 实例化GpioCntlr成员GpioMethod。 + > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** + > 实例化GpioCntlr成员GpioMethod,详见[接口说明](#接口说明)。 -1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf\_device\_desc.h 中定义)类型的全局变量,且moduleName要和device\_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。 +4. **驱动调试:** + 【可选】针对新增驱动程序,建议验证驱动基本功能,例如GPIO控制状态,中断响应情况等。 - 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 - GPIO 驱动入口参考: +## 开发实例 - ``` - struct HdfDriverEntry g_gpioDriverEntry = { - .moduleVersion = 1, - .Bind = Pl061GpioBind, //GPIO不需要实现Bind,本例是一个空实现,厂商可根据自身需要添加相关操作 - .Init = Pl061GpioInit, //见Init参考 - .Release = Pl061GpioRelease, //见Release参考 - .moduleName = "hisi_pl061_driver",//【必要且需要与HCS文件中里面的moduleName匹配】 - }; - //调用HDF_INIT将驱动入口注册到HDF框架中 - HDF_INIT(g_gpioDriverEntry); - ``` +下方将以gpio_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。 -2. 完成驱动入口注册之后,下一步请在device\_info.hcs文件中添加deviceNode信息,并在 gpio\_config.hcs 中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值与核心层GpioCntlr 成员的默认值或限制范围有密切关系。 +1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf_device_desc.h 中定义)类型的全局变量,且moduleName要和device_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。 + 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 - 本例只有一个GPIO控制器,如有多个器件信息,则需要在device\_info文件增加deviceNode信息,以及在gpio\_config文件中增加对应的器件属性。 + GPIO 驱动入口参考: + + ``` + struct HdfDriverEntry g_gpioDriverEntry = { + .moduleVersion = 1, + .Bind = Pl061GpioBind, //GPIO不需要实现Bind,本例是一个空实现,厂商可根据自身需要添加相关操作 + .Init = Pl061GpioInit, //见Init参考 + .Release = Pl061GpioRelease, //见Release参考 + .moduleName = "hisi_pl061_driver",//【必要且需要与HCS文件中里面的moduleName匹配】 + }; + //调用HDF_INIT将驱动入口注册到HDF框架中 + HDF_INIT(g_gpioDriverEntry); + ``` - - device\_info.hcs 配置参考。 +2. 完成驱动入口注册之后,下一步请在device_info.hcs文件中添加deviceNode信息,并在 gpio_config.hcs 中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值与核心层GpioCntlr 成员的默认值或限制范围有密切关系。 + 本例只有一个GPIO控制器,如有多个器件信息,则需要在device_info文件增加deviceNode信息,以及在gpio_config文件中增加对应的器件属性。 - ``` - root { - device_info { - platform :: host { - hostName = "platform_host"; - priority = 50; - device_gpio :: device { - device0 :: deviceNode { - policy = 0; // 等于0,不需要发布服务 - priority = 10; // 驱动启动优先级 - permission = 0644; // 驱动创建设备节点权限 - moduleName = "hisi_pl061_driver"; //【必要】用于指定驱动名称,需要与期望的驱动Entry中的moduleName一致; - deviceMatchAttr = "hisilicon_hi35xx_pl061";//【必要】用于配置控制器私有数据,要与 gpio_config.hcs 中 - //对应控制器保持一致,其他控制器信息也在文件中 - } - } - } - } - } - ``` - - - gpio\_config.hcs 配置参考。 - - ``` - root { - platform { - gpio_config { - controller_0x120d0000 { - match_attr = "hisilicon_hi35xx_pl061"; //【必要】必须和device_info.hcs中的deviceMatchAttr值一致 - groupNum = 12; //【必要】GPIO组索引 需要根据设备情况填写 - bitNum = 8; //【必要】每组GPIO管脚数 - regBase = 0x120d0000;//【必要】物理基地址 - regStep = 0x1000; //【必要】寄存器偏移步进 - irqStart = 48; //【必要】开启中断 - irqShare = 0; //【必要】共享中断 - } - } - } - } - ``` - -3. 完成驱动入口注册之后,最后一步就是以核心层GpioCntlr对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化GpioCntlr成员GpioMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。 - - 自定义结构体参考。 - - 从驱动的角度看,自定义结构体是参数和数据的载体,而且gpio\_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,其中一些重要数值也会传递给核心层GpioCntlr对象,例如索引、管脚数等。 - - ``` - struct Pl061GpioCntlr { - struct GpioCntlr cntlr;//【必要】 是核心层控制对象,其成员定义见下面 - volatile unsigned char *regBase; //【必要】寄存器基地址 - uint32_t phyBase; //【必要】 物理基址 - uint32_t regStep; //【必要】 寄存器偏移步进 - uint32_t irqStart; //【必要】 中断开启 - uint16_t groupNum; //【必要】 用于描述厂商的GPIO端口号的参数 - uint16_t bitNum; //【必要】 用于描述厂商的GPIO端口号的参数 - uint8_t irqShare; //【必要】 共享中断 - struct Pl061GpioGroup *groups; //【可选】 根据厂商需要设置 - }; - struct Pl061GpioGroup { //包括寄存器地址,中断号,中断函数和和锁 - volatile unsigned char *regBase; - unsigned int index; - unsigned int irq; - OsalIRQHandle irqFunc; - OsalSpinlock lock; - }; + - device_info.hcs 配置参考。 - // GpioCntlr是核心层控制器结构体,其中的成员在Init函数中会被赋值 - struct GpioCntlr { - struct IDeviceIoService service; - struct HdfDeviceObject *device; - struct GpioMethod *ops; - struct DListHead list; - OsalSpinlock spin; - uint16_t start; - uint16_t count; - struct GpioInfo *ginfos; - void *priv; - }; - ``` - - - GpioCntlr成员回调函数结构体GpioMethod的实例化,其他成员在Init函数中初始化。 - - ``` - //GpioMethod结构体成员都是回调函数,厂商需要根据表1完成相应的函数功能。 - static struct GpioMethod g_method = { - .request = NULL, - .release = NULL, - .write = Pl061GpioWrite, //写管脚 - .read = Pl061GpioRead, //读管脚 - .setDir = Pl061GpioSetDir, //设置管脚方向 - .getDir = Pl061GpioGetDir, //获取管脚方向 - .toIrq = NULL, - .setIrq = Pl061GpioSetIrq, //设置管脚中断,如不具备此能力可忽略 - .unsetIrq = Pl061GpioUnsetIrq, //取消管脚中断设置,如不具备此能力可忽略 - .enableIrq = Pl061GpioEnableIrq, //使能管脚中断,如不具备此能力可忽略 - .disableIrq = Pl061GpioDisableIrq,//禁止管脚中断,如不具备此能力可忽略 - }; - ``` - - - Init函数参考 - - 入参: - - HdfDeviceObject这个是整个驱动对外暴露的接口参数,具备HCS配置文件的信息。 - - 返回值: - - HDF\_STATUS相关状态(下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf\_base.h中HDF\_STATUS 定义)。 - - **表 2** Init函数说明 - - - - - - - - - - - - - - - - - - - - - - - - - -

状态(值)

-

问题描述

-

HDF_ERR_INVALID_OBJECT

-

控制器对象非法

-

HDF_ERR_MALLOC_FAIL

-

内存分配失败

-

HDF_ERR_INVALID_PARAM

-

参数非法

-

HDF_ERR_IO

-

I/O 错误

-

HDF_SUCCESS

-

初始化成功

-

HDF_FAILURE

-

初始化失败

-
- - 函数说明: - - 初始化自定义结构体对象,初始化GpioCntlr成员,调用核心层GpioCntlrAdd函数,【可选】接入VFS。 - - ``` - static int32_t Pl061GpioInit(struct HdfDeviceObject *device) - { - ... - struct Pl061GpioCntlr *pl061 = &g_pl061;//利用静态全局变量完成初始化 - //static struct Pl061GpioCntlr g_pl061 = { - // .groups = NULL, - // .groupNum = PL061_GROUP_MAX, - // .bitNum = PL061_BIT_MAX, - //}; - ret = Pl061GpioReadDrs(pl061, device->property);//利用从gpio_config.HCS文件读取的属性值来初始化自定义结构体对象成员 - ... - pl061->regBase = OsalIoRemap(pl061->phyBase, pl061->groupNum * pl061->regStep);//地址映射 - ... - ret = Pl061GpioInitCntlrMem(pl061); // 内存分配 - ... - pl061->cntlr.count = pl061->groupNum * pl061->bitNum;//【必要】管脚数量计算 - pl061->cntlr.priv = (void *)device->property; //【必要】存储设备属性 - pl061->cntlr.ops = &g_method; // 【必要】GpioMethod的实例化对象的挂载 - pl061->cntlr.device = device; // 【必要】使HdfDeviceObject与GpioCntlr可以相互转化的前提 - ret = GpioCntlrAdd(&pl061->cntlr); // 【必要】调用此函数填充核心层结构体,返回成功信号后驱动才完全接入平台核心层 - ... - Pl061GpioDebugCntlr(pl061); - #ifdef PL061_GPIO_USER_SUPPORT //【可选】若支持用户级的虚拟文件系统,则接入 - if (GpioAddVfs(pl061->bitNum) != HDF_SUCCESS) { - HDF_LOGE("%s: add vfs fail!", __func__); + ``` + root { + device_info { + platform :: host { + hostName = "platform_host"; + priority = 50; + device_gpio :: device { + device0 :: deviceNode { + policy = 0; // 等于0,不需要发布服务 + priority = 10; // 驱动启动优先级 + permission = 0644; // 驱动创建设备节点权限 + moduleName = "hisi_pl061_driver"; //【必要】用于指定驱动名称,需要与期望的驱动Entry中的moduleName一致; + deviceMatchAttr = "hisilicon_hi35xx_pl061";//【必要】用于配置控制器私有数据,要与 gpio_config.hcs 中 + //对应控制器保持一致,其他控制器信息也在文件中 + } } - #endif - ... - } - ``` + } + } + } + ``` + - gpio_config.hcs 配置参考。 + + ``` + root { + platform { + gpio_config { + controller_0x120d0000 { + match_attr = "hisilicon_hi35xx_pl061"; //【必要】必须和device_info.hcs中的deviceMatchAttr值一致 + groupNum = 12; //【必要】GPIO组索引 需要根据设备情况填写 + bitNum = 8; //【必要】每组GPIO管脚数 + regBase = 0x120d0000;//【必要】物理基地址 + regStep = 0x1000; //【必要】寄存器偏移步进 + irqStart = 48; //【必要】开启中断 + irqShare = 0; //【必要】共享中断 + } + } + } + } + ``` - - Release 函数参考 +3. 完成驱动入口注册之后,最后一步就是以核心层GpioCntlr对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化GpioCntlr成员GpioMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。 + - 自定义结构体参考。 - 入参: + 从驱动的角度看,自定义结构体是参数和数据的载体,而且gpio_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,其中一些重要数值也会传递给核心层GpioCntlr对象,例如索引、管脚数等。 - HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 + + ``` + struct Pl061GpioCntlr { + struct GpioCntlr cntlr;//【必要】 是核心层控制对象,其成员定义见下面 + volatile unsigned char *regBase; //【必要】寄存器基地址 + uint32_t phyBase; //【必要】 物理基址 + uint32_t regStep; //【必要】 寄存器偏移步进 + uint32_t irqStart; //【必要】 中断开启 + uint16_t groupNum; //【必要】 用于描述厂商的GPIO端口号的参数 + uint16_t bitNum; //【必要】 用于描述厂商的GPIO端口号的参数 + uint8_t irqShare; //【必要】 共享中断 + struct Pl061GpioGroup *groups; //【可选】 根据厂商需要设置 + }; + struct Pl061GpioGroup { //包括寄存器地址,中断号,中断函数和和锁 + volatile unsigned char *regBase; + unsigned int index; + unsigned int irq; + OsalIRQHandle irqFunc; + OsalSpinlock lock; + }; + + // GpioCntlr是核心层控制器结构体,其中的成员在Init函数中会被赋值 + struct GpioCntlr { + struct IDeviceIoService service; + struct HdfDeviceObject *device; + struct GpioMethod *ops; + struct DListHead list; + OsalSpinlock spin; + uint16_t start; + uint16_t count; + struct GpioInfo *ginfos; + void *priv; + }; + ``` + - GpioCntlr成员回调函数结构体GpioMethod的实例化,其他成员在Init函数中初始化。 - 返回值: + + ``` + //GpioMethod结构体成员都是回调函数,厂商需要根据表1完成相应的函数功能。 + static struct GpioMethod g_method = { + .request = NULL, + .release = NULL, + .write = Pl061GpioWrite, //写管脚 + .read = Pl061GpioRead, //读管脚 + .setDir = Pl061GpioSetDir, //设置管脚方向 + .getDir = Pl061GpioGetDir, //获取管脚方向 + .toIrq = NULL, + .setIrq = Pl061GpioSetIrq, //设置管脚中断,如不具备此能力可忽略 + .unsetIrq = Pl061GpioUnsetIrq, //取消管脚中断设置,如不具备此能力可忽略 + .enableIrq = Pl061GpioEnableIrq, //使能管脚中断,如不具备此能力可忽略 + .disableIrq = Pl061GpioDisableIrq,//禁止管脚中断,如不具备此能力可忽略 + }; + ``` + + - Init函数参考 + + 入参: + + HdfDeviceObject这个是整个驱动对外暴露的接口参数,具备HCS配置文件的信息。 + + 返回值: + + HDF_STATUS相关状态(下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf_base.h中HDF_STATUS 定义)。 + + **表2** Init函数说明 + + | 状态(值) | 问题描述 | + | -------- | -------- | + | HDF_ERR_INVALID_OBJECT | 控制器对象非法 | + | HDF_ERR_MALLOC_FAIL | 内存分配失败 | + | HDF_ERR_INVALID_PARAM | 参数非法 | + | HDF_ERR_IO | I/O 错误 | + | HDF_SUCCESS | 初始化成功 | + | HDF_FAILURE | 初始化失败 | + + 函数说明: + + 初始化自定义结构体对象,初始化GpioCntlr成员,调用核心层GpioCntlrAdd函数,【可选】接入VFS。 - 无。 + + ``` + static int32_t Pl061GpioInit(struct HdfDeviceObject *device) + { + ... + struct Pl061GpioCntlr *pl061 = &g_pl061;//利用静态全局变量完成初始化 + //static struct Pl061GpioCntlr g_pl061 = { + // .groups = NULL, + // .groupNum = PL061_GROUP_MAX, + // .bitNum = PL061_BIT_MAX, + //}; + ret = Pl061GpioReadDrs(pl061, device->property);//利用从gpio_config.HCS文件读取的属性值来初始化自定义结构体对象成员 + ... + pl061->regBase = OsalIoRemap(pl061->phyBase, pl061->groupNum * pl061->regStep);//地址映射 + ... + ret = Pl061GpioInitCntlrMem(pl061); // 内存分配 + ... + pl061->cntlr.count = pl061->groupNum * pl061->bitNum;//【必要】管脚数量计算 + pl061->cntlr.priv = (void *)device->property; //【必要】存储设备属性 + pl061->cntlr.ops = &g_method; // 【必要】GpioMethod的实例化对象的挂载 + pl061->cntlr.device = device; // 【必要】使HdfDeviceObject与GpioCntlr可以相互转化的前提 + ret = GpioCntlrAdd(&pl061->cntlr); // 【必要】调用此函数填充核心层结构体,返回成功信号后驱动才完全接入平台核心层 + ... + Pl061GpioDebugCntlr(pl061); + #ifdef PL061_GPIO_USER_SUPPORT //【可选】若支持用户级的虚拟文件系统,则接入 + if (GpioAddVfs(pl061->bitNum) != HDF_SUCCESS) { + HDF_LOGE("%s: add vfs fail!", __func__); + } + #endif + ... + } + ``` + - Release 函数参考 - 函数说明: + 入参: - 释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源。所有强制转换获取相应对象的操作**前提**是在Init函数中具备对应赋值的操作。 + HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 - ``` - static void Pl061GpioRelease(struct HdfDeviceObject *device) - { - struct GpioCntlr *cntlr = NULL; - struct Pl061GpioCntlr *pl061 = NULL; - ... - cntlr = GpioCntlrFromDevice(device);//【必要】通过强制转换获取核心层控制对象 - //return (device == NULL) ? NULL : (struct GpioCntlr *)device->service; - ... - #ifdef PL061_GPIO_USER_SUPPORT - GpioRemoveVfs();//与Init中GpioAddVfs相反 - #endif - GpioCntlrRemove(cntlr); //【必要】取消设备信息、服务等内容在核心层上的挂载 - pl061 = ToPl061GpioCntlr(cntlr); //return (struct Pl061GpioCntlr *)cntlr; - Pl061GpioRleaseCntlrMem(pl061); //【必要】锁和内存的释放 - OsalIoUnmap((void *)pl061->regBase);//【必要】解除地址映射 - pl061->regBase = NULL; - } - ``` + 返回值: + 无。 + 函数说明: + 释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源。所有强制转换获取相应对象的操作**前提**是在Init函数中具备对应赋值的操作。 + + + ``` + static void Pl061GpioRelease(struct HdfDeviceObject *device) + { + struct GpioCntlr *cntlr = NULL; + struct Pl061GpioCntlr *pl061 = NULL; + ... + cntlr = GpioCntlrFromDevice(device);//【必要】通过强制转换获取核心层控制对象 + //return (device == NULL) ? NULL : (struct GpioCntlr *)device->service; + ... + #ifdef PL061_GPIO_USER_SUPPORT + GpioRemoveVfs();//与Init中GpioAddVfs相反 + #endif + GpioCntlrRemove(cntlr); //【必要】取消设备信息、服务等内容在核心层上的挂载 + pl061 = ToPl061GpioCntlr(cntlr); //return (struct Pl061GpioCntlr *)cntlr; + Pl061GpioRleaseCntlrMem(pl061); //【必要】锁和内存的释放 + OsalIoUnmap((void *)pl061->regBase);//【必要】解除地址映射 + pl061->regBase = NULL; + } + ``` diff --git a/zh-cn/device-dev/driver/driver-platform-i2c-des.md b/zh-cn/device-dev/driver/driver-platform-i2c-des.md index 535b49a332609ead27020ebe764726d1b8551095..c451e820fe94935c2b14c3701d09c612d1c9d5cb 100644 --- a/zh-cn/device-dev/driver/driver-platform-i2c-des.md +++ b/zh-cn/device-dev/driver/driver-platform-i2c-des.md @@ -1,119 +1,68 @@ -# I2C +# I2C -- [概述](#section5361140416) -- [接口说明](#section545869122317) -- [使用指导](#section1695201514281) - - [使用流程](#section1338373417288) - - [打开I2C控制器](#section13751110132914) - - [进行I2C通信](#section9202183372916) - - [关闭I2C控制器](#section19481164133018) -- [使用实例](#section5302202015300) +## 概述 -## 概述 +- I2C(Inter Integrated Circuit)总线是由Philips公司开发的一种简单、双向二线制同步串行总线。 -- I2C\(Inter Integrated Circuit\)总线是由Philips公司开发的一种简单、双向二线制同步串行总线。 -- I2C以主从方式工作,通常有一个主设备和一个或者多个从设备,主从设备通过SDA\(SerialData\)串行数据线以及SCL\(SerialClock\)串行时钟线两根线相连,如[图1 ](#fig1135561232714)所示。 +- I2C以主从方式工作,通常有一个主设备和一个或者多个从设备,主从设备通过SDA(SerialData)串行数据线以及SCL(SerialClock)串行时钟线两根线相连,如图1所示。 -- I2C数据的传输必须以一个起始信号作为开始条件,以一个结束信号作为传输的停止条件。数据传输以字节为单位,高位在前,逐个bit进行传输。 -- I2C总线上的每一个设备都可以作为主设备或者从设备,而且每一个设备都会对应一个唯一的地址,当主设备需要和某一个从设备通信时,通过广播的方式,将从设备地址写到总线上,如果某个从设备符合此地址,将会发出应答信号,建立传输。 +- I2C数据的传输必须以一个起始信号作为开始条件,以一个结束信号作为传输的停止条件。数据传输以字节为单位,高位在前,逐个bit进行传输。 -- I2C接口定义了完成I2C传输的通用方法集合,包括: +- I2C总线上的每一个设备都可以作为主设备或者从设备,而且每一个设备都会对应一个唯一的地址,当主设备需要和某一个从设备通信时,通过广播的方式,将从设备地址写到总线上,如果某个从设备符合此地址,将会发出应答信号,建立传输。 - - I2C控制器管理: 打开或关闭I2C控制器 - - I2C消息传输:通过消息传输结构体数组进行自定义传输 +- I2C接口定义了完成I2C传输的通用方法集合,包括: + - I2C控制器管理: 打开或关闭I2C控制器 + - I2C消息传输:通过消息传输结构体数组进行自定义传输 - **图 1** I2C物理连线示意图 - ![](figures/I2C物理连线示意图.png "I2C物理连线示意图") + **图1** I2C物理连线示意图 + ![zh-cn_image_0000001160653004](figures/zh-cn_image_0000001160653004.png) -## 接口说明 -**表 1** I2C驱动API接口功能介绍 +## 接口说明 - - - - - - - - - - - - - - - - - - -

功能分类

-

接口名

-

描述

-

I2C控制器管理接口

-

I2cOpen

-

打开I2C控制器

-

I2cClose

-

关闭I2C控制器

-

I2c消息传输接口

-

I2cTransfer

-

自定义传输

-
+ **表1** I2C驱动API接口功能介绍 ->![](../public_sys-resources/icon-note.gif) **说明:** ->本文涉及的所有接口,仅限内核态使用,不支持在用户态使用。 +| 功能分类 | 接口描述 | +| -------- | -------- | +| I2C控制器管理接口 | - I2cOpen:打开I2C控制器
- I2cClose:关闭I2C控制器 | +| I2C消息传输接口 | I2cTransfer:自定义传输 | -## 使用指导 +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> 本文涉及的所有接口,仅限内核态使用,不支持在用户态使用。 -### 使用流程 -使用I2C设备的一般流程如[图2](#fig183017194234)所示。 +## 使用指导 -**图 2** I2C设备使用流程图 -![](figures/I2C设备使用流程图.png "I2C设备使用流程图") -### 打开I2C控制器 +### 使用流程 + +使用I2C设备的一般流程如下图所示。 + + **图2** I2C设备使用流程图 + + ![zh-cn_image_0000001206291495](figures/zh-cn_image_0000001206291495.png) + + +### 打开I2C控制器 在进行I2C通信前,首先要调用I2cOpen打开I2C控制器。 -DevHandle I2cOpen\(int16\_t number\); - -**表 2** I2cOpen参数和返回值描述 - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

number

-

I2C控制器号

-

返回值

-

返回值描述

-

NULL

-

打开I2C控制器失败

-

设备句柄

-

打开的I2C控制器设备句柄

-
+DevHandle I2cOpen(int16_t number); + + **表2** I2cOpen参数和返回值描述 + +| **参数** | **参数描述** | +| -------- | -------- | +| number | I2C控制器号 | +| **返回值** | **返回值描述** | +| NULL | 打开I2C控制器失败 | +| 设备句柄 | 打开的I2C控制器设备句柄 | 假设系统中存在8个I2C控制器,编号从0到7,那么我们现在获取3号控制器 + ``` DevHandle i2cHandle = NULL; /* I2C控制器句柄 / @@ -125,56 +74,27 @@ if (i2cHandle == NULL) { } ``` -### 进行I2C通信 + +### 进行I2C通信 消息传输 -int32\_t I2cTransfer\(DevHandle handle, struct I2cMsg \*msgs, int16\_t count\); - -**表 3** I2cTransfer参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

I2C控制器设备句柄

-

msgs

-

待传输数据的消息结构体数组

-

count

-

消息数组长度

-

返回值

-

返回值描述

-

正整数

-

成功传输的消息结构体数目

-

负数

-

执行失败

-
+int32_t I2cTransfer(DevHandle handle, struct I2cMsg \*msgs, int16_t count); + + **表3** I2cTransfer参数和返回值描述 + +| **参数** | **参数描述** | +| -------- | -------- | +| handle | I2C控制器设备句柄 | +| msgs | 待传输数据的消息结构体数组 | +| count | 消息数组长度 | +| **返回值** | **返回值描述** | +| 正整数 | 成功传输的消息结构体数目 | +| 负数 | 执行失败 | I2C传输消息类型为I2cMsg,每个传输消息结构体表示一次读或写,通过一个消息数组,可以执行若干次的读写组合操作。 + ``` int32_t ret; uint8_t wbuff[2] = { 0x12, 0x13 }; @@ -196,58 +116,54 @@ if (ret != 2) { } ``` ->![](../public_sys-resources/icon-caution.gif) **注意:** ->- I2cMsg结构体中的设备地址不包含读写标志位,读写信息由flags成员变量的读写控制位传递。 ->- 本函数不对消息结构体个数count做限制,其最大个数度由具体I2C控制器决定。 ->- 本函数也不对每个消息结构体中的数据长度做限制,同样由具体I2C控制器决定。 ->- 本函数可能会引起系统休眠,不允许在中断上下文调用 +> ![icon-caution.gif](public_sys-resources/icon-caution.gif) **注意:** +> - I2cMsg结构体中的设备地址不包含读写标志位,读写信息由flags成员变量的读写控制位传递。 +> +> - 本函数不对消息结构体个数count做限制,其最大个数度由具体I2C控制器决定。 +> +> - 本函数也不对每个消息结构体中的数据长度做限制,同样由具体I2C控制器决定。 +> +> - 本函数可能会引起系统休眠,不允许在中断上下文调用 + -### 关闭I2C控制器 +### 关闭I2C控制器 I2C通信完成之后,需要关闭I2C控制器,关闭函数如下所示: -void I2cClose\(DevHandle handle\); - -**表 4** I2cClose参数和返回值描述 - - - - - - - - - - -

参数

-

参数描述

-

handle

-

I2C控制器设备句柄

-
+void I2cClose(DevHandle handle); + + **表4** I2cClose参数和返回值描述 + +| 参数 | 参数描述 | +| -------- | -------- | +| handle | I2C控制器设备句柄 | + ``` I2cClose(i2cHandle); /* 关闭I2C控制器 */ ``` -## 使用实例 + +## 使用实例 本例程以操作开发板上的I2C设备为例,详细展示I2C接口的完整使用流程。 本例拟对Hi3516DV300某开发板上TouchPad设备进行简单的寄存器读写访问,基本硬件信息如下: -- SOC:hi3516dv300。 +- SOC:hi3516dv300。 -- Touch IC:I2C地址为0x38, IC内部寄存器位宽为1字节。 +- Touch IC:I2C地址为0x38, IC内部寄存器位宽为1字节。 -- 原理图信息:TouchPad设备挂接在3号I2C控制器下;IC的复位管脚为3号GPIO。 +- 原理图信息:TouchPad设备挂接在3号I2C控制器下;IC的复位管脚为3号GPIO。 本例程首先对Touch IC进行复位操作(开发板上电默认会给TouchIC供电,本例程不考虑供电),然后对其内部寄存器进行随机读写,测试I2C通路是否正常。 ->![](../public_sys-resources/icon-note.gif) **说明:** ->本例程重点在于展示I2C设备访问流程,并验证I2C通路,所以对于设备寄存器读写值不做关注,读写寄存器导致的行为由设备自身决定。 +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> 本例程重点在于展示I2C设备访问流程,并验证I2C通路,所以对于设备寄存器读写值不做关注,读写寄存器导致的行为由设备自身决定。 示例如下: + ``` #include "i2c_if.h" /* I2C标准接口头文件 */ #include "gpio_if.h" /* GPIO标准接口头文件 */ @@ -420,4 +336,3 @@ static int32_t TestCaseI2c(void) return ret; } ``` - diff --git a/zh-cn/device-dev/driver/driver-platform-i2c-develop.md b/zh-cn/device-dev/driver/driver-platform-i2c-develop.md index 3fd15170cc7e61ea8e3bcc047cf82967bd716562..1b1be694f21ef8647389fef40deb997007aebe82 100755 --- a/zh-cn/device-dev/driver/driver-platform-i2c-develop.md +++ b/zh-cn/device-dev/driver/driver-platform-i2c-develop.md @@ -1,21 +1,20 @@ -# I2C +# I2C -- [概述](#section2040078630114257) -- [接口说明](#section752964871810) -- [开发步骤](#section1085786591114257) -- [开发实例](#section1773332551114257) -## 概述 +## 概述 -I2C(Inter Integrated Circuit)总线是由Philips公司开发的一种简单、双向二线制同步串行总线,在HDF框架中,I2C模块接口适配模式采用统一服务模式,这需要一个设备服务来作为I2C模块的管理器,统一处理外部访问,这会在配置文件中有所体现。统一服务模式适合于同类型设备对象较多的情况,如I2C可能同时具备十几个控制器,采用独立服务模式需要配置更多的设备节点,且服务会占据内存资源。 +I2C(Inter Integrated Circuit)总线是由Philips公司开发的一种简单、双向二线制同步串行总线,在HDF框架中,I2C模块接口适配模式采用统一服务模式,这需要一个设备服务来作为I2C模块的管理器,统一处理外部访问,这会在配置文件中有所体现。统一服务模式适合于同类型设备对象较多的情况,如I2C可能同时具备十几个控制器,采用独立服务模式需要配置更多的设备节点,且服务会占据内存资源。 -**图 1** I2C统一服务模式结构图 -![](figures/统一服务模式结构图.png "I2C统一服务模式结构图") + **图1** I2C统一服务模式结构图 -## 接口说明 + ![zh-cn_image_0000001177082394](figures/zh-cn_image_0000001177082394.png) + + +## 接口说明 I2cMethod和I2cLockMethod定义: + ``` struct I2cMethod { int32_t (*transfer)(struct I2cCntlr *cntlr, struct I2cMsg *msgs, int16_t count); @@ -26,376 +25,295 @@ struct I2cLockMethod {//锁机制操作结构体 }; ``` -**表 1** I2cMethod结构体成员的回调函数功能说明 - - - - - - - - - - - - - - - - -

函数成员

-

入参

-

出参

-

返回值

-

功能

-

transfer

-

cntlr:结构体指针,核心层I2C控制器;msgs:结构体指针,用户消息 ;count:uint16_t,消息数量

-

-

HDF_STATUS相关状态

-

传递用户消息

-
- -## 开发步骤 + **表1** I2cMethod结构体成员的回调函数功能说明 + +| 函数成员 | 入参 | 出参 | 返回值 | 功能 | +| -------- | -------- | -------- | -------- | -------- | +| transfer | cntlr:结构体指针,核心层I2C控制器。
msgs:结构体指针,用户消息。
count:uint16_t,消息数量。 | 无 | HDF_STATUS相关状态 | 传递用户消息 | + + +## 开发步骤 I2C模块适配的三个环节是配置属性文件,实例化驱动入口,以及实例化核心层接口函数。 -1. **实例化驱动入口:** - - 实例化HdfDriverEntry结构体成员。 - - 调用HDF\_INIT将HdfDriverEntry实例化对象注册到HDF框架中。 - -2. **配置属性文件:** - - 在device\_info.hcs文件中添加deviceNode描述。 - - 【可选】添加i2c\_config.hcs器件属性文件。 - -3. **实例化I2C控制器对象:** - - 初始化I2cCntlr成员。 - - 实例化I2cCntlr成员I2cMethod和I2cLockMethod。 - - >![](../public_sys-resources/icon-note.gif) **说明:** - >实例化I2cCntlr成员I2cMethod和I2cLockMethod,详见[接口说明](#section752964871810)。 - - -4. **驱动调试:** - - 【可选】针对新增驱动程序,建议验证驱动基本功能,例如挂载后的信息反馈,消息传输的成功与否等。 - - -## 开发实例 - -下方将以i2c\_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。 - -1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf\_device\_desc.h 中定义)类型的全局变量,且moduleName要和device\_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。 - - 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 - - I2C驱动入口参考: - - I2C模块这种类型的控制器会出现很多个设备挂接的情况,因而在HDF框架中首先会为这类型的设备创建一个管理器对象,并同时对外发布一个管理器服务来统一处理外部访问。这样,用户需要打开某个设备时,会先获取到管理器服务,然后管理器服务根据用户指定参数查找到指定设备。 - - I2C管理器服务的驱动由核心层实现,厂商不需要关注这部分内容的实现,这个但在实现Init函数的时候需要调用核心层的I2cCntlrAdd函数,它会实现相应功能。 - - ``` - struct HdfDriverEntry g_i2cDriverEntry = { - .moduleVersion = 1, - .Init = Hi35xxI2cInit, - .Release = Hi35xxI2cRelease, - .moduleName = "hi35xx_i2c_driver",//【必要且与config.hcs文件里面匹配】 - }; - HDF_INIT(g_i2cDriverEntry); //调用HDF_INIT将驱动入口注册到HDF框架中 - - //核心层i2c_core.c 管理器服务的驱动入口 - struct HdfDriverEntry g_i2cManagerEntry = { - .moduleVersion = 1, - .Bind = I2cManagerBind, - .Init = I2cManagerInit, - .Release = I2cManagerRelease, - .moduleName = "HDF_PLATFORM_I2C_MANAGER",//这与device_info文件中device0对应 - }; - HDF_INIT(g_i2cManagerEntry); - ``` - -2. 完成驱动入口注册之后,下一步请在device\_info.hcs文件中添加deviceNode信息,并在i2c\_config.hcs中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值对于厂商驱动的实现以及核心层I2cCntlr相关成员的默认值或限制范围有密切关系。 - - 统一服务模式的特点是device\_info文件中第一个设备节点必须为I2C管理器,其各项参数必须如[表2](#table96651915911)设置: - - **表 2** 统一服务模式的特点 - - - - - - - - - - - - - - - - - - - -

成员名

-

-

moduleName

-

固定为 HDF_PLATFORM_I2C_MANAGER

-

serviceName

-

固定为 HDF_PLATFORM_I2C_MANAGER

-

policy

-

具体配置为1或2取决于是否对用户态可见

-

deviceMatchAttr

-

没有使用,可忽略

-
- - 从第二个节点开始配置具体I2C控制器信息,此节点并不表示某一路I2C控制器,而是代表一个资源性质设备,用于描述一类I2C控制器的信息。多个控制器之间相互区分的参数是busID和reg\_pbase,这在i2c\_config文件中有所体现。 - - - device\_info.hcs 配置参考。 - - ``` - root { - device_info { - match_attr = "hdf_manager"; - device_i2c :: device { - device0 :: deviceNode { - policy = 2; - priority = 50; - permission = 0644; - moduleName = "HDF_PLATFORM_I2C_MANAGER"; - serviceName = "HDF_PLATFORM_I2C_MANAGER"; - deviceMatchAttr = "hdf_platform_i2c_manager"; - } - device1 :: deviceNode { - policy = 0; // 等于0,不需要发布服务 - priority = 55; // 驱动启动优先级 - permission = 0644; // 驱动创建设备节点权限 - moduleName = "hi35xx_i2c_driver"; //【必要】用于指定驱动名称,需要与期望的驱动Entry中的moduleName一致; - serviceName = "HI35XX_I2C_DRIVER"; //【必要】驱动对外发布服务的名称,必须唯一 - deviceMatchAttr = "hisilicon_hi35xx_i2c";//【必要】用于配置控制器私有数据,要与i2c_config.hcs中对应控制器保持一致 - // 具体的控制器信息在 i2c_config.hcs 中 - } - } - } - } - ``` - - - i2c\_config.hcs 配置参考。 - - ``` - root { - platform { - i2c_config { - match_attr = "hisilicon_hi35xx_i2c";//【必要】需要和device_info.hcs中的deviceMatchAttr值一致 - template i2c_controller { //模板公共参数,继承该模板的节点如果使用模板中的默认值,则节点字段可以缺省 - bus = 0; //【必要】i2c 识别号 - reg_pbase = 0x120b0000; //【必要】物理基地址 - reg_size = 0xd1; //【必要】寄存器位宽 - irq = 0; //【可选】根据厂商需要来使用 - freq = 400000; //【可选】根据厂商需要来使用 - clk = 50000000; //【可选】根据厂商需要来使用 - } - controller_0x120b0000 :: i2c_controller { - bus = 0; - } - controller_0x120b1000 :: i2c_controller { - bus = 1; - reg_pbase = 0x120b1000; - } - ... - } - } - } - ``` - -3. 完成驱动入口注册之后,最后一步就是以核心层I2cCntlr对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化I2cCntlr成员I2cMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。 - - 自定义结构体参考 - - 从驱动的角度看,自定义结构体是参数和数据的载体,而且i2c\_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,其中一些重要数值也会传递给核心层I2cCntlr对象,例如设备号、总线号等。 - - ``` - // 厂商自定义功能结构体 - struct Hi35xxI2cCntlr { - struct I2cCntlr cntlr; //【必要】是核心层控制对象,具体描述见下面 - OsalSpinlock spin; //【必要】厂商需要基于此锁变量对各个 i2c 操作函数实现对应的加锁解锁 - volatile unsigned char *regBase; //【必要】寄存器基地址 - uint16_t regSize; //【必要】寄存器位宽 - int16_t bus; //【必要】i2c_config.hcs 文件中可读取具体值 - uint32_t clk; //【可选】厂商自定义 - uint32_t freq; //【可选】厂商自定义 - uint32_t irq; //【可选】厂商自定义 - uint32_t regBasePhy; //【必要】寄存器物理基地址 - }; - - // I2cCntlr是核心层控制器结构体,其中的成员在Init函数中会被赋值 - struct I2cCntlr { - struct OsalMutex lock; - void *owner; - int16_t busId; - void *priv; - const struct I2cMethod *ops; - const struct I2cLockMethod *lockOps; - }; - ``` - - - I2cCntlr成员回调函数结构体I2cMethod的实例化,和锁机制回调函数结构体I2cLockMethod实例化,其他成员在Init函数中初始化。 - - ``` - // i2c_hi35xx.c 中的示例 - static const struct I2cMethod g_method = { - .transfer = Hi35xxI2cTransfer, - }; - - static const struct I2cLockMethod g_lockOps = { - .lock = Hi35xxI2cLock, //加锁函数 - .unlock = Hi35xxI2cUnlock,//解锁函数 - }; - ``` - - - init函数参考 - - 入参: - - HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 - - 返回值: - - HDF\_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf\_base.h中HDF\_STATUS 定义)。 - - **表 3** init函数入参及返回值参考 - - - - - - - - - - - - - - - - - - - - - - - - - -

状态(值)

-

问题描述

-

HDF_ERR_INVALID_OBJECT

-

控制器对象非法

-

HDF_ERR_INVALID_PARAM

-

参数非法

-

HDF_ERR_MALLOC_FAIL

-

内存分配失败

-

HDF_ERR_IO

-

I/O 错误

-

HDF_SUCCESS

-

传输成功

-

HDF_FAILURE

-

传输失败

-
- - 函数说明: - - 初始化自定义结构体对象,初始化I2cCntlr成员,调用核心层I2cCntlrAdd函数,【可选】接入VFS。 - - ``` - static int32_t Hi35xxI2cInit(struct HdfDeviceObject *device) - { - ... - //遍历、解析 i2c_config.hcs 中的所有配置节点,并分别进行初始化,需要调用Hi35xxI2cParseAndInit函数 - DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) { - ret = Hi35xxI2cParseAndInit(device, childNode);//函数定义见下 - ... - } - ... - } - - static int32_t Hi35xxI2cParseAndInit(struct HdfDeviceObject *device, const struct DeviceResourceNode *node) - { - struct Hi35xxI2cCntlr *hi35xx = NULL; - ... - hi35xx = (struct Hi35xxI2cCntlr *)OsalMemCalloc(sizeof(*hi35xx)); // 内存分配 - ... - hi35xx->regBase = OsalIoRemap(hi35xx->regBasePhy, hi35xx->regSize); // 地址映射 - ... - Hi35xxI2cCntlrInit(hi35xx); // 【必要】i2c设备的初始化 - - hi35xx->cntlr.priv = (void *)node; //【必要】存储设备属性 - hi35xx->cntlr.busId = hi35xx->bus; //【必要】初始化I2cCntlr成员busId - hi35xx->cntlr.ops = &g_method; //【必要】I2cMethod的实例化对象的挂载 - hi35xx->cntlr.lockOps = &g_lockOps; //【必要】I2cLockMethod的实例化对象的挂载 - (void)OsalSpinInit(&hi35xx->spin); //【必要】锁的初始化 - ret = I2cCntlrAdd(&hi35xx->cntlr); //【必要】调用此函数填充核心层结构体,返回成功信号后驱动才完全接入平台核心层 - ... - #ifdef USER_VFS_SUPPORT - (void)I2cAddVfsById(hi35xx->cntlr.busId);//【可选】若支持用户级的虚拟文件系统,则接入 - #endif - return HDF_SUCCESS; - __ERR__: //不成功的话,需要反向执行初始化相关函数 - if (hi35xx != NULL) { - if (hi35xx->regBase != NULL) { - OsalIoUnmap((void *)hi35xx->regBase); - hi35xx->regBase = NULL; - } - OsalMemFree(hi35xx); - hi35xx = NULL; - } - return ret; - } - ``` - - - Release 函数参考 - - 入参: - - HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 - - 返回值: - - 无。 - - 函数说明: - - 释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源。 - - ``` - static void Hi35xxI2cRelease(struct HdfDeviceObject *device) - { - ... - //与Hi35xxI2cInit一样,需要将对每个节点分别进行释放 - DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) { - Hi35xxI2cRemoveByNode(childNode);//函数定义见下 - } - } +1. **实例化驱动入口:** + - 实例化HdfDriverEntry结构体成员。 + - 调用HDF_INIT将HdfDriverEntry实例化对象注册到HDF框架中。 + +2. **配置属性文件:** + - 在device_info.hcs文件中添加deviceNode描述。 + - 【可选】添加i2c_config.hcs器件属性文件。 + +3. **实例化I2C控制器对象:** + - 初始化I2cCntlr成员。 + - 实例化I2cCntlr成员I2cMethod和I2cLockMethod。 + > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** + > 实例化I2cCntlr成员I2cMethod和I2cLockMethod,详见[接口说明](#接口说明)。 + +4. **驱动调试:** + 【可选】针对新增驱动程序,建议验证驱动基本功能,例如挂载后的信息反馈,消息传输的成功与否等。 + + +## 开发实例 + +下方将以i2c_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。 + +1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf_device_desc.h 中定义)类型的全局变量,且moduleName要和device_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。 + 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 + + I2C驱动入口参考: + + I2C模块这种类型的控制器会出现很多个设备挂接的情况,因而在HDF框架中首先会为这类型的设备创建一个管理器对象,并同时对外发布一个管理器服务来统一处理外部访问。这样,用户需要打开某个设备时,会先获取到管理器服务,然后管理器服务根据用户指定参数查找到指定设备。 + + I2C管理器服务的驱动由核心层实现,厂商不需要关注这部分内容的实现,这个但在实现Init函数的时候需要调用核心层的I2cCntlrAdd函数,它会实现相应功能。 + + + ``` + struct HdfDriverEntry g_i2cDriverEntry = { + .moduleVersion = 1, + .Init = Hi35xxI2cInit, + .Release = Hi35xxI2cRelease, + .moduleName = "hi35xx_i2c_driver",//【必要且与config.hcs文件里面匹配】 + }; + HDF_INIT(g_i2cDriverEntry); //调用HDF_INIT将驱动入口注册到HDF框架中 + + //核心层i2c_core.c 管理器服务的驱动入口 + struct HdfDriverEntry g_i2cManagerEntry = { + .moduleVersion = 1, + .Bind = I2cManagerBind, + .Init = I2cManagerInit, + .Release = I2cManagerRelease, + .moduleName = "HDF_PLATFORM_I2C_MANAGER",//这与device_info文件中device0对应 + }; + HDF_INIT(g_i2cManagerEntry); + ``` + +2. 完成驱动入口注册之后,下一步请在device_info.hcs文件中添加deviceNode信息,并在i2c_config.hcs中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值对于厂商驱动的实现以及核心层I2cCntlr相关成员的默认值或限制范围有密切关系。 + 统一服务模式的特点是device_info文件中第一个设备节点必须为I2C管理器,其各项参数必须如表2设置: + + **表2** 统一服务模式的特点 + + | 成员名 | 值 | + | -------- | -------- | + | moduleName | 固定为HDF_PLATFORM_I2C_MANAGER | + | serviceName | 固定为HDF_PLATFORM_I2C_MANAGER | + | policy | 具体配置为1或2取决于是否对用户态可见 | + | deviceMatchAttr | 没有使用,可忽略 | + + 从第二个节点开始配置具体I2C控制器信息,此节点并不表示某一路I2C控制器,而是代表一个资源性质设备,用于描述一类I2C控制器的信息。多个控制器之间相互区分的参数是busID和reg_pbase,这在i2c_config文件中有所体现。 + - device_info.hcs 配置参考。 + + + ``` + root { + device_info { + match_attr = "hdf_manager"; + device_i2c :: device { + device0 :: deviceNode { + policy = 2; + priority = 50; + permission = 0644; + moduleName = "HDF_PLATFORM_I2C_MANAGER"; + serviceName = "HDF_PLATFORM_I2C_MANAGER"; + deviceMatchAttr = "hdf_platform_i2c_manager"; + } + device1 :: deviceNode { + policy = 0; // 等于0,不需要发布服务 + priority = 55; // 驱动启动优先级 + permission = 0644; // 驱动创建设备节点权限 + moduleName = "hi35xx_i2c_driver"; //【必要】用于指定驱动名称,需要与期望的驱动Entry中的moduleName一致; + serviceName = "HI35XX_I2C_DRIVER"; //【必要】驱动对外发布服务的名称,必须唯一 + deviceMatchAttr = "hisilicon_hi35xx_i2c";//【必要】用于配置控制器私有数据,要与i2c_config.hcs中对应控制器保持一致 + // 具体的控制器信息在 i2c_config.hcs 中 + } + } + } + } + ``` + + - i2c_config.hcs 配置参考。 + + + ``` + root { + platform { + i2c_config { + match_attr = "hisilicon_hi35xx_i2c";//【必要】需要和device_info.hcs中的deviceMatchAttr值一致 + template i2c_controller { //模板公共参数,继承该模板的节点如果使用模板中的默认值,则节点字段可以缺省 + bus = 0; //【必要】i2c 识别号 + reg_pbase = 0x120b0000; //【必要】物理基地址 + reg_size = 0xd1; //【必要】寄存器位宽 + irq = 0; //【可选】根据厂商需要来使用 + freq = 400000; //【可选】根据厂商需要来使用 + clk = 50000000; //【可选】根据厂商需要来使用 + } + controller_0x120b0000 :: i2c_controller { + bus = 0; + } + controller_0x120b1000 :: i2c_controller { + bus = 1; + reg_pbase = 0x120b1000; + } + ... + } + } + } + ``` + +3. 完成驱动入口注册之后,最后一步就是以核心层I2cCntlr对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化I2cCntlr成员I2cMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。 + - 自定义结构体参考 + + 从驱动的角度看,自定义结构体是参数和数据的载体,而且i2c_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,其中一些重要数值也会传递给核心层I2cCntlr对象,例如设备号、总线号等。 + - static void Hi35xxI2cRemoveByNode(const struct DeviceResourceNode *node) - { - ... - //【必要】可以调用 I2cCntlrGet 函数通过设备的 busid 获取 I2cCntlr 对象, 以及调用 I2cCntlrRemove 函数来释放 I2cCntlr 对象的内容 - cntlr = I2cCntlrGet(bus); - if (cntlr != NULL && cntlr->priv == node) { - ... - I2cCntlrRemove(cntlr); - //【必要】解除地址映射,锁和内存的释放 - hi35xx = (struct Hi35xxI2cCntlr *)cntlr; - OsalIoUnmap((void *)hi35xx->regBase); - (void)OsalSpinDestroy(&hi35xx->spin); - OsalMemFree(hi35xx); - } - return; - } - ``` + ``` + // 厂商自定义功能结构体 + struct Hi35xxI2cCntlr { + struct I2cCntlr cntlr; //【必要】是核心层控制对象,具体描述见下面 + OsalSpinlock spin; //【必要】厂商需要基于此锁变量对各个 i2c 操作函数实现对应的加锁解锁 + volatile unsigned char *regBase; //【必要】寄存器基地址 + uint16_t regSize; //【必要】寄存器位宽 + int16_t bus; //【必要】i2c_config.hcs 文件中可读取具体值 + uint32_t clk; //【可选】厂商自定义 + uint32_t freq; //【可选】厂商自定义 + uint32_t irq; //【可选】厂商自定义 + uint32_t regBasePhy; //【必要】寄存器物理基地址 + }; + + // I2cCntlr是核心层控制器结构体,其中的成员在Init函数中会被赋值 + struct I2cCntlr { + struct OsalMutex lock; + void *owner; + int16_t busId; + void *priv; + const struct I2cMethod *ops; + const struct I2cLockMethod *lockOps; + }; + ``` + - I2cCntlr成员回调函数结构体I2cMethod的实例化,和锁机制回调函数结构体I2cLockMethod实例化,其他成员在Init函数中初始化。 + + ``` + // i2c_hi35xx.c 中的示例 + static const struct I2cMethod g_method = { + .transfer = Hi35xxI2cTransfer, + }; + + static const struct I2cLockMethod g_lockOps = { + .lock = Hi35xxI2cLock, //加锁函数 + .unlock = Hi35xxI2cUnlock,//解锁函数 + }; + ``` + - Init函数参考 + + 入参: + + HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 + + 返回值: + + HDF_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf_base.h中HDF_STATUS 定义)。 + + **表3** Init函数入参及返回值参考 + + | 状态(值) | 问题描述 | + | -------- | -------- | + | HDF_ERR_INVALID_OBJECT | 控制器对象非法 | + | HDF_ERR_INVALID_PARAM | 参数非法 | + | HDF_ERR_MALLOC_FAIL | 内存分配失败 | + | HDF_ERR_IO | I/O 错误 | + | HDF_SUCCESS | 传输成功 | + | HDF_FAILURE | 传输失败 | + + 函数说明: + + 初始化自定义结构体对象,初始化I2cCntlr成员,调用核心层I2cCntlrAdd函数,【可选】接入VFS。 + + ``` + static int32_t Hi35xxI2cInit(struct HdfDeviceObject *device) + { + ... + //遍历、解析 i2c_config.hcs 中的所有配置节点,并分别进行初始化,需要调用Hi35xxI2cParseAndInit函数 + DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) { + ret = Hi35xxI2cParseAndInit(device, childNode);//函数定义见下 + ... + } + ... + } + + static int32_t Hi35xxI2cParseAndInit(struct HdfDeviceObject *device, const struct DeviceResourceNode *node) + { + struct Hi35xxI2cCntlr *hi35xx = NULL; + ... + hi35xx = (struct Hi35xxI2cCntlr *)OsalMemCalloc(sizeof(*hi35xx)); // 内存分配 + ... + hi35xx->regBase = OsalIoRemap(hi35xx->regBasePhy, hi35xx->regSize); // 地址映射 + ... + Hi35xxI2cCntlrInit(hi35xx); // 【必要】i2c设备的初始化 + + hi35xx->cntlr.priv = (void *)node; //【必要】存储设备属性 + hi35xx->cntlr.busId = hi35xx->bus; //【必要】初始化I2cCntlr成员busId + hi35xx->cntlr.ops = &g_method; //【必要】I2cMethod的实例化对象的挂载 + hi35xx->cntlr.lockOps = &g_lockOps; //【必要】I2cLockMethod的实例化对象的挂载 + (void)OsalSpinInit(&hi35xx->spin); //【必要】锁的初始化 + ret = I2cCntlrAdd(&hi35xx->cntlr); //【必要】调用此函数填充核心层结构体,返回成功信号后驱动才完全接入平台核心层 + ... + #ifdef USER_VFS_SUPPORT + (void)I2cAddVfsById(hi35xx->cntlr.busId);//【可选】若支持用户级的虚拟文件系统,则接入 + #endif + return HDF_SUCCESS; + __ERR__: //不成功的话,需要反向执行初始化相关函数 + if (hi35xx != NULL) { + if (hi35xx->regBase != NULL) { + OsalIoUnmap((void *)hi35xx->regBase); + hi35xx->regBase = NULL; + } + OsalMemFree(hi35xx); + hi35xx = NULL; + } + return ret; + } + ``` + - Release 函数参考 + + 入参: + + HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 + + 返回值: + + 无。 + + 函数说明: + + 释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源。 + + ``` + static void Hi35xxI2cRelease(struct HdfDeviceObject *device) + { + ... + //与Hi35xxI2cInit一样,需要将对每个节点分别进行释放 + DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) { + Hi35xxI2cRemoveByNode(childNode);//函数定义见下 + } + } + + static void Hi35xxI2cRemoveByNode(const struct DeviceResourceNode *node) + { + ... + //【必要】可以调用 I2cCntlrGet 函数通过设备的 busid 获取 I2cCntlr 对象, 以及调用 I2cCntlrRemove 函数来释放 I2cCntlr 对象的内容 + cntlr = I2cCntlrGet(bus); + if (cntlr != NULL && cntlr->priv == node) { + ... + I2cCntlrRemove(cntlr); + //【必要】解除地址映射,锁和内存的释放 + hi35xx = (struct Hi35xxI2cCntlr *)cntlr; + OsalIoUnmap((void *)hi35xx->regBase); + (void)OsalSpinDestroy(&hi35xx->spin); + OsalMemFree(hi35xx); + } + return; + } + ``` diff --git a/zh-cn/device-dev/driver/driver-platform-mipicsi-des.md b/zh-cn/device-dev/driver/driver-platform-mipicsi-des.md index 9b5e164be92a075f1b500f92e7075deeabcfe1d7..52fbc88dfe7258a84695728be97b230cdd34f49e 100755 --- a/zh-cn/device-dev/driver/driver-platform-mipicsi-des.md +++ b/zh-cn/device-dev/driver/driver-platform-mipicsi-des.md @@ -1,20 +1,5 @@ -# MIPI-CSI +# MIPI CSI -- [概述](#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) ## 概述 @@ -57,14 +42,14 @@ ### 接口说明 -**表 3** MIPI-CSI API接口功能介绍 +**表 3** MIPI CSI API接口功能介绍 | 功能分类 | 接口名 | | -------- | -------- | -| 获取/释放MIPI-CSI控制器操作句柄 | MipiCsiOpen:获取MIPI-CSI控制器操作句柄
MipiCsiClose:释放MIPI-CSI控制器操作句柄 | -| MIPI-CSI相应配置 | MipiCsiSetComboDevAttr:设置MIPI,CMOS或者LVDS相机的参数给控制器,参数包括工作模式,图像区域,图像深度,数据速率和物理通道等
MipiCsiSetExtDataType(可选):设置YUV和RAW数据格式和位深
MipiCsiSetHsMode:设置MIPI RX的Lane分布。根据硬件连接的形式选择具体的mode
MipiCsiSetPhyCmvmode:设置共模电压模式 | +| 获取/释放MIPI CSI控制器操作句柄 | MipiCsiOpen:获取MIPI CSI控制器操作句柄
MipiCsiClose:释放MIPI CSI控制器操作句柄 | +| MIPI CSI相应配置 | MipiCsiSetComboDevAttr:设置MIPI,CMOS或者LVDS相机的参数给控制器,参数包括工作模式,图像区域,图像深度,数据速率和物理通道等
MipiCsiSetExtDataType(可选):设置YUV和RAW数据格式和位深
MipiCsiSetHsMode:设置MIPI RX的Lane分布。根据硬件连接的形式选择具体的mode
MipiCsiSetPhyCmvmode:设置共模电压模式 | | 复位/撤销复位Sensor | MipiCsiResetSensor:复位Sensor
MipiCsiUnresetSensor:撤销复位Sensor | | 复位/撤销复位MIPI RX | MipiCsiResetRx:复位MIPI RX。不同的s32WorkingViNum有不同的enSnsType
MipiCsiUnresetRx:撤销复位MIPI RX | | 使能/关闭MIPI的时钟 | MipiCsiEnableClock:使能MIPI的时钟。根据上层函数电泳传递的enSnsType参数决定是用MIPI还是LVDS
MipiCsiDisableClock:关闭MIPI设备的时钟 | @@ -75,16 +60,16 @@ ### 使用流程 -使用MIPI-CSI的一般流程如[图2](#fig2_MIPI_CSIDes)所示。 +使用MIPI CSI的一般流程如图2所示。 -**图 2** MIPI-CSI使用流程图 +**图 2** MIPI CSI使用流程图 ![](figures/MIPI-CSI使用流程图.png) -### 获取MIPI-CSI控制器操作句柄 +### 获取MIPI CSI控制器操作句柄 -在进行MIPI-CSI进行通信前,首先要调用MipiCsiOpen获取控制器操作句柄,该函数会返回指定通道ID的控制器操作句柄。 +在进行MIPI CSI进行通信前,首先要调用MipiCsiOpen获取控制器操作句柄,该函数会返回指定通道ID的控制器操作句柄。 ```c DevHandle MipiCsiOpen(uint8_t id); @@ -101,11 +86,11 @@ DevHandle MipiCsiOpen(uint8_t id); | NULL | 获取失败 | | 设备句柄 | 获取到指令通道的控制器操作句柄,类型为DevHandle | -假设系统中的MIPI-CSI通道为0,获取该通道控制器操作句柄的示例如下: +假设系统中的MIPI CSI通道为0,获取该通道控制器操作句柄的示例如下: ```c DevHandle MipiCsiHandle = NULL; /* 设备句柄 */ -id = 0; /* MiPi-Csi通道ID */ +id = 0; /* MIPI CSI通道ID */ /* 获取控制器操作句柄 */ MipiCsiHandle = MipiCsiOpen(id); @@ -115,9 +100,9 @@ if (MipiCsiHandle == NULL) { } ``` -### MIPI-CSI相应配置 +### MIPI CSI相应配置 -- 写入MIPI-CSI配置 +- 写入MIPI CSI配置 ```c int32_t MipiCsiSetComboDevAttr(DevHandle handle, ComboDevAttr *pAttr); @@ -130,7 +115,7 @@ if (MipiCsiHandle == NULL) { | 参数 | 参数描述 | | ---------- | -------------------------- | | handle | 控制器操作句柄 | - | pAttr | MIPI-CSI相应配置结构体指针 | + | pAttr | MIPI CSI相应配置结构体指针 | | **返回值** | **返回值描述** | | 0 | 设置成功 | | 负数 | 设置失败 | @@ -528,9 +513,9 @@ if (MipiCsiHandle == NULL) { } ``` -### 释放MIPI-CSI控制器操作句柄 +### 释放MIPI CSI控制器操作句柄 -MIPI-CSI使用完成之后,需要释放控制器操作句柄,释放句柄的函数如下所示: +MIPI CSI使用完成之后,需要释放控制器操作句柄,释放句柄的函数如下所示: ```c void MipiCsiClose(DevHandle handle); @@ -544,15 +529,15 @@ void MipiCsiClose(DevHandle handle); | 参数 | 参数描述 | | ------------ | ------------------------------------------------ | - | handle | MIPI-CSI控制器操作句柄 | + | handle | MIPI CSI控制器操作句柄 | ```c -MipiCsiClose(MIPIHandle); /* 释放掉MIPI-CSI控制器操作句柄 */ +MipiCsiClose(MIPIHandle); /* 释放掉MIPI CSI控制器操作句柄 */ ``` ## 使用实例 -MIPI-CSI完整的使用示例如下所示: +MIPI CSI完整的使用示例如下所示: ```c #include "hdf.h" diff --git a/zh-cn/device-dev/driver/driver-platform-mipicsi-develop.md b/zh-cn/device-dev/driver/driver-platform-mipicsi-develop.md index 28ec36c50a330d89c6c3a923ecd0de58afac8e90..ac5cc6654d7eec8065295e95e33961b9bde52694 100755 --- a/zh-cn/device-dev/driver/driver-platform-mipicsi-develop.md +++ b/zh-cn/device-dev/driver/driver-platform-mipicsi-develop.md @@ -1,15 +1,11 @@ -# MIPI-CSI - -- [概述](#section1_MIPI_CSIDevelop) -- [接口说明](#section2_MIPI_CSIDevelop) -- [开发步骤](#section3_MIPI_CSIDevelop) -- [开发实例](#section4_MIPI_CSIDevelop) +# MIPI CSI ## 概述 -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 无服务模式结构图 + ![image1](figures/无服务模式结构图.png) ## 接口说明 @@ -35,7 +31,7 @@ struct MipiCsiCntlrMethod { 表1 MipiCsiCntlrMethod成员的回调函数功能说明 | 成员函数 | 入参 | 出参 | 返回状态 | 功能 | | ------------------ | ------------------------------------------------------------ | ---- | ------------------ | -------------------------- | -| setComboDevAttr | **cntlr**:结构体指针,MipiCsi控制器 ;
**pAttr**:结构体指针,MIPI-CSI相应配置结构体指针 | 无 | HDF_STATUS相关状态 | 写入MIPI-CSI配置 | +| setComboDevAttr | **cntlr**:结构体指针,MipiCsi控制器 ;
**pAttr**:结构体指针,MIPI CSI相应配置结构体指针 | 无 | HDF_STATUS相关状态 | 写入MIPI CSI配置 | | setPhyCmvmode | **cntlr**:结构体指针,MipiCsi控制器 ;
**devno**:uint8_t,设备编号;
**cmvMode**:枚举类型,共模电压模式参数 | 无 | HDF_STATUS相关状态 | 设置共模电压模式 | | setExtDataType | **cntlr**:结构体指针,MipiCsi控制器 ;
**dataType**:结构体指针,定义YUV和原始数据格式以及位深度 | 无 | HDF_STATUS相关状态 | 设置YUV和RAW数据格式和位深 | | setHsMode | **cntlr**:结构体指针,MipiCsi控制器 ;
**laneDivideMode**:枚举类型,lane模式参数 | 无 | HDF_STATUS相关状态 | 设置MIPI RX的Lane分布 | @@ -50,7 +46,7 @@ struct MipiCsiCntlrMethod { ## 开发步骤 -MIPI-CSI模块适配的三个环节是配置属性文件、实例化驱动入、以及实例化核心层接口函数。 +MIPI CSI模块适配的三个环节是配置属性文件、实例化驱动入、以及实例化核心层接口函数。 1. **实例化驱动入口:** - 实例化HdfDriverEntry结构体成员。 @@ -107,7 +103,7 @@ MIPI-CSI模块适配的三个环节是配置属性文件、实例化驱动入、 一般在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 -- MIPI-CSI驱动入口参考 +- MIPI CSI驱动入口参考 ```c struct HdfDriverEntry g_mipiCsiDriverEntry = { @@ -123,7 +119,7 @@ MIPI-CSI模块适配的三个环节是配置属性文件、实例化驱动入、 - 自定义结构体参考 - > 从驱动的角度看,自定义结构体是参数和数据的载体,一般来说,config文件中的数值也会用来初始化结构体成员,本例的mipicsi器件属性在源文件中,故基本成员结构与MipiCsiCntlr无太大差异。 + 从驱动的角度看,自定义结构体是参数和数据的载体,一般来说,config文件中的数值也会用来初始化结构体成员,本例的mipicsi器件属性在源文件中,故基本成员结构与MipiCsiCntlr无太大差异。 ```c typedef struct { @@ -199,23 +195,25 @@ MIPI-CSI模块适配的三个环节是配置属性文件、实例化驱动入、 - **Init函数参考** - > **入参:** - > HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息 - > - > **返回值:** - > HDF_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf_base.h中HDF_STATUS 定义) - > - > | 状态(值) | 问题描述 | - > | :--------------------- | :----------: | - > | HDF_ERR_INVALID_OBJECT | 无效对象 | - > | HDF_ERR_MALLOC_FAIL | 内存分配失败 | - > | HDF_ERR_INVALID_PARAM | 无效参数 | - > | HDF_ERR_IO | I/O 错误 | - > | HDF_SUCCESS | 执行成功 | - > | HDF_FAILURE | 执行失败 | - > - > **函数说明:** - > MipiCsiCntlrMethod的实例化对象的挂载,调用MipiCsiRegisterCntlr,以及其他厂商自定义初始化操作。 + **入参:** + HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息 + + **返回值:** + HDF_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf_base.h中HDF_STATUS 定义) + + + | 状态(值) | 问题描述 | + | :--------------------- | :----------: | + | HDF_ERR_INVALID_OBJECT | 无效对象 | + | HDF_ERR_MALLOC_FAIL | 内存分配失败 | + | HDF_ERR_INVALID_PARAM | 无效参数 | + | HDF_ERR_IO | I/O 错误 | + | HDF_SUCCESS | 执行成功 | + | HDF_FAILURE | 执行失败 | + + **函数说明:** + MipiCsiCntlrMethod的实例化对象的挂载,调用MipiCsiRegisterCntlr,以及其他厂商自定义初始化操作。 + ```c static int32_t Hi35xxMipiCsiInit(struct HdfDeviceObject *device) @@ -282,14 +280,14 @@ MIPI-CSI模块适配的三个环节是配置属性文件、实例化驱动入、 - **Release函数参考** - > **入参:** - > HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 - > - > **返回值:** - > 无 - > - > **函数说明:** - > 该函数需要在驱动入口结构体中赋值给Release接口,当HDF框架调用Init函数初始化驱动失败时,可以调用Release释放驱动资源,该函数中需包含释放内存和删除控制器等操作。所有强制转换获取相应对象的操作**前提**是在Init函数中具备对应赋值的操作。 + **入参:** + HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 + + **返回值:** + 无 + + **函数说明:** + 该函数需要在驱动入口结构体中赋值给Release接口,当HDF框架调用Init函数初始化驱动失败时,可以调用Release释放驱动资源,该函数中需包含释放内存和删除控制器等操作。所有强制转换获取相应对象的操作**前提**是在Init函数中具备对应赋值的操作。 ```c static void Hi35xxMipiCsiRelease(struct HdfDeviceObject *device) diff --git a/zh-cn/device-dev/driver/driver-platform-mipidsi-des.md b/zh-cn/device-dev/driver/driver-platform-mipidsi-des.md index 6be428a3027b44ad6c0a109f18057975a9f0960d..43b17777b21088e4b2a6058f065ac08fd2b13bed 100644 --- a/zh-cn/device-dev/driver/driver-platform-mipidsi-des.md +++ b/zh-cn/device-dev/driver/driver-platform-mipidsi-des.md @@ -1,146 +1,70 @@ -# MIPI DSI - -- [概述](#section16806142183217) -- [接口说明](#section12720125432316) -- [使用指导](#section037231715335) - - [使用流程](#section49299119344) - - [获取MIPI-DSI操作句柄](#section5126155683811) - - [MIPI-DSI相应配置](#section201164274344) - - [发送/回读控制指令](#section199401342173415) - - [释放MIPI-DSI操作句柄](#section161011610357) - -- [使用实例](#section17470126123520) - -## 概述 - -- DSI(Display Serial Interface)是由移动行业处理器接口联盟(Mobile Industry Processor Interface \(MIPI\) Alliance)制定的规范,旨在降低移动设备中显示控制器的成本。它以串行的方式发送像素数据或指令给外设\(通常是LCD或者类似的显示设备\),或从外设中读取状态信息或像素信息;它定义了主机、图像数据源和目标设备之间的串行总线和通信协议。 - -- MIPI-DSI具备高速模式和低速模式两种工作模式,全部数据通道都可以用于单向的高速传输,但只有第一个数据通道才可用于低速双向传输,从属端的状态信息、像素等是通过该数据通道返回。时钟通道专用于在高速传输数据的过程中传输同步时钟信号。 -- 图1显示了简化的DSI接口。从概念上看,符合DSI的接口与基于DBI-2和DPI-2标准的接口具有相同的功能。它向外围设备传输像素或命令数据,并且可以从外围设备读取状态或像素信息。主要区别在于,DSI对所有像素数据、命令和事件进行序列化,而在传统接口中,这些像素数据、命令和事件通常需要附加控制信号才能在并行数据总线上传输。 - - **图 1** DSI发送、接收接口 - ![](figures/DSI发送-接收接口.png "DSI发送-接收接口") - - -## 接口说明 - -**表 1** MIPI-DSI API接口功能介绍 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

功能分类

-

接口名

-

描述

-

设置/获取当前MIPI-DSI相关配置

-

MipiDsiSetCfg

-

设置MIPI-DSI相关配置

-

MipiDsiGetCfg

-

获取当前MIPI-DSI相关配置

-

获取/释放MIPI-DSI操作句柄

-

MipiDsiOpen

-

获取MIPI-DSI操作句柄

-

MipiDsiClose

-

释放MIPI-DSI操作句柄

-

设置MIPI-DSI进入Low power模式/High speed模式

-

MipiDsiSetLpMode

-

设置MIPI-DSI进入Low power模式

-

MipiDsiSetHsMode

-

设置MIPI-DSI进入High speed模式

-

MIPI-DSI发送/回读指令

-

MipiDsiTx

-

MIPI-DSI发送相应指令的接口

-

MipiDsiRx

-

MIPI-DSI按期望长度回读的接口

-
- ->![](../public_sys-resources/icon-note.gif) **说明:** ->本文涉及的所有接口,仅限内核态使用,不支持在用户态使用 - -## 使用指导 - -### 使用流程 - -使用MIPI-DSI的一般流程如[图2](#fig129103491241)所示。 - -**图 2** MIPI-DSI使用流程图 -![](figures/MIPI-DSI使用流程图.png) - -### 获取MIPI-DSI操作句柄 - -在进行MIPI-DSI进行通信前,首先要调用MipiDsiOpen获取操作句柄,该函数会返回指定通道ID的操作句柄。 - -DevHandle MipiDsiOpen\(uint8\_t id\); - -**表 2** MipiDsiOpen的参数和返回值描述 - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

id

-

MIPI DSI通道ID

-

返回值

-

返回值描述

-

NULL

-

获取失败

-

设备句柄

-

获取到指令通道的操作句柄, 类型为DevHandle

-
- -假设系统中的MIPI-DSI通道为0,获取该通道操作句柄的示例如下: +# MIPI DSI + +## 概述 + +- DSI(Display Serial Interface)是由移动行业处理器接口联盟(Mobile Industry Processor Interface (MIPI) Alliance)制定的规范,旨在降低移动设备中显示控制器的成本。它以串行的方式发送像素数据或指令给外设(通常是LCD或者类似的显示设备),或从外设中读取状态信息或像素信息;它定义了主机、图像数据源和目标设备之间的串行总线和通信协议。 + +- MIPI DSI具备高速模式和低速模式两种工作模式,全部数据通道都可以用于单向的高速传输,但只有第一个数据通道才可用于低速双向传输,从属端的状态信息、像素等是通过该数据通道返回。时钟通道专用于在高速传输数据的过程中传输同步时钟信号。 + +- 图1显示了简化的DSI接口。从概念上看,符合DSI的接口与基于DBI-2和DPI-2标准的接口具有相同的功能。它向外围设备传输像素或命令数据,并且可以从外围设备读取状态或像素信息。主要区别在于,DSI对所有像素数据、命令和事件进行序列化,而在传统接口中,这些像素数据、命令和事件通常需要附加控制信号才能在并行数据总线上传输。 + + **图1** DSI发送、接收接口 + + ![zh-cn_image_0000001243192721](figures/zh-cn_image_0000001243192721.png) + + +## 接口说明 + + **表1** MIPI DSI API接口功能介绍 + +| 功能分类 | 接口名 | +| -------- | -------- | +| 设置/获取当前MIPI DSI相关配置 | - MipiDsiSetCfg:设置MIPI DSI相关配置
- MipiDsiGetCfg:获取当前MIPI DSI相关配置 | +| 获取/释放MIPI DSI操作句柄 | - MipiDsiOpen:获取MIPI DSI操作句柄
- MipiDsiClose:释放MIPI DSI操作句柄 | +| 设置MIPI DSI进入Low power模式/High speed模式 | - MipiDsiSetLpMode:设置MIPI DSI进入Low power模式
- MipiDsiSetHsMode:设置MIPI DSI进入High speed模式 | +| MIPI DSI发送/回读指令 | - MipiDsiTx:MIPI DSI发送相应指令的接口
- MipiDsiRx:MIPI DSI按期望长度回读的接口 | + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> 本文涉及的所有接口,仅限内核态使用,不支持在用户态使用。 + + +## 使用指导 + + +### 使用流程 + +使用MIPI DSI的一般流程如下图所示。 + + **图2** MIPI DSI使用流程图 + + ![zh-cn_image_0000001198152838](figures/zh-cn_image_0000001198152838.png) + + +### 获取MIPI DSI操作句柄 + +在进行MIPI DSI进行通信前,首先要调用MipiDsiOpen获取操作句柄,该函数会返回指定通道ID的操作句柄。 + + +``` +DevHandle MipiDsiOpen(uint8_t id); +``` + + **表2** MipiDsiOpen的参数和返回值描述 + +| **参数** | **参数描述** | +| -------- | -------- | +| id | MIPI DSI通道ID | +| **返回值** | **返回值描述** | +| NULL | 获取失败 | +| 设备句柄 | 获取到指令通道的操作句柄, 类型为DevHandle | + +假设系统中的MIPI DSI通道为0,获取该通道操作句柄的示例如下: + + ``` DevHandle mipiDsiHandle = NULL; /* 设备句柄 */ -chnId = 0; /* MIPI-DSI通道ID */ +chnId = 0; /* MIPI DSI通道ID */ /* 获取操作句柄 */ mipiDsiHandle = MipiDsiOpen(chnId); @@ -150,311 +74,205 @@ if (mipiDsiHandle == NULL) { } ``` -### MIPI-DSI相应配置 - -- 写入MIPI-DSI配置 - -int32\_t MipiDsiSetCfg\(DevHandle handle, struct MipiCfg \*cfg\); - -**表 3** MipiDsiSetCfg的参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

操作句柄

-

cfg

-

MIPI-DSI相应配置buf 指针

-

返回值

-

返回值描述

-

0

-

设置成功

-

负数

-

设置失败

-
- -``` -int32_t ret; -struct MipiCfg cfg = {0}; - -/* 当前对接的屏幕配置如下 */ -cfg.lane = DSI_4_LANES; -cfg.mode = DSI_CMD_MODE; -cfg.burstMode = VIDEO_NON_BURST_MODE_SYNC_EVENTS; -cfg.format = FORMAT_RGB_24_BIT; -cfg.pixelClk = 174; -cfg.phyDataRate = 384; -cfg.timingInfo.hsaPixels = 50; -cfg.timingInfo.hbpPixels = 55; -cfg.timingInfo.hlinePixels = 1200; -cfg.timingInfo.yResLines = 1800; -cfg.timingInfo.vbpLines = 33; -cfg.timingInfo.vsaLines = 76; -cfg.timingInfo.vfpLines = 120; -cfg.timingInfo.xResPixels = 1342; -/* 写入配置数据 */ -ret = MipiDsiSetCfg(mipiDsiHandle, &cfg); -if (ret != 0) { - HDF_LOGE("%s: SetMipiCfg fail! ret=%d\n", __func__, ret); - return -1; -} -``` -- 获取当前MIPI-DSI的配置 - -int32\_t MipiDsiGetCfg\(DevHandle handle, struct MipiCfg \*cfg\); - -**表 4** MipiDsiGetCfg的参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

操作句柄

-

cfg

-

MIPI-DSI相应配置buf 指针

-

返回值

-

返回值描述

-

0

-

获取成功

-

负数

-

获取失败

-
+### MIPI DSI相应配置 -``` -int32_t ret; -struct MipiCfg cfg; -memset(&cfg, 0, sizeof(struct MipiCfg)); -ret = MipiDsiGetCfg(mipiDsiHandle, &cfg); -if (ret != HDF_SUCCESS) { - HDF_LOGE("%s: GetMipiCfg fail!\n", __func__); - return HDF_FAILURE; -} -``` - -### 发送/回读控制指令 - -- 发送指令 - -int32\_t MipiDsiTx\(PalHandle handle, struct DsiCmdDesc \*cmd\); - -**表 5** MipiDsiTx的参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

操作句柄

-

cmd

-

需要发送的指令数据指针

-

返回值

-

返回值描述

-

0

-

发送成功

-

负数

-

发送失败

-
+- 写入MIPI DSI配置 + + ``` + int32_t MipiDsiSetCfg(DevHandle handle, struct MipiCfg *cfg); + ``` + + **表3** MipiDsiSetCfg的参数和返回值描述 + + | **参数** | **参数描述** | + | -------- | -------- | + | handle | 操作句柄 | + | cfg | MIPI DSI相应配置buf 指针 | + | **返回值** | **返回值描述** | + | 0 | 设置成功 | + | 负数 | 设置失败 | -``` -int32_t ret; -struct DsiCmdDesc *cmd = OsalMemCalloc(sizeof(struct DsiCmdDesc)); -if (cmd == NULL) { - return HDF_FAILURE; -} -cmd->dtype = DTYPE_DCS_WRITE; -cmd->dlen = 1; -cmd->payload = OsalMemCalloc(sizeof(uint8_t)); -if (cmd->payload == NULL) { - HdfFree(cmd); - return HDF_FAILURE; -} -*(cmd->payload) = DTYPE_GEN_LWRITE; -MipiDsiSetLpMode(mipiHandle); -ret = MipiDsiTx(mipiHandle, cmd); -MipiDsiSetHsMode(mipiHandle); -if (ret != HDF_SUCCESS) { - HDF_LOGE("%s: PalMipiDsiTx fail! ret=%d\n", __func__, ret); - HdfFree(cmd->payload); - HdfFree(cmd); - return HDF_FAILURE; -} -HdfFree(cmd->payload); -HdfFree(cmd); -``` + + ``` + int32_t ret; + struct MipiCfg cfg = {0}; + + /* 当前对接的屏幕配置如下 */ + cfg.lane = DSI_4_LANES; + cfg.mode = DSI_CMD_MODE; + cfg.burstMode = VIDEO_NON_BURST_MODE_SYNC_EVENTS; + cfg.format = FORMAT_RGB_24_BIT; + cfg.pixelClk = 174; + cfg.phyDataRate = 384; + cfg.timingInfo.hsaPixels = 50; + cfg.timingInfo.hbpPixels = 55; + cfg.timingInfo.hlinePixels = 1200; + cfg.timingInfo.yResLines = 1800; + cfg.timingInfo.vbpLines = 33; + cfg.timingInfo.vsaLines = 76; + cfg.timingInfo.vfpLines = 120; + cfg.timingInfo.xResPixels = 1342; + /* 写入配置数据 */ + ret = MipiDsiSetCfg(mipiDsiHandle, &cfg); + if (ret != 0) { + HDF_LOGE("%s: SetMipiCfg fail! ret=%d\n", __func__, ret); + return -1; + } + ``` + +- 获取当前MIPI DSI的配置 + + ``` + int32_t MipiDsiGetCfg(DevHandle handle, struct MipiCfg *cfg); + ``` + + **表4** MipiDsiGetCfg的参数和返回值描述 + + | **参数** | **参数描述** | + | -------- | -------- | + | handle | 操作句柄 | + | cfg | MIPI DSI相应配置buf 指针 | + | **返回值** | **返回值描述** | + | 0 | 获取成功 | + | 负数 | 获取失败 | -- 回读指令 - -int32\_t MipiDsiRx\(DevHandle handle, struct DsiCmdDesc \*cmd, uint32\_t readLen, uint8\_t \*out\); - -**表 6** MipiDsiRx的参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

操作句柄

-

cmd

-

需要回读的指令数据指针

-

readLen

-

期望回读的数据长度

-

out

-

回读的数据buf指针

-

返回值

-

返回值描述

-

0

-

获取成功

-

负数

-

获取失败

-
+ + ``` + int32_t ret; + struct MipiCfg cfg; + memset(&cfg, 0, sizeof(struct MipiCfg)); + ret = MipiDsiGetCfg(mipiDsiHandle, &cfg); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: GetMipiCfg fail!\n", __func__); + return HDF_FAILURE; + } + ``` -``` -int32_t ret; -uint8_t readVal = 0; -struct DsiCmdDesc *cmdRead = OsalMemCalloc(sizeof(struct DsiCmdDesc)); -if (cmdRead == NULL) { - return HDF_FAILURE; -} -cmdRead->dtype = DTYPE_DCS_READ; -cmdRead->dlen = 1; -cmdRead->payload = OsalMemCalloc(sizeof(uint8_t)); -if (cmdRead->payload == NULL) { - HdfFree(cmdRead); - return HDF_FAILURE; -} -*(cmdRead->payload) = DDIC_REG_STATUS; -MipiDsiSetLpMode(mipiDsiHandle); -ret = MipiDsiRx(mipiDsiHandle, cmdRead, sizeof(readVal), &readVal); -MipiDsiSetHsMode(mipiDsiHandle); -if (ret != HDF_SUCCESS) { - HDF_LOGE("%s: MipiDsiRx fail! ret=%d\n", __func__, ret); - HdfFree(cmdRead->payload); - HdfFree(cmdRead); - return HDF_FAILURE; -} -HdfFree(cmdRead->payload); -HdfFree(cmdRead); -``` +### 发送/回读控制指令 -### 释放MIPI-DSI操作句柄 +- 发送指令 + + ``` + int32_t MipiDsiTx(PalHandle handle, struct DsiCmdDesc *cmd); + ``` + + **表5** MipiDsiTx的参数和返回值描述 + + | **参数** | **参数描述** | + | -------- | -------- | + | handle | 操作句柄 | + | cmd | 需要发送的指令数据指针 | + | **返回值** | **返回值描述** | + | 0 | 发送成功 | + | 负数 | 发送失败 | -MIPI-DSI使用完成之后,需要释放操作句柄,释放句柄的函数如下所示: + + ``` + int32_t ret; + struct DsiCmdDesc *cmd = OsalMemCalloc(sizeof(struct DsiCmdDesc)); + if (cmd == NULL) { + return HDF_FAILURE; + } + cmd->dtype = DTYPE_DCS_WRITE; + cmd->dlen = 1; + cmd->payload = OsalMemCalloc(sizeof(uint8_t)); + if (cmd->payload == NULL) { + HdfFree(cmd); + return HDF_FAILURE; + } + *(cmd->payload) = DTYPE_GEN_LWRITE; + MipiDsiSetLpMode(mipiHandle); + ret = MipiDsiTx(mipiHandle, cmd); + MipiDsiSetHsMode(mipiHandle); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: PalMipiDsiTx fail! ret=%d\n", __func__, ret); + HdfFree(cmd->payload); + HdfFree(cmd); + return HDF_FAILURE; + } + HdfFree(cmd->payload); + HdfFree(cmd); + ``` + +- 回读指令 + + ``` + int32_t MipiDsiRx(DevHandle handle, struct DsiCmdDesc *cmd, uint32_t readLen, uint8_t *out); + ``` + + **表6** MipiDsiRx的参数和返回值描述 + + | **参数** | **参数描述** | + | -------- | -------- | + | handle | 操作句柄 | + | cmd | 需要回读的指令数据指针 | + | readLen | 期望回读的数据长度 | + | out | 回读的数据buf指针 | + | **返回值** | **返回值描述** | + | 0 | 获取成功 | + | 负数 | 获取失败 | -void MipiDsiClose\(DevHandle handle\); + + ``` + int32_t ret; + uint8_t readVal = 0; + + struct DsiCmdDesc *cmdRead = OsalMemCalloc(sizeof(struct DsiCmdDesc)); + if (cmdRead == NULL) { + return HDF_FAILURE; + } + cmdRead->dtype = DTYPE_DCS_READ; + cmdRead->dlen = 1; + cmdRead->payload = OsalMemCalloc(sizeof(uint8_t)); + if (cmdRead->payload == NULL) { + HdfFree(cmdRead); + return HDF_FAILURE; + } + *(cmdRead->payload) = DDIC_REG_STATUS; + MipiDsiSetLpMode(mipiDsiHandle); + ret = MipiDsiRx(mipiDsiHandle, cmdRead, sizeof(readVal), &readVal); + MipiDsiSetHsMode(mipiDsiHandle); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: MipiDsiRx fail! ret=%d\n", __func__, ret); + HdfFree(cmdRead->payload); + HdfFree(cmdRead); + return HDF_FAILURE; + } + HdfFree(cmdRead->payload); + HdfFree(cmdRead); + ``` + + +### 释放MIPI DSI操作句柄 + +MIPI DSI使用完成之后,需要释放操作句柄,释放句柄的函数如下所示: + + +``` +void MipiDsiClose(DevHandle handle); +``` 该函数会释放掉由MipiDsiOpen申请的资源。 -**表 7** MipiDsiClose的参数和返回值描述 - - - - - - - - - - -

参数

-

参数描述

-

handle

-

MIPI-DSI操作句柄

-
+ **表7** MipiDsiClose的参数和返回值描述 + +| 参数 | 参数描述 | +| -------- | -------- | +| handle | MIPI DSI操作句柄 | + ``` -MipiDsiClose(mipiHandle); /* 释放掉MIPI-DSI操作句柄 */ +MipiDsiClose(mipiHandle); /* 释放掉MIPI DSI操作句柄 */ ``` -## 使用实例 -MIPI-DSI完整的使用示例如下所示: +## 使用实例 +MIPI DSI完整的使用示例如下所示: + + ``` #include "hdf.h" #include "mipi_dsi_if.h" @@ -548,4 +366,3 @@ void PalMipiDsiTestSample(void) MipiDsiClose(handle); } ``` - diff --git a/zh-cn/device-dev/driver/driver-platform-mipidsi-develop.md b/zh-cn/device-dev/driver/driver-platform-mipidsi-develop.md index 49d492ba8b5ff283573d7446abe0eaaea88e9f20..854bca3dbe060e181f0c7bb33e9cda7484f8fb7b 100755 --- a/zh-cn/device-dev/driver/driver-platform-mipidsi-develop.md +++ b/zh-cn/device-dev/driver/driver-platform-mipidsi-develop.md @@ -1,21 +1,20 @@ -# MIPI-DSI +# MIPI DSI -- [概述](#section1266787503161538) -- [接口说明](#section752964871810) -- [开发步骤](#section545182932161538) -- [开发实例](#section1167576616161538) -## 概述 +## 概述 -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无服务模式结构图 -![](figures/无服务模式结构图.png "DSI无服务模式结构图") + **图1** DSI无服务模式结构图 -## 接口说明 + ![zh-cn_image_0000001176603960](figures/zh-cn_image_0000001176603960.png) + + +## 接口说明 MipiDsiCntlrMethod定义: + ``` struct MipiDsiCntlrMethod { // 核心层结构体的成员函数 int32_t (*setCntlrCfg)(struct MipiDsiCntlr *cntlr); @@ -30,310 +29,212 @@ struct MipiDsiCntlrMethod { // 核心层结构体的成员函数 }; ``` -**表 1** MipiDsiCntlrMethod成员的回调函数功能说明 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

成员函数

-

入参

-

出参

-

返回状态

-

功能

-

setCntlrCfg

-

cntlr: 结构体指针,MipiDsi控制器 ;

-

-

HDF_STATUS相关状态

-

设置控制器参数

-

setCmd

-

cntlr: 结构体指针,MipiDsi控制器 ;cmd: 结构体指针,指令传入值

-

-

HDF_STATUS相关状态

-

向显示设备发送指令

-

getCmd

-

cntlr: 结构体指针,MipiDsi控制器 ;

-

cmd: 结构体指针,用于传出指令值;

-

HDF_STATUS相关状态

-

从显示设备读取信息指令

-

toHs

-

cntlr: 结构体指针,MipiDsi控制器 ;

-

-

HDF_STATUS相关状态

-

设置为高速模式

-

toLp

-

cntlr: 结构体指针,MipiDsi控制器 ;

-

-

HDF_STATUS相关状态

-

设置为低电模式

-
- -## 开发步骤 - -MIPI-DSI模块适配的三个环节是配置属性文件,实例化驱动入口,以及实例化核心层接口函数。 - -1. **实例化驱动入口:** - - 实例化HdfDriverEntry结构体成员。 - - 调用HDF\_INIT将HdfDriverEntry实例化对象注册到HDF框架中。 - -2. **配置属性文件:** - - 在device\_info.hcs文件中添加deviceNode描述。 - - 【可选】添加mipidsi\_config.hcs器件属性文件。 - -3. **实例化MIPIDSI控制器对象:** - - 初始化MipiDsiCntlr成员。 - - 实例化MipiDsiCntlr成员MipiDsiCntlrMethod。 - - >![](../public_sys-resources/icon-note.gif) **说明:** - >实例化MipiDsiCntlr成员MipiDsiCntlrMethod,其定义和成员说明见[接口说明](#section752964871810)。 - - -4. **驱动调试:** - - 【可选】针对新增驱动程序,建议验证驱动基本功能,例如挂载后的信息反馈,数据传输的成功与否等。 - - -## 开发实例 - -下方将以mipi\_tx\_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。 - -1. 一般来说,驱动开发首先需要在 xx\_config.hcs 中配置器件属性,并在device\_info.hcs文件中添加deviceNode描述。器件属性值与核心层MipiDsiCntlr 成员的默认值或限制范围有密切关系,deviceNode信息与驱动入口注册相关。 - - 但本例中MIPI控制器无需配置额外属性,如有厂商需要,则需要在device\_info文件的deviceNode增加deviceMatchAttr信息,以及增加mipidsi\_config文件。 - - device\_info.hcs 配置参考: - - ``` - root { - device_info { - match_attr = "hdf_manager"; - platform :: host { - hostName = "platform_host"; - priority = 50; - device_mipi_dsi:: device { - device0 :: deviceNode { - policy = 0; - priority = 150; - permission = 0644; - moduleName = "HDF_MIPI_TX"; //【必要】用于指定驱动名称,需要与期望的驱动Entry中的moduleName一致; - serviceName = "HDF_MIPI_TX"; // 【必要且唯一】驱动对外发布服务的名称 - } - } - } - } - } - ``` - -2. 完成器件属性文件的配置之后,下一步请实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf\_device\_desc.h 中定义)类型的全局变量,且moduleName要和device\_info.hcs中保持一致。HdfDriverEntry结构体的函数指针成员会被厂商操作函数填充,HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组,方便调用。 - - 一般在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 - - - MIPI-DSI驱动入口参考。 - - ``` - struct HdfDriverEntry g_mipiTxDriverEntry = { - .moduleVersion = 1, - .Init = Hi35xxMipiTxInit, //见Init参考 - .Release = Hi35xxMipiTxRelease,//见Release参考 - .moduleName = "HDF_MIPI_TX", //【必要】需要与device_info.hcs 中保持一致。 - }; - HDF_INIT(g_mipiTxDriverEntry); //调用HDF_INIT将驱动入口注册到HDF框架中 - ``` - -3. 完成驱动入口注册之后,最后一步就是以核心层MipiDsiCntlr对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化MipiDsiCntlr成员MipiDsiCntlrMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。 - - 自定义结构体参考。 - - 从驱动的角度看,自定义结构体是参数和数据的载体,一般来说,config文件中的数值也会用来初始化结构体成员,但本例的mipidsi无器件属性文件,故基本成员结构与MipiDsiCntlr无太大差异。 - - ``` - typedef struct { - unsigned int devno; // 设备号 - short laneId[LANE_MAX_NUM]; // lane号 - OutPutModeTag outputMode; // 输出模式选择:刷新模式,命令行模式和视频流模式 - VideoModeTag videoMode; // 显示设备的同步模式 - OutputFormatTag outputFormat; // 输出DSI图像数据格式:RGB or YUV - SyncInfoTag syncInfo; // 时序相关的设置 - unsigned int phyDataRate; // mbps - unsigned int pixelClk; // KHz - } ComboDevCfgTag; - - // MipiDsiCntlr是核心层控制器结构体,其中的成员在Init函数中会被赋值 - struct MipiDsiCntlr { - struct IDeviceIoService service; - struct HdfDeviceObject *device; - unsigned int devNo; // 设备号 - struct MipiCfg cfg; - struct MipiDsiCntlrMethod *ops; - struct OsalMutex lock; - void *priv; - }; - ``` - - - MipiDsiCntlr成员回调函数结构体MipiDsiCntlrMethod的实例化,其他成员在Init函数中初始化。 - - ``` - static struct MipiDsiCntlrMethod g_method = { - .setCntlrCfg = Hi35xxSetCntlrCfg, - .setCmd = Hi35xxSetCmd, - .getCmd = Hi35xxGetCmd, - .toHs = Hi35xxToHs, - .toLp = Hi35xxToLp, - }; - ``` - - - Init函数参考 - - 入参: - - HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 - - 返回值: - - HDF\_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf\_base.h中HDF\_STATUS 定义)。 - - - - - - - - - - - - - - - - - - - - - - - - - -

状态(值)

-

问题描述

-

HDF_ERR_INVALID_OBJECT

-

无效对象

-

HDF_ERR_MALLOC_FAIL

-

内存分配失败

-

HDF_ERR_INVALID_PARAM

-

无效参数

-

HDF_ERR_IO

-

I/O 错误

-

HDF_SUCCESS

-

执行成功

-

HDF_FAILURE

-

执行失败

-
- - 函数说明: - - MipiDsiCntlrMethod的实例化对象的挂载,调用MipiDsiRegisterCntlr,以及其他厂商自定义初始化操作。 - - ``` - static int32_t Hi35xxMipiTxInit(struct HdfDeviceObject *device) - { - int32_t ret; - g_mipiTx.priv = NULL; //g_mipiTx是定义的全局变量 - //static struct MipiDsiCntlr g_mipiTx { - // .devNo=0 - //}; - g_mipiTx.ops = &g_method;//MipiDsiCntlrMethod的实例化对象的挂载 - ret = MipiDsiRegisterCntlr(&g_mipiTx, device);//【必要】调用核心层函数和g_mipiTx初始化核心层全局变量 - ... - return MipiTxDrvInit(0); //【必要】厂商对设备的初始化,形式不限 - } - - //mipi_dsi_core.c核心层 - int32_t MipiDsiRegisterCntlr(struct MipiDsiCntlr *cntlr, struct HdfDeviceObject *device) - { - ... - //定义的全局变量:static struct MipiDsiHandle g_mipiDsihandle[MAX_CNTLR_CNT]; - if (g_mipiDsihandle[cntlr->devNo].cntlr == NULL) { - (void)OsalMutexInit(&g_mipiDsihandle[cntlr->devNo].lock); - (void)OsalMutexInit(&(cntlr->lock)); + **表1** MipiDsiCntlrMethod成员的回调函数功能说明 + +| 成员函数 | 入参 | 出参 | 返回状态 | 功能 | +| -------- | -------- | -------- | -------- | -------- | +| setCntlrCfg | cntlr:结构体指针,MipiDsi控制器  | 无 | HDF_STATUS相关状态 | 设置控制器参数 | +| setCmd | cntlr:结构体指针,MipiDsi控制器;
cmd:结构体指针,指令传入值; | 无 | HDF_STATUS相关状态 | 向显示设备发送指令 | +| getCmd | cntlr:结构体指针,MipiDsi控制器;
cmd:传入的命令描述结构体指针;
readLen:读取的数据大小; | out:结构体指针,用于存储读取的数据。 | HDF_STATUS相关状态 | 通过发送指令读取数据 | +| toHs | cntlr: 结构体指针,MipiDsi控制器 ; | 无 | HDF_STATUS相关状态 | 设置为高速模式 | +| toLp | cntlr: 结构体指针,MipiDsi控制器 ; | 无 | HDF_STATUS相关状态 | 设置为低电模式 | + + +## 开发步骤 + +MIPI DSI模块适配的三个环节是配置属性文件,实例化驱动入口,以及实例化核心层接口函数。 + +1. **实例化驱动入口:** + - 实例化HdfDriverEntry结构体成员。 + - 调用HDF_INIT将HdfDriverEntry实例化对象注册到HDF框架中。 + +2. **配置属性文件:** + - 在device_info.hcs文件中添加deviceNode描述。 + - 【可选】添加mipidsi_config.hcs器件属性文件。 + +3. **实例化MIPIDSI控制器对象:** + - 初始化MipiDsiCntlr成员。 + - 实例化MipiDsiCntlr成员MipiDsiCntlrMethod。 + > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** + > 实例化MipiDsiCntlr成员MipiDsiCntlrMethod,其定义和成员说明见[接口说明](#接口说明)。 + +4. **驱动调试:** + 【可选】针对新增驱动程序,建议验证驱动基本功能,例如挂载后的信息反馈,数据传输的成功与否等。 + + +## 开发实例 + +下方将以mipi_tx_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。 + +1. 一般来说,驱动开发首先需要在 xx_config.hcs 中配置器件属性,并在device_info.hcs文件中添加deviceNode描述。器件属性值与核心层MipiDsiCntlr 成员的默认值或限制范围有密切关系,deviceNode信息与驱动入口注册相关。 + + 但本例中MIPI控制器无需配置额外属性,如有厂商需要,则需要在device_info文件的deviceNode增加deviceMatchAttr信息,以及增加mipidsi_config文件。 + + device_info.hcs 配置参考: + + ``` + root { + device_info { + match_attr = "hdf_manager"; + platform :: host { + hostName = "platform_host"; + priority = 50; + device_mipi_dsi:: device { + device0 :: deviceNode { + policy = 0; + priority = 150; + permission = 0644; + moduleName = "HDF_MIPI_TX"; //【必要】用于指定驱动名称,需要与期望的驱动Entry中的moduleName一致; + serviceName = "HDF_MIPI_TX"; // 【必要且唯一】驱动对外发布服务的名称 + } + } + } + } + } + ``` + +2. 完成器件属性文件的配置之后,下一步请实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf_device_desc.h 中定义)类型的全局变量,且moduleName要和device_info.hcs中保持一致。HdfDriverEntry结构体的函数指针成员会被厂商操作函数填充,HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组,方便调用。 + 一般在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 + + - MIPI DSI驱动入口参考。 - g_mipiDsihandle[cntlr->devNo].cntlr = cntlr;//初始化MipiDsiHandle成员 - g_mipiDsihandle[cntlr->devNo].priv = NULL; - cntlr->device = device; //使HdfDeviceObject与MipiDsiHandle可以相互转化的前提 - device->service = &(cntlr->service); //使HdfDeviceObject与MipiDsiHandle可以相互转化的前提 - cntlr->priv = NULL; - ... - return HDF_SUCCESS; - } - ... - return HDF_FAILURE; - } - ``` + ``` + struct HdfDriverEntry g_mipiTxDriverEntry = { + .moduleVersion = 1, + .Init = Hi35xxMipiTxInit, //见Init参考 + .Release = Hi35xxMipiTxRelease,//见Release参考 + .moduleName = "HDF_MIPI_TX", //【必要】需要与device_info.hcs 中保持一致。 + }; + HDF_INIT(g_mipiTxDriverEntry); //调用HDF_INIT将驱动入口注册到HDF框架中 + ``` - - Release函数参考 +3. 完成驱动入口注册之后,最后一步就是以核心层MipiDsiCntlr对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化MipiDsiCntlr成员MipiDsiCntlrMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。 + - 自定义结构体参考。 - 入参: + 从驱动的角度看,自定义结构体是参数和数据的载体,一般来说,config文件中的数值也会用来初始化结构体成员,但本例的mipidsi无器件属性文件,故基本成员结构与MipiDsiCntlr无太大差异。 - HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 + + ``` + typedef struct { + unsigned int devno; // 设备号 + short laneId[LANE_MAX_NUM]; // lane号 + OutPutModeTag outputMode; // 输出模式选择:刷新模式,命令行模式和视频流模式 + VideoModeTag videoMode; // 显示设备的同步模式 + OutputFormatTag outputFormat; // 输出DSI图像数据格式:RGB or YUV + SyncInfoTag syncInfo; // 时序相关的设置 + unsigned int phyDataRate; // mbps + unsigned int pixelClk; // KHz + } ComboDevCfgTag; + + // MipiDsiCntlr是核心层控制器结构体,其中的成员在Init函数中会被赋值 + struct MipiDsiCntlr { + struct IDeviceIoService service; + struct HdfDeviceObject *device; + unsigned int devNo; // 设备号 + struct MipiCfg cfg; + struct MipiDsiCntlrMethod *ops; + struct OsalMutex lock; + void *priv; + }; + ``` + - MipiDsiCntlr成员回调函数结构体MipiDsiCntlrMethod的实例化,其他成员在Init函数中初始化。 + + + ``` + static struct MipiDsiCntlrMethod g_method = { + .setCntlrCfg = Hi35xxSetCntlrCfg, + .setCmd = Hi35xxSetCmd, + .getCmd = Hi35xxGetCmd, + .toHs = Hi35xxToHs, + .toLp = Hi35xxToLp, + }; + ``` + - Init函数参考 - 返回值: + 入参: - 无。 + HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 - 函数说明: + 返回值: - 该函数需要在驱动入口结构体中赋值给 Release 接口, 当 HDF 框架调用 Init 函数初始化驱动失败时,可以调用 Release 释放驱动资源, 该函数中需包含释放内存和删除控制器等操作。所有强制转换获取相应对象的操作前提是在Init函数中具备对应赋值的操作。 + HDF_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf_base.h中HDF_STATUS 定义)。 - ``` - static void Hi35xxMipiTxRelease(struct HdfDeviceObject *device) - { - struct MipiDsiCntlr *cntlr = NULL; - ... - cntlr = MipiDsiCntlrFromDevice(device);//这里有HdfDeviceObject到MipiDsiCntlr的强制转化 - //return (device == NULL) ? NULL : (struct MipiDsiCntlr *)device->service; - ... - MipiTxDrvExit(); //【必要】对厂商设备所占资源的释放 - MipiDsiUnregisterCntlr(&g_mipiTx); //空函数 - g_mipiTx.priv = NULL; - HDF_LOGI("%s: unload mipi_tx driver 1212!", __func__); - } - ``` + + | 状态(值) | 问题描述 | + | -------- | -------- | + | HDF_ERR_INVALID_OBJECT | 无效对象 | + | HDF_ERR_MALLOC_FAIL | 内存分配失败 | + | HDF_ERR_INVALID_PARAM | 无效参数 | + | HDF_ERR_IO | I/O 错误 | + | HDF_SUCCESS | 执行成功 | + | HDF_FAILURE | 执行失败 | + 函数说明: + MipiDsiCntlrMethod的实例化对象的挂载,调用MipiDsiRegisterCntlr,以及其他厂商自定义初始化操作。 + + ``` + static int32_t Hi35xxMipiTxInit(struct HdfDeviceObject *device) + { + int32_t ret; + g_mipiTx.priv = NULL; //g_mipiTx是定义的全局变量 + //static struct MipiDsiCntlr g_mipiTx { + // .devNo=0 + //}; + g_mipiTx.ops = &g_method;//MipiDsiCntlrMethod的实例化对象的挂载 + ret = MipiDsiRegisterCntlr(&g_mipiTx, device);//【必要】调用核心层函数和g_mipiTx初始化核心层全局变量 + ... + return MipiTxDrvInit(0); //【必要】厂商对设备的初始化,形式不限 + } + + //mipi_dsi_core.c核心层 + int32_t MipiDsiRegisterCntlr(struct MipiDsiCntlr *cntlr, struct HdfDeviceObject *device) + { + ... + //定义的全局变量:static struct MipiDsiHandle g_mipiDsihandle[MAX_CNTLR_CNT]; + if (g_mipiDsihandle[cntlr->devNo].cntlr == NULL) { + (void)OsalMutexInit(&g_mipiDsihandle[cntlr->devNo].lock); + (void)OsalMutexInit(&(cntlr->lock)); + + g_mipiDsihandle[cntlr->devNo].cntlr = cntlr;//初始化MipiDsiHandle成员 + g_mipiDsihandle[cntlr->devNo].priv = NULL; + cntlr->device = device; //使HdfDeviceObject与MipiDsiHandle可以相互转化的前提 + device->service = &(cntlr->service); //使HdfDeviceObject与MipiDsiHandle可以相互转化的前提 + cntlr->priv = NULL; + ... + return HDF_SUCCESS; + } + ... + return HDF_FAILURE; + } + ``` + - Release函数参考 + + 入参: + + HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 + + 返回值: + + 无。 + + 函数说明: + + 该函数需要在驱动入口结构体中赋值给 Release 接口, 当 HDF 框架调用 Init 函数初始化驱动失败时,可以调用 Release 释放驱动资源, 该函数中需包含释放内存和删除控制器等操作。所有强制转换获取相应对象的操作前提是在Init函数中具备对应赋值的操作。 + + + ``` + static void Hi35xxMipiTxRelease(struct HdfDeviceObject *device) + { + struct MipiDsiCntlr *cntlr = NULL; + ... + cntlr = MipiDsiCntlrFromDevice(device);//这里有HdfDeviceObject到MipiDsiCntlr的强制转化 + //return (device == NULL) ? NULL : (struct MipiDsiCntlr *)device->service; + ... + MipiTxDrvExit(); //【必要】对厂商设备所占资源的释放 + MipiDsiUnregisterCntlr(&g_mipiTx); //空函数 + g_mipiTx.priv = NULL; + HDF_LOGI("%s: unload mipi_tx driver 1212!", __func__); + } + ``` diff --git a/zh-cn/device-dev/driver/driver-platform-mmc-develop.md b/zh-cn/device-dev/driver/driver-platform-mmc-develop.md index 80dea26f8728f8ed7bad062451d1b2aa3c88fdff..0c0cf18b3b079b8fd6c2be05dc7c2d5e93540832 100755 --- a/zh-cn/device-dev/driver/driver-platform-mmc-develop.md +++ b/zh-cn/device-dev/driver/driver-platform-mmc-develop.md @@ -1,21 +1,19 @@ -# MMC +# MMC -- [概述](#section1846388309162704) -- [接口说明](#section752964871810) -- [开发步骤](#section1617495117162704) -- [开发实例](#section1220893490162704) -## 概述 +## 概述 MMC(MultiMedia Card),即多媒体卡,在HDF框架中,MMC的接口适配模式采用独立服务模式,在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。独立服务模式可以直接借助HDFDeviceManager的服务管理能力,但需要为每个设备单独配置设备节点,增加内存占用。 -**图 1** MMC独立服务模式结构图 -![](figures/独立服务模式结构图.png "MMC独立服务模式结构图") + **图1** MMC独立服务模式结构图 + ![zh-cn_image_0000001176603968](figures/zh-cn_image_0000001176603968.png) -## 接口说明 + +## 接口说明 MmcCntlrOps定义: + ``` struct MmcCntlrOps { int32_t (*request)(struct MmcCntlr *cntlr, struct MmcCmd *cmd); @@ -36,517 +34,353 @@ struct MmcCntlrOps { }; ``` -**表 1** MmcCntlrOps结构体成员的回调函数功能说明 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

成员函数

-

入参

-

返回值

-

功能

-

doRequest

-

cntlr: 核心层结构体指针;mmc控制器 ;cmd: 结构体指针,传入命令值

-

HDF_STATUS相关状态

-

request相应处理

-

setClock

-

cntlr: 核心层结构体指针;mmc控制器 ;clock: 时钟传入值

-

HDF_STATUS相关状态

-

设置时钟频率

-

setPowerMode

-

cntlr: 核心层结构体指针;mmc控制器 ;mode: 枚举值(见MmcPowerMode定义),功耗模式

-

HDF_STATUS相关状态

-

设置功耗模式

-

setBusWidth

-

cntlr: 核心层结构体指针;mmc控制器 ;width: 枚举值(见MmcBusWidth定义),总线带宽

-

HDF_STATUS相关状态

-

设置总线带宽

-

setBusTiming

-

cntlr: 核心层结构体指针;mmc控制器 ;timing: 枚举值(见MmcBusTiming定义),总线时序

-

HDF_STATUS相关状态

-

设置总线时序

-

setSdioIrq

-

cntlr: 核心层结构体指针;mmc控制器 ;enable: 布尔值,控制中断

-

HDF_STATUS相关状态

-

使能/去使能SDIO中断

-

hardwareReset

-

cntlr: 核心层结构体指针;mmc控制器 ;

-

HDF_STATUS相关状态

-

复位硬件

-

systemInit

-

cntlr: 核心层结构体指针;mmc控制器 ;

-

HDF_STATUS相关状态

-

系统初始化

-

setEnhanceSrobe

-

cntlr: 核心层结构体指针,mmc控制器 ;enable: 布尔值,设置功能

-

HDF_STATUS相关状态

-

设置增强选通

-

switchVoltage

-

cntlr: 核心层结构体指针;mmc控制器 ;volt: 枚举值,电压值(3.3,1.8,1.2V);

-

HDF_STATUS相关状态

-

设置电压值

-

devReadOnly

-

cntlr: 核心层结构体指针;mmc控制器 ;

-

布尔值

-

检验设备是否只读

-

cardPluged

-

cntlr: 核心层结构体指针;mmc控制器 ;

-

布尔值

-

检验设备是否拔出

-

devBusy

-

cntlr: 核心层结构体指针;mmc控制器 ;

-

布尔值

-

检验设备是否忙碌

-

tune

-

cntlr: 核心层结构体指针;mmc控制器 ;cmdCode: uint32_t,命令代码;

-

HDF_STATUS相关状态

-

调谐

-

rescanSdioDev

-

cntlr: 核心层结构体指针;mmc控制器 ;

-

HDF_STATUS相关状态

-

扫描并添加SDIO设备

-
- -## 开发步骤 + **表1** MmcCntlrOps结构体成员的回调函数功能说明 + +| 成员函数 | 入参 | 返回值 | 功能 | +| -------- | -------- | -------- | -------- | +| doRequest | cntlr: 核心层结构体指针;mmc控制器 ;cmd: 结构体指针,传入命令值 | HDF_STATUS相关状态 | request相应处理 | +| setClock | cntlr: 核心层结构体指针;mmc控制器 ;clock: 时钟传入值 | HDF_STATUS相关状态 | 设置时钟频率 | +| setPowerMode | cntlr: 核心层结构体指针;mmc控制器 ;mode: 枚举值(见MmcPowerMode定义),功耗模式 | HDF_STATUS相关状态 | 设置功耗模式 | +| setBusWidth | cntlr: 核心层结构体指针;mmc控制器 ;width: 枚举值(见MmcBusWidth定义),总线带宽 | HDF_STATUS相关状态 | 设置总线带宽 | +| setBusTiming | cntlr: 核心层结构体指针;mmc控制器 ;timing: 枚举值(见MmcBusTiming定义),总线时序 | HDF_STATUS相关状态 | 设置总线时序 | +| setSdioIrq | cntlr: 核心层结构体指针;mmc控制器 ;enable: 布尔值,控制中断 | HDF_STATUS相关状态 | 使能/去使能SDIO中断 | +| hardwareReset | cntlr: 核心层结构体指针;mmc控制器 ; | HDF_STATUS相关状态 | 复位硬件 | +| systemInit | cntlr: 核心层结构体指针;mmc控制器 ; | HDF_STATUS相关状态 | 系统初始化 | +| setEnhanceSrobe | cntlr: 核心层结构体指针,mmc控制器 ;enable: 布尔值,设置功能 | HDF_STATUS相关状态 | 设置增强选通 | +| switchVoltage | cntlr: 核心层结构体指针;mmc控制器 ;volt: 枚举值,电压值(3.3,1.8,1.2V); | HDF_STATUS相关状态 | 设置电压值 | +| devReadOnly | cntlr: 核心层结构体指针;mmc控制器 ; | 布尔值 | 检验设备是否只读 | +| cardPluged | cntlr: 核心层结构体指针;mmc控制器 ; | 布尔值 | 检验设备是否拔出 | +| devBusy | cntlr: 核心层结构体指针;mmc控制器 ; | 布尔值 | 检验设备是否忙碌 | +| tune | cntlr: 核心层结构体指针;mmc控制器 ;cmdCode: uint32_t,命令代码; | HDF_STATUS相关状态 | 调谐 | +| rescanSdioDev | cntlr: 核心层结构体指针;mmc控制器 ; | HDF_STATUS相关状态 | 扫描并添加SDIO设备 | + + +## 开发步骤 MMC模块适配的三个环节是配置属性文件,实例化驱动入口,以及实例化核心层接口函数。 -1. **实例化驱动入口:** - - 实例化HdfDriverEntry结构体成员。 - - 调用HDF\_INIT将HdfDriverEntry实例化对象注册到HDF框架中。 - -2. **配置属性文件:** - - 在device\_info.hcs文件中添加deviceNode描述。 - - 【可选】添加mmc\_config.hcs器件属性文件。 - -3. **实例化MMC控制器对象:** - - 初始化MmcCntlr成员。 - - 实例化MmcCntlr成员MmcCntlrOps。 - - >![](../public_sys-resources/icon-note.gif) **说明:** - >实例化MmcCntlr成员MmcCntlrOps,其定义和成员说明见[接口说明](#section752964871810)。 +1. **实例化驱动入口:** + - 实例化HdfDriverEntry结构体成员。 + - 调用HDF_INIT将HdfDriverEntry实例化对象注册到HDF框架中。 +2. **配置属性文件:** + - 在device_info.hcs文件中添加deviceNode描述。 + - 【可选】添加mmc_config.hcs器件属性文件。 -4. **驱动调试:** +3. **实例化MMC控制器对象:** + - 初始化MmcCntlr成员。 + - 实例化MmcCntlr成员MmcCntlrOps。 + > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** + > 实例化MmcCntlr成员MmcCntlrOps,其定义和成员说明见[接口说明](#接口说明)。 - 【可选】针对新增驱动程序,建议验证驱动基本功能,例如挂载后的信息反馈,设备启动是否成功等。 +4. **驱动调试:** + 【可选】针对新增驱动程序,建议验证驱动基本功能,例如挂载后的信息反馈,设备启动是否成功等。 -## 开发实例 +## 开发实例 下方将以himci.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。 -1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf\_device\_desc.h 中定义)类型的全局变量,且moduleName要和device\_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。 - - 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 - - MMC驱动入口参考: - - ``` - struct HdfDriverEntry g_mmcDriverEntry = { - .moduleVersion = 1, - .Bind = HimciMmcBind, //见Bind参考 - .Init = HimciMmcInit, //见Init参考 - .Release = HimciMmcRelease, //见Release参考 - .moduleName = "hi3516_mmc_driver",//【必要且与HCS文件中里面的moduleName匹配】 - }; - HDF_INIT(g_mmcDriverEntry); //调用HDF_INIT将驱动入口注册到HDF框架中 - ``` - -2. 完成驱动入口注册之后,下一步请在device\_info.hcs文件中添加deviceNode信息,并在mmc\_config.hcs中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值与核心层MmcCntlr成员的默认值或限制范围有密切关系。 - - 如有多个器件信息,则需要在device\_info文件增加deviceNode信息,以及在mmc\_config文件中增加对应的器件属性**。** - - - device\_info.hcs 配置参考。 - - ``` - root { - device_info { - match_attr = "hdf_manager"; - platform :: host { - hostName = "platform_host"; - priority = 50; - device_mmc:: device { - device0 :: deviceNode { - policy = 2; - priority = 10; - permission = 0644; - moduleName = "hi3516_mmc_driver"; //【必要】用于指定驱动名称,需要与驱动Entry中的moduleName一致; - serviceName = "HDF_PLATFORM_MMC_0"; //【必要】驱动对外发布服务的名称,必须唯一 - deviceMatchAttr = "hi3516_mmc_emmc";//【必要】用于配置控制器私有数据,要与 mmc_config.hcs 中对应控制器保持一致 - } - device1 :: deviceNode { - policy = 1; - priority = 20; - permission = 0644; - moduleName = "hi3516_mmc_driver"; - serviceName = "HDF_PLATFORM_MMC_1"; - deviceMatchAttr = "hi3516_mmc_sd"; //SD类型 - } - device2 :: deviceNode { - policy = 1; - priority = 30; - permission = 0644; - moduleName = "hi3516_mmc_driver"; - serviceName = "HDF_PLATFORM_MMC_2"; - deviceMatchAttr = "hi3516_mmc_sdio";//SDIO类型 - } +1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf_device_desc.h 中定义)类型的全局变量,且moduleName要和device_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。 + + 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 + + MMC驱动入口参考: + + ``` + struct HdfDriverEntry g_mmcDriverEntry = { + .moduleVersion = 1, + .Bind = HimciMmcBind, //见Bind参考 + .Init = HimciMmcInit, //见Init参考 + .Release = HimciMmcRelease, //见Release参考 + .moduleName = "hi3516_mmc_driver",//【必要且与HCS文件中里面的moduleName匹配】 + }; + HDF_INIT(g_mmcDriverEntry); //调用HDF_INIT将驱动入口注册到HDF框架中 + ``` + +2. 完成驱动入口注册之后,下一步请在device_info.hcs文件中添加deviceNode信息,并在mmc_config.hcs中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值与核心层MmcCntlr成员的默认值或限制范围有密切关系。 + 如有多个器件信息,则需要在device_info文件增加deviceNode信息,以及在mmc_config文件中增加对应的器件属性**。** + - device_info.hcs 配置参考。 + + + ``` + root { + device_info { + match_attr = "hdf_manager"; + platform :: host { + hostName = "platform_host"; + priority = 50; + device_mmc:: device { + device0 :: deviceNode { + policy = 2; + priority = 10; + permission = 0644; + moduleName = "hi3516_mmc_driver"; //【必要】用于指定驱动名称,需要与驱动Entry中的moduleName一致; + serviceName = "HDF_PLATFORM_MMC_0"; //【必要】驱动对外发布服务的名称,必须唯一 + deviceMatchAttr = "hi3516_mmc_emmc";//【必要】用于配置控制器私有数据,要与 mmc_config.hcs 中对应控制器保持一致 + } + device1 :: deviceNode { + policy = 1; + priority = 20; + permission = 0644; + moduleName = "hi3516_mmc_driver"; + serviceName = "HDF_PLATFORM_MMC_1"; + deviceMatchAttr = "hi3516_mmc_sd"; //SD类型 + } + device2 :: deviceNode { + policy = 1; + priority = 30; + permission = 0644; + moduleName = "hi3516_mmc_driver"; + serviceName = "HDF_PLATFORM_MMC_2"; + deviceMatchAttr = "hi3516_mmc_sdio";//SDIO类型 + } + } + } + } + } + ``` + + - mmc_config.hcs 配置参考。 + + + ``` + root { + platform { + mmc_config { + template mmc_controller {//模板公共参数,继承该模板的节点如果使用模板中的默认值,则节点字段可以缺省 + match_attr = ""; + voltDef = 0; // 3.3V + freqMin = 50000; //【必要】最小频率值 + freqMax = 100000000; //【必要】最大频率值 + freqDef = 400000; //【必要】默认频率值 + maxBlkNum = 2048; //【必要】最大的block号 + maxBlkSize = 512; //【必要】最大的block个数 + ocrDef = 0x300000; //【必要】工作电压设置相关 + caps2 = 0; //【必要】属性寄存器相关,见mmc_caps.h 中 MmcCaps2 定义 + regSize = 0x118; //【必要】寄存器位宽 + hostId = 0; //【必要】主机号 + regBasePhy = 0x10020000;//【必要】寄存器物理基地址 + irqNum = 63; //【必要】中断号 + devType = 2; //【必要】模式选择:emmc, SD, SDIO ,COMBO + caps = 0x0001e045; //【必要】属性寄存器相关,见mmc_caps.h 中 MmcCaps 定义 + } + controller_0x10100000 :: mmc_controller { + match_attr = "hi3516_mmc_emmc";//【必要】需要和device_info.hcs中的deviceMatchAttr值一致 + hostId = 0; + regBasePhy = 0x10100000; + irqNum = 96; + devType = 0; // emmc类型 + caps = 0xd001e045; + caps2 = 0x60; + } + controller_0x100f0000 :: mmc_controller { + match_attr = "hi3516_mmc_sd"; + hostId = 1; + regBasePhy = 0x100f0000; + irqNum = 62; + devType = 1; // sd类型 + caps = 0xd001e005; + } + controller_0x10020000 :: mmc_controller { + match_attr = "hi3516_mmc_sdio"; + hostId = 2; + regBasePhy = 0x10020000; + irqNum = 63; + devType = 2; // sdio类型 + caps = 0x0001e04d; + } + } + } + } + ``` + +3. 完成驱动入口注册之后,最后一步就是以核心层MmcCntlr对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化MmcCntlr成员MmcCntlrOps(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。 + - 自定义结构体参考。 + + 从驱动的角度看,自定义结构体是参数和数据的载体,而且mmc_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员 ,一些重要数值也会传递给核心层对象。 + + + ``` + struct HimciHost { + struct MmcCntlr *mmc;//【必要】核心层结构体 + struct MmcCmd *cmd; //【必要】核心层结构体,传递命令的,相关命令见枚举量 MmcCmdCode + //【可选】根据厂商驱动需要添加 + void *base; + enum HimciPowerStatus powerStatus; + uint8_t *alignedBuff; + uint32_t buffLen; + struct scatterlist dmaSg; + struct scatterlist *sg; + uint32_t dmaSgNum; + DMA_ADDR_T dmaPaddr; + uint32_t *dmaVaddr; + uint32_t irqNum; + bool isTuning; + uint32_t id; + struct OsalMutex mutex; + bool waitForEvent; + HIMCI_EVENT himciEvent; + }; + //MmcCntlr是核心层控制器结构体,其中的成员在bind函数中会被赋值 + struct MmcCntlr { + struct IDeviceIoService service; + struct HdfDeviceObject *hdfDevObj; + struct PlatformDevice device; + struct OsalMutex mutex; + struct OsalSem released; + uint32_t devType; + struct MmcDevice *curDev; + struct MmcCntlrOps *ops; + struct PlatformQueue *msgQueue; + uint16_t index; + uint16_t voltDef; + uint32_t vddBit; + uint32_t freqMin; + uint32_t freqMax; + uint32_t freqDef; + union MmcOcr ocrDef; + union MmcCaps caps; + union MmcCaps2 caps2; + uint32_t maxBlkNum; + uint32_t maxBlkSize; + uint32_t maxReqSize; + bool devPluged; + bool detecting; + void *priv; + }; + ``` + + - MmcCntlr成员回调函数结构体MmcCntlrOps的实例化,其他成员在Bind函数中初始化。 + + + ``` + static struct MmcCntlrOps g_himciHostOps = { + .request = HimciDoRequest, + .setClock = HimciSetClock, + .setPowerMode = HimciSetPowerMode, + .setBusWidth = HimciSetBusWidth, + .setBusTiming = HimciSetBusTiming, + .setSdioIrq = HimciSetSdioIrq, + .hardwareReset = HimciHardwareReset, + .systemInit = HimciSystemInit, + .setEnhanceSrobe= HimciSetEnhanceSrobe, + .switchVoltage = HimciSwitchVoltage, + .devReadOnly = HimciDevReadOnly, + .devPluged = HimciCardPluged, + .devBusy = HimciDevBusy, + .tune = HimciTune, + .rescanSdioDev = HimciRescanSdioDev, + }; + ``` + - Bind函数参考 + + 入参**:** + + HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 + + 返回值: + + HDF_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf_base.h中HDF_STATUS 定义)。 + + | 状态(值) | 问题描述 | + | -------- | -------- | + | HDF_ERR_INVALID_OBJECT | 控制器对象非法 | + | HDF_ERR_MALLOC_FAIL | 内存分配失败 | + | HDF_ERR_INVALID_PARAM | 参数非法 | + | HDF_ERR_IO | I/O 错误 | + | HDF_SUCCESS | 初始化成功 | + | HDF_FAILURE | 初始化失败 | + + 函数说明: + + MmcCntlr,HimciHost,HdfDeviceObject之间互相赋值,方便其他函数可以相互转化,初始化自定义结构体HimciHost对象,初始化MmcCntlr成员,调用核心层MmcCntlrAdd函数。 + + + ``` + static int32_t HimciMmcBind(struct HdfDeviceObject *obj) + { + struct MmcCntlr *cntlr = NULL; + struct HimciHost *host = NULL; + int32_t ret; + cntlr = (struct MmcCntlr *)OsalMemCalloc(sizeof(struct MmcCntlr)); + host = (struct HimciHost *)OsalMemCalloc(sizeof(struct HimciHost)); + + host->mmc = cntlr; //【必要】使HimciHost与MmcCntlr可以相互转化的前提 + cntlr->priv = (void *)host; //【必要】使HimciHost与MmcCntlr可以相互转化的前提 + cntlr->ops = &g_himciHostOps; //【必要】MmcCntlrOps的实例化对象的挂载 + cntlr->hdfDevObj = obj; //【必要】使HdfDeviceObject与MmcCntlr可以相互转化的前提 + obj->service = &cntlr->service; //【必要】使HdfDeviceObject与MmcCntlr可以相互转化的前提 + ret = MmcCntlrParse(cntlr, obj); //【必要】 初始化 cntlr. 失败就 goto _ERR; + ... + ret = HimciHostParse(host, obj); //【必要】 初始化 host对象的相关属性,失败就 goto _ERR; + ... + ret = HimciHostInit(host, cntlr);//厂商自定义的初始化,失败就 goto _ERR; + ... + ret = MmcCntlrAdd(cntlr); //调用核心层函数 失败就 goto _ERR; + ... + (void)MmcCntlrAddDetectMsgToQueue(cntlr);//将卡检测消息添加到队列中。 + HDF_LOGD("HimciMmcBind: success."); + return HDF_SUCCESS; + _ERR: + HimciDeleteHost(host); + HDF_LOGD("HimciMmcBind: fail, err = %d.", ret); + return ret; + } + ``` + + - Init函数参考 + + 入参: + + HdfDeviceObject是整个驱动对外暴露的接口参数,具备HCS配置文件的信息。 + + 返回值: + + HDF_STATUS相关状态。 + + 函数说明: + + 实现ProcMciInit。 + + + ``` + static int32_t HimciMmcInit(struct HdfDeviceObject *obj) + { + static bool procInit = false; + (void)obj; + if (procInit == false) { + if (ProcMciInit() == HDF_SUCCESS) { + procInit = true; + HDF_LOGD("HimciMmcInit: proc init success."); } - } } - } - ``` - - - mmc\_config.hcs 配置参考。 - - ``` - root { - platform { - mmc_config { - template mmc_controller {//模板公共参数,继承该模板的节点如果使用模板中的默认值,则节点字段可以缺省 - match_attr = ""; - voltDef = 0; // 3.3V - freqMin = 50000; //【必要】最小频率值 - freqMax = 100000000; //【必要】最大频率值 - freqDef = 400000; //【必要】默认频率值 - maxBlkNum = 2048; //【必要】最大的block号 - maxBlkSize = 512; //【必要】最大的block个数 - ocrDef = 0x300000; //【必要】工作电压设置相关 - caps2 = 0; //【必要】属性寄存器相关,见mmc_caps.h 中 MmcCaps2 定义 - regSize = 0x118; //【必要】寄存器位宽 - hostId = 0; //【必要】主机号 - regBasePhy = 0x10020000;//【必要】寄存器物理基地址 - irqNum = 63; //【必要】中断号 - devType = 2; //【必要】模式选择:emmc, SD, SDIO ,COMBO - caps = 0x0001e045; //【必要】属性寄存器相关,见mmc_caps.h 中 MmcCaps 定义 - } - controller_0x10100000 :: mmc_controller { - match_attr = "hi3516_mmc_emmc";//【必要】需要和device_info.hcs中的deviceMatchAttr值一致 - hostId = 0; - regBasePhy = 0x10100000; - irqNum = 96; - devType = 0; // emmc类型 - caps = 0xd001e045; - caps2 = 0x60; - } - controller_0x100f0000 :: mmc_controller { - match_attr = "hi3516_mmc_sd"; - hostId = 1; - regBasePhy = 0x100f0000; - irqNum = 62; - devType = 1; // sd类型 - caps = 0xd001e005; - } - controller_0x10020000 :: mmc_controller { - match_attr = "hi3516_mmc_sdio"; - hostId = 2; - regBasePhy = 0x10020000; - irqNum = 63; - devType = 2; // sdio类型 - caps = 0x0001e04d; - } - } - } - } - ``` - -3. 完成驱动入口注册之后,最后一步就是以核心层MmcCntlr对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化MmcCntlr成员MmcCntlrOps(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。 - - 自定义结构体参考。 - - 从驱动的角度看,自定义结构体是参数和数据的载体,而且mmc\_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员 ,一些重要数值也会传递给核心层对象。 - - ``` - struct HimciHost { - struct MmcCntlr *mmc;//【必要】核心层结构体 - struct MmcCmd *cmd; //【必要】核心层结构体,传递命令的,相关命令见枚举量 MmcCmdCode - //【可选】根据厂商驱动需要添加 - void *base; - enum HimciPowerStatus powerStatus; - uint8_t *alignedBuff; - uint32_t buffLen; - struct scatterlist dmaSg; - struct scatterlist *sg; - uint32_t dmaSgNum; - DMA_ADDR_T dmaPaddr; - uint32_t *dmaVaddr; - uint32_t irqNum; - bool isTuning; - uint32_t id; - struct OsalMutex mutex; - bool waitForEvent; - HIMCI_EVENT himciEvent; - }; - //MmcCntlr是核心层控制器结构体,其中的成员在bind函数中会被赋值 - struct MmcCntlr { - struct IDeviceIoService service; - struct HdfDeviceObject *hdfDevObj; - struct PlatformDevice device; - struct OsalMutex mutex; - struct OsalSem released; - uint32_t devType; - struct MmcDevice *curDev; - struct MmcCntlrOps *ops; - struct PlatformQueue *msgQueue; - uint16_t index; - uint16_t voltDef; - uint32_t vddBit; - uint32_t freqMin; - uint32_t freqMax; - uint32_t freqDef; - union MmcOcr ocrDef; - union MmcCaps caps; - union MmcCaps2 caps2; - uint32_t maxBlkNum; - uint32_t maxBlkSize; - uint32_t maxReqSize; - bool devPluged; - bool detecting; - void *priv; - }; - ``` - - - MmcCntlr成员回调函数结构体MmcCntlrOps的实例化,其他成员在Bind函数中初始化。 - - ``` - static struct MmcCntlrOps g_himciHostOps = { - .request = HimciDoRequest, - .setClock = HimciSetClock, - .setPowerMode = HimciSetPowerMode, - .setBusWidth = HimciSetBusWidth, - .setBusTiming = HimciSetBusTiming, - .setSdioIrq = HimciSetSdioIrq, - .hardwareReset = HimciHardwareReset, - .systemInit = HimciSystemInit, - .setEnhanceSrobe= HimciSetEnhanceSrobe, - .switchVoltage = HimciSwitchVoltage, - .devReadOnly = HimciDevReadOnly, - .devPluged = HimciCardPluged, - .devBusy = HimciDevBusy, - .tune = HimciTune, - .rescanSdioDev = HimciRescanSdioDev, - }; - ``` - - - Bind函数参考 - - 入参**:** - - HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 - - 返回值: - - HDF\_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf\_base.h中HDF\_STATUS 定义)。 - - - - - - - - - - - - - - - - - - - - - - - - - -

状态(值)

-

问题描述

-

HDF_ERR_INVALID_OBJECT

-

控制器对象非法

-

HDF_ERR_MALLOC_FAIL

-

内存分配失败

-

HDF_ERR_INVALID_PARAM

-

参数非法

-

HDF_ERR_IO

-

I/O 错误

-

HDF_SUCCESS

-

初始化成功

-

HDF_FAILURE

-

初始化失败

-
- - 函数说明: - - MmcCntlr,HimciHost,HdfDeviceObject之间互相赋值,方便其他函数可以相互转化,初始化自定义结构体HimciHost对象,初始化MmcCntlr成员,调用核心层MmcCntlrAdd函数。 - - ``` - static int32_t HimciMmcBind(struct HdfDeviceObject *obj) - { - struct MmcCntlr *cntlr = NULL; - struct HimciHost *host = NULL; - int32_t ret; - cntlr = (struct MmcCntlr *)OsalMemCalloc(sizeof(struct MmcCntlr)); - host = (struct HimciHost *)OsalMemCalloc(sizeof(struct HimciHost)); - - host->mmc = cntlr; //【必要】使HimciHost与MmcCntlr可以相互转化的前提 - cntlr->priv = (void *)host; //【必要】使HimciHost与MmcCntlr可以相互转化的前提 - cntlr->ops = &g_himciHostOps; //【必要】MmcCntlrOps的实例化对象的挂载 - cntlr->hdfDevObj = obj; //【必要】使HdfDeviceObject与MmcCntlr可以相互转化的前提 - obj->service = &cntlr->service; //【必要】使HdfDeviceObject与MmcCntlr可以相互转化的前提 - ret = MmcCntlrParse(cntlr, obj); //【必要】 初始化 cntlr. 失败就 goto _ERR; - ... - ret = HimciHostParse(host, obj); //【必要】 初始化 host对象的相关属性,失败就 goto _ERR; - ... - ret = HimciHostInit(host, cntlr);//厂商自定义的初始化,失败就 goto _ERR; - ... - ret = MmcCntlrAdd(cntlr); //调用核心层函数 失败就 goto _ERR; - ... - (void)MmcCntlrAddDetectMsgToQueue(cntlr);//将卡检测消息添加到队列中。 - HDF_LOGD("HimciMmcBind: success."); - return HDF_SUCCESS; - _ERR: - HimciDeleteHost(host); - HDF_LOGD("HimciMmcBind: fail, err = %d.", ret); - return ret; - } - ``` - - - Init函数参考 - - 入参: - - HdfDeviceObject是整个驱动对外暴露的接口参数,具备HCS配置文件的信息。 - - 返回值: - - HDF\_STATUS相关状态。 - - 函数说明: - - 实现ProcMciInit。 - - ``` - static int32_t HimciMmcInit(struct HdfDeviceObject *obj) - { - static bool procInit = false; - (void)obj; - if (procInit == false) { - if (ProcMciInit() == HDF_SUCCESS) { - procInit = true; - HDF_LOGD("HimciMmcInit: proc init success."); - } - } - HDF_LOGD("HimciMmcInit: success."); - return HDF_SUCCESS; - } - ``` - - - Release函数参考 - - 入参: - - HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 - - 返回值: - - 无。 - - 函数说明: - - 释放内存和删除控制器等操作,该函数需要在驱动入口结构体中赋值给Release接口,当HDF框架调用Init函数初始化驱动失败时,可以调用 Release释放驱动资源。所有强制转换获取相应对象的操作**前提**是在Init函数中具备对应赋值的操作。 - - ``` - static void HimciMmcRelease(struct HdfDeviceObject *obj) - { - struct MmcCntlr *cntlr = NULL; - ... - cntlr = (struct MmcCntlr *)obj->service;//这里有HdfDeviceObject到MmcCntlr的强制转化,通过service成员,赋值见Bind函数 - ... - HimciDeleteHost((struct HimciHost *)cntlr->priv);//厂商自定义的内存释放函数,这里有MmcCntlr到HimciHost的强制转化 - } - ``` + HDF_LOGD("HimciMmcInit: success."); + return HDF_SUCCESS; + } + ``` + - Release函数参考 + + 入参: + + HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 + + 返回值: + + 无。 + 函数说明: + 释放内存和删除控制器等操作,该函数需要在驱动入口结构体中赋值给Release接口,当HDF框架调用Init函数初始化驱动失败时,可以调用 Release释放驱动资源。所有强制转换获取相应对象的操作**前提**是在Init函数中具备对应赋值的操作。 + + ``` + static void HimciMmcRelease(struct HdfDeviceObject *obj) + { + struct MmcCntlr *cntlr = NULL; + ... + cntlr = (struct MmcCntlr *)obj->service;//这里有HdfDeviceObject到MmcCntlr的强制转化,通过service成员,赋值见Bind函数 + ... + HimciDeleteHost((struct HimciHost *)cntlr->priv);//厂商自定义的内存释放函数,这里有MmcCntlr到HimciHost的强制转化 + } + ``` diff --git a/zh-cn/device-dev/driver/driver-platform-pwm-des.md b/zh-cn/device-dev/driver/driver-platform-pwm-des.md index 287bc0fdaf4e88624daec0e4aa38766f7bc6ab0c..00c326f44ebf1cc30c0ba2e43ead82743876df1d 100644 --- a/zh-cn/device-dev/driver/driver-platform-pwm-des.md +++ b/zh-cn/device-dev/driver/driver-platform-pwm-des.md @@ -1,140 +1,82 @@ -# PWM - -- [概述](#section1_PWM_des) - - [PwmConfig结构体](#section1.1_PWM_des) -- [接口说明](#section2_PWM_des) -- [使用指导](#section3_PWM_des) - - [使用流程](#section3.1_PWM_des) - - [获取PWM设备句柄](#section3.2_PWM_des) - - [销毁PWM设备句柄](#section3.3_PWM_des) - - [使能](#section3.4_PWM_des) - - [禁用](#section3.5_PWM_des) - - [设置PWM设备周期](#section3.6_PWM_des) - - [设置PWM设备占空时间](#section3.7_PWM_des) - - [设置PWM设备极性](#section3.8_PWM_des) - - [设置PWM设备参数](#section3.9_PWM_des) - - [获取PWM设备参数](#section3.10_PWM_des) - -- [使用实例](#section3_PWM_des) - -## 概述 - -- PWM是脉冲宽度调制(Pulse Width Modulation)的缩写,是一种对模拟信号电平进行数字编码,转换为脉冲的一种技术。常用于马达控制、背光亮度调节等。 - -- PWM接口定义了操作PWM设备的通用方法集合,包括: - - PWM设备句柄获取和销毁。 - - PWM周期、占空比、极性的设置。 - - PWM使能和关闭。 - - PWM配置信息的获取和设置 - -### PwmConfig结构体 - -**表1** PwmConfig结构体介绍 - - - -| 名称 | 描述 | -| -------- | ------------------------------------------------------------ | -| duty | 占空时间,以纳秒为单位 | -| period | PWM周期,以纳秒为单位 | -| number | 要生成的方波数。正值表示将生成指定数量的方波,0表示方波将不断产生 | -| polarity | 极性:正极性/反极性 | -| status | 状态:启用状态/禁用状态 | - -## 接口说明 - -**表2** PWM设备API接口功能介绍 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
功能分类接口名描述
PWM句柄操作PwmOpen获取PWM设备驱动句柄
PwmClose释放PWM设备驱动句柄
使能/禁用PWMPwmEnable使能PWM
PwmDisable禁用PWM
PWM配置操作PwmSetPeriod设置PWM周期
PwmSetDuty设置PWM占空时间
PwmSetPolarity设置PWM极性
设置/获取PWM配置信息PwmSetConfig设置PWM设备参数
PwmGetConfig获取PWM设备参数
- - - ->![](../public_sys-resources/icon-note.gif) **说明:** ->PWM当前仅限内核态使用,不支持在用户态使用。 - -## 使用指导 - -### 使用流程 - -在操作系统启动过程中,驱动管理模块根据配置文件加载PWM驱动,PWM驱动会检测PWM器件并初始化驱动。 - -使用PWM设备的一般流程如[图1](#fig1_PWM_des)所示。 - -**图 1** PWM设备使用流程图 - - -![](figures/PWM设备使用流程图.png) - -### 获取PWM设备句柄 +# PWM + + +## 概述 + +PWM是脉冲宽度调制(Pulse Width Modulation)的缩写,是一种对模拟信号电平进行数字编码并将其转换为脉冲的技术。常用于马达控制、背光亮度调节等。 + + PWM接口定义了操作PWM设备的通用方法集合,包括: +- PWM设备句柄获取和释放。 + +- PWM周期、占空比、极性的设置。 + +- PWM使能和关闭。 + +- PWM配置信息的获取和设置。 + + +### PwmConfig结构体 + + **表1** PwmConfig结构体介绍 + +| 名称 | 描述 | +| -------- | -------- | +| duty | 占空时间,以纳秒为单位。 | +| period | PWM周期,以纳秒为单位。 | +| number | 要生成的方波数。
- 正值:表示将生成指定数量的方波,
- 0:表示方波将不断产生。 | +| polarity | 极性:正极性/反极性。 | +| status | 状态:启用状态/禁用状态。 | + + +## 接口说明 + + **表2** PWM驱动API接口功能介绍 + +| 功能分类 | 接口描述 | +| -------- | -------- | +| PWM句柄操作 | - PwmOpen:获取PWM设备驱动句柄
- PwmClose:释放PWM设备驱动句柄 | +| 使能/禁用PWM | - PwmEnable:使能PWM
- PwmDisable:禁用PWM | +| PWM配置操作 | - PwmSetPeriod:设置PWM周期
- PwmSetDuty:设置PWM占空时间
- PwmSetPolarity:设置PWM极性 | +| 设置/获取PWM配置信息 | - PwmSetConfig:设置PWM设备参数
- PwmGetConfig:获取PWM设备参数 | + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> 本文涉及的所有接口,仅限内核态使用,不支持在用户态使用。 + + +## 使用指导 + + +### 使用流程 + +使用PWM的一般流程如下图所示。 + + **图1** PWM使用流程图 + +![zh-cn_image_0000001206372673](figures/zh-cn_image_0000001206372673.png) + + +### 获取PWM设备句柄 在操作PWM设备时,首先要调用PwmOpen获取PWM设备句柄,该函数会返回指定设备号的PWM设备句柄。 -```c + +``` DevHandle PwmOpen(uint32_t num); ``` -**表3** PwmOpen参数和返回值描述 + **表3** PwmOpen参数和返回值描述 - - -| 参数 | 参数描述 | -| ---------- | ----------------------- | +| **参数** | **参数描述** | +| -------- | -------- | | num | PWM设备编号 | | **返回值** | **返回值描述** | | handle | 获取成功返回PWM设备句柄 | | NULL | 获取失败 | +假设系统中的PWM设备号为0,获取该PWM设备句柄的示例如下: + -```c +``` uint32_t num = 0; /* PWM设备号 */ DevHandle handle = NULL; @@ -145,48 +87,49 @@ if (handle == NULL) { } ``` -### 销毁PWM设备句柄 + +### 销毁PWM设备句柄 关闭PWM设备,系统释放对应的资源。 -```c -void PwmClose(DevHandle handle); -``` -**表4** PwmClose参数描述 +``` +voidPwmClose(DevHandle handle); +``` - + **表4** PwmClose参数描述 -| 参数 | 参数描述 | -| ------ | ----------- | -| handle | PWM设备句柄 | +| **参数** | **参数描述** | +| -------- | -------- | +| handle | PWM设备句柄 | -```c +``` /* 销毁PWM设备句柄 */ PwmClose(handle); ``` -### 使能 + +### 使能 启用PWM设备。 -```c + +``` int32_t PwmEnable(DevHandle handle); ``` -**表5** PwmEnable参数描述 - - + **表5** PwmEnable参数和返回值描述 -| 参数 | 参数描述 | -| ---------- | -------------- | +| **参数** | **参数描述** | +| -------- | -------- | | handle | PWM设备句柄 | | **返回值** | **返回值描述** | | 0 | 使能成功 | | 负数 | 使能失败 | -```c + +``` int32_t ret; /*启用PWM设备*/ @@ -196,26 +139,27 @@ if (ret != 0) { } ``` -### 禁用 + +### 禁用 禁用PWM设备。 -```c + +``` int32_t PwmDisable(DevHandle handle); ``` -**表6** PwmDisable参数描述 - - + **表6** PwmDisable参数和返回值描述 -| 参数 | 参数描述 | -| ---------- | -------------- | +| **参数** | **参数描述** | +| -------- | -------- | | handle | PWM设备句柄 | | **返回值** | **返回值描述** | | 0 | 禁用成功 | | 负数 | 禁用失败 | -```c + +``` int32_t ret; /*禁用PWM设备*/ @@ -225,27 +169,28 @@ if (ret != 0) { } ``` -### 设置PWM设备周期 + +### 设置PWM设备周期 设置PWM设备周期。 -```c + +``` int32_t PwmSetPeriod(DevHandle handle, uint32_t period); ``` -**表7** PwmSetPeriod参数描述 - - + **表7** PwmSetPeriod参数和返回值描述 -| 参数 | 参数描述 | -| ---------- | ------------------------ | +| **参数** | **参数描述** | +| -------- | -------- | | handle | PWM设备句柄 | | period | 要设置的周期,单位为纳秒 | | **返回值** | **返回值描述** | | 0 | 设置成功 | | 负数 | 设置失败 | -```c + +``` int32_t ret; /*设置周期为50000000纳秒*/ @@ -254,27 +199,29 @@ if (ret != 0) { /*错误处理*/ } ``` -### 设置PWM设备占空时间 + + +### 设置设备占空时间 设置PWM设备占空时间。 -```c + +``` int32_t PwmSetDuty(DevHandle handle, uint32_t duty); ``` -**表8** PwmSetDuty参数描述 - - + **表8** PwmSetDuty参数和返回值描述 -| 参数 | 参数描述 | -| ---------- | ---------------------------- | +| **参数** | **参数描述** | +| -------- | -------- | | handle | PWM设备句柄 | | duty | 要设置的占空时间,单位为纳秒 | | **返回值** | **返回值描述** | | 0 | 设置成功 | | 负数 | 设置失败 | -```c + +``` int32_t ret; /*设置占空时间为25000000纳秒*/ @@ -283,27 +230,29 @@ if (ret != 0) { /*错误处理*/ } ``` -### 设置PWM设备极性 + + +### 设置PWM设备极性 设置PWM设备极性。 -```c + +``` int32_t PwmSetPolarity(DevHandle handle, uint8_t polarity); ``` -**表9** PwmSetPolarity参数描述 - - + **表9** PwmSetPolarity参数和返回值描述 -| 参数 | 参数描述 | -| ---------- | ------------------- | +| **参数** | **参数描述** | +| -------- | -------- | | handle | PWM设备句柄 | | polarity | 要设置的极性,正/反 | | **返回值** | **返回值描述** | | 0 | 设置成功 | | 负数 | 设置失败 | -```c + +``` int32_t ret; /*设置极性为反*/ @@ -314,34 +263,34 @@ if (ret != 0) { ``` -### 设置PWM设备参数 +### 设置PWM设备参数 设置PWM设备参数。 -```c + +``` int32_t PwmSetConfig(DevHandle handle, struct PwmConfig *config); ``` -**表10** PwmSetConfig参数描述 + **表10** PwmSetConfig参数和返回值描述 - - -| 参数 | 参数描述 | -| ---------- | -------------- | +| **参数** | **参数描述** | +| -------- | -------- | | handle | PWM设备句柄 | -| *config | 参数指针 | +| \*config | 参数指针 | | **返回值** | **返回值描述** | | 0 | 设置成功 | | 负数 | 设置失败 | -```c + +``` int32_t ret; struct PwmConfig pcfg; -pcfg.duty = 25000000; /*占空时间为25000000纳秒*/ -pcfg.period = 50000000; /*周期为50000000纳秒*/ -pcfg.number = 0; /*不断产生方波*/ +pcfg.duty = 25000000; /*占空时间为25000000纳秒*/ +pcfg.period = 50000000; /*周期为50000000纳秒*/ +pcfg.number = 0; /*不断产生方波*/ pcfg.polarity = PWM_INVERTED_POLARITY; /*极性为反*/ -pcfg.status = PWM_ENABLE_STATUS; /*运行状态为启用*/ +pcfg.status = PWM_ENABLE_STATUS; /*运行状态为启用*/ /*设置PWM设备参数*/ ret = PwmSetConfig(handle, &pcfg); @@ -350,27 +299,28 @@ if (ret != 0) { } ``` -### 获取PWM设备参数 + +### 获取PWM设备参数 获取PWM设备参数。 -```c + +``` int32_t PwmGetConfig(DevHandle handle, struct PwmConfig *config); ``` -**表11** PwmGetConfig参数描述 - - + **表11** PwmGetConfig参数和返回值描述 -| 参数 | 参数描述 | -| ---------- | -------------- | +| **参数** | **参数描述** | +| -------- | -------- | | handle | PWM设备句柄 | -| *config | 参数指针 | +| \*config | 参数指针 | | **返回值** | **返回值描述** | | 0 | 获取成功 | | 负数 | 获取失败 | -```c + +``` int32_t ret; struct PwmConfig pcfg; @@ -381,10 +331,12 @@ if (ret != 0) { } ``` -## 使用实例 + +## 使用实例 PWM设备完整的使用示例如下所示,首先获取PWM设备句柄,然后设置设备周期、占空时间、极性,获取设备参数。使能,设置设备参数,禁用,最后销毁PWM设备句柄。 + ``` void PwmTestSample(void) { @@ -393,12 +345,12 @@ void PwmTestSample(void) DevHandle handle = NULL; struct PwmConfig pcfg; - pcfg.duty = 20000000; /*占空时间为20000000纳秒*/ - pcfg.period = 40000000; /*周期为40000000纳秒*/ - pcfg.number = 100; /*生成100个方波*/ + pcfg.duty = 20000000; /*占空时间为20000000纳秒*/ + pcfg.period = 40000000; /*周期为40000000纳秒*/ + pcfg.number = 100; /*生成100个方波*/ pcfg.polarity = PWM_NORMAL_POLARITY; /*极性为正*/ pcfg.status = PWM_ENABLE_STATUS; /*运行状态为启用*/ - + /* PWM设备编号,要填写实际平台上的编号 */ num = 1; @@ -429,14 +381,14 @@ void PwmTestSample(void) HDF_LOGE("PwmSetPolarity: failed, ret %d\n", ret); goto _ERR; } - + /*获取PWM设备参数*/ ret = PwmGetConfig(handle, &pcfg); if (ret != 0) { HDF_LOGE("PwmGetConfig: failed, ret %d\n", ret); goto _ERR; } - + /*启用PWM设备*/ ret = PwmEnable(handle); if (ret != 0) { @@ -457,7 +409,7 @@ void PwmTestSample(void) HDF_LOGE("PwmDisable: failed, ret %d\n", ret); goto _ERR; } - + _ERR: /* 销毁PWM设备句柄 */ PwmClose(handle); diff --git a/zh-cn/device-dev/driver/driver-platform-pwm-develop.md b/zh-cn/device-dev/driver/driver-platform-pwm-develop.md index 9d927033fa4f97c645c552bd7306a7542a0571f0..a08df5d68d61c27fe37615b26acdd2ee965a8335 100755 --- a/zh-cn/device-dev/driver/driver-platform-pwm-develop.md +++ b/zh-cn/device-dev/driver/driver-platform-pwm-develop.md @@ -1,21 +1,19 @@ -# PWM +# PWM -- [概述](#section1591602238164144) -- [接口说明](#section752964871810) -- [开发步骤](#section967396342164144) -- [开发实例](#section1883877829164144) -## 概述 +## 概述 PWM(Pulse Width Modulator)即脉冲宽度调节器,在HDF框架中,PWM的接口适配模式采用独立服务模式,在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。独立服务模式可以直接借助HDFDeviceManager的服务管理能力,但需要为每个设备单独配置设备节点,增加内存占用。 -**图 1** PWM独立服务模式结构图 -![](figures/独立服务模式结构图.png "PWM独立服务模式结构图") + **图1** PWM独立服务模式结构图 + ![zh-cn_image_0000001176603944](figures/zh-cn_image_0000001176603944.png) -## 接口说明 + +## 接口说明 PwmMethod定义: + ``` struct PwmMethod { int32_t (*setConfig)(struct PwmDev *pwm, struct PwmConfig *config); @@ -24,328 +22,259 @@ struct PwmMethod { }; ``` -**表 1** PwmMethod结构体成员的回调函数功能说明 - - - - - - - - - - - - - - - - - - - - - - - - -

成员函数

-

入参

-

返回值

-

功能

-

setConfig

-

pwm: 结构体指针,核心层PWM控制器;

-

config: 结构体指针,属性传入值;

-

HDF_STATUS相关状态

-

配置属性

-

open

-

pwm: 结构体指针,核心层PWM控制器;

-

HDF_STATUS相关状态

-

打开设备

-

close

-

pwm: 结构体指针,核心层PWM控制器;

-

HDF_STATUS相关状态

-

关闭设备

-
- -## 开发步骤 + **表1** PwmMethod结构体成员的回调函数功能说明 + +| 成员函数 | 入参 | 返回值 | 功能 | +| -------- | -------- | -------- | -------- | +| setConfig | **pwm**:  结构体指针,核心层PWM控制器;
**config**:  结构体指针,属性传入值; | HDF_STATUS相关状态 | 配置属性 | +| open | **pwm**:  结构体指针,核心层PWM控制器; | HDF_STATUS相关状态 | 打开设备 | +| close | **pwm**:  结构体指针,核心层PWM控制器; | HDF_STATUS相关状态 | 关闭设备 | + + +## 开发步骤 PWM模块适配HDF框架的三个环节是配置属性文件,实例化驱动入口,以及填充核心层接口函数。 -1. **实例化驱动入口:** - - 实例化HdfDriverEntry结构体成员。 - - 调用HDF\_INIT将HdfDriverEntry实例化对象注册到HDF框架中。 - -2. **配置属性文件:** - - 在device\_info.hcs文件中添加deviceNode描述。 - - 【可选】添加pwm\_config.hcs器件属性文件。 - -3. **实例化PWM控制器对象:** - - 初始化PwmDev成员。 - - 实例化PwmDev成员PwmMethod。 - - >![](../public_sys-resources/icon-note.gif) **说明:** - >实例化PwmDev成员PwmMethod,其定义和成员说明见[接口说明](#section752964871810)。 - - -4. **驱动调试:** - - 【可选】针对新增驱动程序,建议验证驱动基本功能,例如PWM控制状态,中断响应情况等。 - - -## 开发实例 - -下方将以pwm\_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。 - -1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf\_device\_desc.h 中定义)类型的全局变量,且moduleName要和device\_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。 - - 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 - - PWM驱动入口参考 - - ``` - struct HdfDriverEntry g_hdfPwm = { - .moduleVersion = 1, - .moduleName = "HDF_PLATFORM_PWM",//【必要 且与 HCS文件中里面的moduleName匹配】 - .Bind = HdfPwmBind, - .Init = HdfPwmInit, - .Release = HdfPwmRelease, - }; - //调用HDF_INIT将驱动入口注册到HDF框架中 - HDF_INIT(g_hdfPwm); - ``` - -2. 完成驱动入口注册之后,下一步请在device\_info.hcs文件中添加deviceNode信息,并在 pwm\_config.hcs 中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值与核心层PwmDev成员的默认值或限制范围有密切关系。 如有更多个器件信息,则需要在device\_info文件增加deviceNode信息,以及在pwm\_config文件中增加对应的器件属性**。** - - device\_info.hcs 配置参考。 - - ``` - root { - device_info { - platform :: host { - hostName = "platform_host"; - priority = 50; - device_pwm :: device {//为每一个 pwm 控制器配置一个HDF设备节点,存在多个时【必须】添加,否则不用 - device0 :: deviceNode { - policy = 1; // 等于1,向内核态发布服务 - priority = 80; // 驱动启动优先级 - permission = 0644;// 驱动创建设备节点权限 - moduleName = "HDF_PLATFORM_PWM"; //【必要】用于指定驱动名称,需要与期望的驱动Entry中的moduleName一致; - serviceName = "HDF_PLATFORM_PWM_0";//【必要且唯一】驱动对外发布服务的名称 - deviceMatchAttr = "hisilicon_hi35xx_pwm_0";//【必要】用于配置控制器私有数据,要与 pwm_config.hcs 中对应 - // 控制器保持一致,具体的控制器信息在 pwm_config.hcs 中 - } - device1 :: deviceNode { - policy = 1; - priority = 80; - permission = 0644; - moduleName = "HDF_PLATFORM_PWM"; - serviceName = "HDF_PLATFORM_PWM_1"; - deviceMatchAttr = "hisilicon_hi35xx_pwm_1"; - } +1. **实例化驱动入口:** + - 实例化HdfDriverEntry结构体成员。 + - 调用HDF_INIT将HdfDriverEntry实例化对象注册到HDF框架中。 + +2. **配置属性文件:** + - 在device_info.hcs文件中添加deviceNode描述。 + - 【可选】添加pwm_config.hcs器件属性文件。 + +3. **实例化PWM控制器对象:** + - 初始化PwmDev成员。 + - 实例化PwmDev成员PwmMethod。 + > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** + > 实例化PwmDev成员PwmMethod,其定义和成员说明见[接口说明](#接口说明)。 + +4. **驱动调试:** + 【可选】针对新增驱动程序,建议验证驱动基本功能,例如PWM控制状态,中断响应情况等。 + + +## 开发实例 + +下方将以pwm_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。 + +1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf_device_desc.h 中定义)类型的全局变量,且moduleName要和device_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。 + + 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 + + PWM驱动入口参考 + + ``` + struct HdfDriverEntry g_hdfPwm = { + .moduleVersion = 1, + .moduleName = "HDF_PLATFORM_PWM",//【必要 且与 HCS文件中里面的moduleName匹配】 + .Bind = HdfPwmBind, + .Init = HdfPwmInit, + .Release = HdfPwmRelease, + }; + //调用HDF_INIT将驱动入口注册到HDF框架中 + HDF_INIT(g_hdfPwm); + ``` + +2. 完成驱动入口注册之后,下一步请在device_info.hcs文件中添加deviceNode信息,并在 pwm_config.hcs 中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值与核心层PwmDev成员的默认值或限制范围有密切关系。 如有更多个器件信息,则需要在device_info文件增加deviceNode信息,以及在pwm_config文件中增加对应的器件属性**。** + - device_info.hcs 配置参考。 + + + ``` + root { + device_info { + platform :: host { + hostName = "platform_host"; + priority = 50; + device_pwm :: device {//为每一个 pwm 控制器配置一个HDF设备节点,存在多个时【必须】添加,否则不用 + device0 :: deviceNode { + policy = 1; // 等于1,向内核态发布服务 + priority = 80; // 驱动启动优先级 + permission = 0644;// 驱动创建设备节点权限 + moduleName = "HDF_PLATFORM_PWM"; //【必要】用于指定驱动名称,需要与期望的驱动Entry中的moduleName一致; + serviceName = "HDF_PLATFORM_PWM_0";//【必要且唯一】驱动对外发布服务的名称 + deviceMatchAttr = "hisilicon_hi35xx_pwm_0";//【必要】用于配置控制器私有数据,要与 pwm_config.hcs 中对应 + // 控制器保持一致,具体的控制器信息在 pwm_config.hcs 中 + } + device1 :: deviceNode { + policy = 1; + priority = 80; + permission = 0644; + moduleName = "HDF_PLATFORM_PWM"; + serviceName = "HDF_PLATFORM_PWM_1"; + deviceMatchAttr = "hisilicon_hi35xx_pwm_1"; } } } } - ``` - - - pwm\_config.hcs 配置参考。 - - ``` - root { - platform { - pwm_config { - template pwm_device { //【必要】模板配置,继承该模板的节点如果使用模板中的默认值,则节点字段可以缺省 - serviceName = ""; - match_attr = ""; - num = 0; //【必要】设备号 - base = 0x12070000; //【必要】地址映射需要 - } - device_0x12070000 :: pwm_device { - match_attr = "hisilicon_hi35xx_pwm_0";//【必要】需要和device_info.hcs中的deviceMatchAttr值一致 - } - device_0x12070020 :: pwm_device { //存在多个设备时【必须】添加,否则不用 - match_attr = "hisilicon_hi35xx_pwm_1"; - num = 1; - base = 0x12070020; //【必要】地址映射需要 - } + } + ``` + - pwm_config.hcs 配置参考。 + + + ``` + root { + platform { + pwm_config { + template pwm_device { //【必要】模板配置,继承该模板的节点如果使用模板中的默认值,则节点字段可以缺省 + serviceName = ""; + match_attr = ""; + num = 0; //【必要】设备号 + base = 0x12070000; //【必要】地址映射需要 + } + device_0x12070000 :: pwm_device { + match_attr = "hisilicon_hi35xx_pwm_0";//【必要】需要和device_info.hcs中的deviceMatchAttr值一致 + } + device_0x12070020 :: pwm_device { //存在多个设备时【必须】添加,否则不用 + match_attr = "hisilicon_hi35xx_pwm_1"; + num = 1; + base = 0x12070020; //【必要】地址映射需要 } } } - ``` + } + ``` -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 PwmDev dev; //【必要】 核心层结构体 - volatile unsigned char *base; - struct HiPwmRegs *reg; // 设备属性结构体,可自定义 - bool supportPolarity; - }; - // PwmDev是核心层控制器结构体,其中的成员在Init函数中会被赋值 - struct PwmDev { - struct IDeviceIoService service; - struct HdfDeviceObject *device; - struct PwmConfig cfg; //属性结构体,相关定义见下 - struct PwmMethod *method; //钩子函数模板 - bool busy; - uint32_t num; //设备号 - OsalSpinlock lock; - void *priv; //私有数据,一般存储自定义结构体首地址,方便调用 - }; - struct PwmConfig { - uint32_t duty; // 占空时间 nanoseconds - uint32_t period; // pwm 周期 nanoseconds - uint32_t number; // pwm 连续个数 - uint8_t polarity; // Polarity - // ------------------- | -------------- - // PWM_NORMAL_POLARITY | Normal polarity - // PWM_INVERTED_POLARITY | Inverted polarity - // - uint8_t status; // 运行状态 - // ------------------ | ----------------- - // PWM_DISABLE_STATUS | Disabled - // PWM_ENABLE_STATUS | Enabled - }; - ``` - - - PwmDev成员回调函数结构体PwmMethod的实例化,其他成员在Init函数中初始化。 - - ``` - // pwm_hi35xx.c 中的示例:钩子函数的填充 - struct PwmMethod g_pwmOps = { - .setConfig = HiPwmSetConfig,//配置属性 - }; - ``` - - - Init函数参考 - - 入参: - - HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 - - 返回值: - - HDF\_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf\_base.h中HDF\_STATUS 定义)。 - - - - - - - - - - - - - - - - - - - - - - - - - -

状态(值)

-

问题描述

-

HDF_ERR_INVALID_OBJECT

-

控制器对象非法

-

HDF_ERR_MALLOC_FAIL

-

内存分配失败

-

HDF_ERR_INVALID_PARAM

-

参数非法

-

HDF_ERR_IO

-

I/O 错误

-

HDF_SUCCESS

-

初始化成功

-

HDF_FAILURE

-

初始化失败

-
- - 函数说明: - - 初始化自定义结构体对象,初始化PwmDev成员,调用核心层PwmDeviceAdd函数。 - - ``` - //此处bind函数为空函数,可与init函数结合,也可根据厂商需要实现相关操作 - static int32_t HdfPwmBind(struct HdfDeviceObject *obj) - { - (void)obj; - return HDF_SUCCESS; - } - - static int32_t HdfPwmInit(struct HdfDeviceObject *obj) - { - int ret; - struct HiPwm *hp = NULL; - ... - hp = (struct HiPwm *)OsalMemCalloc(sizeof(*hp)); - ... - ret = HiPwmProbe(hp, obj); //【必要】实现见下 - ... - return ret; - } - - static int32_t HiPwmProbe(struct HiPwm *hp, struct HdfDeviceObject *obj) - { - uint32_t tmp; - struct DeviceResourceIface *iface = NULL; + ``` + struct HiPwm { + struct PwmDev dev; //【必要】 核心层结构体 + volatile unsigned char *base; + struct HiPwmRegs *reg; // 设备属性结构体,可自定义 + bool supportPolarity; + }; + + // PwmDev是核心层控制器结构体,其中的成员在Init函数中会被赋值 + struct PwmDev { + struct IDeviceIoService service; + struct HdfDeviceObject *device; + struct PwmConfig cfg; //属性结构体,相关定义见下 + struct PwmMethod *method; //钩子函数模板 + bool busy; + uint32_t num; //设备号 + OsalSpinlock lock; + void *priv; //私有数据,一般存储自定义结构体首地址,方便调用 + }; + struct PwmConfig { + uint32_t duty; // 占空时间 nanoseconds + uint32_t period; // pwm 周期 nanoseconds + uint32_t number; // pwm 连续个数 + uint8_t polarity; // Polarity + // ------------------- | -------------- + // PWM_NORMAL_POLARITY | Normal polarity + // PWM_INVERTED_POLARITY | Inverted polarity + // + uint8_t status; // 运行状态 + // ------------------ | ----------------- + // PWM_DISABLE_STATUS | Disabled + // PWM_ENABLE_STATUS | Enabled + }; + ``` + + - PwmDev成员回调函数结构体PwmMethod的实例化,其他成员在Init函数中初始化。 + - iface = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);//初始化自定义结构体HiPwm - ... - - hp->reg = (struct HiPwmRegs *)hp->base; //初始化自定义结构体HiPwm - hp->supportPolarity = false; //初始化自定义结构体HiPwm - hp->dev.method = &g_pwmOps; //PwmMethod的实例化对象的挂载 - hp->dev.cfg.duty = PWM_DEFAULT_DUTY_CYCLE; //初始化PwmDev - hp->dev.cfg.period = PWM_DEFAULT_PERIOD; //初始化PwmDev - hp->dev.cfg.polarity = PWM_DEFAULT_POLARITY; //初始化PwmDev - hp->dev.cfg.status = PWM_DISABLE_STATUS; //初始化PwmDev - hp->dev.cfg.number = 0; //初始化PwmDev - hp->dev.busy = false; //初始化PwmDev - if (PwmDeviceAdd(obj, &(hp->dev)) != HDF_SUCCESS) {//【重要】调用核心层函数,初始化hp->dev 的设备和服务 - OsalIoUnmap((void *)hp->base); - return HDF_FAILURE; - } - return HDF_SUCCESS; - } - ``` + ``` + // pwm_hi35xx.c 中的示例:钩子函数的填充 + struct PwmMethod g_pwmOps = { + .setConfig = HiPwmSetConfig,//配置属性 + }; + ``` + - Init函数参考 - - Release 函数参考 + 入参: - 入参: + HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 - HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 + 返回值: - 返回值: + HDF_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf_base.h中HDF_STATUS 定义)。 - 无。 + | 状态(值) | 问题描述 | + | -------- | -------- | + | HDF_ERR_INVALID_OBJECT | 控制器对象非法 | + | HDF_ERR_MALLOC_FAIL | 内存分配失败 | + | HDF_ERR_INVALID_PARAM | 参数非法 | + | HDF_ERR_IO | I/O 错误 | + | HDF_SUCCESS | 初始化成功 | + | HDF_FAILURE | 初始化失败 | - 函数说明: + 函数说明: - 释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源。 + 初始化自定义结构体对象,初始化PwmDev成员,调用核心层PwmDeviceAdd函数。 - ``` - static void HdfPwmRelease(struct HdfDeviceObject *obj) - { - struct HiPwm *hp = NULL; - ... - hp = (struct HiPwm *)obj->service;//这里有HdfDeviceObject到HiPwm的强制转化 - ... - PwmDeviceRemove(obj, &(hp->dev));//【必要】调用核心层函数,释放PwmDev的设备和服务,这里有HiPwm到PwmDev的强制转化 - HiPwmRemove(hp); //释放HiPwm - } - ``` + + ``` + //此处bind函数为空函数,可与init函数结合,也可根据厂商需要实现相关操作 + static int32_t HdfPwmBind(struct HdfDeviceObject *obj) + { + (void)obj; + return HDF_SUCCESS; + } + + static int32_t HdfPwmInit(struct HdfDeviceObject *obj) + { + int ret; + struct HiPwm *hp = NULL; + ... + hp = (struct HiPwm *)OsalMemCalloc(sizeof(*hp)); + ... + ret = HiPwmProbe(hp, obj); //【必要】实现见下 + ... + return ret; + } + + static int32_t HiPwmProbe(struct HiPwm *hp, struct HdfDeviceObject *obj) + { + uint32_t tmp; + struct DeviceResourceIface *iface = NULL; + + iface = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);//初始化自定义结构体HiPwm + ... + + hp->reg = (struct HiPwmRegs *)hp->base; //初始化自定义结构体HiPwm + hp->supportPolarity = false; //初始化自定义结构体HiPwm + hp->dev.method = &g_pwmOps; //PwmMethod的实例化对象的挂载 + hp->dev.cfg.duty = PWM_DEFAULT_DUTY_CYCLE; //初始化PwmDev + hp->dev.cfg.period = PWM_DEFAULT_PERIOD; //初始化PwmDev + hp->dev.cfg.polarity = PWM_DEFAULT_POLARITY; //初始化PwmDev + hp->dev.cfg.status = PWM_DISABLE_STATUS; //初始化PwmDev + hp->dev.cfg.number = 0; //初始化PwmDev + hp->dev.busy = false; //初始化PwmDev + if (PwmDeviceAdd(obj, &(hp->dev)) != HDF_SUCCESS) {//【重要】调用核心层函数,初始化hp->dev 的设备和服务 + OsalIoUnmap((void *)hp->base); + return HDF_FAILURE; + } + return HDF_SUCCESS; + } + ``` + - Release 函数参考 + + 入参: + + HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 + 返回值: + 无。 + 函数说明: + + 释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源。 + + + ``` + static void HdfPwmRelease(struct HdfDeviceObject *obj) + { + struct HiPwm *hp = NULL; + ... + hp = (struct HiPwm *)obj->service;//这里有HdfDeviceObject到HiPwm的强制转化 + ... + PwmDeviceRemove(obj, &(hp->dev));//【必要】调用核心层函数,释放PwmDev的设备和服务,这里有HiPwm到PwmDev的强制转化 + HiPwmRemove(hp); //释放HiPwm + } + ``` diff --git a/zh-cn/device-dev/driver/driver-platform-rtc-des.md b/zh-cn/device-dev/driver/driver-platform-rtc-des.md index 521a9ceefe94cfbb6dfb3870867b800b68fbdcb0..faaff11de42bb4bcb149eea939a2e4b7c37bd6d6 100644 --- a/zh-cn/device-dev/driver/driver-platform-rtc-des.md +++ b/zh-cn/device-dev/driver/driver-platform-rtc-des.md @@ -1,164 +1,65 @@ -# RTC - -- [概述](#section104842041574) -- [接口说明](#section20331159102519) -- [使用指导](#section20636145604113) - - [使用流程](#section16919828134215) - - [创建RTC设备句柄](#section1131212144310) - - [销毁RTC设备句柄](#section10744117144314) - - [注册RTC定时报警回调函数](#section14839440184320) - - [操作RTC](#section161927578433) - -- [使用实例](#section1186111020456) - -## 概述 - -RTC\(real-time clock\)为操作系统中的实时时钟设备,为操作系统提供精准的实时时间和定时报警功能。当设备下电后,通过外置电池供电,RTC继续记录操作系统时间;设备上电后,RTC提供实时时钟给操作系统,确保断电后系统时间的连续性。 - -## 接口说明 - -**表 1** RTC设备API接口功能介绍 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

功能分类

-

接口名

-

描述

-

RTC句柄操作

-

RtcOpen

-

获取RTC设备驱动句柄

-

RtcClose

-

释放RTC设备驱动句柄

-

RTC时间操作接口

-

RtcReadTime

-

读RTC时间信息,包括年、月、星期、日、时、分、秒、毫秒

-

RtcWriteTime

-

写RTC时间信息,包括年、月、星期、日、时、分、秒、毫秒

-

RTC报警操作接口

-

RtcReadAlarm

-

读RTC报警时间信息

-

RtcWriteAlarm

-

写RTC报警时间信息

-

RtcRegisterAlarmCallback

-

注册报警超时回调函数

-

RtcAlarmInterruptEnable

-

使能/去使能RTC报警中断

-

RTC配置操作

-

RtcGetFreq

-

读RTC外接晶振频率

-

RtcSetFreq

-

配置RTC外接晶振频率

-

RtcReset

-

RTC复位

-

读写用户定义寄存器

-

RtcReadReg

-

读用户自定义寄存器

-

RtcWriteReg

-

写用户自定义寄存器

-
- ->![](../public_sys-resources/icon-note.gif) **说明:** ->本文涉及的所有接口,仅限内核态使用,不支持在用户态使用。 - -## 使用指导 - -### 使用流程 +# RTC + + +## 概述 + +RTC(real-time clock)为操作系统中的实时时钟设备,为操作系统提供精准的实时时间和定时报警功能。当设备下电后,通过外置电池供电,RTC继续记录操作系统时间;设备上电后,RTC提供实时时钟给操作系统,确保断电后系统时间的连续性。 + + +## 接口说明 + + **表1** RTC设备API接口功能介绍 + +| 功能分类 | 接口名 | 描述 | +| -------- | -------- | -------- | +| RTC句柄操作 | RtcOpen:获取RTC设备驱动句柄
RtcClose:释放RTC设备驱动句柄 | 获取RTC设备驱动句柄 | +| RTC时间操作接口 | RtcReadTime | 读RTC时间信息,包括年、月、星期、日、时、分、秒、毫秒 | +| RtcWriteTime | 写RTC时间信息,包括年、月、星期、日、时、分、秒、毫秒 | +| RTC报警操作接口 | RtcReadAlarm | 读RTC报警时间信息 | +| RtcWriteAlarm | 写RTC报警时间信息 | +| RtcRegisterAlarmCallback | 注册报警超时回调函数 | +| RtcAlarmInterruptEnable | 使能/去使能RTC报警中断 | +| RTC配置操作 | RtcGetFreq | 读RTC外接晶振频率 | +| RtcSetFreq | 配置RTC外接晶振频率 | +| RtcReset | RTC复位 | +| 读写用户定义寄存器 | RtcReadReg | 读用户自定义寄存器 | +| RtcWriteReg | 写用户自定义寄存器 | + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> 本文涉及的所有接口,仅限内核态使用,不支持在用户态使用。 + + +## 使用指导 + + +### 使用流程 在操作系统启动过程中,驱动管理模块根据配置文件加载RTC驱动,RTC驱动会检测RTC器件并初始化驱动。 -使用RTC设备的一般流程如[图1](#fig1610020107333)所示。 +使用RTC设备的一般流程如下图所示。 -**图 1** RTC设备使用流程图 -![](figures/RTC设备使用流程图.png "RTC设备使用流程图") + **图1** RTC设备使用流程图 + ![zh-cn_image_0000001160971552](figures/zh-cn_image_0000001160971552.png) -### 创建RTC设备句柄 + +### 创建RTC设备句柄 RTC驱动加载成功后,驱动开发者使用驱动框架提供的查询接口并调用RTC设备驱动接口。 ->![](../public_sys-resources/icon-note.gif) **说明:** ->当前操作系统支持一个RTC设备。 - -DevHandle RtcOpen\(void\); - -**表 2** RtcOpen参数和返回值描述 - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

void

-

NA

-

返回值

-

返回值描述

-

handle

-

操作成功返回 指针类型

-

NULL

-

操作失败

-
+> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> 当前操作系统支持一个RTC设备。 + +DevHandle RtcOpen(void); + + **表2** RtcOpen参数和返回值描述 + +| **参数** | **参数描述** | +| -------- | -------- | +| void | NA | +| **返回值** | **返回值描述** | +| handle | 操作成功返回  指针类型 | +| NULL | 操作失败 | + ``` DevHandle handle = NULL; @@ -170,82 +71,44 @@ if (handle == NULL) { } ``` -### 销毁RTC设备句柄 + +### 销毁RTC设备句柄 销毁RTC设备句柄,系统释放对应的资源。 -void RtcClose\(DevHandle handle\); +void RtcClose(DevHandle handle); -**表 3** RtcClose参数描述 + **表3** RtcClose参数描述 + +| **参数** | **参数描述** | +| -------- | -------- | +| handle | RTC设备句柄 | - - - - - - - - -

参数

-

参数描述

-

handle

-

RTC设备句柄

-
``` /* 销毁RTC句柄 */ RtcClose(handle); ``` -### 注册RTC定时报警回调函数 + +### 注册RTC定时报警回调函数 系统启动后需要注册RTC定时报警回调函数,报警超时后触发回调函数。 -int32\_t RtcRegisterAlarmCallback\(DevHandle handle, enum RtcAlarmIndex alarmIndex, RtcAlarmCallback cb\); - -**表 4** RtcRegisterAlarmCallback参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

RTC设备句柄

-

alarmIndex

-

报警索引

-

cb

-

定时报警回调函数

-

返回值

-

返回值描述

-

0

-

操作成功

-

负数

-

操作失败

-
- -注册RTC\_ALARM\_INDEX\_A的定时报警处理函数, 示例如下: +int32_t RtcRegisterAlarmCallback(DevHandle handle, enum RtcAlarmIndex alarmIndex, RtcAlarmCallback cb); + + **表4** RtcRegisterAlarmCallback参数和返回值描述 + +| **参数** | **参数描述** | +| -------- | -------- | +| handle | RTC设备句柄 | +| alarmIndex | 报警索引 | +| cb | 定时报警回调函数 | +| **返回值** | **返回值描述** | +| 0 | 操作成功 | +| 负数 | 操作失败 | + + 注册RTC_ALARM_INDEX_A的定时报警处理函数, 示例如下: ``` /* 用户注册RTC定时报警回调函数的方法 */ @@ -268,49 +131,25 @@ if (ret != 0) { } ``` -### 操作RTC -- 读取RTC时间。 +### 操作RTC + +- 读取RTC时间。 系统从RTC读取时间信息,包括年、月、星期、日、时、分、秒、毫秒,则可以通过以下函数完成: -int32\_t RtcReadTime\(DevHandle handle, struct RtcTime \*time\); - -**表 5** RtcReadTime参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

RTC设备句柄

-

time

-

RTC读取时间信息,包括年、月、星期、日、时、分、秒、毫秒

-

返回值

-

返回值描述

-

0

-

操作成功

-

负数

-

操作失败

-
+int32_t RtcReadTime(DevHandle handle, struct RtcTime \*time); + + **表5** RtcReadTime参数和返回值描述 + +| **参数** | **参数描述** | +| -------- | -------- | +| handle | RTC设备句柄 | +| time | RTC读取时间信息,包括年、月、星期、日、时、分、秒、毫秒 | +| **返回值** | **返回值描述** | +| 0 | 操作成功 | +| 负数 | 操作失败 | + ``` int32_t ret; @@ -323,50 +162,25 @@ if (ret != 0) { } ``` -- 设置RTC时间 +- 设置RTC时间 设置RTC时间,则可以通过以下函数完成: -int32\_t RtcWriteTime\(DevHandle handle, struct RtcTime \*time\); - -**表 6** RtcWriteTime参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

RTC设备句柄

-

time

-

写RTC时间信息,包括年、月、星期、日、时、分、秒、毫秒

-

返回值

-

返回值描述

-

0

-

操作成功

-

负数

-

操作失败

-
- ->![](../public_sys-resources/icon-note.gif) **说明:** ->RTC起始时间为UTC 1970/01/01 Thursday 00:00:00,年的最大取值按照用户器件手册要求计算配置,星期不用配置。 +int32_t RtcWriteTime(DevHandle handle, struct RtcTime \*time); + + **表6** RtcWriteTime参数和返回值描述 + +| **参数** | **参数描述** | +| -------- | -------- | +| handle | RTC设备句柄 | +| time | 写RTC时间信息,包括年、月、星期、日、时、分、秒、毫秒 | +| **返回值** | **返回值描述** | +| 0 | 操作成功 | +| 负数 | 操作失败 | + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> RTC起始时间为UTC 1970/01/01 Thursday 00:00:00,年的最大取值按照用户器件手册要求计算配置,星期不用配置。 + ``` int32_t ret; @@ -387,52 +201,23 @@ if (ret != 0) { } ``` -- 读取RTC报警时间 +- 读取RTC报警时间 如果需要读取定时报警时间,则可以通过以下函数完成: -int32\_t RtcReadAlarm\(DevHandle handle, enum RtcAlarmIndex alarmIndex, struct RtcTime \*time\); - -**表 7** RtcReadAlarm参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

RTC设备句柄

-

alarmIndex

-

报警索引

-

time

-

RTC报警时间信息,包括年、月、星期、日、时、分、秒、毫秒

-

返回值

-

返回值描述

-

0

-

操作成功

-

负数

-

操作失败

-
+int32_t RtcReadAlarm(DevHandle handle, enum RtcAlarmIndex alarmIndex, struct RtcTime \*time); + + **表7** RtcReadAlarm参数和返回值描述 + +| **参数** | **参数描述** | +| -------- | -------- | +| handle | RTC设备句柄 | +| alarmIndex | 报警索引 | +| time | RTC报警时间信息,包括年、月、星期、日、时、分、秒、毫秒 | +| **返回值** | **返回值描述** | +| 0 | 操作成功 | +| 负数 | 操作失败 | + ``` int32_t ret; @@ -445,55 +230,26 @@ if (ret != 0) { } ``` -- 设置RTC报警时间 +- 设置RTC报警时间 根据报警索引设置RTC报警时间,通过以下函数完成: -int32\_t RtcWriteAlarm\(DevHandle handle, enum RtcAlarmIndex alarmIndex, struct RtcTime \*time\); - -**表 8** RtcWriteAlarm参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

RTC设备句柄

-

alarmIndex

-

报警索引

-

time

-

RTC报警时间信息,包括年、月、星期、日、时、分、秒、毫秒

-

返回值

-

返回值描述

-

0

-

操作成功

-

负数

-

操作失败

-
- ->![](../public_sys-resources/icon-note.gif) **说明:** ->RTC起始时间为UTC 1970/01/01 Thursday 00:00:00,年的最大取值按照用户器件手册要求计算配置,星期不用配置。 +int32_t RtcWriteAlarm(DevHandle handle, enum RtcAlarmIndex alarmIndex, struct RtcTime \*time); + + **表8** RtcWriteAlarm参数和返回值描述 + +| **参数** | **参数描述** | +| -------- | -------- | +| handle | RTC设备句柄 | +| alarmIndex | 报警索引 | +| time | RTC报警时间信息,包括年、月、星期、日、时、分、秒、毫秒 | +| **返回值** | **返回值描述** | +| 0 | 操作成功 | +| 负数 | 操作失败 | + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> RTC起始时间为UTC 1970/01/01 Thursday 00:00:00,年的最大取值按照用户器件手册要求计算配置,星期不用配置。 + ``` int32_t ret; @@ -514,52 +270,23 @@ if (ret != 0) { } ``` -- 设置定时报警中断使能或去使能 +- 设置定时报警中断使能或去使能 在启动报警操作前,需要先设置报警中断使能,报警超时后会触发告警回调函数,可以通过以下函数完成: -int32\_t RtcAlarmInterruptEnable\(DevHandle handle, enum RtcAlarmIndex alarmIndex, uint8\_t enable\); - -**表 9** RtcAlarmInterruptEnable参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

RTC设备句柄

-

alarmIndex

-

报警索引

-

enable

-

RTC报警中断配置,1:使能,0:去使能

-

返回值

-

返回值描述

-

0

-

操作成功

-

负数

-

操作失败

-
+int32_t RtcAlarmInterruptEnable(DevHandle handle, enum RtcAlarmIndex alarmIndex, uint8_t enable); + + **表9** RtcAlarmInterruptEnable参数和返回值描述 + +| **参数** | **参数描述** | +| -------- | -------- | +| handle | RTC设备句柄 | +| alarmIndex | 报警索引 | +| enable | RTC报警中断配置,1:使能,0:去使能 | +| **返回值** | **返回值描述** | +| 0 | 操作成功 | +| 负数 | 操作失败 | + ``` int32_t ret; @@ -571,47 +298,22 @@ if (ret != 0) { } ``` -- 读取RTC外频 +- 读取RTC外频 读取RTC外接晶体振荡频率,可以通过以下函数完成: -int32\_t RtcGetFreq\(DevHandle handle, uint32\_t \*freq\); - -**表 10** RtcGetFreq参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

RTC设备句柄

-

freq

-

RTC的外接晶体振荡频率,单位(HZ)

-

返回值

-

返回值描述

-

0

-

操作成功

-

负数

-

操作失败

-
+int32_t RtcGetFreq(DevHandle handle, uint32_t \*freq); + + **表10** RtcGetFreq参数和返回值描述 + +| **参数** | **参数描述** | +| -------- | -------- | +| handle | RTC设备句柄 | +| freq | RTC的外接晶体振荡频率,单位(HZ) | +| **返回值** | **返回值描述** | +| 0 | 操作成功 | +| 负数 | 操作失败 | + ``` int32_t ret; @@ -624,47 +326,22 @@ if (ret != 0) { } ``` -- 配置RTC外频 +- 配置RTC外频 配置RTC外接晶体振荡频率,可以通过以下函数完成: -int32\_t RtcSetFreq\(DevHandle handle, uint32\_t freq\); - -**表 11** RtcSetFreq参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

RTC设备句柄

-

freq

-

RTC的外接晶体振荡频率,单位(HZ)

-

返回值

-

返回值描述

-

0

-

操作成功

-

负数

-

操作失败

-
+int32_t RtcSetFreq(DevHandle handle, uint32_t freq); + + **表11** RtcSetFreq参数和返回值描述 + +| **参数** | **参数描述** | +| -------- | -------- | +| handle | RTC设备句柄 | +| freq | RTC的外接晶体振荡频率,单位(HZ) | +| **返回值** | **返回值描述** | +| 0 | 操作成功 | +| 负数 | 操作失败 | + ``` int32_t ret; @@ -677,42 +354,21 @@ if (ret != 0) { } ``` -- 复位RTC +- 复位RTC 复位RTC,复位RTC后各配置寄存器恢复默认值,可以通过以下函数完成: -int32\_t RtcReset\(DevHandle handle\); - -**表 12** RtcReset参数和返回值描述 - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

RTC设备句柄

-

返回值

-

返回值描述

-

0

-

操作成功

-

负数

-

操作失败

-
+int32_t RtcReset(DevHandle handle); + + **表12** RtcReset参数和返回值描述 + +| **参数** | **参数描述** | +| -------- | -------- | +| handle | RTC设备句柄 | +| **返回值** | **返回值描述** | +| 0 | 操作成功 | +| 负数 | 操作失败 | + ``` int32_t ret; @@ -724,52 +380,23 @@ if (ret != 0) { } ``` -- 读取RTC自定义寄存器配置 +- 读取RTC自定义寄存器配置 按照用户定义的寄存器索引,读取对应的寄存器配置,一个索引对应一字节的配置值,通过以下函数完成: -int32\_t RtcReadReg\(DevHandle handle, uint8\_t usrDefIndex, uint8\_t \*value\); - -**表 13** RtcReadReg参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

RTC设备句柄

-

usrDefIndex

-

用户定义的寄存器对应索引

-

value

-

寄存器值

-

返回值

-

返回值描述

-

0

-

操作成功

-

负数

-

操作失败

-
+int32_t RtcReadReg(DevHandle handle, uint8_t usrDefIndex, uint8_t \*value); + + **表13** RtcReadReg参数和返回值描述 + +| **参数** | **参数描述** | +| -------- | -------- | +| handle | RTC设备句柄 | +| usrDefIndex | 用户定义的寄存器对应索引 | +| value | 寄存器值 | +| **返回值** | **返回值描述** | +| 0 | 操作成功 | +| 负数 | 操作失败 | + ``` int32_t ret; @@ -783,52 +410,23 @@ if (ret != 0) { } ``` -- 设置RTC自定义寄存器配置 +- 设置RTC自定义寄存器配置 按照用户定义的寄存器索引,设置对应的寄存器配置,一个索引对应一字节的配置值,通过以下函数完成: -int32\_t RtcWriteReg\(DevHandle handle, uint8\_t usrDefIndex, uint8\_t value\); - -**表 14** RtcWriteReg参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

RTC设备句柄

-

usrDefIndex

-

用户定义的寄存器对应索引

-

value

-

寄存器值

-

返回值

-

返回值描述

-

0

-

操作成功

-

负数

-

操作失败

-
+int32_t RtcWriteReg(DevHandle handle, uint8_t usrDefIndex, uint8_t value); + + **表14** RtcWriteReg参数和返回值描述 + +| **参数** | **参数描述** | +| -------- | -------- | +| handle | RTC设备句柄 | +| usrDefIndex | 用户定义的寄存器对应索引 | +| value | 寄存器值 | +| **返回值** | **返回值描述** | +| 0 | 操作成功 | +| 负数 | 操作失败 | + ``` int32_t ret; @@ -842,17 +440,22 @@ if (ret != 0) { } ``` -## 使用实例 + +## 使用实例 本实例提供RTC接口的完整使用流程: -1. 系统启动,驱动管理模块会识别系统当前的RTC器件; -2. 驱动管理模块完成RTC设备的初始化和设备创建; -3. 用户通过不同API,对该RTC设备进行对应的操作; -4. 关闭RTC设备,释放设备资源。 +1. 系统启动,驱动管理模块会识别系统当前的RTC器件; + +2. 驱动管理模块完成RTC设备的初始化和设备创建; + +3. 用户通过不同API,对该RTC设备进行对应的操作; + +4. 关闭RTC设备,释放设备资源。 示例如下: + ``` #include "rtc_if.h" int32_t RtcAlarmACallback(enum RtcAlarmIndex alarmIndex) @@ -938,4 +541,3 @@ void RtcTestSample(void) RtcClose(handle); } ``` - diff --git a/zh-cn/device-dev/driver/driver-platform-rtc-develop.md b/zh-cn/device-dev/driver/driver-platform-rtc-develop.md index 8b5023bf9f92bcf28d5ae4ae84d7d6bad572c2b9..07c0df5ac1dc3b49787983d9dfcd7c17d53d937a 100755 --- a/zh-cn/device-dev/driver/driver-platform-rtc-develop.md +++ b/zh-cn/device-dev/driver/driver-platform-rtc-develop.md @@ -1,21 +1,20 @@ -# RTC +# RTC -- [概述](#section509989381142407) -- [接口说明](#section752964871810) -- [开发步骤](#section1784450860142407) -- [开发实例](#section1594883301142407) -## 概述 +## 概述 -RTC\(real-time clock\)为操作系统中的实时时钟设备,在HDF框架中,RTC的接口适配模式采用独立服务模式,在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。独立服务模式可以直接借助HDFDeviceManager的服务管理能力,但需要为每个设备单独配置设备节点,增加内存占用。 +RTC(real-time clock)为操作系统中的实时时钟设备,在HDF框架中,RTC的接口适配模式采用独立服务模式,在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。独立服务模式可以直接借助HDFDeviceManager的服务管理能力,但需要为每个设备单独配置设备节点,增加内存占用。 -**图 1** RTC独立服务模式结构图 -![](figures/独立服务模式结构图.png "RTC独立服务模式结构图") + **图1** RTC独立服务模式结构图 -## 接口说明 + ![zh-cn_image_0000001177082386](figures/zh-cn_image_0000001177082386.png) + + +## 接口说明 RtcMethod定义: + ``` struct RtcMethod { int32_t (*ReadTime)(struct RtcHost *host, struct RtcTime *time); @@ -32,430 +31,273 @@ struct RtcMethod { }; ``` -**表 1** RtcMethod结构体成员的回调函数功能说明 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

函数

-

入参

-

出参

-

返回值

-

功能

-

ReadTime

-

host: 结构体指针,核心层RTC控制器 ;

-

time: 结构体指针,传出的时间值;

-

HDF_STATUS相关状态

-

读RTC时间信息

-

WriteTime

-

host: 结构体指针,核心层RTC控制器 ;time: 结构体指针,时间传入值;

-

-

HDF_STATUS相关状态

-

写RTC时间信息(包括毫秒~年)

-

ReadAlarm

-

host: 结构体指针,核心层RTC控制器 ;alarmIndex: 枚举值,闹钟报警索引 ;

-

time: 结构体指针,传出的时间值;

-

HDF_STATUS相关状态

-

读RTC报警时间信息

-

WriteAlarm

-

host: 结构体指针,核心层RTC控制器 ;alarmIndex: 枚举值,闹钟报警索引 ;time: 结构体指针,时间传入值;

-

-

HDF_STATUS相关状态

-

写RTC报警时间信息

-

RegisterAlarmCallback

-

host: 结构体指针,核心层RTC控制器 ;alarmIndex: 枚举值,闹钟报警索引 ;cb:函数指针,回调函数;

-

-

HDF_STATUS相关状态

-

注册报警超时回调函数

-

AlarmInterruptEnable

-

host: 结构体指针,核心层RTC控制器 ;alarmIndex: 枚举值,闹钟报警索引 ;enable: 布尔值,控制报警;

-

-

HDF_STATUS相关状态

-

使能/去使能RTC报警中断

-

GetFreq

-

host: 结构体指针,核心层RTC控制器 ;

-

freq: uint32_t指针,传出的频率值;

-

HDF_STATUS相关状态

-

读RTC外接晶振频率

-

SetFreq

-

host: 结构体指针,核心层RTC控制器 ;freq: uint32_t,频率传入值;

-

-

HDF_STATUS相关状态

-

配置RTC外接晶振频率

-

Reset

-

host: 结构体指针,核心层RTC控制器 ;

-

-

HDF_STATUS相关状态

-

RTC复位

-

ReadReg

-

host: 结构体指针,核心层RTC控制器 ;usrDefIndex: 结构体,用户自定义寄存器索引;

-

value: uint8_t指针,传出的寄存器值;

-

HDF_STATUS相关状态

-

按照用户定义的寄存器索引,读取对应的寄存器配置,一个索引对应一字节的配置值

-

WriteReg

-

host: 结构体指针,核心层RTC控制器 ;usrDefIndex: 结构体,用户自定义寄存器索引;value: uint8_t,寄存器传入值;

-

-

HDF_STATUS相关状态

-

按照用户定义的寄存器索引,设置对应的寄存器配置,一个索引对应一字节的配置值

-
- -## 开发步骤 - -RTC模块适配HDF框架的三个环节是配置属性文件,实例化驱动入口,以及填充核心层接口函数。 - -1. **实例化驱动入口:** - - 实例化HdfDriverEntry结构体成员。 - - 调用HDF\_INIT将HdfDriverEntry实例化对象注册到HDF框架中。 + **表1** RtcMethod结构体成员的回调函数功能说明 -2. **配置属性文件:** - - 在device\_info.hcs文件中添加deviceNode描述。 - - 【可选】添加rtc\_config.hcs器件属性文件。 +| 函数 | 入参 | 出参 | 返回值 | 功能 | +| -------- | -------- | -------- | -------- | -------- | +| ReadTime | host: 结构体指针,核心层RTC控制器 ; | time: 结构体指针,传出的时间值; | HDF_STATUS相关状态 | 读RTC时间信息 | +| WriteTime | host: 结构体指针,核心层RTC控制器 ;time: 结构体指针,时间传入值; | 无 | HDF_STATUS相关状态 | 写RTC时间信息(包括毫秒~年) | +| ReadAlarm | host: 结构体指针,核心层RTC控制器 ;alarmIndex: 枚举值,闹钟报警索引 ; | time: 结构体指针,传出的时间值; | HDF_STATUS相关状态 | 读RTC报警时间信息 | +| WriteAlarm | host: 结构体指针,核心层RTC控制器 ;alarmIndex: 枚举值,闹钟报警索引 ;time: 结构体指针,时间传入值; | 无 | HDF_STATUS相关状态 | 写RTC报警时间信息 | +| RegisterAlarmCallback | host: 结构体指针,核心层RTC控制器 ;alarmIndex: 枚举值,闹钟报警索引 ;cb:函数指针,回调函数; | 无 | HDF_STATUS相关状态 | 注册报警超时回调函数 | +| AlarmInterruptEnable | host: 结构体指针,核心层RTC控制器 ;alarmIndex: 枚举值,闹钟报警索引 ;enable: 布尔值,控制报警; | 无 | HDF_STATUS相关状态 | 使能/去使能RTC报警中断 | +| GetFreq | host: 结构体指针,核心层RTC控制器 ; | freq: uint32_t指针,传出的频率值; | HDF_STATUS相关状态 | 读RTC外接晶振频率 | +| SetFreq | host: 结构体指针,核心层RTC控制器 ;freq: uint32_t,频率传入值; | 无 | HDF_STATUS相关状态 | 配置RTC外接晶振频率 | +| Reset | host: 结构体指针,核心层RTC控制器 ; | 无 | HDF_STATUS相关状态 | RTC复位 | +| ReadReg | host: 结构体指针,核心层RTC控制器 ;usrDefIndex: 结构体,用户自定义寄存器索引; | value: uint8_t指针,传出的寄存器值; | HDF_STATUS相关状态 | 按照用户定义的寄存器索引,读取对应的寄存器配置,一个索引对应一字节的配置值 | +| WriteReg | host: 结构体指针,核心层RTC控制器 ;usrDefIndex: 结构体,用户自定义寄存器索引;value: uint8_t,寄存器传入值; | 无 | HDF_STATUS相关状态 | 按照用户定义的寄存器索引,设置对应的寄存器配置,一个索引对应一字节的配置值 | -3. **实例化RTC控制器对象:** - - 初始化RtcHost成员。 - - 实例化RtcHost成员RtcMethod。 - >![](../public_sys-resources/icon-note.gif) **说明:** - >实例化RtcHost成员RtcMethod,其定义和成员说明见[接口说明](#section752964871810)。 +## 开发步骤 +RTC模块适配HDF框架的三个环节是配置属性文件,实例化驱动入口,以及填充核心层接口函数。 -4. **驱动调试:** - - 【可选】针对新增驱动程序,建议验证驱动基本功能,例如RTC控制状态,中断响应情况等。 +1. **实例化驱动入口:** + - 实例化HdfDriverEntry结构体成员。 + - 调用HDF_INIT将HdfDriverEntry实例化对象注册到HDF框架中。 + +2. **配置属性文件:** + - 在device_info.hcs文件中添加deviceNode描述。 + - 【可选】添加rtc_config.hcs器件属性文件。 + +3. **实例化RTC控制器对象:** + - 初始化RtcHost成员。 + - 实例化RtcHost成员RtcMethod。 + > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** + > 实例化RtcHost成员RtcMethod,其定义和成员说明见[接口说明](#接口说明)。 + +4. **驱动调试:** + 【可选】针对新增驱动程序,建议验证驱动基本功能,例如RTC控制状态,中断响应情况等。 + + +## 开发实例 + +下方将以rtc_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。 + +1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf_device_desc.h 中定义)类型的全局变量,且moduleName要和device_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。 + 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 + + RTC驱动入口参考: + + ``` + struct HdfDriverEntry g_rtcDriverEntry = { + .moduleVersion = 1, + .Bind = HiRtcBind, //见Bind参考 + .Init = HiRtcInit, //见Init参考 + .Release = HiRtcRelease, //见Release参考 + .moduleName = "HDF_PLATFORM_RTC",//【必要】且与 HCS 里面的名字匹配 + }; + //调用HDF_INIT将驱动入口注册到HDF框架中 + HDF_INIT(g_rtcDriverEntry); + ``` + +2. 完成驱动入口注册之后,下一步请在device_info.hcs文件中添加deviceNode信息,并在 rtc_config.hcs 中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值与核心层RtcHost成员的默认值或限制范围有密切关系。 + 本例只有一个RTC控制器,如有多个器件信息,则需要在device_info文件增加deviceNode信息,以及在rtc_config文件中增加对应的器件属性。 + - device_info.hcs 配置参考。 + + + ``` + root { + device_info { + platform :: host { + device_rtc :: device { + device0 :: deviceNode { + policy = 1; //2:用户态可见,1:内核态可见,0:不需要发布服务 + priority = 30; //优先级越大,值越小 + permission = 0644; //驱动创建设备节点权限 + moduleName = "HDF_PLATFORM_RTC"; //【必要】用于指定驱动名称,需要与驱动Entry中的moduleName一致 + serviceName = "HDF_PLATFORM_RTC"; //【必要】驱动对外发布服务的名称,必须唯一 + deviceMatchAttr = "hisilicon_hi35xx_rtc";//【必要】需要与设备hcs文件中的 match_attr 匹配 + } + } + } + } + } + ``` + + - rtc_config.hcs 配置参考。 + + + ``` + root { + platform { + rtc_config { + controller_0x12080000 { + match_attr = "hisilicon_hi35xx_rtc";//【必要】需要和device_info.hcs中的deviceMatchAttr值一致 + rtcSpiBaseAddr = 0x12080000; //地址映射相关 + regAddrLength = 0x100; //地址映射相关 + irq = 37; //中断号 + supportAnaCtrl = false; + supportLock = false; + anaCtrlAddr = 0xff; + lock0Addr = 0xff; + lock1Addr = 0xff; + lock2Addr = 0xff; + lock3Addr = 0xff; + } + } + } + } + ``` + +3. 完成驱动入口注册之后,最后一步就是以核心层RtcHost对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化RtcHost成员RtcMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。 + - 自定义结构体参考。 + + 从驱动的角度看,自定义结构体是参数和数据的载体,而且rtc_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员。 + + ``` + struct RtcConfigInfo { + uint32_t spiBaseAddr; //地址映射相关 + volatile void *remapBaseAddr; //地址映射相关 + uint16_t regAddrLength; //地址映射相关 + uint8_t supportAnaCtrl; //是否支持anactrl + uint8_t supportLock; //是否支持锁 + uint8_t irq; //中断号 + uint8_t alarmIndex; //闹钟索引 + uint8_t anaCtrlAddr; //anactrl地址 + struct RtcLockAddr lockAddr; //锁地址 + RtcAlarmCallback cb; //回调函数 + struct OsalMutex mutex; //互斥锁 + }; + + // RtcHost是核心层控制器结构体,其中的成员在Init函数中会被赋值 + struct RtcHost { + struct IDeviceIoService service; + struct HdfDeviceObject *device; + struct RtcMethod *method; + void *data; + }; + ``` + - RtcHost成员回调函数结构体RtcMethod的实例化,其他成员在Init函数中初始化。 -## 开发实例 + + ``` + // rtc_hi35xx.c 中的示例:钩子函数的填充 + static struct RtcMethod g_method = { + .ReadTime = HiRtcReadTime, + .WriteTime = HiRtcWriteTime, + .ReadAlarm = HiReadAlarm, + .WriteAlarm = HiWriteAlarm, + .RegisterAlarmCallback = HiRegisterAlarmCallback, + .AlarmInterruptEnable = HiAlarmInterruptEnable, + .GetFreq = HiGetFreq, + .SetFreq = HiSetFreq, + .Reset = HiReset, + .ReadReg = HiReadReg, + .WriteReg = HiWriteReg, + }; + ``` + + - Bind 函数参考 + + 入参: + + HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 + + 返回值: + + HDF_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf_base.h中HDF_STATUS 定义)。 + + **表2** Bind 函数入参及返回值对照表 + + | 状态(值) | 问题描述 | + | -------- | -------- | + | HDF_ERR_INVALID_OBJECT | 控制器对象非法 | + | HDF_ERR_MALLOC_FAIL | 内存分配失败 | + | HDF_ERR_INVALID_PARAM | 参数非法 | + | HDF_ERR_IO | I/O 错误 | + | HDF_SUCCESS | 初始化成功 | + | HDF_FAILURE | 初始化失败 | + + 函数说明: + + 关联HdfDeviceObject对象和RtcHost。 -下方将以rtc\_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。 + + ``` + static int32_t HiRtcBind(struct HdfDeviceObject *device) + { + struct RtcHost *host = NULL; + host = RtcHostCreate(device); //实际是申请内存并挂接device: host->device = device; + //使HdfDeviceObject与RtcHost可以相互转化的前提 + ... + device->service = &host->service;//使HdfDeviceObject与RtcHost可以相互转化的前提 + //方便后续通过调用RtcHostFromDevice 实现全局性质的host 使用 + return HDF_SUCCESS; + } + ``` -1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf\_device\_desc.h 中定义)类型的全局变量,且moduleName要和device\_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。 + - Init函数参考 - 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 + 入参: - RTC驱动入口参考: + HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 - ``` - struct HdfDriverEntry g_rtcDriverEntry = { - .moduleVersion = 1, - .Bind = HiRtcBind, //见Bind参考 - .Init = HiRtcInit, //见Init参考 - .Release = HiRtcRelease, //见Release参考 - .moduleName = "HDF_PLATFORM_RTC",//【必要】且与 HCS 里面的名字匹配 - }; - //调用HDF_INIT将驱动入口注册到HDF框架中 - HDF_INIT(g_rtcDriverEntry); - ``` + 返回值: -2. 完成驱动入口注册之后,下一步请在device\_info.hcs文件中添加deviceNode信息,并在 rtc\_config.hcs 中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值与核心层RtcHost成员的默认值或限制范围有密切关系。 + HDF_STATUS相关状态。 - 本例只有一个RTC控制器,如有多个器件信息,则需要在device\_info文件增加deviceNode信息,以及在rtc\_config文件中增加对应的器件属性。 + 函数说明: - - device\_info.hcs 配置参考。 + 初始化自定义结构体对象,初始化RtcHost成员。 - ``` - root { - device_info { - platform :: host { - device_rtc :: device { - device0 :: deviceNode { - policy = 1; //2:用户态可见,1:内核态可见,0:不需要发布服务 - priority = 30; //优先级越大,值越小 - permission = 0644; //驱动创建设备节点权限 - moduleName = "HDF_PLATFORM_RTC"; //【必要】用于指定驱动名称,需要与驱动Entry中的moduleName一致 - serviceName = "HDF_PLATFORM_RTC"; //【必要】驱动对外发布服务的名称,必须唯一 - deviceMatchAttr = "hisilicon_hi35xx_rtc";//【必要】需要与设备hcs文件中的 match_attr 匹配 - } - } - } - } + + ``` + static int32_t HiRtcInit(struct HdfDeviceObject *device) + { + struct RtcHost *host = NULL; + struct RtcConfigInfo *rtcInfo = NULL; + ... + host = RtcHostFromDevice(device);//这里有HdfDeviceObject到RtcHost的强制转化 + rtcInfo = OsalMemCalloc(sizeof(*rtcInfo)); + ... + //HiRtcConfigData 会从设备配置树中读取属性填充rtcInfo 的supportAnaCtrl, supportLock, spiBaseAddr, regAddrLength, irq + //为HiRtcSwInit 和HiRtcSwInit 提供参数,...函数内部处理失败后内存释放等操作 + if (HiRtcConfigData(rtcInfo, device->property) != 0) { + ... } - ``` - - - rtc\_config.hcs 配置参考。 - - ``` - root { - platform { - rtc_config { - controller_0x12080000 { - match_attr = "hisilicon_hi35xx_rtc";//【必要】需要和device_info.hcs中的deviceMatchAttr值一致 - rtcSpiBaseAddr = 0x12080000; //地址映射相关 - regAddrLength = 0x100; //地址映射相关 - irq = 37; //中断号 - supportAnaCtrl = false; - supportLock = false; - anaCtrlAddr = 0xff; - lock0Addr = 0xff; - lock1Addr = 0xff; - lock2Addr = 0xff; - lock3Addr = 0xff; - } - } - } + if (HiRtcSwInit(rtcInfo) != 0) {//地址映射以及中断注册相关 + ... } - ``` - -3. 完成驱动入口注册之后,最后一步就是以核心层RtcHost对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化RtcHost成员RtcMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。 - - 自定义结构体参考。 - - 从驱动的角度看,自定义结构体是参数和数据的载体,而且rtc\_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员。 - - ``` - struct RtcConfigInfo { - uint32_t spiBaseAddr; //地址映射相关 - volatile void *remapBaseAddr; //地址映射相关 - uint16_t regAddrLength; //地址映射相关 - uint8_t supportAnaCtrl; //是否支持anactrl - uint8_t supportLock; //是否支持锁 - uint8_t irq; //中断号 - uint8_t alarmIndex; //闹钟索引 - uint8_t anaCtrlAddr; //anactrl地址 - struct RtcLockAddr lockAddr; //锁地址 - RtcAlarmCallback cb; //回调函数 - struct OsalMutex mutex; //互斥锁 - }; - - // RtcHost是核心层控制器结构体,其中的成员在Init函数中会被赋值 - struct RtcHost { - struct IDeviceIoService service; - struct HdfDeviceObject *device; - struct RtcMethod *method; - void *data; - }; - ``` - - - RtcHost成员回调函数结构体RtcMethod的实例化,其他成员在Init函数中初始化。 - - ``` - // rtc_hi35xx.c 中的示例:钩子函数的填充 - static struct RtcMethod g_method = { - .ReadTime = HiRtcReadTime, - .WriteTime = HiRtcWriteTime, - .ReadAlarm = HiReadAlarm, - .WriteAlarm = HiWriteAlarm, - .RegisterAlarmCallback = HiRegisterAlarmCallback, - .AlarmInterruptEnable = HiAlarmInterruptEnable, - .GetFreq = HiGetFreq, - .SetFreq = HiSetFreq, - .Reset = HiReset, - .ReadReg = HiReadReg, - .WriteReg = HiWriteReg, - }; - ``` - - - Bind 函数参考 - - 入参: - - HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 - - 返回值: - - HDF\_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf\_base.h中HDF\_STATUS 定义)。 - - **表 2** Bind 函数入参及返回值对照表 - - - - - - - - - - - - - - - - - - - - - - - - - -

状态(值)

-

问题描述

-

HDF_ERR_INVALID_OBJECT

-

控制器对象非法

-

HDF_ERR_MALLOC_FAIL

-

内存分配失败

-

HDF_ERR_INVALID_PARAM

-

参数非法

-

HDF_ERR_IO

-

I/O 错误

-

HDF_SUCCESS

-

初始化成功

-

HDF_FAILURE

-

初始化失败

-
- - 函数说明: - - 关联HdfDeviceObject对象和RtcHost。 - - ``` - static int32_t HiRtcBind(struct HdfDeviceObject *device) - { - struct RtcHost *host = NULL; - host = RtcHostCreate(device); //实际是申请内存并挂接device: host->device = device; - //使HdfDeviceObject与RtcHost可以相互转化的前提 + if (HiRtcHwInit(rtcInfo) != 0) {//初始化anaCtrl 和 lockAddr 相关内容 ... - device->service = &host->service;//使HdfDeviceObject与RtcHost可以相互转化的前提 - //方便后续通过调用RtcHostFromDevice 实现全局性质的host 使用 - return HDF_SUCCESS; } - ``` + + host->method = &g_method;//RtcMethod的实例化对象的挂载 + host->data = rtcInfo; //使RtcConfigInfo与RtcHost可以相互转化的前提 + HDF_LOGI("Hdf dev service:%s init success!", HdfDeviceGetServiceName(device)); + return HDF_SUCCESS; + } + ``` + - Release 函数参考 - - Init函数参考 + 入参: - 入参**:** + HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 - HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 + 返回值: - 返回值**:** + 无。 - HDF\_STATUS相关状态。 + 函数说明: - 函数说明: + 释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源。所有强制转换获取相应对象的操作前提是在Init或Bind函数中具备对应赋值的操作。 - 初始化自定义结构体对象,初始化RtcHost成员。 - - ``` - static int32_t HiRtcInit(struct HdfDeviceObject *device) - { + + ``` + static void HiRtcRelease(struct HdfDeviceObject *device) + { struct RtcHost *host = NULL; struct RtcConfigInfo *rtcInfo = NULL; ... - host = RtcHostFromDevice(device);//这里有HdfDeviceObject到RtcHost的强制转化 - rtcInfo = OsalMemCalloc(sizeof(*rtcInfo)); - ... - //HiRtcConfigData 会从设备配置树中读取属性填充rtcInfo 的supportAnaCtrl, supportLock, spiBaseAddr, regAddrLength, irq - //为HiRtcSwInit 和HiRtcSwInit 提供参数,...函数内部处理失败后内存释放等操作 - if (HiRtcConfigData(rtcInfo, device->property) != 0) { - ... - } - if (HiRtcSwInit(rtcInfo) != 0) {//地址映射以及中断注册相关 - ... - } - if (HiRtcHwInit(rtcInfo) != 0) {//初始化anaCtrl 和 lockAddr 相关内容 - ... + host = RtcHostFromDevice(device); //这里有HdfDeviceObject到RtcHost的强制转化 + rtcInfo = (struct RtcConfigInfo *)host->data;//这里有RtcHost到RtcConfigInfo的强制转化 + if (rtcInfo != NULL) { + HiRtcSwExit(rtcInfo); + OsalMemFree(rtcInfo); //释放RtcConfigInfo + host->data = NULL; } - - host->method = &g_method;//RtcMethod的实例化对象的挂载 - host->data = rtcInfo; //使RtcConfigInfo与RtcHost可以相互转化的前提 - HDF_LOGI("Hdf dev service:%s init success!", HdfDeviceGetServiceName(device)); - return HDF_SUCCESS; - } - ``` - - - Release 函数参考 - - 入参**:** - - HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 - - 返回值**:** - - 无。 - - 函数说明: - - 释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源。所有强制转换获取相应对象的操作前提是在Init或Bind函数中具备对应赋值的操作。 - - ``` - static void HiRtcRelease(struct HdfDeviceObject *device) - { - struct RtcHost *host = NULL; - struct RtcConfigInfo *rtcInfo = NULL; - ... - host = RtcHostFromDevice(device); //这里有HdfDeviceObject到RtcHost的强制转化 - rtcInfo = (struct RtcConfigInfo *)host->data;//这里有RtcHost到RtcConfigInfo的强制转化 - if (rtcInfo != NULL) { - HiRtcSwExit(rtcInfo); - OsalMemFree(rtcInfo); //释放RtcConfigInfo - host->data = NULL; - } - RtcHostDestroy(host); //释放RtcHost - } - ``` - - - + RtcHostDestroy(host); //释放RtcHost + } + ``` diff --git a/zh-cn/device-dev/driver/driver-platform-sdio-des.md b/zh-cn/device-dev/driver/driver-platform-sdio-des.md index a3a0d13450beed13fea5e28b162d594ca2620fb9..8d29167692a7f06520fd40efeec71ddb51849d90 100644 --- a/zh-cn/device-dev/driver/driver-platform-sdio-des.md +++ b/zh-cn/device-dev/driver/driver-platform-sdio-des.md @@ -1,217 +1,78 @@ -# SDIO - -- [概述](#section1155271783811) -- [接口说明](#section12601496259) -- [使用指导](#section1878939192515) - - [使用流程](#section1490685512255) - - [打开SDIO控制器](#section10782428132616) - - [独占HOST](#section11263172312715) - - [使能SDIO设备](#section17861486271) - - [注册SDIO中断](#section521213262286) - - [进行SDIO通信](#section85661522153420) - - [释放SDIO中断](#section1683449352) - - [去使能SDIO设备](#section15379324143611) - - [释放HOST](#section536018263713) - - [关闭SDIO控制器](#section4752739183716) - -- [使用实例](#section376910122382) - -## 概述 - -- SDIO是安全数字输入输出接口(Secure Digital Input and Output)的缩写,是从SD内存卡接口的基础上演化出来的一种外设接口。SDIO接口兼容以前的SD内存卡,并且可以连接支持SDIO接口的设备。 -- SDIO的应用比较广泛,目前,有许多手机都支持SDIO功能,并且很多SDIO外设也被开发出来,使得手机外接外设更加容易。常见的SDIO外设有WLAN、GPS、CAMERA、蓝牙等。 -- SDIO总线有两端,其中一端是主机端(HOST),另一端是设备端(DEVICE)。所有的通信都是由HOST端发出命令开始的,在DEVICE端只要能解析HOST的命令,就可以同HOST进行通信了。SDIO的HOST可以连接多个DEVICE,如下图所示: - - - CLK信号:HOST给DEVICE的时钟信号。 - - VDD信号:电源信号。 - - VSS信号:Ground信号。 - - D0-3信号:4条数据线,其中,DAT1信号线复用为中断线,在1BIT模式下DAT0用来传输数据,在4BIT模式下DAT0-DAT3用来传输数据。 - - CMD信号:用于HOST发送命令和DEVICE回复响应。 - - **图 1** SDIO的HOST-DEVICE连接示意图 - ![](figures/SDIO的HOST-DEVICE连接示意图.png "SDIO的HOST-DEVICE连接示意图") - -- SDIO接口定义了操作SDIO的通用方法集合,包括打开/关闭SDIO控制器、独占/释放HOST、使能/去使能设备、申请/释放中断、读写、获取/设置公共信息等。 - -## 接口说明 - -**表 1** SDIO驱动API接口功能介绍 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

功能分类

-

接口名

-

描述

-

SDIO设备打开/关闭接口

-

SdioOpen

-

打开指定总线号的SDIO控制器

-

SdioClose

-

关闭SDIO控制器

-

SDIO读写接口

-

SdioReadBytes

-

从指定地址开始,增量读取指定长度的数据

-

SdioWriteBytes

-

从指定地址开始,增量写入指定长度的数据

-

SdioReadBytesFromFixedAddr

-

从固定地址读取指定长度的数据

-

SdioWriteBytesToFixedAddr

-

向固定地址写入指定长度的数据

-

SdioReadBytesFromFunc0

-

从SDIO function 0的指定地址空间读取指定长度的数据

-

SdioWriteBytesToFunc0

-

向SDIO function 0的指定地址空间写入指定长度的数据

-

SDIO设置块大小接口

-

SdioSetBlockSize

-

设置块的大小

-

SDIO获取/设置公共信息接口

-

SdioGetCommonInfo

-

获取公共信息

-

SdioSetCommonInfo

-

设置公共信息

-

SDIO刷新数据接口

-

SdioFlushData

-

刷新数据

-

SDIO独占/释放HOST接口

-

SdioClaimHost

-

独占Host

-

SdioReleaseHost

-

释放Host

-

SDIO使能/去使能功能设备接口

-

SdioEnableFunc

-

使能SDIO功能设备

-

SdioDisableFunc

-

去使能SDIO功能设备

-

SDIO申请/释放中断接口

-

SdioClaimIrq

-

申请中断

-

SdioReleaseIrq

-

释放中断

-
- ->![](../public_sys-resources/icon-note.gif) **说明:** ->本文涉及的所有接口,目前只支持在内核态使用,不支持在用户态使用。 - -## 使用指导 - -### 使用流程 - -使用SDIO的一般流程如[图2](#fig1969028202613)所示。 - -**图 2** SDIO使用流程图 -![](figures/SDIO使用流程图.png "SDIO使用流程图") - -### 打开SDIO控制器 +# SDIO + + +## 概述 + +- SDIO是安全数字输入输出接口(Secure Digital Input and Output)的缩写,是从SD内存卡接口的基础上演化出来的一种外设接口。SDIO接口兼容以前的SD内存卡,并且可以连接支持SDIO接口的设备。 + +- SDIO的应用比较广泛,目前,有许多手机都支持SDIO功能,并且很多SDIO外设也被开发出来,使得手机外接外设更加容易。常见的SDIO外设有WLAN、GPS、CAMERA、蓝牙等。 + +- SDIO总线有两端,其中一端是主机端(HOST),另一端是设备端(DEVICE)。所有的通信都是由HOST端发出命令开始的,在DEVICE端只要能解析HOST的命令,就可以同HOST进行通信了。SDIO的HOST可以连接多个DEVICE,如下图所示: + - CLK信号:HOST给DEVICE的时钟信号。 + - VDD信号:电源信号。 + - VSS信号:Ground信号。 + - D0-3信号:4条数据线,其中,DAT1信号线复用为中断线,在1BIT模式下DAT0用来传输数据,在4BIT模式下DAT0-DAT3用来传输数据。 + - CMD信号:用于HOST发送命令和DEVICE回复响应。 + + **图1** SDIO的HOST-DEVICE连接示意图 + + ![zh-cn_image_0000001206092987](figures/zh-cn_image_0000001206092987.png) + +- SDIO接口定义了操作SDIO的通用方法集合,包括打开/关闭SDIO控制器、独占/释放HOST、使能/去使能设备、申请/释放中断、读写、获取/设置公共信息等。 + + +## 接口说明 + + **表1** SDIO驱动API接口功能介绍 + +| 功能分类 | 接口描述 | +| -------- | -------- | +| SDIO设备打开/关闭接口 | - SdioOpen:打开指定总线号的SDIO控制器
- SdioClose:关闭SDIO控制器 | +| SDIO读写接口 | - SdioReadBytes:从指定地址开始,增量读取指定长度的数据
- SdioWriteBytes:从指定地址开始,增量写入指定长度的数据
- SdioReadBytesFromFixedAddr:从固定地址读取指定长度的数据
- SdioWriteBytesToFixedAddr:向固定地址写入指定长度的数据
- SdioReadBytesFromFunc0:从SDIO function 0的指定地址空间读取指定长度的数据
- SdioWriteBytesToFunc0:向SDIO function 0的指定地址空间写入指定长度的数据 | +| SDIO设置块大小接口 | SdioSetBlockSize:设置块的大小 | +| SDIO获取/设置公共信息接口 | - SdioGetCommonInfo:获取公共信息
- SdioSetCommonInfo:设置公共信息 | +| SDIO刷新数据接口 | SdioFlushData:刷新数据 | +| SDIO独占/释放HOST接口 | - SdioClaimHost:独占Host
- SdioReleaseHost:释放Host | +| SDIO使能/去使能功能设备接口 | - SdioEnableFunc:使能SDIO功能设备
- SdioDisableFunc:去使能SDIO功能设备 | +| SDIO申请/释放中断接口 | - SdioClaimIrq:申请中断
- SdioReleaseIrq:释放中断 | + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> 本文涉及的所有接口,目前只支持在内核态使用,不支持在用户态使用。 + + +## 使用指导 + + +### 使用流程 + +使用SDIO的一般流程如下图所示。 + + **图2** SDIO使用流程图 + + ![zh-cn_image_0000001206171539](figures/zh-cn_image_0000001206171539.png) + + +### 打开SDIO控制器 在使用SDIO进行通信前,首先要调用SdioOpen获取SDIO控制器的设备句柄,该函数会返回指定总线号的SDIO控制器的设备句柄。 -DevHandle SdioOpen\(int16\_t mmcBusNum, struct SdioFunctionConfig \*config\); - -**表 2** SdioOpen函数的参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

mmcBusNum

-

总线号

-

config

-

SDIO功能配置信息

-

返回值

-

返回值描述

-

NULL

-

获取SDIO控制器的设备句柄失败

-

设备句柄

-

SDIO控制器的设备句柄

-
- -打开SDIO控制器的示例如下: + +``` +DevHandle SdioOpen(int16_t mmcBusNum, struct SdioFunctionConfig *config); +``` + + **表2** SdioOpen函数的参数和返回值描述 +| 参数 | 参数描述 | +| -------- | -------- | +| mmcBusNum | 总线号 | +| config | SDIO功能配置信息 | +| **返回值** | **返回值描述** | +| NULL | 获取SDIO控制器的设备句柄失败 | +| 设备句柄 | SDIO控制器的设备句柄 | + + 打开SDIO控制器的示例如下: + ``` DevHandle handle = NULL; struct SdioFunctionConfig config; @@ -225,75 +86,51 @@ if (handle == NULL) { } ``` -### 独占HOST + +### 独占HOST 获取到SDIO控制器的设备句柄之后,需要先独占HOST才能进行SDIO后续的一系列操作,独占HOST函数如下所示: -void SdioClaimHost\(DevHandle handle\); - -**表 3** SdioClaimHost函数的参数描述 - - - - - - - - - - -

参数

-

参数描述

-

handle

-

SDIO控制器的设备句柄

-
+ +``` +void SdioClaimHost(DevHandle handle); +``` + + **表3** SdioClaimHost函数的参数描述 + +| 参数 | 参数描述 | +| -------- | -------- | +| handle | SDIO控制器的设备句柄 | 独占HOST示例如下: + ``` SdioClaimHost(handle); /* 独占HOST */ ``` -### 使能SDIO设备 + +### 使能SDIO设备 在访问寄存器之前,需要先使能SDIO设备,使能SDIO设备的函数如下所示: -int32\_t SdioEnableFunc\(DevHandle handle\); - -**表 4** SdioEnableFunc函数的参数和返回值描述 - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

SDIO控制器的设备句柄

-

返回值

-

返回值描述

-

0

-

SDIO使能成功

-

负数

-

SDIO使能失败

-
+ +``` +int32_t SdioEnableFunc(DevHandle handle); +``` + + **表4** SdioEnableFunc函数的参数和返回值描述 + +| 参数 | 参数描述 | +| -------- | -------- | +| handle | SDIO控制器的设备句柄 | +| **返回值** | **返回值描述** | +| 0 | SDIO使能成功 | +| 负数 | SDIO使能失败 | 使能SDIO设备的示例如下: + ``` int32_t ret; /* 使能SDIO设备 */ @@ -303,51 +140,28 @@ if (ret != 0) { } ``` -### 注册SDIO中断 + +### 注册SDIO中断 在通信之前,还需要注册SDIO中断,注册SDIO中断函数如下图所示: -int32\_t SdioClaimIrq\(DevHandle handle, SdioIrqHandler \*handler\); - -**表 5** SdioClaimIrq函数的参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

SDIO控制器的设备句柄

-

handler

-

中断服务函数指针

-

返回值

-

返回值描述

-

0

-

注册中断成功

-

负数

-

注册中断失败

-
- -注册SDIO中的示例如下: + +``` +int32_t SdioClaimIrq(DevHandle handle, SdioIrqHandler *handler); +``` + **表5** SdioClaimIrq函数的参数和返回值描述 + +| 参数 | 参数描述 | +| -------- | -------- | +| handle | SDIO控制器的设备句柄 | +| handler | 中断服务函数指针 | +| **返回值** | **返回值描述** | +| 0 | 注册中断成功 | +| 负数 | 注册中断失败 | + + 注册SDIO中的示例如下: + ``` /* 中断服务函数需要根据各自平台的情况去实现 */ static void SdioIrqFunc(void *data) @@ -367,453 +181,236 @@ if (ret != 0) { } ``` -### 进行SDIO通信 - -- 向SDIO设备增量写入指定长度的数据 - -对应的接口函数如下所示: - -int32\_t SdioWriteBytes\(DevHandle handle, uint8\_t \*data, uint32\_t addr, uint32\_t size\); - -**表 6** SdioWriteBytes函数的参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

SDIO控制器的设备句柄

-

data

-

待写入数据的指针

-

addr

-

待写入数据的起始地址

-

size

-

待写入数据的长度

-

返回值

-

返回值描述

-

0

-

SDIO写数据成功

-

负数

-

SDIO写数据失败

-
- -向SDIO设备增量写入指定长度的数据的示例如下: -``` -int32_t ret; -uint8_t wbuff[] = {1,2,3,4,5}; -uint32_t addr = 0x100 + 0x09; -/* 向SDIO设备起始地址0x109,增量写入5个字节的数据 */ -ret = SdioWriteBytes(handle, wbuff, addr, sizeof(wbuff) / sizeof(wbuff[0])); -if (ret != 0) { - HDF_LOGE("SdioWriteBytes: failed, ret %d\n", ret); -} -``` - -- 从SDIO设备增量读取指定长度的数据 - -对应的接口函数如下所示: - -int32\_t SdioReadBytes\(DevHandle handle, uint8\_t \*data, uint32\_t addr, uint32\_t size\); - -**表 7** SdioReadBytes函数的参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

SDIO控制器的设备句柄

-

data

-

接收读取数据的指针

-

addr

-

待读取数据的起始地址

-

size

-

待读取数据的长度

-

返回值

-

返回值描述

-

0

-

SDIO读数据成功

-

负数

-

SDIO读数据失败

-
- -从SDIO设备增量读取指定长度的数据的示例如下: +### 进行SDIO通信 + +- 向SDIO设备增量写入指定长度的数据 + + 对应的接口函数如下所示: + + + ``` + int32_t SdioWriteBytes(DevHandle handle, uint8_t *data, uint32_t addr, uint32_t size); + ``` + + **表6** SdioWriteBytes函数的参数和返回值描述 + + | 参数 | 参数描述 | + | -------- | -------- | + | handle | SDIO控制器的设备句柄 | + | data | 待写入数据的指针 | + | addr | 待写入数据的起始地址 | + | size | 待写入数据的长度 | + | **返回值** | **返回值描述** | + | 0 | SDIO写数据成功 | + | 负数 | SDIO写数据失败 | + + 向SDIO设备增量写入指定长度的数据的示例如下: + + + ``` + int32_t ret; + uint8_t wbuff[] = {1,2,3,4,5}; + uint32_t addr = 0x100 + 0x09; + /* 向SDIO设备起始地址0x109,增量写入5个字节的数据 */ + ret = SdioWriteBytes(handle, wbuff, addr, sizeof(wbuff) / sizeof(wbuff[0])); + if (ret != 0) { + HDF_LOGE("SdioWriteBytes: failed, ret %d\n", ret); + } + ``` + +- 从SDIO设备增量读取指定长度的数据 + + 对应的接口函数如下所示: + + + ``` + int32_t SdioReadBytes(DevHandle handle, uint8_t *data, uint32_t addr, uint32_t size); + ``` + + **表7** SdioReadBytes函数的参数和返回值描述 + + | 参数 | 参数描述 | + | -------- | -------- | + | handle | SDIO控制器的设备句柄 | + | data | 接收读取数据的指针 | + | addr | 待读取数据的起始地址 | + | size | 待读取数据的长度 | + | **返回值** | **返回值描述** | + | 0 | SDIO读数据成功 | + | 负数 | SDIO读数据失败 | + + 从SDIO设备增量读取指定长度的数据的示例如下: + + + ``` + int32_t ret; + uint8_t rbuff[5] = {0}; + uint32_t addr = 0x100 + 0x09; + /* 从SDIO设备起始地址0x109,增量读取5个字节的数据 */ + ret = SdioReadBytes(handle, rbuff, addr, 5); + if (ret != 0) { + HDF_LOGE("SdioReadBytes: failed, ret %d\n", ret); + } + ``` + +- 向SDIO设备的固定地址写入指定长度的数据 + 对应的接口函数如下所示: -``` -int32_t ret; -uint8_t rbuff[5] = {0}; -uint32_t addr = 0x100 + 0x09; -/* 从SDIO设备起始地址0x109,增量读取5个字节的数据 */ -ret = SdioReadBytes(handle, rbuff, addr, 5); -if (ret != 0) { - HDF_LOGE("SdioReadBytes: failed, ret %d\n", ret); -} -``` + + ``` + int32_t SdioWriteBytesToFixedAddr(DevHandle handle, uint8_t *data, uint32_t addr, uint32_t size, uint32_t scatterLen); + ``` + + **表8** SdioWriteBytesToFixedAddr函数的参数和返回值描述 + + | 参数 | 参数描述 | + | -------- | -------- | + | handle | SDIO控制器的设备句柄 | + | data | 待写入数据的指针 | + | addr | 待写入数据的固定地址 | + | size | 待写入数据的长度 | + | scatterLen | 集散表的长度。如果该字段不为0,则data为集散表类型。 | + | **返回值** | **返回值描述** | + | 0 | SDIO写数据成功 | + | 负数 | SDIO写数据失败 | + + 向SDIO设备的固定地址写入指定长度的数据的示例如下: -- 向SDIO设备的固定地址写入指定长度的数据 - - 对应的接口函数如下所示: - - int32\_t SdioWriteBytesToFixedAddr\(DevHandle handle, uint8\_t \*data, uint32\_t addr, uint32\_t size, uint32\_t scatterLen\); - - **表 8** SdioWriteBytesToFixedAddr函数的参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

SDIO控制器的设备句柄

-

data

-

待写入数据的指针

-

addr

-

待写入数据的固定地址

-

size

-

待写入数据的长度

-

scatterLen

-

集散表的长度。如果该字段不为0,则data为集散表类型。

-

返回值

-

返回值描述

-

0

-

SDIO写数据成功

-

负数

-

SDIO写数据失败

-
- - 向SDIO设备的固定地址写入指定长度的数据的示例如下: - - ``` - int32_t ret; - uint8_t wbuff[] = {1,2,3,4,5}; - uint32_t addr = 0x100 + 0x09; - /* 向SDIO设备固定地址0x109写入5个字节的数据 */ - ret = SdioWriteBytesToFixedAddr(handle, wbuff, addr, sizeof(wbuff) / sizeof(wbuff[0]), 0); - if (ret != 0) { - HDF_LOGE("SdioWriteBytesToFixedAddr: failed, ret %d\n", ret); - } - ``` - -- 从SDIO设备的固定地址读取指定长度的数据 - - 对应的接口函数如下所示: - - int32\_t SdioReadBytesFromFixedAddr\(DevHandle handle, uint8\_t \*data, uint32\_t addr, uint32\_t size, uint32\_t scatterLen\); - - **表 9** SdioReadBytesFromFixedAddr函数的参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

SDIO控制器的设备句柄

-

data

-

接收读取数据的指针

-

addr

-

待读取数据的起始地址

-

size

-

待读取数据的长度

-

scatterLen

-

集散表的长度。如果该字段不为0,则data为集散表类型。

-

返回值

-

返回值描述

-

0

-

SDIO读数据成功

-

负数

-

SDIO读数据失败

-
- - 从SDIO设备的固定地址读取指定长度的数据的示例如下: - - ``` - int32_t ret; - uint8_t rbuff[5] = {0}; - uint32_t addr = 0x100 + 0x09; - /* 从SDIO设备固定地址0x109中读取5个字节的数据 */ - ret = SdioReadBytesFromFixedAddr(handle, rbuff, addr, 5, 0); - if (ret != 0) { - HDF_LOGE("SdioReadBytesFromFixedAddr: failed, ret %d\n", ret); - } - ``` - - -- 向SDIO function 0的指定地址空间写入指定长度的数据 - -当前只支持写入一个字节的数据,对应的接口函数如下所示: - -int32\_t SdioWriteBytesToFunc0\(DevHandle handle, uint8\_t \*data, uint32\_t addr, uint32\_t size\); - -**表 10** SdioWriteBytesToFunc0函数的参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

SDIO控制器的设备句柄

-

data

-

待写入数据的指针

-

addr

-

待写入数据的起始地址

-

size

-

待写入数据的长度

-

返回值

-

返回值描述

-

0

-

SDIO写数据成功

-

负数

-

SDIO写数据失败

-
- -向SDIO function 0的指定地址空间写入指定长度的数据的示例如下: + + ``` + int32_t ret; + uint8_t wbuff[] = {1,2,3,4,5}; + uint32_t addr = 0x100 + 0x09; + /* 向SDIO设备固定地址0x109写入5个字节的数据 */ + ret = SdioWriteBytesToFixedAddr(handle, wbuff, addr, sizeof(wbuff) / sizeof(wbuff[0]), 0); + if (ret != 0) { + HDF_LOGE("SdioWriteBytesToFixedAddr: failed, ret %d\n", ret); + } + ``` + +- 从SDIO设备的固定地址读取指定长度的数据 + 对应的接口函数如下所示: -``` -int32_t ret; -uint8_t wbuff = 1; -/* 向SDIO function 0地址0x2中写入1字节的数据 */ -ret = SdioWriteBytesToFunc0(handle, &wbuff, 0x2, 1); -if (ret != 0) { - HDF_LOGE("SdioWriteBytesToFunc0: failed, ret %d\n", ret); -} -``` + + ``` + int32_t SdioReadBytesFromFixedAddr(DevHandle handle, uint8_t *data, uint32_t addr, uint32_t size, uint32_t scatterLen); + ``` + + **表9** SdioReadBytesFromFixedAddr函数的参数和返回值描述 + + | 参数 | 参数描述 | + | -------- | -------- | + | handle | SDIO控制器的设备句柄 | + | data | 接收读取数据的指针 | + | addr | 待读取数据的起始地址 | + | size | 待读取数据的长度 | + | scatterLen | 集散表的长度。如果该字段不为0,则data为集散表类型。 | + | **返回值** | **返回值描述** | + | 0 | SDIO读数据成功 | + | 负数 | SDIO读数据失败 | + + 从SDIO设备的固定地址读取指定长度的数据的示例如下: -- 从SDIO function 0的指定地址空间读取指定长度的数据 - -当前只支持读取一个字节的数据,对应的接口函数如下所示: - -int32\_t SdioReadBytesFromFunc0\(DevHandle handle, uint8\_t \*data, uint32\_t addr, uint32\_t size\); - -**表 11** SdioReadBytesFromFunc0函数的参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

SDIO控制器的设备句柄

-

data

-

接收读取数据的指针

-

addr

-

待读取数据的起始地址

-

size

-

待读取数据的长度

-

返回值

-

返回值描述

-

0

-

SDIO读数据成功

-

负数

-

SDIO读数据失败

-
- -从SDIO function 0的指定地址空间读取指定长度的数据的示例如下: + + ``` + int32_t ret; + uint8_t rbuff[5] = {0}; + uint32_t addr = 0x100 + 0x09; + /* 从SDIO设备固定地址0x109中读取5个字节的数据 */ + ret = SdioReadBytesFromFixedAddr(handle, rbuff, addr, 5, 0); + if (ret != 0) { + HDF_LOGE("SdioReadBytesFromFixedAddr: failed, ret %d\n", ret); + } + ``` + +- 向SDIO function 0的指定地址空间写入指定长度的数据 + + 当前只支持写入一个字节的数据,对应的接口函数如下所示: + + + ``` + int32_t SdioWriteBytesToFunc0(DevHandle handle, uint8_t *data, uint32_t addr, uint32_t size); + ``` + + **表10** SdioWriteBytesToFunc0函数的参数和返回值描述 + + | 参数 | 参数描述 | + | -------- | -------- | + | handle | SDIO控制器的设备句柄 | + | data | 待写入数据的指针 | + | addr | 待写入数据的起始地址 | + | size | 待写入数据的长度 | + | **返回值** | **返回值描述** | + | 0 | SDIO写数据成功 | + | 负数 | SDIO写数据失败 | + + 向SDIO function 0的指定地址空间写入指定长度的数据的示例如下: + + + ``` + int32_t ret; + uint8_t wbuff = 1; + /* 向SDIO function 0地址0x2中写入1字节的数据 */ + ret = SdioWriteBytesToFunc0(handle, &wbuff, 0x2, 1); + if (ret != 0) { + HDF_LOGE("SdioWriteBytesToFunc0: failed, ret %d\n", ret); + } + ``` + +- 从SDIO function 0的指定地址空间读取指定长度的数据 + + 当前只支持读取一个字节的数据,对应的接口函数如下所示: + + + ``` + int32_t SdioReadBytesFromFunc0(DevHandle handle, uint8_t *data, uint32_t addr, uint32_t size); + ``` + + **表11** SdioReadBytesFromFunc0函数的参数和返回值描述 + + | 参数 | 参数描述 | + | -------- | -------- | + | handle | SDIO控制器的设备句柄 | + | data | 接收读取数据的指针 | + | addr | 待读取数据的起始地址 | + | size | 待读取数据的长度 | + | **返回值** | **返回值描述** | + | 0 | SDIO读数据成功 | + | 负数 | SDIO读数据失败 | + + 从SDIO function 0的指定地址空间读取指定长度的数据的示例如下: + + + ``` + int32_t ret; + uint8_t rbuff; + /* 从SDIO function 0设备地址0x2中读取1字节的数据 */ + ret = SdioReadBytesFromFunc0(handle, &rbuff, 0x2, 1); + if (ret != 0) { + HDF_LOGE("SdioReadBytesFromFunc0: failed, ret %d\n", ret); + } + ``` + + +### 释放SDIO中断 -``` -int32_t ret; -uint8_t rbuff; -/* 从SDIO function 0设备地址0x2中读取1字节的数据 */ -ret = SdioReadBytesFromFunc0(handle, &rbuff, 0x2, 1); -if (ret != 0) { - HDF_LOGE("SdioReadBytesFromFunc0: failed, ret %d\n", ret); -} -``` +通信完成之后,需要释放SDIO中断,函数如下所示: -### 释放SDIO中断 +int32_t SdioReleaseIrq(DevHandle handle); -通信完成之后,需要释放SDIO中断,函数如下所示: + **表12** SdioReleaseIrq函数的参数和返回值描述 -int32\_t SdioReleaseIrq\(DevHandle handle\); - -**表 12** SdioReleaseIrq函数的参数和返回值描述 - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

SDIO控制器的设备句柄

-

返回值

-

返回值描述

-

0

-

释放SDIO中断成功

-

负数

-

释放SDIO中断失败

-
+| 参数 | 参数描述 | +| -------- | -------- | +| handle | SDIO控制器的设备句柄 | +| **返回值** | **返回值描述** | +| 0 | 释放SDIO中断成功 | +| 负数 | 释放SDIO中断失败 | 释放SDIO中断的示例如下: + ``` int32_t ret; /* 释放SDIO中断 */ @@ -823,46 +420,25 @@ if (ret != 0) { } ``` -### 去使能SDIO设备 + +### 去使能SDIO设备 通信完成之后,还需要去使能SDIO设备,函数如下所示: -int32\_t SdioDisableFunc\(DevHandle handle\); - -**表 13** SdioDisableFunc函数的参数和返回值描述 - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

SDIO控制器的设备句柄

-

返回值

-

返回值描述

-

0

-

去使能SDIO设备成功

-

负数

-

去使能SDIO设备失败

-
+int32_t SdioDisableFunc(DevHandle handle); + + **表13** SdioDisableFunc函数的参数和返回值描述 + +| 参数 | 参数描述 | +| -------- | -------- | +| handle | SDIO控制器的设备句柄 | +| **返回值** | **返回值描述** | +| 0 | 去使能SDIO设备成功 | +| 负数 | 去使能SDIO设备失败 | 去使能SDIO设备的示例如下: + ``` int32_t ret; /* 去使能SDIO设备 */ @@ -872,70 +448,59 @@ if (ret != 0) { } ``` -### 释放HOST + +### 释放HOST 通信完成之后,还需要释放去HOST,函数如下所示: -void SdioReleaseHost\(DevHandle handle\); - -**表 14** SdioReleaseHost函数的参数描述 - - - - - - - - - - -

参数

-

参数描述

-

handle

-

SDIO控制器的设备句柄

-
+ +``` +void SdioReleaseHost(DevHandle handle); +``` + + **表14** SdioReleaseHost函数的参数描述 + +| 参数 | 参数描述 | +| -------- | -------- | +| handle | SDIO控制器的设备句柄 | 释放HOST的示例如下: + ``` SdioReleaseHost(handle); /* 释放HOST */ ``` -### 关闭SDIO控制器 + +### 关闭SDIO控制器 SDIO通信完成之后,最后需要关闭SDIO控制器,函数如下所示: -void SdioClose\(DevHandle handle\); + +``` +void SdioClose(DevHandle handle); +``` 该函数会释放掉申请的资源。 -**表 15** SdioClose函数的参数描述 - - - - - - - - - - -

参数

-

参数描述

-

handle

-

SDIO控制器的设备句柄

-
+ **表15** SdioClose函数的参数描述 + +| 参数 | 参数描述 | +| -------- | -------- | +| handle | SDIO控制器的设备句柄 | 关闭SDIO控制器的示例如下: + ``` SdioClose(handle); /* 关闭SDIO控制器 */ ``` -## 使用实例 -SDIO设备完整的使用示例如下所示,首先打开总线号为1的SDIO控制器,然后独占HOST、使能设备、注册中断,接着进行SDIO通信(读写等),通信完成之后,释放中断、去使能设备、释放HOST,最后关闭SDIO控制器。 +## 使用实例 + SDIO设备完整的使用示例如下所示,首先打开总线号为1的SDIO控制器,然后独占HOST、使能设备、注册中断,接着进行SDIO通信(读写等),通信完成之后,释放中断、去使能设备、释放HOST,最后关闭SDIO控制器。 + ``` #include "hdf_log.h" #include "sdio_if.h" @@ -1060,4 +625,3 @@ ENABLE_ERR: SdioClose(handle); } ``` - diff --git a/zh-cn/device-dev/driver/driver-platform-sdio-develop.md b/zh-cn/device-dev/driver/driver-platform-sdio-develop.md index bfc2d147b1baf29aada5dc6c359a942587726ddc..81b8701d9de1ce42adae3123bf865bd72147bc44 100755 --- a/zh-cn/device-dev/driver/driver-platform-sdio-develop.md +++ b/zh-cn/device-dev/driver/driver-platform-sdio-develop.md @@ -1,21 +1,19 @@ -# SDIO +# SDIO -- [概述](#section1347805272150053) -- [接口说明](#section752964871810) -- [开发步骤](#section581179475150053) -- [开发实例](#section2112250242150053) -## 概述 +## 概述 -SDIO由SD卡发展而来,被统称为MMC(MultiMediaCard),相关技术差别不大,在HDF框架中,SDIO的接口适配模式采用独立服务模式,在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。独立服务模式可以直接借助HDFDeviceManager的服务管理能力,但需要为每个设备单独配置设备节点,增加内存占用。 +SDIO由SD卡发展而来,被统称为mmc(MultiMediaCard),相关技术差别不大,在HDF框架中,SDIO的接口适配模式采用独立服务模式,在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。独立服务模式可以直接借助HDFDeviceManager的服务管理能力,但需要为每个设备单独配置设备节点,增加内存占用。 -**图 1** SDIO独立服务模式结构图 -![](figures/独立服务模式结构图.png "SDIO独立服务模式结构图") + **图1** SDIO独立服务模式结构图 + ![zh-cn_image_0000001177082420](figures/zh-cn_image_0000001177082420.png) -## 接口说明 + +## 接口说明 SdioDeviceOps定义: + ``` // 函数模板 struct SdioDeviceOps { @@ -39,494 +37,275 @@ struct SdioDeviceOps { }; ``` -**表 1** SdioDeviceOps结构体成员的回调函数功能说明 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

函数

-

入参

-

出参

-

返回值

-

功能

-

incrAddrReadBytes

-

dev: 结构体指针,SDIO设备控制器;addr: uint32_t,地址值;size: uint32_t,大小

-

data: uint8_t指针,传出值;

-

HDF_STATUS相关状态

-

从指定的SDIO地址增量读取给定长度的数据

-

incrAddrWriteBytes

-

dev: 结构体指针,SDIO设备控制器;data: uint8_t指针,传入值;addr: uint32_t,地址值;size: uint32_t,大小

-

-

HDF_STATUS相关状态

-

将给定长度的数据增量写入指定的SDIO地址

-

fixedAddrReadBytes

-

dev: 结构体指针,SDIO设备控制器;addr: uint32_t,地址值;size: uint32_t,大小;scatterLen: uint32_t,数据长度;

-

data: uint8_t指针,传出值;

-

HDF_STATUS相关状态

-

从固定SDIO地址读取给定长度的数据。

-

fixedAddrWriteBytes

-

dev: 结构体指针,SDIO设备控制器;data: uint8_t指针,传入值;addr: uint32_t,地址值;size: uint32_t,大小;scatterLen: uint32_t,数据长度;

-

-

HDF_STATUS相关状态

-

将给定长度的数据写入固定SDIO地址

-

func0ReadBytes

-

dev: 结构体指针,SDIO设备控制器;addr: uint32_t,地址值;size: uint32_t,大小;

-

data: uint8_t指针,传出值;

-

HDF_STATUS相关状态

-

从SDIO函数0的地址空间读取给定长度的数据。

-

func0WriteBytes

-

dev: 结构体指针,SDIO设备控制器;data: uint8_t指针,传入值;addr: uint32_t,地址值;size: uint32_t,大小;

-

-

HDF_STATUS相关状态

-

将给定长度的数据写入SDIO函数0的地址空间。

-

setBlockSize

-

dev: 结构体指针,SDIO设备控制器;blockSize: uint32_t,Block大小

-

-

HDF_STATUS相关状态

-

设置block大小

-

getCommonInfo

-

dev: 联合体指针,SDIO设备控制器;infoType: uint32_t,info类型;

-

info: 结构体指针,传出SdioFuncInfo信息;

-

HDF_STATUS相关状态

-

获取CommonInfo,说明见下

-

setCommonInfo

-

dev: 结构体指针,SDIO设备控制器;info: 联合体指针,SdioFuncInfo信息传入;infoType: uint32_t,info类型;

-

-

HDF_STATUS相关状态

-

设置CommonInfo,说明见下

-

flushData

-

dev: 结构体指针,SDIO设备控制器;

-

-

HDF_STATUS相关状态

-

当SDIO需要重新初始化或发生意外错误时调用的函数

-

enableFunc

-

dev: 结构体指针,SDIO设备控制器;

-

-

HDF_STATUS相关状态

-

使能SDIO设备

-

disableFunc

-

dev: 结构体指针,SDIO设备控制器;

-

-

HDF_STATUS相关状态

-

去使能SDIO设备

-

claimIrq

-

dev: 结构体指针,SDIO设备控制器;irqHandler: void函数指针;

-

-

HDF_STATUS相关状态

-

注册SDIO中断

-

releaseIrq

-

dev: 结构体指针,SDIO设备控制器;

-

-

HDF_STATUS相关状态

-

释放SDIO中断

-

findFunc

-

dev: 结构体指针,SDIO设备控制器;configData: 结构体指针, SDIO函数关键信息

-

-

HDF_STATUS相关状态

-

寻找匹配的funcNum

-

claimHost

-

dev: 结构体指针,SDIO设备控制器;

-

-

HDF_STATUS相关状态

-

独占HOST

-

releaseHost

-

dev: 结构体指针,SDIO设备控制器;

-

-

HDF_STATUS相关状态

-

释放HOST

-
- ->![](../public_sys-resources/icon-note.gif) **说明:** ->CommonInfo包括maxBlockNum\(单个request中最大block数\), maxBlockSize\(单个block最大字节数\), maxRequestSize\(单个Request最大字节数\), enTimeout\(最大超时时间,毫秒\), funcNum\(功能编号1\~7\), irqCap\(IRQ capabilities\), \(void \*\)data. - -## 开发步骤 + **表1** SdioDeviceOps结构体成员的回调函数功能说明 + +| 函数 | 入参 | 出参 | 返回值 | 功能 | +| -------- | -------- | -------- | -------- | -------- | +| incrAddrReadBytes | dev: 结构体指针,SDIO设备控制器;addr: uint32_t,地址值;size: uint32_t,大小 | data: uint8_t指针,传出值; | HDF_STATUS相关状态 | 从指定的SDIO地址增量读取给定长度的数据 | +| incrAddrWriteBytes | dev: 结构体指针,SDIO设备控制器;data: uint8_t指针,传入值;addr: uint32_t,地址值;size: uint32_t,大小 | 无 | HDF_STATUS相关状态 | 将给定长度的数据增量写入指定的SDIO地址 | +| fixedAddrReadBytes | dev: 结构体指针,SDIO设备控制器;addr: uint32_t,地址值;size: uint32_t,大小;scatterLen: uint32_t,数据长度; | data: uint8_t指针,传出值; | HDF_STATUS相关状态 | 从固定SDIO地址读取给定长度的数据。 | +| fixedAddrWriteBytes | dev: 结构体指针,SDIO设备控制器;data: uint8_t指针,传入值;addr: uint32_t,地址值;size: uint32_t,大小;scatterLen: uint32_t,数据长度; | 无 | HDF_STATUS相关状态 | 将给定长度的数据写入固定SDIO地址 | +| func0ReadBytes | dev: 结构体指针,SDIO设备控制器;addr: uint32_t,地址值;size: uint32_t,大小; | data: uint8_t指针,传出值; | HDF_STATUS相关状态 | 从SDIO函数0的地址空间读取给定长度的数据。 | +| func0WriteBytes | dev: 结构体指针,SDIO设备控制器;data: uint8_t指针,传入值;addr: uint32_t,地址值;size: uint32_t,大小; | 无 | HDF_STATUS相关状态 | 将给定长度的数据写入SDIO函数0的地址空间。 | +| setBlockSize | dev: 结构体指针,SDIO设备控制器;blockSize: uint32_t,Block大小 | 无 | HDF_STATUS相关状态 | 设置block大小 | +| getCommonInfo | dev: 联合体指针,SDIO设备控制器;infoType: uint32_t,info类型; | info: 结构体指针,传出SdioFuncInfo信息; | HDF_STATUS相关状态 | 获取CommonInfo,说明见下 | +| setCommonInfo | dev: 结构体指针,SDIO设备控制器;info: 联合体指针,SdioFuncInfo信息传入;infoType: uint32_t,info类型; | 无 | HDF_STATUS相关状态 | 设置CommonInfo,说明见下 | +| flushData | dev: 结构体指针,SDIO设备控制器; | 无 | HDF_STATUS相关状态 | 当SDIO需要重新初始化或发生意外错误时调用的函数 | +| enableFunc | dev: 结构体指针,SDIO设备控制器; | 无 | HDF_STATUS相关状态 | 使能SDIO设备 | +| disableFunc | dev: 结构体指针,SDIO设备控制器; | 无 | HDF_STATUS相关状态 | 去使能SDIO设备 | +| claimIrq | dev: 结构体指针,SDIO设备控制器;irqHandler: void函数指针; | 无 | HDF_STATUS相关状态 | 注册SDIO中断 | +| releaseIrq | dev: 结构体指针,SDIO设备控制器; | 无 | HDF_STATUS相关状态 | 释放SDIO中断 | +| findFunc | dev: 结构体指针,SDIO设备控制器;configData: 结构体指针, SDIO函数关键信息 | 无 | HDF_STATUS相关状态 | 寻找匹配的funcNum | +| claimHost | dev: 结构体指针,SDIO设备控制器; | 无 | HDF_STATUS相关状态 | 独占HOST | +| releaseHost | dev: 结构体指针,SDIO设备控制器; | 无 | HDF_STATUS相关状态 | 释放HOST | + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> CommonInfo包括maxBlockNum(单个request中最大block数), maxBlockSize(单个block最大字节数), maxRequestSize(单个Request最大字节数), enTimeout(最大超时时间,毫秒), funcNum(功能编号1~7), irqCap(IRQ capabilities), (void \*)data. + + +## 开发步骤 SDIO模块适配HDF框架的三个环节是配置属性文件,实例化驱动入口,以及填充核心层接口函数。 -1. **实例化驱动入口:** - - 实例化HdfDriverEntry结构体成员。 - - 调用HDF\_INIT将HdfDriverEntry实例化对象注册到HDF框架中。 - -2. **配置属性文件:** - - 在device\_info.hcs文件中添加deviceNode描述。 - - 【可选】添加sdio\_config.hcs器件属性文件。 - -3. **实例化SDIO控制器对象:** - - 初始化SdioDevice成员。 - - 实例化SdioDevice成员SdioDeviceOps。 - - >![](../public_sys-resources/icon-note.gif) **说明:** - >实例化SdioDevice成员SdioDeviceOps,其定义和成员说明见[接口说明](#section752964871810)。 - - -4. **驱动调试:** - - 【可选】针对新增驱动程序,建议验证驱动基本功能,例如SDIO控制状态,中断响应情况等。 - - -## 开发实例 - -下方将以sdio\_adapter.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。 - -1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf\_device\_desc.h 中定义)类型的全局变量,且moduleName要和device\_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。 - - 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 - - SDIO 驱动入口参考: - - ``` - struct HdfDriverEntry g_sdioDriverEntry = { - .moduleVersion = 1, - .Bind = Hi35xxLinuxSdioBind, //见Bind参考 - .Init = Hi35xxLinuxSdioInit, //见Init参考 - .Release = Hi35xxLinuxSdioRelease,//见Release参考 - .moduleName = "HDF_PLATFORM_SDIO",//【必要 且与 HCS文件中里面的moduleName匹配】 - }; - //调用HDF_INIT将驱动入口注册到HDF框架中 - HDF_INIT(g_sdioDriverEntry); - ``` - -2. 完成驱动入口注册之后,下一步请在device\_info.hcs文件中添加deviceNode信息,并在 sdio\_config.hcs 中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值与核心层SdioDevice成员的默认值或限制范围有密切关系。 - - 本例只有一个SDIO控制器,如有多个器件信息,则需要在device\_info文件增加deviceNode信息,以及在sdio\_config文件中增加对应的器件属性。 - - - device\_info.hcs 配置参考: +1. **实例化驱动入口:** + - 实例化HdfDriverEntry结构体成员。 + - 调用HDF_INIT将HdfDriverEntry实例化对象注册到HDF框架中。 + +2. **配置属性文件:** + - 在device_info.hcs文件中添加deviceNode描述。 + - 【可选】添加sdio_config.hcs器件属性文件。 + +3. **实例化SDIO控制器对象:** + - 初始化SdioDevice成员。 + - 实例化SdioDevice成员SdioDeviceOps。 + > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** + > 实例化SdioDevice成员SdioDeviceOps,其定义和成员说明见[接口说明](#接口说明)。 + +4. **驱动调试:** + 【可选】针对新增驱动程序,建议验证驱动基本功能,例如SDIO控制状态,中断响应情况等。 + + +## 开发实例 + +下方将以sdio_adapter.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。 + +1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf_device_desc.h 中定义)类型的全局变量,且moduleName要和device_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。 + 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 + + SDIO 驱动入口参考: + + ``` + struct HdfDriverEntry g_sdioDriverEntry = { + .moduleVersion = 1, + .Bind = Hi35xxLinuxSdioBind, //见Bind参考 + .Init = Hi35xxLinuxSdioInit, //见Init参考 + .Release = Hi35xxLinuxSdioRelease,//见Release参考 + .moduleName = "HDF_PLATFORM_SDIO",//【必要 且与 HCS文件中里面的moduleName匹配】 + }; + //调用HDF_INIT将驱动入口注册到HDF框架中 + HDF_INIT(g_sdioDriverEntry); + ``` + +2. 完成驱动入口注册之后,下一步请在device_info.hcs文件中添加deviceNode信息,并在 sdio_config.hcs 中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值与核心层SdioDevice成员的默认值或限制范围有密切关系。 + 本例只有一个SDIO控制器,如有多个器件信息,则需要在device_info文件增加deviceNode信息,以及在sdio_config文件中增加对应的器件属性。 + - device_info.hcs 配置参考: + + + ``` + root { + device_info { + match_attr = "hdf_manager"; + platform :: host { + hostName = "platform_host"; + priority = 50; + device_sdio :: device { + device0 :: deviceNode { + policy = 1; + priority = 70; + permission = 0644; + moduleName = "HDF_PLATFORM_SDIO"; //【必要】用于指定驱动名称,需要与驱动Entry中的moduleName一致; + serviceName = "HDF_PLATFORM_MMC_2"; //【必要】驱动对外发布服务的名称,必须唯一 + deviceMatchAttr = "hisilicon_hi35xx_sdio_0";//【必要】用于配置控制器私有数据,要与sdio_config.hcs中对应控制器保持一致 + } + } + } + } + } + ``` + + - sdio_config.hcs 配置参考: + + + ``` + root { + platform { + sdio_config { + template sdio_controller { + match_attr = ""; + hostId = 2; //【必要】模式固定为2,在mmc_config.hcs有介绍 + devType = 2; //【必要】模式固定为2,在mmc_config.hcs有介绍 + } + controller_0x2dd1 :: sdio_controller { + match_attr = "hisilicon_hi35xx_sdio_0";//【必要】需要和device_info.hcs中的deviceMatchAttr值一致 + } + } + } + ``` + +3. 完成驱动入口注册之后,最后一步就是以核心层SdioDevice对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化SdioDevice成员SdioDeviceOps(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。 + - 自定义结构体参考: + + 从驱动的角度看,自定义结构体是参数和数据的载体,而且sdio_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,一些重要数值也会传递给核心层对象。 - ``` - root { - device_info { - match_attr = "hdf_manager"; - platform :: host { - hostName = "platform_host"; - priority = 50; - device_sdio :: device { - device0 :: deviceNode { - policy = 1; - priority = 70; - permission = 0644; - moduleName = "HDF_PLATFORM_SDIO"; //【必要】用于指定驱动名称,需要与驱动Entry中的moduleName一致; - serviceName = "HDF_PLATFORM_MMC_2"; //【必要】驱动对外发布服务的名称,必须唯一 - deviceMatchAttr = "hisilicon_hi35xx_sdio_0";//【必要】用于配置控制器私有数据,要与sdio_config.hcs中对应控制器保持一致 - } - } - } - } - } - ``` - - - sdio\_config.hcs 配置参考: - - ``` - root { - platform { - sdio_config { - template sdio_controller { - match_attr = ""; - hostId = 2; //【必要】模式固定为2,在mmc_config.hcs有介绍 - devType = 2; //【必要】模式固定为2,在mmc_config.hcs有介绍 - } - controller_0x2dd1 :: sdio_controller { - match_attr = "hisilicon_hi35xx_sdio_0";//【必要】需要和device_info.hcs中的deviceMatchAttr值一致 - } - } - } - ``` - -3. 完成驱动入口注册之后,最后一步就是以核心层SdioDevice对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化SdioDevice成员SdioDeviceOps(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。 - - 自定义结构体参考: - - 从驱动的角度看,自定义结构体是参数和数据的载体,而且sdio\_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,一些重要数值也会传递给核心层对象。 - - ``` - typedef struct { - uint32_t maxBlockNum; // 单个request最大的block个数 - uint32_t maxBlockSize; // 单个block最大的字节数1~2048 - uint32_t maxRequestSize; // 单个request最大的字节数 1~2048 - uint32_t enTimeout; // 最大超时时间,单位毫秒,且不能超过一秒 - uint32_t funcNum; // 函数编号1~7 - uint32_t irqCap; // 中断能力 - void *data; // 私有数据 - } SdioFuncInfo; - - //SdioDevice是核心层控制器结构体,其中的成员在Bind函数中会被赋值 - struct SdioDevice { - struct SdDevice sd; - struct SdioDeviceOps *sdioOps; - struct SdioRegister sdioReg; - uint32_t functions; - struct SdioFunction *sdioFunc[SDIO_MAX_FUNCTION_NUMBER]; - struct SdioFunction *curFunction; - struct OsalThread thread; /* irq thread */ - struct OsalSem sem; - bool irqPending; - bool threadRunning; - }; - ``` - - - SdioDevice成员回调函数结构体SdioDeviceOps的实例化,其他成员在Init函数中初始化。 - - ``` - static struct SdioDeviceOps g_sdioDeviceOps = { - .incrAddrReadBytes = Hi35xxLinuxSdioIncrAddrReadBytes, - .incrAddrWriteBytes = Hi35xxLinuxSdioIncrAddrWriteBytes, - .fixedAddrReadBytes = Hi35xxLinuxSdioFixedAddrReadBytes, - .fixedAddrWriteBytes = Hi35xxLinuxSdioFixedAddrWriteBytes, - .func0ReadBytes = Hi35xxLinuxSdioFunc0ReadBytes, - .func0WriteBytes = Hi35xxLinuxSdioFunc0WriteBytes, - .setBlockSize = Hi35xxLinuxSdioSetBlockSize, - .getCommonInfo = Hi35xxLinuxSdioGetCommonInfo, - .setCommonInfo = Hi35xxLinuxSdioSetCommonInfo, - .flushData = Hi35xxLinuxSdioFlushData, - .enableFunc = Hi35xxLinuxSdioEnableFunc, - .disableFunc = Hi35xxLinuxSdioDisableFunc, - .claimIrq = Hi35xxLinuxSdioClaimIrq, - .releaseIrq = Hi35xxLinuxSdioReleaseIrq, - .findFunc = Hi35xxLinuxSdioFindFunc, - .claimHost = Hi35xxLinuxSdioClaimHost, - .releaseHost = Hi35xxLinuxSdioReleaseHost, - }; - ``` - - - Bind函数参考 - - 入参: - - HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 - - 返回值: - - HDF\_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf\_base.h中HDF\_STATUS 定义)。 - - **表 2** Bind函数入参及返回值 - - - - - - - - - - - - - - - - - - - - - - - - - -

状态(值)

-

问题描述

-

HDF_ERR_INVALID_OBJECT

-

控制器对象非法

-

HDF_ERR_MALLOC_FAIL

-

内存分配失败

-

HDF_ERR_INVALID_PARAM

-

参数非法

-

HDF_ERR_IO

-

I/O 错误

-

HDF_SUCCESS

-

初始化成功

-

HDF_FAILURE

-

初始化失败

-
- - 函数说明: - - 初始化自定义结构体对象,初始化SdioCntlr成员,调用核心层SdioCntlrAdd函数,以及其他厂商自定义初始化操作。 - - ``` - static int32_t Hi35xxLinuxSdioBind(struct HdfDeviceObject *obj) - { - struct MmcCntlr *cntlr = NULL; - int32_t ret; - ... - cntlr = (struct MmcCntlr *)OsalMemCalloc(sizeof(struct MmcCntlr));// 分配内存 - ... - cntlr->ops = &g_sdioCntlrOps; //【必要】struct MmcCntlrOps g_sdioCntlrOps={ - // .rescanSdioDev = Hi35xxLinuxSdioRescan,}; - cntlr->hdfDevObj = obj; //【必要】使HdfDeviceObject与MmcCntlr可以相互转化的前提 - obj->service = &cntlr->service;//【必要】使HdfDeviceObject与MmcCntlr可以相互转化的前提 - ret = Hi35xxLinuxSdioCntlrParse(cntlr, obj);//【必要】初始化cntlr 的 index, devType, 失败则 goto _ERR; - ... - ret = MmcCntlrAdd(cntlr); //【必要】调用核心层mmc_core.c的函数, 失败则 goto _ERR; - ... - ret = MmcCntlrAllocDev(cntlr, (enum MmcDevType)cntlr->devType);//【必要】调用核心层mmc_core.c的函数, 失败则 goto _ERR; - ... - - MmcDeviceAddOps(cntlr->curDev, &g_sdioDeviceOps);//【必要】调用核心层mmc_core.c的函数, 钩子函数挂载 - HDF_LOGD("Hi35xxLinuxSdioBind: Success!"); - return HDF_SUCCESS; - _ERR: - Hi35xxLinuxSdioDeleteCntlr(cntlr); - HDF_LOGE("Hi35xxLinuxSdioBind: Fail!"); - return HDF_FAILURE; - } - ``` - - - Init函数参考 - - 入参: - - HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 - - 返回值: - - HDF\_STATUS相关状态。 - - 函数说明: + ``` + typedef struct { + uint32_t maxBlockNum; // 单个request最大的block个数 + uint32_t maxBlockSize; // 单个block最大的字节数1~2048 + uint32_t maxRequestSize; // 单个request最大的字节数 1~2048 + uint32_t enTimeout; // 最大超时时间,单位毫秒,且不能超过一秒 + uint32_t funcNum; // 函数编号1~7 + uint32_t irqCap; // 中断能力 + void *data; // 私有数据 + } SdioFuncInfo; + + //SdioDevice是核心层控制器结构体,其中的成员在Bind函数中会被赋值 + struct SdioDevice { + struct SdDevice sd; + struct SdioDeviceOps *sdioOps; + struct SdioRegister sdioReg; + uint32_t functions; + struct SdioFunction *sdioFunc[SDIO_MAX_FUNCTION_NUMBER]; + struct SdioFunction *curFunction; + struct OsalThread thread; /* irq thread */ + struct OsalSem sem; + bool irqPending; + bool threadRunning; + }; + ``` + - SdioDevice成员回调函数结构体SdioDeviceOps的实例化,其他成员在Init函数中初始化。 - 无操作,可根据厂商需要添加。 - - ``` - static int32_t Hi35xxLinuxSdioInit(struct HdfDeviceObject *obj) - { - (void)obj;//无操作,可根据厂商需要添加 - HDF_LOGD("Hi35xxLinuxSdioInit: Success!"); - return HDF_SUCCESS; - } - ``` - - - Release函数参考 - - 入参: + + ``` + static struct SdioDeviceOps g_sdioDeviceOps = { + .incrAddrReadBytes = Hi35xxLinuxSdioIncrAddrReadBytes, + .incrAddrWriteBytes = Hi35xxLinuxSdioIncrAddrWriteBytes, + .fixedAddrReadBytes = Hi35xxLinuxSdioFixedAddrReadBytes, + .fixedAddrWriteBytes = Hi35xxLinuxSdioFixedAddrWriteBytes, + .func0ReadBytes = Hi35xxLinuxSdioFunc0ReadBytes, + .func0WriteBytes = Hi35xxLinuxSdioFunc0WriteBytes, + .setBlockSize = Hi35xxLinuxSdioSetBlockSize, + .getCommonInfo = Hi35xxLinuxSdioGetCommonInfo, + .setCommonInfo = Hi35xxLinuxSdioSetCommonInfo, + .flushData = Hi35xxLinuxSdioFlushData, + .enableFunc = Hi35xxLinuxSdioEnableFunc, + .disableFunc = Hi35xxLinuxSdioDisableFunc, + .claimIrq = Hi35xxLinuxSdioClaimIrq, + .releaseIrq = Hi35xxLinuxSdioReleaseIrq, + .findFunc = Hi35xxLinuxSdioFindFunc, + .claimHost = Hi35xxLinuxSdioClaimHost, + .releaseHost = Hi35xxLinuxSdioReleaseHost, + }; + ``` + - Bind函数参考 + + 入参: + + HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 + + 返回值: + + HDF_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf_base.h中HDF_STATUS 定义)。 + **表2** Bind函数入参及返回值 + + | 状态(值) | 问题描述 | + | -------- | -------- | + | HDF_ERR_INVALID_OBJECT | 控制器对象非法 | + | HDF_ERR_MALLOC_FAIL | 内存分配失败 | + | HDF_ERR_INVALID_PARAM | 参数非法 | + | HDF_ERR_IO | I/O 错误 | + | HDF_SUCCESS | 初始化成功 | + | HDF_FAILURE | 初始化失败 | + + 函数说明: + + 初始化自定义结构体对象,初始化SdioCntlr成员,调用核心层SdioCntlrAdd函数,以及其他厂商自定义初始化操作。 - HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 + + ``` + static int32_t Hi35xxLinuxSdioBind(struct HdfDeviceObject *obj) + { + struct MmcCntlr *cntlr = NULL; + int32_t ret; + ... + cntlr = (struct MmcCntlr *)OsalMemCalloc(sizeof(struct MmcCntlr));// 分配内存 + ... + cntlr->ops = &g_sdioCntlrOps; //【必要】struct MmcCntlrOps g_sdioCntlrOps={ + // .rescanSdioDev = Hi35xxLinuxSdioRescan,}; + cntlr->hdfDevObj = obj; //【必要】使HdfDeviceObject与MmcCntlr可以相互转化的前提 + obj->service = &cntlr->service;//【必要】使HdfDeviceObject与MmcCntlr可以相互转化的前提 + ret = Hi35xxLinuxSdioCntlrParse(cntlr, obj);//【必要】初始化cntlr 的 index, devType, 失败则 goto _ERR; + ... + ret = MmcCntlrAdd(cntlr); //【必要】调用核心层mmc_core.c的函数, 失败则 goto _ERR; + ... + ret = MmcCntlrAllocDev(cntlr, (enum MmcDevType)cntlr->devType);//【必要】调用核心层mmc_core.c的函数, 失败则 goto _ERR; + ... + + MmcDeviceAddOps(cntlr->curDev, &g_sdioDeviceOps);//【必要】调用核心层mmc_core.c的函数, 钩子函数挂载 + HDF_LOGD("Hi35xxLinuxSdioBind: Success!"); + return HDF_SUCCESS; + + _ERR: + Hi35xxLinuxSdioDeleteCntlr(cntlr); + HDF_LOGE("Hi35xxLinuxSdioBind: Fail!"); + return HDF_FAILURE; + } + ``` + + - Init函数参考 + + 入参: + + HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 + + 返回值: + + HDF_STATUS相关状态。 + + 函数说明: + + 无操作,可根据厂商需要添加。 - 返回值: + + ``` + static int32_t Hi35xxLinuxSdioInit(struct HdfDeviceObject *obj) + { + (void)obj;//无操作,可根据厂商需要添加 + HDF_LOGD("Hi35xxLinuxSdioInit: Success!"); + return HDF_SUCCESS; + } + ``` + - Release函数参考 - 无。 + 入参: - 函数说明: + HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 - 释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源。所有强制转换获取相应对象的操作前提是在Bind函数中具备对应赋值的操作。 + 返回值: - ``` - static void Hi35xxLinuxSdioRelease(struct HdfDeviceObject *obj) - { - if (obj == NULL) { - return; - } - Hi35xxLinuxSdioDeleteCntlr((struct MmcCntlr *)obj->service);//【必要】自定义的内存释放函数,这里有HdfDeviceObject到MmcCntlr的强制转化 - } - ``` + 无。 + 函数说明: + 释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源。所有强制转换获取相应对象的操作前提是在Bind函数中具备对应赋值的操作。 + + ``` + static void Hi35xxLinuxSdioRelease(struct HdfDeviceObject *obj) + { + if (obj == NULL) { + return; + } + Hi35xxLinuxSdioDeleteCntlr((struct MmcCntlr *)obj->service);//【必要】自定义的内存释放函数,这里有HdfDeviceObject到MmcCntlr的强制转化 + } + ``` diff --git a/zh-cn/device-dev/driver/driver-platform-spi-des.md b/zh-cn/device-dev/driver/driver-platform-spi-des.md index 033a3b0e06d8469ad5cce3955b0b971c0a5af27a..9ba3a752524162e32f23aa07d47fdf439007a9b2 100644 --- a/zh-cn/device-dev/driver/driver-platform-spi-des.md +++ b/zh-cn/device-dev/driver/driver-platform-spi-des.md @@ -1,165 +1,92 @@ -# SPI - -- [概述](#section193356154511) -- [接口说明](#section1325964832615) -- [使用指导](#section71363452477) - - [使用流程](#section32846814820) - - [获取SPI设备句柄](#section1927265711481) - - [获取SPI设备属性](#section541133418493) - - [配置SPI设备属性](#section7870106145010) - - [进行SPI通信](#section13324155195013) - - [销毁SPI设备句柄](#section19661632135117) - -- [使用实例](#section06541058155120) - -## 概述 - -- SPI是串行外设接口(Serial Peripheral Interface)的缩写,是一种高速的,全双工,同步的通信总线。 -- SPI是由Motorola公司开发,用于在主设备和从设备之间进行通信,常用于与闪存、实时时钟、传感器以及模数转换器等进行通信。 -- SPI以主从方式工作,通常有一个主设备和一个或者多个从设备。主设备和从设备之间一般用4根线相连,它们分别是: - - SCLK – 时钟信号,由主设备产生; - - MOSI – 主设备数据输出,从设备数据输入; - - MISO – 主设备数据输入,从设备数据输出; - - CS – 片选,从设备使能信号,由主设备控制。 - - -- 一个主设备和两个从设备的连接示意图如[图1](#fig89085710359)所示,Device A和Device B共享主设备的SCLK、MISO和MOSI三根引脚,Device A的片选CS0连接主设备的CS0,Device B的片选CS1连接主设备的CS1。 - -**图 1** SPI主从设备连接示意图。 -![](figures/SPI主从设备连接示意图.png "SPI主从设备连接示意图") - -- SPI通信通常由主设备发起,通过以下步骤完成一次通信: - -1. 通过CS选中要通信的从设备,在任意时刻,一个主设备上最多只能有一个从设备被选中。 -2. 通过SCLK给选中的从设备提供时钟信号。 -3. 基于SCLK时钟信号,主设备数据通过MOSI发送给从设备,同时通过MISO接收从设备发送的数据,完成通信。 - -- 根据SCLK时钟信号的CPOL(Clock Polarity,时钟极性)和CPHA(Clock Phase,时钟相位)的不同组合,SPI有以下四种工作模式: - - CPOL=0,CPHA=0 时钟信号idle状态为低电平,第一个时钟边沿采样数据。 - - CPOL=0,CPHA=1 时钟信号idle状态为低电平,第二个时钟边沿采样数据。 - - CPOL=1,CPHA=0 时钟信号idle状态为高电平,第一个时钟边沿采样数据。 - - CPOL=1,CPHA=1 时钟信号idle状态为高电平,第二个时钟边沿采样数据。 - - -- SPI接口定义了操作SPI设备的通用方法集合,包括: - - SPI设备句柄获取和释放。 - - SPI读写: 从SPI设备读取或写入指定长度数据。 - - SPI自定义传输:通过消息传输结构体执行任意读写组合过程。 - - SPI设备配置:获取和设置SPI设备属性。 - - ->![](../public_sys-resources/icon-note.gif) **说明:** ->当前只支持主机模式,不支持从机模式。 - -## 接口说明 - -**表 1** SPI驱动API接口功能介绍 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

功能分类

-

接口名

-

描述

-

SPI设备句柄获取释放接口

-

SpiOpen

-

获取SPI设备句柄

-

SpiClose

-

释放SPI设备句柄

-

SPI读写接口

-

SpiRead

-

读取指定长度的数据

-

SpiWrite

-

写入指定长度的数据

-

SpiTransfer

-

SPI数据传输接口

-

SPI设备配置接口

-

-

SpiSetCfg

-

根据指定参数,配置SPI设备

-

SpiGetCfg

-

获取SPI设备配置参数

-
- ->![](../public_sys-resources/icon-note.gif) **说明:** ->本文涉及的所有接口,仅限内核态使用,不支持在用户态使用。 - -## 使用指导 - -### 使用流程 - -使用SPI的一般流程如[图2](#fig1586912310348)所示。 - -**图 2** SPI使用流程图 -![](figures/SPI使用流程图.png "SPI使用流程图") - -### 获取SPI设备句柄 +# SPI + + +## 概述 + +- SPI是串行外设接口(Serial Peripheral Interface)的缩写,是一种高速的,全双工,同步的通信总线。 + +- SPI是由Motorola公司开发,用于在主设备和从设备之间进行通信,常用于与闪存、实时时钟、传感器以及模数转换器等进行通信。 + +- SPI以主从方式工作,通常有一个主设备和一个或者多个从设备。主设备和从设备之间一般用4根线相连,它们分别是: + - SCLK – 时钟信号,由主设备产生; + - MOSI – 主设备数据输出,从设备数据输入; + - MISO – 主设备数据输入,从设备数据输出; + - CS – 片选,从设备使能信号,由主设备控制。 + +- 一个主设备和两个从设备的连接示意图如下所示,Device A和Device B共享主设备的SCLK、MISO和MOSI三根引脚,Device A的片选CS0连接主设备的CS0,Device B的片选CS1连接主设备的CS1。 + + **图1** SPI主从设备连接示意图 + + ![zh-cn_image_0000001160971308](figures/zh-cn_image_0000001160971308.png) + +- SPI通信通常由主设备发起,通过以下步骤完成一次通信: + 1. 通过CS选中要通信的从设备,在任意时刻,一个主设备上最多只能有一个从设备被选中。 + 2. 通过SCLK给选中的从设备提供时钟信号。 + 3. 基于SCLK时钟信号,主设备数据通过MOSI发送给从设备,同时通过MISO接收从设备发送的数据,完成通信。 + +- 根据SCLK时钟信号的CPOL(Clock Polarity,时钟极性)和CPHA(Clock Phase,时钟相位)的不同组合,SPI有以下四种工作模式: + - CPOL=0,CPHA=0 时钟信号idle状态为低电平,第一个时钟边沿采样数据。 + - CPOL=0,CPHA=1 时钟信号idle状态为低电平,第二个时钟边沿采样数据。 + - CPOL=1,CPHA=0 时钟信号idle状态为高电平,第一个时钟边沿采样数据。 + - CPOL=1,CPHA=1 时钟信号idle状态为高电平,第二个时钟边沿采样数据。 + +- SPI接口定义了操作SPI设备的通用方法集合,包括: + - SPI设备句柄获取和释放。 + - SPI读写: 从SPI设备读取或写入指定长度数据。 + - SPI自定义传输:通过消息传输结构体执行任意读写组合过程。 + - SPI设备配置:获取和设置SPI设备属性。 + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> 当前只支持主机模式,不支持从机模式。 + + +## 接口说明 + + **表1** SPI驱动API接口功能介绍 + +| 功能分类 | 接口名 | +| -------- | -------- | +| SPI设备句柄获取释放接口 | - SpiOpen:获取SPI设备句柄
- SpiClose:释放SPI设备句柄 | +| SPI读写接口 | - SpiRead:读取指定长度的数据
- SpiWrite:写入指定长度的数据
- SpiTransfer:SPI数据传输接口 | +| SPI设备配置接口 | - SpiSetCfg:根据指定参数,配置SPI设备
- SpiGetCfg:获取SPI设备配置参数 | + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> 本文涉及的所有接口,仅限内核态使用,不支持在用户态使用。 + + +## 使用指导 + + +### 使用流程 + +使用SPI的一般流程如下图所示。 + + **图2** SPI使用流程图 + + ![zh-cn_image_0000001206291275](figures/zh-cn_image_0000001206291275.png) + + +### 获取SPI设备句柄 在使用SPI进行通信时,首先要调用SpiOpen获取SPI设备句柄,该函数会返回指定总线号和片选号的SPI设备句柄。 -DevHandle SpiOpen\(const struct SpiDevInfo \*info\); - -**表 2** SpiOpen参数和返回值描述 - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

info

-

SPI设备描述符

-

返回值

-

返回值描述

-

NULL

-

获取SPI设备句柄失败

-

设备句柄

-

对应的SPI设备句柄

-
+ +``` +DevHandle SpiOpen(const struct SpiDevInfo *info); +``` + + **表2** SpiOpen参数和返回值描述 + +| **参数** | **参数描述** | +| -------- | -------- | +| info | SPI设备描述符 | +| **返回值** | **返回值描述** | +| NULL | 获取SPI设备句柄失败 | +| 设备句柄 | 对应的SPI设备句柄 | 假设系统中的SPI设备总线号为0,片选号为0,获取该SPI设备句柄的示例如下: + ``` struct SpiDevInfo spiDevinfo; /* SPI设备描述符 */ DevHandle spiHandle = NULL; /* SPI设备句柄 */ @@ -174,47 +101,26 @@ if (spiHandle == NULL) { } ``` -### 获取SPI设备属性 + +### 获取SPI设备属性 在获取到SPI设备句柄之后,需要配置SPI设备属性。配置SPI设备属性之前,可以先获取SPI设备属性,获取SPI设备属性的函数如下所示: -int32\_t SpiGetCfg\(DevHandle handle, struct SpiCfg \*cfg\); - -**表 3** SpiGetCfg参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

SPI设备句柄

-

cfg

-

SPI设备配置参数

-

返回值

-

返回值描述

-

0

-

获取配置成功

-

负数

-

获取配置失败

-
+ +``` +int32_t SpiGetCfg(DevHandle handle, struct SpiCfg *cfg); +``` + + **表3** SpiGetCfg参数和返回值描述 + +| **参数** | **参数描述** | +| -------- | -------- | +| handle | SPI设备句柄 | +| cfg | SPI设备配置参数 | +| **返回值** | **返回值描述** | +| 0 | 获取配置成功 | +| 负数 | 获取配置失败 | + ``` int32_t ret; @@ -225,47 +131,26 @@ if (ret != 0) { } ``` -### 配置SPI设备属性 + +### 配置SPI设备属性 在获取到SPI设备句柄之后,需要配置SPI设备属性,配置SPI设备属性的函数如下所示: -int32\_t SpiSetCfg\(DevHandle handle, struct SpiCfg \*cfg\); - -**表 4** SpiSetCfg参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

SPI设备句柄

-

cfg

-

SPI设备配置参数

-

返回值

-

返回值描述

-

0

-

配置成功

-

负数

-

配置失败

-
+ +``` +int32_t SpiSetCfg(DevHandle handle, struct SpiCfg *cfg); +``` + + **表4** SpiSetCfg参数和返回值描述 + +| **参数** | **参数描述** | +| -------- | -------- | +| handle | SPI设备句柄 | +| cfg | SPI设备配置参数 | +| **返回值** | **返回值描述** | +| 0 | 配置成功 | +| 负数 | 配置失败 | + ``` int32_t ret; @@ -280,218 +165,137 @@ if (ret != 0) { } ``` -### 进行SPI通信 - -- 向SPI设备写入指定长度的数据 - -如果只向SPI设备写一次数据,则可以通过以下函数完成: - -int32\_t SpiWrite\(DevHandle handle, uint8\_t \*buf, uint32\_t len\); - -**表 5** SpiWrite参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

SPI设备句柄

-

buf

-

待写入数据的指针

-

len

-

待写入的数据长度

-

返回值

-

返回值描述

-

0

-

写入成功

-

负数

-

写入失败

-
-``` -int32_t ret; -uint8_t wbuff[4] = {0x12, 0x34, 0x56, 0x78}; -/* 向SPI设备写入指定长度的数据 */ -ret = SpiWrite(spiHandle, wbuff, 4); -if (ret != 0) { - HDF_LOGE("SpiWrite: failed, ret %d\n", ret); -} -``` +### 进行SPI通信 -- 从SPI设备读取指定长度的数据 - -如果只读取一次数据,则可以通过以下函数完成: - -int32\_t SpiRead\(DevHandle handle, uint8\_t \*buf, uint32\_t len\); - -**表 6** SpiRead参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

SPI设备句柄

-

buf

-

待读取数据的指针

-

len

-

待读取的数据长度

-

返回值

-

返回值描述

-

0

-

读取成功

-

负数

-

读取失败

-
+- 向SPI设备写入指定长度的数据 -``` -int32_t ret; -uint8_t rbuff[4] = {0}; -/* 从SPI设备读取指定长度的数据 */ -ret = SpiRead(spiHandle, rbuff, 4); -if (ret != 0) { - HDF_LOGE("SpiRead: failed, ret %d\n", ret); -} -``` + 如果只向SPI设备写一次数据,则可以通过以下函数完成: -- 自定义传输 - -如果需要发起一次自定义传输,则可以通过以下函数完成: - -int32\_t SpiTransfer\(DevHandle handle, struct SpiMsg \*msgs, uint32\_t count\); - -**表 7** SpiTransfer参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

SPI设备句柄

-

msgs

-

待传输数据的数组

-

count

-

msgs数组长度

-

返回值

-

返回值描述

-

0

-

执行成功

-

负数

-

执行失败

-
-``` -int32_t ret; -uint8_t wbuff[1] = {0x12}; -uint8_t rbuff[1] = {0}; -struct SpiMsg msg; /* 自定义传输的消息*/ -msg.wbuf = wbuff; /* 写入的数据 */ -msg.rbuf = rbuff; /* 读取的数据 */ -msg.len = 1; /* 读取、写入数据的长度都是1 */ -msg.csChange = 1; /* 进行下一次传输前关闭片选 */ -msg.delayUs = 0; /* 进行下一次传输前不进行延时 */ -msg.speed = 115200; /* 本次传输的速度 */ -/* 进行一次自定义传输,传输的msg个数为1 */ -ret = SpiTransfer(spiHandle, &msg, 1); -if (ret != 0) { - HDF_LOGE("SpiTransfer: failed, ret %d\n", ret); -} -``` + ``` + int32_t SpiWrite(DevHandle handle, uint8_t *buf, uint32_t len); + ``` + + **表5** SpiWrite参数和返回值描述 + + | **参数** | **参数描述** | + | -------- | -------- | + | handle | SPI设备句柄 | + | buf | 待写入数据的指针 | + | len | 待写入的数据长度 | + | **返回值** | **返回值描述** | + | 0 | 写入成功 | + | 负数 | 写入失败 | + + + ``` + int32_t ret; + uint8_t wbuff[4] = {0x12, 0x34, 0x56, 0x78}; + /* 向SPI设备写入指定长度的数据 */ + ret = SpiWrite(spiHandle, wbuff, 4); + if (ret != 0) { + HDF_LOGE("SpiWrite: failed, ret %d\n", ret); + } + ``` + +- 从SPI设备读取指定长度的数据 + + 如果只读取一次数据,则可以通过以下函数完成: -### 销毁SPI设备句柄 + + ``` + int32_t SpiRead(DevHandle handle, uint8_t *buf, uint32_t len); + ``` + + **表6** SpiRead参数和返回值描述 + + | **参数** | **参数描述** | + | -------- | -------- | + | handle | SPI设备句柄 | + | buf | 待读取数据的指针 | + | len | 待读取的数据长度 | + | **返回值** | **返回值描述** | + | 0 | 读取成功 | + | 负数 | 读取失败 | + + + ``` + int32_t ret; + uint8_t rbuff[4] = {0}; + /* 从SPI设备读取指定长度的数据 */ + ret = SpiRead(spiHandle, rbuff, 4); + if (ret != 0) { + HDF_LOGE("SpiRead: failed, ret %d\n", ret); + } + ``` + +- 自定义传输 + + 如果需要发起一次自定义传输,则可以通过以下函数完成: + + + ``` + int32_t SpiTransfer(DevHandle handle, struct SpiMsg *msgs, uint32_t count); + ``` + + **表7** SpiTransfer参数和返回值描述 + + | **参数** | **参数描述** | + | -------- | -------- | + | handle | SPI设备句柄 | + | msgs | 待传输数据的数组 | + | count | msgs数组长度 | + | **返回值** | **返回值描述** | + | 0 | 执行成功 | + | 负数 | 执行失败 | + + + ``` + int32_t ret; + uint8_t wbuff[1] = {0x12}; + uint8_t rbuff[1] = {0}; + struct SpiMsg msg; /* 自定义传输的消息*/ + msg.wbuf = wbuff; /* 写入的数据 */ + msg.rbuf = rbuff; /* 读取的数据 */ + msg.len = 1; /* 读取、写入数据的长度都是1 */ + msg.csChange = 1; /* 进行下一次传输前关闭片选 */ + msg.delayUs = 0; /* 进行下一次传输前不进行延时 */ + msg.speed = 115200; /* 本次传输的速度 */ + /* 进行一次自定义传输,传输的msg个数为1 */ + ret = SpiTransfer(spiHandle, &msg, 1); + if (ret != 0) { + HDF_LOGE("SpiTransfer: failed, ret %d\n", ret); + } + ``` + + +### 销毁SPI设备句柄 SPI通信完成之后,需要销毁SPI设备句柄,销毁SPI设备句柄的函数如下所示: -void SpiClose\(DevHandle handle\); + +``` +void SpiClose(DevHandle handle); +``` 该函数会释放掉申请的资源。 -**表 8** SpiClose参数描述 - - - - - - - - - -

参数

-

参数描述

-

handle

-

SPI设备句柄

-
+ **表8** SpiClose参数描述 + +| **参数** | **参数描述** | +| -------- | -------- | +| handle | SPI设备句柄 | + ``` SpiClose(spiHandle); /* 销毁SPI设备句柄 */ ``` -## 使用实例 -SPI设备完整的使用示例如下所示,首先获取SPI设备句柄,然后配置SPI设备属性,接着调用读写接口进行数据传输,最后销毁SPI设备句柄。 +## 使用实例 + + SPI设备完整的使用示例如下所示,首先获取SPI设备句柄,然后配置SPI设备属性,接着调用读写接口进行数据传输,最后销毁SPI设备句柄。 ``` #include "hdf_log.h" @@ -558,4 +362,3 @@ err: SpiClose(spiHandle); } ``` - diff --git a/zh-cn/device-dev/driver/driver-platform-spi-develop.md b/zh-cn/device-dev/driver/driver-platform-spi-develop.md index ee6ad7d952ae0e72f370fe578982311f9a08bfdf..ec8226d368b81ad72fe68dee0bc2fa0bc4d4d55a 100755 --- a/zh-cn/device-dev/driver/driver-platform-spi-develop.md +++ b/zh-cn/device-dev/driver/driver-platform-spi-develop.md @@ -1,21 +1,20 @@ -# SPI +# SPI -- [概述](#section84922229152909) -- [接口说明](#section752964871810) -- [开发步骤](#section799667984152909) -- [开发实例](#section956157227152909) -## 概述 +## 概述 SPI即串行外设接口(Serial Peripheral Interface),在HDF框架中,SPI的接口适配模式采用独立服务模式,在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。独立服务模式可以直接借助HDFDeviceManager的服务管理能力,但需要为每个设备单独配置设备节点,增加内存占用。 -**图 1** SPI独立服务模式结构图 -![](figures/独立服务模式结构图.png "SPI独立服务模式结构图") + **图1** SPI独立服务模式结构图 -## 接口说明 + ![zh-cn_image_0000001176603992](figures/zh-cn_image_0000001176603992.png) + + +## 接口说明 SpiCntlrMethod定义: + ``` struct SpiCntlrMethod { int32_t (*GetCfg)(struct SpiCntlr *cntlr, struct SpiCfg *cfg); @@ -26,424 +25,340 @@ struct SpiCntlrMethod { }; ``` -**表 1** SpiCntlrMethod结构体成员的回调函数功能说明 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

成员函数

-

入参

-

返回值

-

功能

-

Transfer

-

cntlr:结构体指针,核心层spi控制器;
msg:结构体指针,Spi消息;
count:uint32_t,消息个数;

-

HDF_STATUS相关状态

-

传输消息

-

SetCfg

-

cntlr;结构体指针,核心层spi控制器;
cfg:结构体指针,Spi属性;

-

HDF_STATUS相关状态

-

设置控制器属性

-

GetCfg

-

cntlr:结构体指针,核心层spi控制器;
cfg:结构体指针,Spi属性;

-

HDF_STATUS相关状态

-

获取控制器属性

-

Open

-

cntlr:结构体指针,核心层spi控制器;

-

HDF_STATUS相关状态

-

打开SPI

-

Close

-

cntlr:结构体指针,核心层spi控制器;

-

HDF_STATUS相关状态

-

关闭SPI

-
- -## 开发步骤 + **表1** SpiCntlrMethod结构体成员的回调函数功能说明 + +| 成员函数 | 入参 | 返回值 | 功能 | +| -------- | -------- | -------- | -------- | +| Transfer | cntlr:结构体指针,核心层spi控制器。
msg:结构体指针,Spi消息。
count:uint32_t,消息个数。 | HDF_STATUS相关状态 | 传输消息 | +| SetCfg | cntlr:结构体指针,核心层spi控制器。
cfg:结构体指针,Spi属性。 | HDF_STATUS相关状态 | 设置控制器属性 | +| GetCfg | cntlr:结构体指针,核心层spi控制器。
cfg:结构体指针,Spi属性。 | HDF_STATUS相关状态 | 获取控制器属性 | +| Open | cntlr:结构体指针,核心层spi控制器。 | HDF_STATUS相关状态 | 打开SPI | +| Close | cntlr:结构体指针,核心层spi控制器。 | HDF_STATUS相关状态 | 关闭SPI | + + +## 开发步骤 SPI模块适配HDF框架的三个环节是配置属性文件,实例化驱动入口,以及实例化核心层接口函数。 -1. **实例化驱动入口:** - - 实例化HdfDriverEntry结构体成员。 - - 调用HDF\_INIT将HdfDriverEntry实例化对象注册到HDF框架中。 - -2. **配置属性文件:** - - 在device\_info.hcs文件中添加deviceNode描述。 - - 【可选】添加spi\_config.hcs器件属性文件。 - -3. **实例化SPI控制器对象:** - - 初始化SpiCntlr成员。 - - 实例化SpiCntlr成员SpiCntlrMethod。 - - >![](../public_sys-resources/icon-note.gif) **说明:** - >实例化SpiCntlr成员SpiCntlrMethod,其定义和成员说明见[接口说明](#section752964871810)。 - - -4. **驱动调试:** - - 【可选】针对新增驱动程序,建议验证驱动基本功能,例如spi控制状态,中断响应情况等。 - - -## 开发实例 - -下方将以spi\_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。 - -1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf\_device\_desc.h 中定义)类型的全局变量,且moduleName要和device\_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。 - - 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 - - SPI驱动入口参考: - - ``` - struct HdfDriverEntry g_hdfSpiDevice = { - .moduleVersion = 1, - .moduleName = "HDF_PLATFORM_SPI",//【必要 且与 HCS文件中里面的moduleName匹配】 - .Bind = HdfSpiDeviceBind, //见Bind参考 - .Init = HdfSpiDeviceInit, //见Init参考 - .Release = HdfSpiDeviceRelease, //见Release参考 - }; - //调用HDF_INIT将驱动入口注册到HDF框架中 - HDF_INIT(g_hdfSpiDevice); - ``` - -2. 完成驱动入口注册之后,下一步请在device\_info.hcs文件中添加deviceNode信息,并在 spi\_config.hcs 中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值与核心层SpiCntlr 成员的默认值或限制范围有密切关系。 - - 本例只有一个SPI控制器,如有多个器件信息,则需要在device\_info文件增加deviceNode信息,以及在spi\_config文件中增加对应的器件属性。 - - - device\_info.hcs 配置参考。 - - ``` - root { - device_info { - match_attr = "hdf_manager"; - platform :: host { - hostName = "platform_host"; - priority = 50; - device_spi :: device { //为每一个 SPI 控制器配置一个HDF设备节点 - device0 :: deviceNode { - policy = 1; - priority = 60; - permission = 0644; - moduleName = "HDF_PLATFORM_SPI"; - serviceName = "HDF_PLATFORM_SPI_0"; - deviceMatchAttr = "hisilicon_hi35xx_spi_0"; - } - device1 :: deviceNode { - policy = 1; - priority = 60; - permission = 0644; - moduleName = "HDF_PLATFORM_SPI"; // 【必要】用于指定驱动名称,该字段的值必须和驱动入口结构的moduleName值一致 - serviceName = "HDF_PLATFORM_SPI_1"; // 【必要且唯一】驱动对外发布服务的名称 - deviceMatchAttr = "hisilicon_hi35xx_spi_1";// 需要与设备hcs文件中的 match_attr 匹配 - } - ... - } - } - } - } - ``` - - - spi\_config.hcs 配置参考。 - - ``` - root { - platform { - spi_config {//每一个SPI控制器配置私有数据 - template spi_controller {//模板公共参数, 继承该模板的节点如果使用模板中的默认值, 则节点字段可以缺省 - serviceName = ""; - match_attr = ""; - transferMode = 0; // 数据传输模式:中断传输(0),流控传输(1),DMA传输(2) - busNum = 0; // 总线号 - clkRate = 100000000; - bitsPerWord = 8; // 传输位宽 - mode = 19; // SPI 数据的输入输出模式 - maxSpeedHz = 0; // 最大时钟频率 - minSpeedHz = 0; // 最小时钟频率 - speed = 2000000; // 当前消息传输速度 - fifoSize = 256; // FIFO大小 - numCs = 1; // 片选号 - regBase = 0x120c0000; // 地址映射需要 - irqNum = 100; // 中断号 - REG_CRG_SPI = 0x120100e4; // CRG_REG_BASE(0x12010000) + 0x0e4 - CRG_SPI_CKEN = 0; - CRG_SPI_RST = 0; - REG_MISC_CTRL_SPI = 0x12030024; // MISC_REG_BASE(0x12030000) + 0x24 - MISC_CTRL_SPI_CS = 0; - MISC_CTRL_SPI_CS_SHIFT = 0; - } - controller_0x120c0000 :: spi_controller { - busNum = 0; //【必要】总线号 - CRG_SPI_CKEN = 0x10000; // (0x1 << 16) 0:close clk, 1:open clk - CRG_SPI_RST = 0x1; // (0x1 << 0) 0:cancel reset, 1:reset - match_attr = "hisilicon_hi35xx_spi_0";//【必要】需要和device_info.hcs中的deviceMatchAttr值一致 - } - controller_0x120c1000 :: spi_controller { - busNum = 1; - CRG_SPI_CKEN = 0x20000; // (0x1 << 17) 0:close clk, 1:open clk - CRG_SPI_RST = 0x2; // (0x1 << 1) 0:cancel reset, 1:reset - match_attr = "hisilicon_hi35xx_spi_1"; - regBase = 0x120c1000; //【必要】地址映射需要 - irqNum = 101; //【必要】中断号 - } - ... - // 【可选】可新增,但需要在 device_info.hcs 添加对应的节点 - } - } - } - ``` - -3. 完成驱动入口注册之后,最后一步就是以核心层SpiCntlr对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化SpiCntlr成员SpiCntlrMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。 - - 自定义结构体参考。 - - 从驱动的角度看,自定义结构体是参数和数据的载体,而且spi\_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,一些重要数值也会传递给核心层对象,例如设备号、总线号等。 - - ``` - struct Pl022 {//对应于hcs中的参数 - struct SpiCntlr *cntlr; - struct DListHead deviceList; - struct OsalSem sem; - volatile unsigned char *phyBase; - volatile unsigned char *regBase; - uint32_t irqNum; - uint32_t busNum; - uint32_t numCs; - uint32_t curCs; - uint32_t speed; - uint32_t fifoSize; - uint32_t clkRate; - uint32_t maxSpeedHz; - uint32_t minSpeedHz; - uint32_t regCrg; - uint32_t clkEnBit; - uint32_t clkRstBit; - uint32_t regMiscCtrl; - uint32_t miscCtrlCsShift; - uint32_t miscCtrlCs; - uint16_t mode; - uint8_t bitsPerWord; - uint8_t transferMode; - }; - - //SpiCntlr是核心层控制器结构体,其中的成员在Init函数中会被赋值 - struct SpiCntlr { - struct IDeviceIoService service; - struct HdfDeviceObject *device; - uint32_t busNum; - uint32_t numCs; - uint32_t curCs; - struct OsalMutex lock; - struct SpiCntlrMethod *method; - struct DListHead list; - void *priv; - }; - ``` - - - SpiCntlr成员回调函数结构体SpiCntlrMethod的实例化,其他成员在Init函数中初始化。 - - ``` - // spi_hi35xx.c 中的示例:钩子函数的实例化 - struct SpiCntlrMethod g_method = { - .Transfer = Pl022Transfer, - .SetCfg = Pl022SetCfg, - .GetCfg = Pl022GetCfg, - .Open = Pl022Open, - .Close = Pl022Close, - }; - ``` - - - Bind 函数参考 - - 入参: - - HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 - - 返回值: - - HDF\_STATUS相关状态。 - - 函数说明: - - 将 SpiCntlr 对象同 HdfDeviceObject 进行了关联。 - - ``` - static int32_t HdfSpiDeviceBind(struct HdfDeviceObject *device) - { - ... - return (SpiCntlrCreate(device) == NULL) ? HDF_FAILURE : HDF_SUCCESS; - } +1. **实例化驱动入口:** + - 实例化HdfDriverEntry结构体成员。 + - 调用HDF_INIT将HdfDriverEntry实例化对象注册到HDF框架中。 + +2. **配置属性文件:** + - 在device_info.hcs文件中添加deviceNode描述。 + - 【可选】添加spi_config.hcs器件属性文件。 + +3. **实例化SPI控制器对象:** + - 初始化SpiCntlr成员。 + - 实例化SpiCntlr成员SpiCntlrMethod。 + > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** + > 实例化SpiCntlr成员SpiCntlrMethod,其定义和成员说明见[接口说明](#接口说明)。 + +4. **驱动调试:** + 【可选】针对新增驱动程序,建议验证驱动基本功能,例如spi控制状态,中断响应情况等。 + + +## 开发实例 + +下方将以spi_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。 + +1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf_device_desc.h 中定义)类型的全局变量,且moduleName要和device_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。 + 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 + + SPI驱动入口参考: + + ``` + struct HdfDriverEntry g_hdfSpiDevice = { + .moduleVersion = 1, + .moduleName = "HDF_PLATFORM_SPI",//【必要 且与 HCS文件中里面的moduleName匹配】 + .Bind = HdfSpiDeviceBind, //见Bind参考 + .Init = HdfSpiDeviceInit, //见Init参考 + .Release = HdfSpiDeviceRelease, //见Release参考 + }; + //调用HDF_INIT将驱动入口注册到HDF框架中 + HDF_INIT(g_hdfSpiDevice); + ``` + +2. 完成驱动入口注册之后,下一步请在device_info.hcs文件中添加deviceNode信息,并在 spi_config.hcs 中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值与核心层SpiCntlr 成员的默认值或限制范围有密切关系。 + 本例只有一个SPI控制器,如有多个器件信息,则需要在device_info文件增加deviceNode信息,以及在spi_config文件中增加对应的器件属性。 + - device_info.hcs 配置参考。 + + + ``` + root { + device_info { + match_attr = "hdf_manager"; + platform :: host { + hostName = "platform_host"; + priority = 50; + device_spi :: device { //为每一个 SPI 控制器配置一个HDF设备节点 + device0 :: deviceNode { + policy = 1; + priority = 60; + permission = 0644; + moduleName = "HDF_PLATFORM_SPI"; + serviceName = "HDF_PLATFORM_SPI_0"; + deviceMatchAttr = "hisilicon_hi35xx_spi_0"; + } + device1 :: deviceNode { + policy = 1; + priority = 60; + permission = 0644; + moduleName = "HDF_PLATFORM_SPI"; // 【必要】用于指定驱动名称,该字段的值必须和驱动入口结构的moduleName值一致 + serviceName = "HDF_PLATFORM_SPI_1"; // 【必要且唯一】驱动对外发布服务的名称 + deviceMatchAttr = "hisilicon_hi35xx_spi_1";// 需要与设备hcs文件中的 match_attr 匹配 + } + ... + } + } + } + } + ``` + + - spi_config.hcs 配置参考。 + + + ``` + root { + platform { + spi_config {//每一个SPI控制器配置私有数据 + template spi_controller {//模板公共参数, 继承该模板的节点如果使用模板中的默认值, 则节点字段可以缺省 + serviceName = ""; + match_attr = ""; + transferMode = 0; // 数据传输模式:中断传输(0),流控传输(1),DMA传输(2) + busNum = 0; // 总线号 + clkRate = 100000000; + bitsPerWord = 8; // 传输位宽 + mode = 19; // SPI 数据的输入输出模式 + maxSpeedHz = 0; // 最大时钟频率 + minSpeedHz = 0; // 最小时钟频率 + speed = 2000000; // 当前消息传输速度 + fifoSize = 256; // FIFO大小 + numCs = 1; // 片选号 + regBase = 0x120c0000; // 地址映射需要 + irqNum = 100; // 中断号 + REG_CRG_SPI = 0x120100e4; // CRG_REG_BASE(0x12010000) + 0x0e4 + CRG_SPI_CKEN = 0; + CRG_SPI_RST = 0; + REG_MISC_CTRL_SPI = 0x12030024; // MISC_REG_BASE(0x12030000) + 0x24 + MISC_CTRL_SPI_CS = 0; + MISC_CTRL_SPI_CS_SHIFT = 0; + } + controller_0x120c0000 :: spi_controller { + busNum = 0; //【必要】总线号 + CRG_SPI_CKEN = 0x10000; // (0x1 << 16) 0:close clk, 1:open clk + CRG_SPI_RST = 0x1; // (0x1 << 0) 0:cancel reset, 1:reset + match_attr = "hisilicon_hi35xx_spi_0";//【必要】需要和device_info.hcs中的deviceMatchAttr值一致 + } + controller_0x120c1000 :: spi_controller { + busNum = 1; + CRG_SPI_CKEN = 0x20000; // (0x1 << 17) 0:close clk, 1:open clk + CRG_SPI_RST = 0x2; // (0x1 << 1) 0:cancel reset, 1:reset + match_attr = "hisilicon_hi35xx_spi_1"; + regBase = 0x120c1000; //【必要】地址映射需要 + irqNum = 101; //【必要】中断号 + } + ... + // 【可选】可新增,但需要在 device_info.hcs 添加对应的节点 + } + } + } + ``` + +3. 完成驱动入口注册之后,最后一步就是以核心层SpiCntlr对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化SpiCntlr成员SpiCntlrMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。 + - 自定义结构体参考。 + + 从驱动的角度看,自定义结构体是参数和数据的载体,而且spi_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,一些重要数值也会传递给核心层对象,例如设备号、总线号等。 + - struct SpiCntlr *SpiCntlrCreate(struct HdfDeviceObject *device) - { - struct SpiCntlr *cntlr = NULL; //创建核心层 SpiCntlr 对象 - ... - cntlr = (struct SpiCntlr *)OsalMemCalloc(sizeof(*cntlr));//分配内存 - ... - cntlr->device = device; //使HdfDeviceObject与SpiCntlr可以相互转化的前提 - device->service = &(cntlr->service);//使HdfDeviceObject与SpiCntlr可以相互转化的前提 - (void)OsalMutexInit(&cntlr->lock); //锁初始化 - DListHeadInit(&cntlr->list); //添加对应的节点 - cntlr->priv = NULL; - return cntlr; - } - ``` - - - Init函数参考 - - 入参: - - HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 - - 返回值: - - HDF\_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见/drivers/framework/include/utils/hdf\_base.h中HDF\_STATUS 定义)。 - - **表 2** init函数入参和返回值 - - - - - - - - - - - - - - - - - - - - - - - - - -

状态(值)

-

问题描述

-

HDF_ERR_INVALID_OBJECT

-

控制器对象非法

-

HDF_ERR_MALLOC_FAIL

-

内存分配失败

-

HDF_ERR_INVALID_PARAM

-

参数非法

-

HDF_ERR_IO

-

I/O 错误

-

HDF_SUCCESS

-

初始化成功

-

HDF_FAILURE

-

初始化失败

-
- - 函数说明: - - 初始化自定义结构体对象,初始化SpiCntlr成员。 - - ``` - static int32_t HdfSpiDeviceInit(struct HdfDeviceObject *device) - { - int32_t ret; - struct SpiCntlr *cntlr = NULL; - ... - cntlr = SpiCntlrFromDevice(device);//这里有HdfDeviceObject到SpiCntlr的强制转化,通过service成员,赋值见Bind函数 - //return (device == NULL) ? NULL : (struct SpiCntlr *)device->service; - ... - ret = Pl022Init(cntlr, device);//【必要】实例化厂商自定义操作对象,示例见下 - ... - ret = Pl022Probe(cntlr->priv); - ... - return ret; - } + ``` + struct Pl022 {//对应于hcs中的参数 + struct SpiCntlr *cntlr; + struct DListHead deviceList; + struct OsalSem sem; + volatile unsigned char *phyBase; + volatile unsigned char *regBase; + uint32_t irqNum; + uint32_t busNum; + uint32_t numCs; + uint32_t curCs; + uint32_t speed; + uint32_t fifoSize; + uint32_t clkRate; + uint32_t maxSpeedHz; + uint32_t minSpeedHz; + uint32_t regCrg; + uint32_t clkEnBit; + uint32_t clkRstBit; + uint32_t regMiscCtrl; + uint32_t miscCtrlCsShift; + uint32_t miscCtrlCs; + uint16_t mode; + uint8_t bitsPerWord; + uint8_t transferMode; + }; + + //SpiCntlr是核心层控制器结构体,其中的成员在Init函数中会被赋值 + struct SpiCntlr { + struct IDeviceIoService service; + struct HdfDeviceObject *device; + uint32_t busNum; + uint32_t numCs; + uint32_t curCs; + struct OsalMutex lock; + struct SpiCntlrMethod *method; + struct DListHead list; + void *priv; + }; + ``` + + - SpiCntlr成员回调函数结构体SpiCntlrMethod的实例化,其他成员在Init函数中初始化。 + - static int32_t Pl022Init(struct SpiCntlr *cntlr, const struct HdfDeviceObject *device) - { - int32_t ret; - struct Pl022 *pl022 = NULL; - ... - pl022 = (struct Pl022 *)OsalMemCalloc(sizeof(*pl022));//申请内存 - ... - ret = SpiGetBaseCfgFromHcs(pl022, device->property); //初始化busNum, numCs, speed, fifoSize, clkRate,mode, bitsPerWord, transferMode参数值 - ... - ret = SpiGetRegCfgFromHcs(pl022, device->property); //初始化regBase, phyBase, irqNum, regCrg, clkEnBit,clkRstBit, regMiscCtrl, regMiscCtrl, miscCtrlCs,miscCtrlCsShift参数值 - ... - //计算最大,最小速度对应的频率 - pl022->maxSpeedHz = (pl022->clkRate) / ((SCR_MIN + 1) * CPSDVSR_MIN); - pl022->minSpeedHz = (pl022->clkRate) / ((SCR_MAX + 1) * CPSDVSR_MAX); - DListHeadInit(&pl022->deviceList);//初始化DList链表 - pl022->cntlr = cntlr; //使Pl022与SpiCntlr可以相互转化的前提 - cntlr->priv = pl022; //使Pl022与SpiCntlr可以相互转化的前提 - cntlr->busNum = pl022->busNum; //给SpiCntlr的busNum赋值 - cntlr->method = &g_method; //SpiCntlrMethod的实例化对象的挂载 - ... - ret = Pl022CreatAndInitDevice(pl022); - if (ret != 0) { - Pl022Release(pl022); //初始化失败就释放Pl022对象 - return ret; - } - return 0; - } - ``` - - - Release函数参考 - - 入参: - - HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 - - 返回值: - - 无。 - - 函数说明: - - 释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源。所有强制转换获取相应对象的操作**前提**是在Init函数中具备对应赋值的操作。 - - ``` - static void HdfSpiDeviceRelease(struct HdfDeviceObject *device) - { - struct SpiCntlr *cntlr = NULL; - ... - cntlr = SpiCntlrFromDevice(device);//这里有HdfDeviceObject到SpiCntlr的强制转化,通过service成员,赋值见Bind函数 - // return (device==NULL) ?NULL:(struct SpiCntlr *)device->service; - ... - if (cntlr->priv != NULL) { - Pl022Remove((struct Pl022 *)cntlr->priv);//这里有SpiCntlr到Pl022的强制转化 - } - SpiCntlrDestroy(cntlr); //释放Pl022对象 - } - ``` + ``` + // spi_hi35xx.c 中的示例:钩子函数的实例化 + struct SpiCntlrMethod g_method = { + .Transfer = Pl022Transfer, + .SetCfg = Pl022SetCfg, + .GetCfg = Pl022GetCfg, + .Open = Pl022Open, + .Close = Pl022Close, + }; + ``` + + - Bind 函数参考 + 入参: + HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 + 返回值: + + HDF_STATUS相关状态。 + + 函数说明: + + 将 SpiCntlr 对象同 HdfDeviceObject 进行了关联。 + + + ``` + static int32_t HdfSpiDeviceBind(struct HdfDeviceObject *device) + { + ... + return (SpiCntlrCreate(device) == NULL) ? HDF_FAILURE : HDF_SUCCESS; + } + + struct SpiCntlr *SpiCntlrCreate(struct HdfDeviceObject *device) + { + struct SpiCntlr *cntlr = NULL; //创建核心层 SpiCntlr 对象 + ... + cntlr = (struct SpiCntlr *)OsalMemCalloc(sizeof(*cntlr));//分配内存 + ... + cntlr->device = device; //使HdfDeviceObject与SpiCntlr可以相互转化的前提 + device->service = &(cntlr->service);//使HdfDeviceObject与SpiCntlr可以相互转化的前提 + (void)OsalMutexInit(&cntlr->lock); //锁初始化 + DListHeadInit(&cntlr->list); //添加对应的节点 + cntlr->priv = NULL; + return cntlr; + } + ``` + + - Init函数参考 + + 入参: + + HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 + + 返回值: + + HDF_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf_base.h中HDF_STATUS 定义)。 + + **表2** Init函数入参和返回值 + + | 状态(值) | 问题描述 | + | -------- | -------- | + | HDF_ERR_INVALID_OBJECT | 控制器对象非法 | + | HDF_ERR_MALLOC_FAIL | 内存分配失败 | + | HDF_ERR_INVALID_PARAM | 参数非法 | + | HDF_ERR_IO | I/O 错误 | + | HDF_SUCCESS | 初始化成功 | + | HDF_FAILURE | 初始化失败 | + + 函数说明: + + 初始化自定义结构体对象,初始化SpiCntlr成员。 + + + ``` + static int32_t HdfSpiDeviceInit(struct HdfDeviceObject *device) + { + int32_t ret; + struct SpiCntlr *cntlr = NULL; + ... + cntlr = SpiCntlrFromDevice(device);//这里有HdfDeviceObject到SpiCntlr的强制转化,通过service成员,赋值见Bind函数 + //return (device == NULL) ? NULL : (struct SpiCntlr *)device->service; + ... + ret = Pl022Init(cntlr, device);//【必要】实例化厂商自定义操作对象,示例见下 + ... + ret = Pl022Probe(cntlr->priv); + ... + return ret; + } + + static int32_t Pl022Init(struct SpiCntlr *cntlr, const struct HdfDeviceObject *device) + { + int32_t ret; + struct Pl022 *pl022 = NULL; + ... + pl022 = (struct Pl022 *)OsalMemCalloc(sizeof(*pl022));//申请内存 + ... + ret = SpiGetBaseCfgFromHcs(pl022, device->property); //初始化busNum, numCs, speed, fifoSize, clkRate,mode, bitsPerWord, transferMode参数值 + ... + ret = SpiGetRegCfgFromHcs(pl022, device->property); //初始化regBase, phyBase, irqNum, regCrg, clkEnBit,clkRstBit, regMiscCtrl, regMiscCtrl, miscCtrlCs,miscCtrlCsShift参数值 + ... + //计算最大,最小速度对应的频率 + pl022->maxSpeedHz = (pl022->clkRate) / ((SCR_MIN + 1) * CPSDVSR_MIN); + pl022->minSpeedHz = (pl022->clkRate) / ((SCR_MAX + 1) * CPSDVSR_MAX); + DListHeadInit(&pl022->deviceList);//初始化DList链表 + pl022->cntlr = cntlr; //使Pl022与SpiCntlr可以相互转化的前提 + cntlr->priv = pl022; //使Pl022与SpiCntlr可以相互转化的前提 + cntlr->busNum = pl022->busNum; //给SpiCntlr的busNum赋值 + cntlr->method = &g_method; //SpiCntlrMethod的实例化对象的挂载 + ... + ret = Pl022CreatAndInitDevice(pl022); + if (ret != 0) { + Pl022Release(pl022); //初始化失败就释放Pl022对象 + return ret; + } + return 0; + } + ``` + - Release函数参考 + + 入参: + + HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 + + 返回值: + + 无。 + + 函数说明: + + 释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源。所有强制转换获取相应对象的操作**前提**是在Init函数中具备对应赋值的操作。 + + + ``` + static void HdfSpiDeviceRelease(struct HdfDeviceObject *device) + { + struct SpiCntlr *cntlr = NULL; + ... + cntlr = SpiCntlrFromDevice(device);//这里有HdfDeviceObject到SpiCntlr的强制转化,通过service成员,赋值见Bind函数 + // return (device==NULL) ?NULL:(struct SpiCntlr *)device->service; + ... + if (cntlr->priv != NULL) { + Pl022Remove((struct Pl022 *)cntlr->priv);//这里有SpiCntlr到Pl022的强制转化 + } + SpiCntlrDestroy(cntlr); //释放Pl022对象 + } + ``` diff --git a/zh-cn/device-dev/driver/driver-platform-uart-des.md b/zh-cn/device-dev/driver/driver-platform-uart-des.md index d094332869782c3d4bf9ec999fe44327939d19a8..3c4ecf3466a2a34a13f7bb2783f45d15334b4dc7 100644 --- a/zh-cn/device-dev/driver/driver-platform-uart-des.md +++ b/zh-cn/device-dev/driver/driver-platform-uart-des.md @@ -1,167 +1,79 @@ -# UART - -- [概述](#section833012453535) -- [接口说明](#section1928742202715) -- [使用指导](#section12779050105412) - - [使用流程](#section1858116395510) - - [获取UART设备句柄](#section124512065617) - - [UART设置波特率](#section86881004579) - - [UART获取波特率](#section897032965712) - - [UART设置设备属性](#section129141884588) - - [UART获取设备属性](#section18689637165812) - - [设置UART传输模式](#section72713435918) - - [向UART设备写入指定长度的数据](#section128001736155919) - - [从UART设备中读取指定长度的数据](#section92851601604) - - [销毁UART设备句柄](#section1477410521406) - -- [使用实例](#section35404241311) - -## 概述 - -- UART是通用异步收发传输器(Universal Asynchronous Receiver/Transmitter)的缩写,是通用串行数据总线,用于异步通信。该总线双向通信,可以实现全双工传输。 -- UART应用比较广泛,常用于输出打印信息,也可以外接各种模块,如GPS、蓝牙等。 -- 两个UART设备的连接示意图如下,UART与其他模块一般用2线(图1)或4线(图2)相连,它们分别是: - - TX:发送数据端,和对端的RX相连; - - RX:接收数据端,和对端的TX相连; - - RTS:发送请求信号,用于指示本设备是否准备好,可接受数据,和对端CTS相连; - - CTS:允许发送信号,用于判断是否可以向对端发送数据,和对端RTS相连; - - **图 1** 2线UART设备连接示意图 - ![](figures/2线UART设备连接示意图.png "2线UART设备连接示意图") - - **图 2** 4线UART设备连接示意图 - ![](figures/4线UART设备连接示意图.png "4线UART设备连接示意图") - - -- UART通信之前,收发双方需要约定好一些参数:波特率、数据格式(起始位、数据位、校验位、停止位)等。通信过程中,UART通过TX发送给对端数据,通过RX接收对端发送的数据。当UART接收缓存达到预定的门限值时,RTS变为不可发送数据,对端的CTS检测到不可发送数据,则停止发送数据。 -- UART接口定义了操作UART端口的通用方法集合,包括获取、释放设备句柄、读写数据、获取和设置波特率、获取和设置设备属性。 - -## 接口说明 - -**表 1** UART驱动API接口功能介绍 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

功能分类

-

接口名

-

描述

-

UART获取/释放设备句柄

-

-

UartOpen

-

UART获取设备句柄

-

UartClose

-

UART释放设备句柄

-

UART读写接口

-

-

UartRead

-

从UART设备中读取指定长度的数据

-

UartWrite

-

向UART设备中写入指定长度的数据

-

UART获取/设置波特率接口

-

UartGetBaud

-

UART获取波特率

-

UartSetBaud

-

UART设置波特率

-

UART获取/设置设备属性

-

-

UartGetAttribute

-

UART获取设备属性

-

UartSetAttribute

-

UART设置设备属性

-

UART设置传输模式

-

UartSetTransMode

-

UART设置传输模式

-
- ->![](../public_sys-resources/icon-note.gif) **说明:** ->本文涉及的所有接口,仅限内核态使用,不支持在用户态使用。 - -## 使用指导 - -### 使用流程 - -使用UART的一般流程如[图3](#fig99673244388)所示。 - -**图 3** UART使用流程图 -![](figures/UART使用流程图.png "UART使用流程图") - -### 获取UART设备句柄 +# UART + + +## 概述 + +- UART是通用异步收发传输器(Universal Asynchronous Receiver/Transmitter)的缩写,是通用串行数据总线,用于异步通信。该总线双向通信,可以实现全双工传输。 + +- UART应用比较广泛,常用于输出打印信息,也可以外接各种模块,如GPS、蓝牙等。 + +- 两个UART设备的连接示意图如下,UART与其他模块一般用2线(图1)或4线(图2)相连,它们分别是: + - TX:发送数据端,和对端的RX相连; + - RX:接收数据端,和对端的TX相连; + - RTS:发送请求信号,用于指示本设备是否准备好,可接受数据,和对端CTS相连; + - CTS:允许发送信号,用于判断是否可以向对端发送数据,和对端RTS相连; + + **图1** 2线UART设备连接示意图 + + ![zh-cn_image_0000001160812804](figures/zh-cn_image_0000001160812804.png) + + **图2** 4线UART设备连接示意图 + + ![zh-cn_image_0000001206372789](figures/zh-cn_image_0000001206372789.png) + +- UART通信之前,收发双方需要约定好一些参数:波特率、数据格式(起始位、数据位、校验位、停止位)等。通信过程中,UART通过TX发送给对端数据,通过RX接收对端发送的数据。当UART接收缓存达到预定的门限值时,RTS变为不可发送数据,对端的CTS检测到不可发送数据,则停止发送数据。 + +- UART接口定义了操作UART端口的通用方法集合,包括获取、释放设备句柄、读写数据、获取和设置波特率、获取和设置设备属性。 + + +## 接口说明 + + **表1** UART驱动API接口功能介绍 + +| 功能分类 | 接口名 | +| -------- | -------- | +| UART获取/释放设备句柄 | - UartOpen:UART获取设备句柄
- UartClose:UART释放设备句柄 | +| UART读写接口 | - UartRead:从UART设备中读取指定长度的数据
- UartWrite:向UART设备中写入指定长度的数据 | +| UART获取/设置波特率接口 | - UartGetBaud:UART获取波特率
- UartSetBaud:UART设置波特率 | +| UART获取/设置设备属性 | - UartGetAttribute:UART获取设备属性
- UartSetAttribute:UART设置设备属性 | +| UART设置传输模式 | UartSetTransMode:UART设置传输模式 | + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> 本文涉及的所有接口,仅限内核态使用,不支持在用户态使用。 + + +## 使用指导 + + +### 使用流程 + +使用UART的一般流程如下图所示。 + + **图3** UART使用流程图 + + ![zh-cn_image_0000001206092753](figures/zh-cn_image_0000001206092753.png) + + +### 获取UART设备句柄 在使用UART进行通信时,首先要调用UartOpen获取UART设备句柄,该函数会返回指定端口号的UART设备句柄。 -DevHandle UartOpen\(uint32\_t port\); - -**表 2** UartOpen参数和返回值描述 - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

port

-

UART设备号

-

返回值

-

返回值描述

-

NULL

-

获取UART设备句柄失败

-

设备句柄

-

UART设备句柄

-
- -假设系统中的UART端口号为3,获取该UART设备句柄的示例如下: + +``` +DevHandle UartOpen(uint32_t port); +``` + **表2** UartOpen参数和返回值描述 + +| 参数 | 参数描述 | +| -------- | -------- | +| port | UART设备号 | +| **返回值** | **返回值描述** | +| NULL | 获取UART设备句柄失败 | +| 设备句柄 | UART设备句柄 | + + 假设系统中的UART端口号为3,获取该UART设备句柄的示例如下: + ``` DevHandle handle = NULL; /* UART设备句柄 */ uint32_t port = 3; /* UART设备端口号 */ @@ -172,51 +84,29 @@ if (handle == NULL) { } ``` -### UART设置波特率 + +### UART设置波特率 在通信之前,需要设置UART的波特率,设置波特率的函数如下所示: -int32\_t UartSetBaud\(DevHandle handle, uint32\_t baudRate\); - -**表 3** UartSetBaud参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

UART设备句柄

-

baudRate

-

待设置的波特率值

-

返回值

-

返回值描述

-

0

-

UART设置波特率成功

-

负数

-

UART设置波特率失败

-
+ +``` +int32_t UartSetBaud(DevHandle handle, uint32_t baudRate); +``` + + **表3** UartSetBaud参数和返回值描述 + +| 参数 | 参数描述 | +| -------- | -------- | +| handle | UART设备句柄 | +| baudRate | 待设置的波特率值 | +| **返回值** | **返回值描述** | +| 0 | UART设置波特率成功 | +| 负数 | UART设置波特率失败 | 假设需要设置的UART波特率为9600,设置波特率的实例如下: + ``` int32_t ret; /* 设置UART波特率 */ @@ -226,51 +116,29 @@ if (ret != 0) { } ``` -### UART获取波特率 + +### UART获取波特率 设置UART的波特率后,可以通过获取波特率接口来查看UART当前的波特率,获取波特率的函数如下所示: -int32\_t UartGetBaud\(DevHandle handle, uint32\_t \*baudRate\); - -**表 4** UartGetBaud参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

UART设备句柄

-

baudRate

-

接收波特率值的指针

-

返回值

-

返回值描述

-

0

-

UART获取波特率成功

-

负数

-

UART获取波特率失败

-
+ +``` +int32_t UartGetBaud(DevHandle handle, uint32_t *baudRate); +``` + + **表4** UartGetBaud参数和返回值描述 + +| 参数 | 参数描述 | +| -------- | -------- | +| handle | UART设备句柄 | +| baudRate | 接收波特率值的指针 | +| **返回值** | **返回值描述** | +| 0 | UART获取波特率成功 | +| 负数 | UART获取波特率失败 | 获取波特率的实例如下: + ``` int32_t ret; uint32_t baudRate; @@ -281,51 +149,29 @@ if (ret != 0) { } ``` -### UART设置设备属性 + +### UART设置设备属性 在通信之前,需要设置UART的设备属性,设置设备属性的函数如下图所示: -int32\_t UartSetAttribute\(DevHandle handle, struct UartAttribute \*attribute\); - -**表 5** UartSetAttribute参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

UART设备句柄

-

attribute

-

待设置的设备属性

-

返回值

-

返回值描述

-

0

-

UART设置设备属性成功

-

负数

-

UART设置设备属性失败

-
+ +``` +int32_t UartSetAttribute(DevHandle handle, struct UartAttribute *attribute); +``` + + **表5** UartSetAttribute参数和返回值描述 + +| 参数 | 参数描述 | +| -------- | -------- | +| handle | UART设备句柄 | +| attribute | 待设置的设备属性 | +| **返回值** | **返回值描述** | +| 0 | UART设置设备属性成功 | +| 负数 | UART设置设备属性失败 | 设置UART的设备属性的实例如下: + ``` int32_t ret; struct UartAttribute attribute; @@ -343,51 +189,29 @@ if (ret != 0) { } ``` -### UART获取设备属性 + +### UART获取设备属性 设置UART的设备属性后,可以通过获取设备属性接口来查看UART当前的设备属性,获取设备属性的函数如下图所示: -int32\_t UartGetAttribute\(DevHandle handle, struct UartAttribute \*attribute\); - -**表 6** UartGetAttribute参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

UART设备句柄

-

attribute

-

接收UART设备属性的指针

-

返回值

-

返回值描述

-

0

-

UART获取设备属性成功

-

负数

-

UART获取设备属性失败

-
+ +``` +int32_t UartGetAttribute(DevHandle handle, struct UartAttribute *attribute); +``` + + **表6** UartGetAttribute参数和返回值描述 + +| 参数 | 参数描述 | +| -------- | -------- | +| handle | UART设备句柄 | +| attribute | 接收UART设备属性的指针 | +| **返回值** | **返回值描述** | +| 0 | UART获取设备属性成功 | +| 负数 | UART获取设备属性失败 | 获取UART的设备属性的实例如下: + ``` int32_t ret; struct UartAttribute attribute; @@ -398,51 +222,29 @@ if (ret != 0) { } ``` -### 设置UART传输模式 + +### 设置UART传输模式 在通信之前,需要设置UART的传输模式,设置传输模式的函数如下图所示: -int32\_t UartSetTransMode\(DevHandle handle, enum UartTransMode mode\); - -**表 7** UartSetTransMode参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

UART设备句柄

-

mode

-

待设置的传输模式,

-

返回值

-

返回值描述

-

0

-

UART设置传输模式成功

-

负数

-

UART设置传输模式失败

-
- -假设需要设置的UART传输模式为UART\_MODE\_RD\_BLOCK,设置传输模式的实例如下: + +``` +int32_t UartSetTransMode(DevHandle handle, enum UartTransMode mode); +``` + + **表7** UartSetTransMode参数和返回值描述 +| 参数 | 参数描述 | +| -------- | -------- | +| handle | UART设备句柄 | +| mode | 待设置的传输模式, | +| **返回值** | **返回值描述** | +| 0 | UART设置传输模式成功 | +| 负数 | UART设置传输模式失败 | + +假设需要设置的UART传输模式为UART_MODE_RD_BLOCK,设置传输模式的实例如下: + + ``` int32_t ret; /* 设置UART传输模式 */ @@ -452,56 +254,30 @@ if (ret != 0) { } ``` -### 向UART设备写入指定长度的数据 + +### 向UART设备写入指定长度的数据 对应的接口函数如下所示: -int32\_t UartWrite\(DevHandle handle, uint8\_t \*data, uint32\_t size\); - -**表 8** UartWrite参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

UART设备句柄

-

data

-

待写入数据的指针

-

size

-

待写入数据的长度

-

返回值

-

返回值描述

-

0

-

UART写数据成功

-

负数

-

UART写数据失败

-
+ +``` +int32_t UartWrite(DevHandle handle, uint8_t *data, uint32_t size); +``` + + **表8** UartWrite参数和返回值描述 + +| 参数 | 参数描述 | +| -------- | -------- | +| handle | UART设备句柄 | +| data | 待写入数据的指针 | +| size | 待写入数据的长度 | +| **返回值** | **返回值描述** | +| 0 | UART写数据成功 | +| 负数 | UART写数据失败 | 写入指定长度数据的实例如下: + ``` int32_t ret; uint8_t wbuff[5] = {1, 2, 3, 4, 5}; @@ -512,56 +288,30 @@ if (ret != 0) { } ``` -### 从UART设备中读取指定长度的数据 + +### 从UART设备中读取指定长度的数据 对应的接口函数如下所示: -int32\_t UartRead\(DevHandle handle, uint8\_t \*data, uint32\_t size\); - -**表 9** UartRead参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

UART设备句柄

-

data

-

接收读取数据的指针

-

size

-

待读取数据的长度

-

返回值

-

返回值描述

-

非负数

-

UART读取到的数据长度

-

负数

-

UART读取数据失败

-
+ +``` +int32_t UartRead(DevHandle handle, uint8_t *data, uint32_t size); +``` + + **表9** UartRead参数和返回值描述 + +| 参数 | 参数描述 | +| -------- | -------- | +| handle | UART设备句柄 | +| data | 接收读取数据的指针 | +| size | 待读取数据的长度 | +| **返回值** | **返回值描述** | +| 非负数 | UART读取到的数据长度 | +| 负数 | UART读取数据失败 | 读取指定长度数据的实例如下: + ``` int32_t ret; uint8_t rbuff[5] = {0}; @@ -572,44 +322,39 @@ if (ret < 0) { } ``` ->![](../public_sys-resources/icon-caution.gif) **注意:** ->UART返回值为非负值,表示UART读取成功。若返回值等于0,表示UART无有效数据可以读取。若返回值大于0,表示实际读取到的数据长度,该长度小于或等于传入的参数size的大小,并且不超过当前正在使用的UART控制器规定的最大单次读取数据长度的值。 +> ![icon-caution.gif](public_sys-resources/icon-caution.gif) **注意:** +> UART返回值为非负值,表示UART读取成功。若返回值等于0,表示UART无有效数据可以读取。若返回值大于0,表示实际读取到的数据长度,该长度小于或等于传入的参数size的大小,并且不超过当前正在使用的UART控制器规定的最大单次读取数据长度的值。 + -### 销毁UART设备句柄 +### 销毁UART设备句柄 UART通信完成之后,需要销毁UART设备句柄,函数如下所示: -void UartClose\(DevHandle handle\); + +``` +void UartClose(DevHandle handle); +``` 该函数会释放申请的资源。 -**表 10** UartClose参数和返回值描述 - - - - - - - - - - -

参数

-

参数描述

-

handle

-

UART设备句柄

-
+ **表10** UartClose参数和返回值描述 + +| 参数 | 参数描述 | +| -------- | -------- | +| handle | UART设备句柄 | 销毁UART设备句柄的实例如下: + ``` UartClose(handle); /* 销毁UART设备句柄 * ``` -## 使用实例 -UART设备完整的使用示例如下所示,首先获取UART设备句柄,接着设置波特率、设备属性和传输模式,之后进行UART通信,最后销毁UART设备句柄。 +## 使用实例 + UART设备完整的使用示例如下所示,首先获取UART设备句柄,接着设置波特率、设备属性和传输模式,之后进行UART通信,最后销毁UART设备句柄。 + ``` #include "hdf_log.h" #include "uart_if.h" @@ -672,4 +417,3 @@ _ERR: UartClose(handle); } ``` - diff --git a/zh-cn/device-dev/driver/driver-platform-uart-develop.md b/zh-cn/device-dev/driver/driver-platform-uart-develop.md index b0c410be520e08c8f7551afbb25d54de9c1b229a..100c1eca835b7f1026a5f96edc9ca1b7366c45a4 100755 --- a/zh-cn/device-dev/driver/driver-platform-uart-develop.md +++ b/zh-cn/device-dev/driver/driver-platform-uart-develop.md @@ -1,21 +1,20 @@ -# UART +# UART -- [概述](#section1761881586154520) -- [接口说明](#section752964871810) -- [开发步骤](#section944397404154520) -- [开发实例](#section774610224154520) -## 概述 +## 概述 UART是通用异步收发传输器(Universal Asynchronous Receiver/Transmitter)的缩写,在HDF框架中,UART的接口适配模式采用独立服务模式。在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。独立服务模式可以直接借助HDFDeviceManager的服务管理能力,但需要为每个设备单独配置设备节点,增加内存占用。 -**图 1** UART独立服务模式结构图 -![](figures/独立服务模式结构图.png "UART独立服务模式结构图") + **图1** UART独立服务模式结构图 -## 接口说明 + ![zh-cn_image_0000001176603980](figures/zh-cn_image_0000001176603980.png) + + +## 接口说明 UartHostMethod定义: + ``` struct UartHostMethod { int32_t (*Init)(struct UartHost *host); @@ -31,517 +30,370 @@ struct UartHostMethod { }; ``` -**表 1** UartHostMethod结构体成员的回调函数功能说明 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

函数

-

入参

-

出参

-

返回值

-

功能

-

Init

-

host: 结构体指针,核心层uart控制器;

-

-

HDF_STATUS相关状态

-

初始化Uart设备

-

Deinit

-

host: 结构体指针,核心层uart控制器;

-

-

HDF_STATUS相关状态

-

去初始化Uart设备

-

Read

-

host: 结构体指针,核心层uart控制器;size:uint32_t,数据大小;

-

data: uint8_t指针,传出的数据

-

HDF_STATUS相关状态

-

接收数据 RX

-

Write

-

host: 结构体指针,核心层uart控制器;data:uint8_t指针,传入数据;size:uint32_t,数据大小;

-

-

HDF_STATUS相关状态

-

发送数据 TX

-

SetBaud

-

host: 结构体指针,核心层uart控制器;baudRate: uint32_t指针,波特率传入值;

-

-

HDF_STATUS相关状态

-

设置波特率

-

GetBaud

-

host: 结构体指针,核心层uart控制器;

-

baudRate: uint32_t指针,传出的波特率;

-

HDF_STATUS相关状态

-

获取当前设置的波特率

-

GetAttribute

-

host: 结构体指针,核心层uart控制器;

-

attribute: 结构体指针,传出的属性值(见uart_if.h中UartAttribute定义)

-

HDF_STATUS相关状态

-

获取设备uart相关属性

-

SetAttribute

-

host: 结构体指针,核心层uart控制器;attribute: 结构体指针,属性传入值;

-

-

HDF_STATUS相关状态

-

设置设备uart相关属性

-

SetTransMode

-

host: 结构体指针,核心层uart控制器;mode: 枚举值(见uart_if.h中UartTransMode定义),传输模式

-

-

HDF_STATUS相关状态

-

设置传输模式

-

PollEvent

-

host: 结构体指针,核心层uart控制器;filep: void 指针,file ;table: void 指针,poll_table ;

-

-

HDF_STATUS相关状态

-

poll机制

-
- -## 开发步骤 - -UART模块适配HDF框架的三个环节是配置属性文件,实例化驱动入口,以及实例化核心层接口函数。 - -1. **实例化驱动入口:** - - 实例化HdfDriverEntry结构体成员。 - - 调用HDF\_INIT将HdfDriverEntry实例化对象注册到HDF框架中。 - -2. **配置属性文件:** - - 在device\_info.hcs文件中添加deviceNode描述。 - - 【可选】添加uart\_config.hcs器件属性文件。 + **表1** UartHostMethod结构体成员的回调函数功能说明 -3. **实例化UART控制器对象:** - - 初始化UartHost成员。 - - 实例化UartHost成员UartHostMethod。 +| 函数 | 入参 | 出参 | 返回值 | 功能 | +| -------- | -------- | -------- | -------- | -------- | +| Init | host: 结构体指针,核心层uart控制器; | 无 | HDF_STATUS相关状态 | 初始化Uart设备 | +| Deinit | host: 结构体指针,核心层uart控制器; | 无 | HDF_STATUS相关状态 | 去初始化Uart设备 | +| Read | host: 结构体指针,核心层uart控制器;size:uint32_t,数据大小; | data: uint8_t指针,传出的数据 | HDF_STATUS相关状态 | 接收数据 RX | +| Write | host: 结构体指针,核心层uart控制器;data:uint8_t指针,传入数据;size:uint32_t,数据大小; | 无 | HDF_STATUS相关状态 | 发送数据 TX | +| SetBaud | host: 结构体指针,核心层uart控制器;baudRate: uint32_t指针,波特率传入值; | 无 | HDF_STATUS相关状态 | 设置波特率 | +| GetBaud | host: 结构体指针,核心层uart控制器; | baudRate: uint32_t指针,传出的波特率; | HDF_STATUS相关状态 | 获取当前设置的波特率 | +| GetAttribute | host: 结构体指针,核心层uart控制器; | attribute: 结构体指针,传出的属性值(见uart_if.h中UartAttribute定义) | HDF_STATUS相关状态 | 获取设备uart相关属性 | +| SetAttribute | host: 结构体指针,核心层uart控制器;attribute: 结构体指针,属性传入值; | 无 | HDF_STATUS相关状态 | 设置设备uart相关属性 | +| SetTransMode | host: 结构体指针,核心层uart控制器;mode: 枚举值(见uart_if.h中UartTransMode定义),传输模式 | 无 | HDF_STATUS相关状态 | 设置传输模式 | +| PollEvent | host: 结构体指针,核心层uart控制器;filep: void 指针,file ;table: void 指针,poll_table ; | 无 | HDF_STATUS相关状态 | poll机制 | - >![](../public_sys-resources/icon-note.gif) **说明:** - >实例化UartHost成员UartHostMethod,其定义和成员说明见[接口说明](#section752964871810)。 +## 开发步骤 -4. **驱动调试:** +UART模块适配HDF框架的三个环节是配置属性文件,实例化驱动入口,以及实例化核心层接口函数。 - 【可选】针对新增驱动程序,建议验证驱动基本功能,例如UART控制状态,中断响应情况等。 +1. **实例化驱动入口:** + - 实例化HdfDriverEntry结构体成员。 + - 调用HDF_INIT将HdfDriverEntry实例化对象注册到HDF框架中。 + +2. **配置属性文件:** + - 在device_info.hcs文件中添加deviceNode描述。 + - 【可选】添加uart_config.hcs器件属性文件。 + +3. **实例化UART控制器对象:** + - 初始化UartHost成员。 + - 实例化UartHost成员UartHostMethod。 + > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** + > 实例化UartHost成员UartHostMethod,其定义和成员说明见[接口说明](#接口说明)。 + +4. **驱动调试:** + 【可选】针对新增驱动程序,建议验证驱动基本功能,例如UART控制状态,中断响应情况等。 + + +## 开发实例 + +下方将以uart_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。 + +1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf_device_desc.h 中定义)类型的全局变量,且moduleName要和device_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。 + 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 + + UART驱动入口参考: + + ``` + struct HdfDriverEntry g_hdfUartDevice = { + .moduleVersion = 1, + .moduleName = "HDF_PLATFORM_UART",//【必要且与 HCS 里面的名字匹配】 + .Bind = HdfUartDeviceBind, //见Bind参考 + .Init = HdfUartDeviceInit, //见Init参考 + .Release = HdfUartDeviceRelease, //见Release参考 + }; + //调用HDF_INIT将驱动入口注册到HDF框架中 + HDF_INIT(g_hdfUartDevice); + ``` + +2. 完成驱动入口注册之后,下一步请在device_info.hcs文件中添加deviceNode信息,并在 uart_config.hcs 中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值与核心层UartHost成员的默认值或限制范围有密切关系。 + 本例只有一个UART控制器,如有多个器件信息,则需要在device_info文件增加deviceNode信息,以及在uart_config文件中增加对应的器件属性。 + - device_info.hcs 配置参考。 + + + ``` + root { + device_info { + match_attr = "hdf_manager"; + platform :: host { + hostName = "platform_host"; + priority = 50; + device_uart :: device { + device0 :: deviceNode { + policy = 1; //驱动服务发布的策略,policy大于等于1(用户态可见为2,仅内核态可见为1); + priority = 40; //驱动启动优先级 + permission = 0644; //驱动创建设备节点权限 + moduleName = "HDF_PLATFORM_UART"; //驱动名称,该字段的值必须和驱动入口结构的moduleName值一致 + serviceName = "HDF_PLATFORM_UART_0";//驱动对外发布服务的名称,必须唯一,必须要按照HDF_PLATFORM_UART_X的格式,X为UART控制器编号 + deviceMatchAttr = "hisilicon_hi35xx_uart_0";//驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值一致 + } + device1 :: deviceNode { + policy = 2; + permission = 0644; + priority = 40; + moduleName = "HDF_PLATFORM_UART"; + serviceName = "HDF_PLATFORM_UART_1"; + deviceMatchAttr = "hisilicon_hi35xx_uart_1"; + } + ... + } + } + } + } + ``` + + - uart_config.hcs 配置参考。 + + + ``` + root { + platform { + template uart_controller {//模板公共参数, 继承该模板的节点如果使用模板中的默认值, 则节点字段可以缺省 + match_attr = ""; + num = 0; //【必要】设备号 + baudrate = 115200; //【必要】波特率,数值可按需填写 + fifoRxEn = 1; //【必要】使能接收FIFO + fifoTxEn = 1; //【必要】使能发送FIFO + flags = 4; //【必要】标志信号 + regPbase = 0x120a0000; //【必要】地址映射需要 + interrupt = 38; //【必要】中断号 + iomemCount = 0x48; //【必要】地址映射需要 + } + controller_0x120a0000 :: uart_controller { + match_attr = "hisilicon_hi35xx_uart_0";//【必要】必须和device_info.hcs中对应的设备的deviceMatchAttr值一致 + } + controller_0x120a1000 :: uart_controller { + num = 1; + baudrate = 9600; + regPbase = 0x120a1000; + interrupt = 39; + match_attr = "hisilicon_hi35xx_uart_1"; + } + ... + // 【可选】可新增,但需要在 device_info.hcs 添加对应的节点 + } + } + ``` + +3. 完成驱动入口注册之后,最后一步就是以核心层UartHost对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化UartHost成员UartHostMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。 + - 自定义结构体参考。 + + 从驱动的角度看,自定义结构体是参数和数据的载体,而且uart_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,一些重要数值也会传递给核心层对象,例如设备号等。 + + ``` + struct UartPl011Port { //接口相关的结构体 + int32_t enable; + unsigned long physBase; //物理地址 + uint32_t irqNum; //中断号 + uint32_t defaultBaudrate;//默认波特率 + uint32_t flags; //标志信号,下面三个宏与之相关 + #define PL011_FLG_IRQ_REQUESTED (1 << 0) + #define PL011_FLG_DMA_RX_REQUESTED (1 << 1) + #define PL011_FLG_DMA_TX_REQUESTED (1 << 2) + struct UartDmaTransfer *rxUdt; //DMA传输相关 + struct UartDriverData *udd; //见下 + }; + struct UartDriverData { //数据传输相关的结构体 + uint32_t num; + uint32_t baudrate; //波特率(可设置) + struct UartAttribute attr; //数据位、停止位等传输属性相关 + struct UartTransfer *rxTransfer; //缓冲区相关,可理解为FIFO结构 + wait_queue_head_t wait; //条件变量相关的排队等待信号 + int32_t count; //数据数量 + int32_t state; //uart控制器状态 + #define UART_STATE_NOT_OPENED 0 + #define UART_STATE_OPENING 1 + #define UART_STATE_USEABLE 2 + #define UART_STATE_SUSPENED 3 + uint32_t flags; //状态标志 + #define UART_FLG_DMA_RX (1 << 0) + #define UART_FLG_DMA_TX (1 << 1) + #define UART_FLG_RD_BLOCK (1 << 2) + RecvNotify recv; //函数指针类型,指向串口数据接收函数 + struct UartOps *ops; //自定义函数指针结构体,详情见device/hisilicon/drivers/uart/uart_pl011.c + void *private; //一般用来存储UartPl011Port首地址,方便调用 + }; + + // UartHost是核心层控制器结构体,其中的成员在Init函数中会被赋值 + struct UartHost { + struct IDeviceIoService service; + struct HdfDeviceObject *device; + uint32_t num; + OsalAtomic atom; + void *priv; //一般存储厂商自定义结构体首地址,方便后者被调用 + struct UartHostMethod *method; //核心层钩子函数,厂商需要实现其成员函数功能并实例化 + }; + ``` + - UartHost成员回调函数结构体UartHostMethod的实例化,其他成员在Bind函数中初始化。 -## 开发实例 + + ``` + // uart_hi35xx.c 中的示例:钩子函数的实例化 + struct UartHostMethod g_uartHostMethod = { + .Init = Hi35xxInit, + .Deinit = Hi35xxDeinit, + .Read = Hi35xxRead, + .Write = Hi35xxWrite, + .SetBaud = Hi35xxSetBaud, + .GetBaud = Hi35xxGetBaud, + .SetAttribute = Hi35xxSetAttribute, + .GetAttribute = Hi35xxGetAttribute, + .SetTransMode = Hi35xxSetTransMode, + .pollEvent = Hi35xxPollEvent, + }; + ``` + + - Bind函数参考 + + 入参: + + HdfDeviceObject 这个是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 + + 返回值: + + HDF_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf_base.h中HDF_STATUS 定义)。 + + **表2** Bind函数入参和返回值 + + | 状态(值) | 问题描述 | + | -------- | -------- | + | HDF_ERR_INVALID_OBJECT | 控制器对象非法 | + | HDF_ERR_MALLOC_FAIL | 内存分配失败 | + | HDF_ERR_INVALID_PARAM | 参数非法 | + | HDF_ERR_IO | I/O 错误 | + | HDF_SUCCESS | 初始化成功 | + | HDF_FAILURE | 初始化失败 | + + 函数说明: + + 初始化自定义结构体对象,初始化UartHost成员。 -下方将以uart\_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。 + + ``` + //uart_hi35xx.c + static int32_t HdfUartDeviceBind(struct HdfDeviceObject *device) + { + ... + return (UartHostCreate(device) == NULL) ? HDF_FAILURE : HDF_SUCCESS;//【必须做】调用核心层函数 UartHostCreate + } + //uart_core.c 核心层 UartHostCreate 函数说明 + struct UartHost *UartHostCreate(struct HdfDeviceObject *device) + { + struct UartHost *host = NULL; //新建 UartHost + ... + host = (struct UartHost *)OsalMemCalloc(sizeof(*host));//分配内存 + ... + host->device = device; //【必要】使HdfDeviceObject与UartHost可以相互转化的前提 + device->service = &(host->service);//【必要】使HdfDeviceObject与UartHost可以相互转化的前提 + host->device->service->Dispatch = UartIoDispatch;//为 service 成员的 Dispatch 方法赋值 + OsalAtomicSet(&host->atom, 0); //原子量初始化或者原子量设置 + host->priv = NULL; + host->method = NULL; + return host; + } + ``` + + - Init函数参考 + + 入参: + + HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 + + 返回值: + + HDF_STATUS相关状态。 + + 函数说明: + + 初始化自定义结构体对象,初始化UartHost成员,调用核心层UartAddDev函数,接入VFS。 -1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf\_device\_desc.h 中定义)类型的全局变量,且moduleName要和device\_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。 + + ``` + int32_t HdfUartDeviceInit(struct HdfDeviceObject *device) + { + int32_t ret; + struct UartHost *host = NULL; + HDF_LOGI("%s: entry", __func__); + ... + host = UartHostFromDevice(device);//通过service成员后强制转为UartHost,赋值是在Bind函数中 + ... + ret = Hi35xxAttach(host, device); //完成UartHost对象的初始化,见下 + ... + host->method = &g_uartHostMethod; //UartHostMethod的实例化对象的挂载 + return ret; + } + //完成 UartHost 对象的初始化 + static int32_t Hi35xxAttach(struct UartHost *host, struct HdfDeviceObject *device) + { + int32_t ret; + //udd 和 port 对象是厂商自定义的结构体对象,可根据需要实现相关功能 + struct UartDriverData *udd = NULL; + struct UartPl011Port *port = NULL; + ... + // 【必要相关功能】步骤【1】~【7】主要实现对 udd 对象的实例化赋值,然后赋值给核心层UartHost对象上 + udd = (struct UartDriverData *)OsalMemCalloc(sizeof(*udd));//【1】 + ... + port = (struct UartPl011Port *)OsalMemCalloc(sizeof(struct UartPl011Port));//【2】 + ... + udd->ops = Pl011GetOps();//【3】设备开启、关闭、属性设置、发送操作等函数挂载 + udd->recv = PL011UartRecvNotify;//【4】数据接收通知函数(条件锁机制)挂载 + udd->count = 0; //【5】 + port->udd = udd; //【6】使UartPl011Port与UartDriverData可以相互转化的前提 + ret = UartGetConfigFromHcs(port, device->property);//【必要】 此步骤是将 HdfDeviceObject 的属性传递给厂商自定义结构体 + // 用于相关操作,示例代码见下 + ... + udd->private = port; //【7】 + + host->priv = udd; //【必要】使UartHost与UartDriverData可以相互转化的前提 + host->num = udd->num;//【必要】uart 设备号 + UartAddDev(host); //【必要】核心层uart_dev.c 中的函数,作用:注册了一个字符设备节点到vfs, 这样从用户态可以通过这个虚拟文件节点访问uart + return HDF_SUCCESS; + } + + static int32_t UartGetConfigFromHcs(struct UartPl011Port *port, const struct DeviceResourceNode *node) + { + uint32_t tmp, regPbase, iomemCount; + struct UartDriverData *udd = port->udd; + struct DeviceResourceIface *iface = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE); + ... + //通过请求参数提取相应的值,并赋值给厂商自定义的结构体 + if (iface->GetUint32(node, "num", &udd->num, 0) != HDF_SUCCESS) { + HDF_LOGE("%s: read busNum fail", __func__); + return HDF_FAILURE; + } + ... + return 0; + } + ``` + - Release函数参考 - 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 + 入参: - UART驱动入口参考: + HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 - ``` - struct HdfDriverEntry g_hdfUartDevice = { - .moduleVersion = 1, - .moduleName = "HDF_PLATFORM_UART",//【必要且与 HCS 里面的名字匹配】 - .Bind = HdfUartDeviceBind, //见Bind参考 - .Init = HdfUartDeviceInit, //见Init参考 - .Release = HdfUartDeviceRelease, //见Release参考 - }; - //调用HDF_INIT将驱动入口注册到HDF框架中 - HDF_INIT(g_hdfUartDevice); - ``` + 返回值: -2. 完成驱动入口注册之后,下一步请在device\_info.hcs文件中添加deviceNode信息,并在 uart\_config.hcs 中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值与核心层UartHost成员的默认值或限制范围有密切关系。 + 无。 - 本例只有一个UART控制器,如有多个器件信息,则需要在device\_info文件增加deviceNode信息,以及在uart\_config文件中增加对应的器件属性。 + 函数说明: - - device\_info.hcs 配置参考。 + 该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源, 该函数中需包含释放内存和删除控制器等操作。所有强制转换获取相应对象的操作前提是在Init函数中具备对应赋值的操作。 - ``` - root { - device_info { - match_attr = "hdf_manager"; - platform :: host { - hostName = "platform_host"; - priority = 50; - device_uart :: device { - device0 :: deviceNode { - policy = 1; //驱动服务发布的策略,policy大于等于1(用户态可见为2,仅内核态可见为1); - priority = 40; //驱动启动优先级 - permission = 0644; //驱动创建设备节点权限 - moduleName = "HDF_PLATFORM_UART"; //驱动名称,该字段的值必须和驱动入口结构的moduleName值一致 - serviceName = "HDF_PLATFORM_UART_0";//驱动对外发布服务的名称,必须唯一,必须要按照HDF_PLATFORM_UART_X的格式,X为UART控制器编号 - deviceMatchAttr = "hisilicon_hi35xx_uart_0";//驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值一致 - } - device1 :: deviceNode { - policy = 2; - permission = 0644; - priority = 40; - moduleName = "HDF_PLATFORM_UART"; - serviceName = "HDF_PLATFORM_UART_1"; - deviceMatchAttr = "hisilicon_hi35xx_uart_1"; - } - ... - } - } + + ``` + void HdfUartDeviceRelease(struct HdfDeviceObject *device) + { + struct UartHost *host = NULL; + ... + host = UartHostFromDevice(device);//这里有HdfDeviceObject到UartHost的强制转化,通过service成员,赋值见Bind函数 + ... + if (host->priv != NULL) { + Hi35xxDetach(host); //厂商自定义的内存释放函数,见下 } - } - ``` - - - uart\_config.hcs 配置参考。 - - ``` - root { - platform { - template uart_controller {//模板公共参数, 继承该模板的节点如果使用模板中的默认值, 则节点字段可以缺省 - match_attr = ""; - num = 0; //【必要】设备号 - baudrate = 115200; //【必要】波特率,数值可按需填写 - fifoRxEn = 1; //【必要】使能接收FIFO - fifoTxEn = 1; //【必要】使能发送FIFO - flags = 4; //【必要】标志信号 - regPbase = 0x120a0000; //【必要】地址映射需要 - interrupt = 38; //【必要】中断号 - iomemCount = 0x48; //【必要】地址映射需要 - } - controller_0x120a0000 :: uart_controller { - match_attr = "hisilicon_hi35xx_uart_0";//【必要】必须和device_info.hcs中对应的设备的deviceMatchAttr值一致 - } - controller_0x120a1000 :: uart_controller { - num = 1; - baudrate = 9600; - regPbase = 0x120a1000; - interrupt = 39; - match_attr = "hisilicon_hi35xx_uart_1"; - } - ... - // 【可选】可新增,但需要在 device_info.hcs 添加对应的节点 + UartHostDestroy(host); //调用核心层函数释放host + } + + static void Hi35xxDetach(struct UartHost *host) + { + struct UartDriverData *udd = NULL; + struct UartPl011Port *port = NULL; + ... + udd = host->priv; //这里有UartHost到UartDriverData的转化 + ... + UartRemoveDev(host);//VFS注销 + port = udd->private;//这里有UartDriverData到UartPl011Port的转化 + if (port != NULL) { + if (port->physBase != 0) { + OsalIoUnmap((void *)port->physBase);//地址反映射 + } + OsalMemFree(port); + udd->private = NULL; } - } - ``` - -3. 完成驱动入口注册之后,最后一步就是以核心层UartHost对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化UartHost成员UartHostMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。 - - 自定义结构体参考。 - - 从驱动的角度看,自定义结构体是参数和数据的载体,而且uart\_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,一些重要数值也会传递给核心层对象,例如设备号等。 - - ``` - struct UartPl011Port { //接口相关的结构体 - int32_t enable; - unsigned long physBase; //物理地址 - uint32_t irqNum; //中断号 - uint32_t defaultBaudrate;//默认波特率 - uint32_t flags; //标志信号,下面三个宏与之相关 - #define PL011_FLG_IRQ_REQUESTED (1 << 0) - #define PL011_FLG_DMA_RX_REQUESTED (1 << 1) - #define PL011_FLG_DMA_TX_REQUESTED (1 << 2) - struct UartDmaTransfer *rxUdt; //DMA传输相关 - struct UartDriverData *udd; //见下 - }; - struct UartDriverData { //数据传输相关的结构体 - uint32_t num; - uint32_t baudrate; //波特率(可设置) - struct UartAttribute attr; //数据位、停止位等传输属性相关 - struct UartTransfer *rxTransfer; //缓冲区相关,可理解为FIFO结构 - wait_queue_head_t wait; //条件变量相关的排队等待信号 - int32_t count; //数据数量 - int32_t state; //uart控制器状态 - #define UART_STATE_NOT_OPENED 0 - #define UART_STATE_OPENING 1 - #define UART_STATE_USEABLE 2 - #define UART_STATE_SUSPENED 3 - uint32_t flags; //状态标志 - #define UART_FLG_DMA_RX (1 << 0) - #define UART_FLG_DMA_TX (1 << 1) - #define UART_FLG_RD_BLOCK (1 << 2) - RecvNotify recv; //函数指针类型,指向串口数据接收函数 - struct UartOps *ops; //自定义函数指针结构体,详情见device/hisilicon/drivers/uart/uart_pl011.c - void *private; //一般用来存储UartPl011Port首地址,方便调用 - }; - - // UartHost是核心层控制器结构体,其中的成员在Init函数中会被赋值 - struct UartHost { - struct IDeviceIoService service; - struct HdfDeviceObject *device; - uint32_t num; - OsalAtomic atom; - void *priv; //一般存储厂商自定义结构体首地址,方便后者被调用 - struct UartHostMethod *method; //核心层钩子函数,厂商需要实现其成员函数功能并实例化 - }; - ``` - - - UartHost成员回调函数结构体UartHostMethod的实例化,其他成员在Bind函数中初始化。 - - ``` - // uart_hi35xx.c 中的示例:钩子函数的实例化 - struct UartHostMethod g_uartHostMethod = { - .Init = Hi35xxInit, - .Deinit = Hi35xxDeinit, - .Read = Hi35xxRead, - .Write = Hi35xxWrite, - .SetBaud = Hi35xxSetBaud, - .GetBaud = Hi35xxGetBaud, - .SetAttribute = Hi35xxSetAttribute, - .GetAttribute = Hi35xxGetAttribute, - .SetTransMode = Hi35xxSetTransMode, - .pollEvent = Hi35xxPollEvent, - }; - ``` - - - Bind函数参考 - - 入参: - - HdfDeviceObject 这个是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 - - **返回值:** - - HDF\_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf\_base.h中HDF\_STATUS 定义)。 - - **表 2** Bind函数入参和返回值 - - - - - - - - - - - - - - - - - - - - - - - - - -

状态(值)

-

问题描述

-

HDF_ERR_INVALID_OBJECT

-

控制器对象非法

-

HDF_ERR_MALLOC_FAIL

-

内存分配失败

-

HDF_ERR_INVALID_PARAM

-

参数非法

-

HDF_ERR_IO

-

I/O 错误

-

HDF_SUCCESS

-

初始化成功

-

HDF_FAILURE

-

初始化失败

-
- - 函数说明: - - 初始化自定义结构体对象,初始化UartHost成员。 - - ``` - //uart_hi35xx.c - static int32_t HdfUartDeviceBind(struct HdfDeviceObject *device) - { - ... - return (UartHostCreate(device) == NULL) ? HDF_FAILURE : HDF_SUCCESS;//【必须做】调用核心层函数 UartHostCreate - } - //uart_core.c 核心层 UartHostCreate 函数说明 - struct UartHost *UartHostCreate(struct HdfDeviceObject *device) - { - struct UartHost *host = NULL; //新建 UartHost - ... - host = (struct UartHost *)OsalMemCalloc(sizeof(*host));//分配内存 - ... - host->device = device; //【必要】使HdfDeviceObject与UartHost可以相互转化的前提 - device->service = &(host->service);//【必要】使HdfDeviceObject与UartHost可以相互转化的前提 - host->device->service->Dispatch = UartIoDispatch;//为 service 成员的 Dispatch 方法赋值 - OsalAtomicSet(&host->atom, 0); //原子量初始化或者原子量设置 - host->priv = NULL; - host->method = NULL; - return host; - } - ``` - - - Init函数参考 - - 入参**:** - - HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 - - 返回值: - - HDF\_STATUS相关状态。 - - 函数说明: - - 初始化自定义结构体对象,初始化UartHost成员,调用核心层UartAddDev函数,接入VFS。 - - ``` - int32_t HdfUartDeviceInit(struct HdfDeviceObject *device) - { - int32_t ret; - struct UartHost *host = NULL; - HDF_LOGI("%s: entry", __func__); - ... - host = UartHostFromDevice(device);//通过service成员后强制转为UartHost,赋值是在Bind函数中 - ... - ret = Hi35xxAttach(host, device); //完成UartHost对象的初始化,见下 - ... - host->method = &g_uartHostMethod; //UartHostMethod的实例化对象的挂载 - return ret; - } - //完成 UartHost 对象的初始化 - static int32_t Hi35xxAttach(struct UartHost *host, struct HdfDeviceObject *device) - { - int32_t ret; - //udd 和 port 对象是厂商自定义的结构体对象,可根据需要实现相关功能 - struct UartDriverData *udd = NULL; - struct UartPl011Port *port = NULL; - ... - // 【必要相关功能】步骤【1】~【7】主要实现对 udd 对象的实例化赋值,然后赋值给核心层UartHost对象上 - udd = (struct UartDriverData *)OsalMemCalloc(sizeof(*udd));//【1】 - ... - port = (struct UartPl011Port *)OsalMemCalloc(sizeof(struct UartPl011Port));//【2】 - ... - udd->ops = Pl011GetOps();//【3】设备开启、关闭、属性设置、发送操作等函数挂载 - udd->recv = PL011UartRecvNotify;//【4】数据接收通知函数(条件锁机制)挂载 - udd->count = 0; //【5】 - port->udd = udd; //【6】使UartPl011Port与UartDriverData可以相互转化的前提 - ret = UartGetConfigFromHcs(port, device->property);//【必要】 此步骤是将 HdfDeviceObject 的属性传递给厂商自定义结构体 - // 用于相关操作,示例代码见下 - ... - udd->private = port; //【7】 - - host->priv = udd; //【必要】使UartHost与UartDriverData可以相互转化的前提 - host->num = udd->num;//【必要】uart 设备号 - UartAddDev(host); //【必要】核心层uart_dev.c 中的函数,作用:注册了一个字符设备节点到vfs, 这样从用户态可以通过这个虚拟文件节点访问uart - return HDF_SUCCESS; - } - - static int32_t UartGetConfigFromHcs(struct UartPl011Port *port, const struct DeviceResourceNode *node) - { - uint32_t tmp, regPbase, iomemCount; - struct UartDriverData *udd = port->udd; - struct DeviceResourceIface *iface = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE); - ... - //通过请求参数提取相应的值,并赋值给厂商自定义的结构体 - if (iface->GetUint32(node, "num", &udd->num, 0) != HDF_SUCCESS) { - HDF_LOGE("%s: read busNum fail", __func__); - return HDF_FAILURE; - } - ... - return 0; - } - ``` - - - Release函数参考 - - 入参: - - HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 - - 返回值: - - 无。 - - 函数说明: - - 该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源, 该函数中需包含释放内存和删除控制器等操作。所有强制转换获取相应对象的操作**前提**是在Init函数中具备对应赋值的操作。 - - ``` - void HdfUartDeviceRelease(struct HdfDeviceObject *device) - { - struct UartHost *host = NULL; - ... - host = UartHostFromDevice(device);//这里有HdfDeviceObject到UartHost的强制转化,通过service成员,赋值见Bind函数 - ... - if (host->priv != NULL) { - Hi35xxDetach(host); //厂商自定义的内存释放函数,见下 - } - UartHostDestroy(host); //调用核心层函数释放host - } - - static void Hi35xxDetach(struct UartHost *host) - { - struct UartDriverData *udd = NULL; - struct UartPl011Port *port = NULL; - ... - udd = host->priv; //这里有UartHost到UartDriverData的转化 - ... - UartRemoveDev(host);//VFS注销 - port = udd->private;//这里有UartDriverData到UartPl011Port的转化 - if (port != NULL) { - if (port->physBase != 0) { - OsalIoUnmap((void *)port->physBase);//地址反映射 - } - (void)OsalMemFree(port); - udd->private = NULL; - } - (void)OsalMemFree(udd);//释放UartDriverData - host->priv = NULL; - } - ``` - - - + OsalMemFree(udd);//释放UartDriverData + host->priv = NULL; + } + ``` diff --git a/zh-cn/device-dev/driver/driver-platform-watchdog-des.md b/zh-cn/device-dev/driver/driver-platform-watchdog-des.md index fcc46c34fcc16906c9f15e55016aea94513f3f58..8afe4197992d7c6fb44364ba17f6b1944e60675f 100644 --- a/zh-cn/device-dev/driver/driver-platform-watchdog-des.md +++ b/zh-cn/device-dev/driver/driver-platform-watchdog-des.md @@ -1,139 +1,56 @@ -# WATCHDOG - -- [概述](#section14918241977) -- [接口说明](#section1180575010271) -- [使用指导](#section10103184312813) - - [使用流程](#section10181195910815) - - [打开看门狗设备](#section66089201107) - - [获取看门狗状态](#section786624341011) - - [设置超时时间](#section182386137111) - - [获取超时时间](#section1883310371114) - - [启动看门狗](#section82501405123) - - [喂狗](#section3547530101211) - - [停止看门狗](#section944595841217) - - [关闭看门狗设备](#section96561824121311) - -- [使用实例](#section1724514523135) - -## 概述 - -看门狗(watchdog),又叫看门狗计时器(watchdog timer),是一种硬件的计时设备,当系统的主程序发生某些错误时,导致未及时清除看门狗计时器的计时值,这时看门狗计时器就会对系统发出复位信号,使系统从悬停状态恢复到正常运作状态。 - -## 接口说明 - -**表 1** 看门狗 API接口功能介绍 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

功能分类

-

接口名

-

描述

-

打开/关闭看门狗

-

WatchdogOpen

-

打开看门狗设备

-

WatchdogClose

-

关闭看门狗设备

-

启动/停止看门狗

-

WatchdogStart

-

启动看门狗

-

WatchdogStop

-

停止看门狗

-

设置/获取超时时间

-

WatchdogSetTimeout

-

设置看门狗超时时间

-

WatchdogGetTimeout

-

获取看门狗超时时间

-

获取看门狗状态

-

WatchdogGetStatus

-

获取看门狗状态

-

清除看门狗定时器

-

WatchdogFeed

-

清除看门狗定时器(喂狗)

-
- ->![](../public_sys-resources/icon-note.gif) **说明:** ->本文涉及看门狗的所有接口,仅限内核态使用,不支持在用户态使用。 - -## 使用指导 - -### 使用流程 - -使用看门狗的一般流程如[图1](#fig430533913392)所示。 - -**图 1** 看门狗使用流程图 -![](figures/看门狗使用流程图.png "看门狗使用流程图") - -### 打开看门狗设备 +# WatchDog + + +## 概述 + +看门狗(Watchdog),又叫看门狗计时器(Watchdog timer),是一种硬件的计时设备。当系统主程序发生错误导致未及时清除看门狗计时器的计时值时,看门狗计时器就会对系统发出复位信号,使系统从悬停状态恢复到正常运作状态。 + + +## 接口说明 + + **表1** 看门狗API接口功能介绍 + +| 功能分类 | 接口描述 | +| -------- | -------- | +| 打开/关闭看门狗 | WatchdogOpen:打开看门狗设备
WatchdogClose:关闭看门狗设备 | +| 启动/停止看门狗 | WatchdogStart:启动看门狗
WatchdogStop:停止看门狗 | +| 设置/获取超时时间 | WatchdogSetTimeout:设置看门狗超时时间
WatchdogGetTimeout:获取看门狗超时时间 | +| 获取看门狗状态 | WatchdogGetStatus:获取看门狗状态 | +| 清除看门狗定时器 | WatchdogFeed:清除看门狗定时器(喂狗) | + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> 本文涉及的看门狗的所有接口,仅限内核态使用,不支持在用户态使用。 + + +## 使用指导 + + +### 使用流程 + +使用看门狗的一般流程如下图所示。 + + **图1** 看门狗使用流程图 + ![zh-cn_image_0000001160652842](figures/zh-cn_image_0000001160652842.png) + + +### 打开看门狗设备 在操作看门狗之前,需要使用WatchdogOpen打开一个看门狗设备,一个系统可能有多个看门狗,通过ID号来打开指定的看门狗设备: -DevHandle WatchdogOpen\(int16\_t wdtId\); - -**表 2** WatchdogOpen参数和返回值描述 - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

wdtId

-

看门狗设备号

-

返回值

-

返回值描述

-

NULL

-

打开失败

-

DevHandle类型指针

-

看门狗设备句柄

-
+ +``` +DevHandle WatchdogOpen(int16_t wdtId); +``` + + **表2** WatchdogOpen参数和返回值描述 + +| **参数** | **参数描述** | +| -------- | -------- | +| wdtId | 看门狗设备号 | +| **返回值** | **返回值描述** | +| NULL | 打开失败 | +| DevHandle类型指针 | 看门狗设备句柄 | + ``` DevHandle handle = NULL; @@ -144,46 +61,24 @@ if (handle == NULL) { } ``` -### 获取看门狗状态 - -int32\_t WatchdogGetStatus\(DevHandle handle, int32\_t \*status\); - -**表 3** WatchdogGetStatus参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

看门狗设备句柄

-

status

-

获取到的启动状态指针

-

返回值

-

返回值描述

-

0

-

获取成功

-

负数

-

获取失败

-
+ +### 获取看门狗状态 + + +``` +int32_t WatchdogGetStatus(DevHandle handle, int32_t *status); +``` + + **表3** WatchdogGetStatus参数和返回值描述 + +| **参数** | **参数描述** | +| -------- | -------- | +| handle | 看门狗设备句柄 | +| status | 获取到的看门狗状态的指针 | +| **返回值** | **返回值描述** | +| 0 | 获取成功 | +| 负数 | 获取失败 | + ``` int32_t ret; @@ -196,46 +91,24 @@ if (ret != 0) { } ``` -### 设置超时时间 - -int32\_t WatchdogSetTimeout\(DevHandle \*handle, uint32\_t seconds\); - -**表 4** WatchdogSetTimeout参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

看门狗设备句柄

-

seconds

-

超时时间,单位为秒

-

返回值

-

返回值描述

-

0

-

设置成功

-

负数

-

设置失败

-
+ +### 设置超时时间 + + +``` +int32_t WatchdogSetTimeout(DevHandle *handle, uint32_t seconds); +``` + + **表4** WatchdogSetTimeout参数和返回值描述 + +| **参数** | **参数描述** | +| -------- | -------- | +| handle | 看门狗设备句柄 | +| seconds | 超时时间,单位为秒 | +| **返回值** | **返回值描述** | +| 0 | 设置成功 | +| 负数 | 设置失败 | + ``` int32_t ret; @@ -248,46 +121,24 @@ if (ret != 0) { } ``` -### 获取超时时间 - -int32\_t WatchdogGetTimeout\(DevHandle \*handle, uint32\_t \*seconds\); - -**表 5** WatchdogGetTimeout参数和返回值描述 - - - - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

看门狗设备句柄

-

seconds

-

接收超时时间的指针,单位为秒

-

返回值

-

返回值描述

-

0

-

获取成功

-

负数

-

获取失败

-
+ +### 获取超时时间 + + +``` +int32_t WatchdogGetTimeout(DevHandle *handle, uint32_t *seconds); +``` + + **表5** WatchdogGetTimeout参数和返回值描述 + +| **参数** | **参数描述** | +| -------- | -------- | +| handle | 看门狗设备句柄 | +| seconds | 接收超时时间的指针,单位为秒 | +| **返回值** | **返回值描述** | +| 0 | 获取成功 | +| 负数 | 获取失败 | + ``` int32_t ret; @@ -300,41 +151,23 @@ if (ret != 0) { } ``` -### 启动看门狗 - -int32\_t WatchdogStart\(DevHandle handle\); - -**表 6** WatchdogStart参数和返回值描述 - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

看门狗设备句柄

-

返回值

-

返回值描述

-

0

-

启动成功

-

负数

-

启动失败

-
+ +### 启动看门狗 + + +``` +int32_t WatchdogStart(DevHandle handle); +``` + + **表6** WatchdogStart参数和返回值描述 + +| **参数** | **参数描述** | +| -------- | -------- | +| handle | 看门狗设备句柄 | +| **返回值** | **返回值描述** | +| 0 | 启动成功 | +| 负数 | 启动失败 | + ``` int32_t ret; @@ -346,41 +179,23 @@ if (ret != 0) { } ``` -### 喂狗 - -int32\_t WatchdogFeed\(DevHandle handle\); - -**表 7** WatchdogFeed参数和返回值描述 - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

看门狗设备句柄

-

返回值

-

返回值描述

-

0

-

喂狗成功

-

负数

-

喂狗失败

-
+ +### 喂狗 + + +``` +int32_t WatchdogFeed(DevHandle handle); +``` + + **表7** WatchdogFeed参数和返回值描述 + +| **参数** | **参数描述** | +| -------- | -------- | +| handle | 看门狗设备句柄 | +| **返回值** | **返回值描述** | +| 0 | 喂狗成功 | +| 负数 | 喂狗失败 | + ``` int32_t ret; @@ -392,41 +207,23 @@ if (ret != 0) { } ``` -### 停止看门狗 - -int32\_t WatchdogStop\(DevHandle handle\); - -**表 8** WatchdogStop参数和返回值描述 - - - - - - - - - - - - - - - - - - - -

参数

-

参数描述

-

handle

-

看门狗设备句柄

-

返回值

-

返回值描述

-

0

-

停止成功

-

负数

-

停止失败

-
+ +### 停止看门狗 + + +``` +int32_t WatchdogStop(DevHandle handle); +``` + + **表8** WatchdogStop参数和返回值描述 + +| **参数** | **参数描述** | +| -------- | -------- | +| handle | 看门狗设备句柄 | +| **返回值** | **返回值描述** | +| 0 | 停止成功 | +| 负数 | 停止失败 | + ``` int32_t ret; @@ -438,45 +235,41 @@ if (ret != 0) { } ``` -### 关闭看门狗设备 + +### 关闭看门狗设备 当操作完毕时,使用WatchdogClose关闭打开的设备句柄: -void WatchdogClose\(DevHandle handle\); -**表 9** WatchdogClose参数和返回值描述 +``` +void WatchdogClose(DevHandle handle); +``` + + **表9** WatchdogClose参数和返回值描述 + +| **参数** | **参数描述** | +| -------- | -------- | +| handle | 看门狗设备句柄 | - - - - - - - - - -

参数

-

参数描述

-

handle

-

看门狗设备句柄

-
``` /* 关闭看门狗 */ ret = WatchdogClose(handle); ``` -## 使用实例 + +## 使用实例 本例程提供看门狗的完整使用流程。 在本例程中,我们打开一个看门狗设备,设置超时时间并启动计时: -- 首先定期喂狗,即按时清除看门狗定时器,确保系统不会因定时器超时而复位。 -- 接着再停止喂狗,观察定时器到期后系统是否发生复位行为。 +- 首先定期喂狗,即按时清除看门狗定时器,确保系统不会因定时器超时而复位。 -示例如下: +- 接着再停止喂狗,观察定时器到期后系统是否发生复位行为。 + 示例如下: + ``` #include "watchdog_if.h" #include "hdf_log.h" @@ -496,7 +289,7 @@ static int32_t TestCaseWatchdog(void) /* 打开0号看门狗设备 */ handle = WatchdogOpen(0); if (handle == NULL) { - HDF_LOGE("Open watchdog fail!"); + HDF_LOGE("Open watchdog failed!"); return -1; } @@ -520,14 +313,14 @@ static int32_t TestCaseWatchdog(void) /* 启动看门狗,开始计时 */ ret = WatchdogStart(handle); if (ret != HDF_SUCCESS) { - HDF_LOGE("%s: satrt fail! ret:%d\n", __func__, ret); + HDF_LOGE("%s: start fail! ret:%d\n", __func__, ret); WatchdogClose(handle); return ret; } /* 每隔1S喂狗一次 */ for (i = 0; i < WATCHDOG_TEST_FEED_TIME; i++) { - HDF_LOGE("%s: feeding watchdog %d times... \n", __func__, i); + HDF_LOGI("%s: feeding watchdog %d times... \n", __func__, i); ret = WatchdogFeed(handle); if (ret != HDF_SUCCESS) { HDF_LOGE("%s: feed dog fail! ret:%d\n", __func__, ret); @@ -537,18 +330,17 @@ static int32_t TestCaseWatchdog(void) OsalSleep(1); } /* 由于喂狗间隔小于超时时间,系统不会发生复位,此日志可以正常打印 */ - HDF_LOGE("%s: no reset ... feeding test OK!!!\n", __func__); + HDF_LOGI("%s: no reset ... feeding test OK!!!\n", __func__); /* 接下来持续不喂狗,使得看门狗计时器超时 */ for (i = 0; i < WATCHDOG_TEST_FEED_TIME; i++) { - HDF_LOGE("%s: watiting dog buck %d times... \n", __func__, i); + HDF_LOGI("%s: waiting dog buck %d times... \n", __func__, i); OsalSleep(1); } /* 当不喂狗时间到达之前设定的超时时间的时候,系统会发生复位,理论上观察不到此日志的打印 */ - HDF_LOGE("%s: dog has't buck!!! \n", __func__, i); + HDF_LOGI("%s: dog hasn't back!!! \n", __func__, i); WatchdogClose(handle); return -1; } ``` - diff --git a/zh-cn/device-dev/driver/driver-platform-watchdog-develop.md b/zh-cn/device-dev/driver/driver-platform-watchdog-develop.md index eda28043c4ffac4aedf14ba132895ca9bee13b90..9a8b1645cc3baf5ceafdb9ec2d885d9657d932da 100755 --- a/zh-cn/device-dev/driver/driver-platform-watchdog-develop.md +++ b/zh-cn/device-dev/driver/driver-platform-watchdog-develop.md @@ -1,21 +1,20 @@ -# WatchDog +# WatchDog -- [概述](#section1315827527160117) -- [接口说明](#section752964871810) -- [开发步骤](#section477974542160117) -- [开发实例](#section1832270347160117) -## 概述 +## 概述 看门狗(Watchdog),又叫看门狗计时器(Watchdog timer),是一种硬件的计时设备,在HDF框架中,Watchdog接口适配模式采用独立服务模式,在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。独立服务模式可以直接借助HDFDeviceManager的服务管理能力,但需要为每个设备单独配置设备节点,增加内存占用。 -**图 1** Watchdog独立服务模式结构图 -![](figures/独立服务模式结构图.png "Watchdog独立服务模式结构图") + **图1** Watchdog独立服务模式结构图 -## 接口说明 + ![zh-cn_image_0000001177082396](figures/zh-cn_image_0000001177082396.png) + + +## 接口说明 WatchdogMethod定义: + ``` struct WatchdogMethod { int32_t (*getStatus)(struct WatchdogCntlr *wdt, int32_t *status); @@ -29,337 +28,233 @@ struct WatchdogMethod { }; ``` -**表 1** WatchdogMethod成员的回调函数功能说明 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

成员函数

-

入参

-

出参

-

返回值

-

功能

-

getStatus

-

wdt: 结构体指针,核心层WDG控制器;

-

status: int32_t指针,表示狗的状态(打开或关闭);

-

HDF_STATUS相关状态

-

获取看门狗所处的状态

-

start

-

wdt: 结构体指针,核心层WDG控制器;

-

-

HDF_STATUS相关状态

-

打开开门狗

-

stop

-

wdt: 结构体指针,核心层WDG控制器;

-

-

HDF_STATUS相关状态

-

关闭开门狗

-

setTimeout

-

wdt: 结构体指针,核心层WDG控制器;seconds: uint32_t,时间传入值;

-

-

HDF_STATUS相关状态

-

设置超时时间值,单位秒,需要保证看门狗实际运行的时间符合该值

-

getTimeout

-

wdt: 结构体指针,核心层WDG控制器;

-

seconds: uint32_t,传出的时间值

-

HDF_STATUS相关状态

-

回读设置的超时时间值

-

feed

-

wdt: 结构体指针,核心层WDG控制器;

-

-

HDF_STATUS相关状态

-

喂狗

-
- -## 开发步骤 + **表1** WatchdogMethod成员的回调函数功能说明 + +| 成员函数 | 入参 | 出参 | 返回值 | 功能 | +| -------- | -------- | -------- | -------- | -------- | +| getStatus | wdt: 结构体指针,核心层WDG控制器; | status: int32_t指针,表示狗的状态(打开或关闭); | HDF_STATUS相关状态 | 获取看门狗所处的状态 | +| start | wdt: 结构体指针,核心层WDG控制器; | 无 | HDF_STATUS相关状态 | 打开开门狗 | +| stop | wdt: 结构体指针,核心层WDG控制器; | 无 | HDF_STATUS相关状态 | 关闭开门狗 | +| setTimeout | wdt: 结构体指针,核心层WDG控制器;seconds: uint32_t,时间传入值; | 无 | HDF_STATUS相关状态 | 设置超时时间值,单位秒,需要保证看门狗实际运行的时间符合该值 | +| getTimeout | wdt: 结构体指针,核心层WDG控制器; | seconds: uint32_t,传出的时间值 | HDF_STATUS相关状态 | 回读设置的超时时间值 | +| feed | wdt: 结构体指针,核心层WDG控制器; | 无 | HDF_STATUS相关状态 | 喂狗 | + + +## 开发步骤 Watchdog模块适配HDF框架的三个环节是配置属性文件,实例化驱动入口,以及实例化核心层接口函数。 -1. **实例化驱动入口:** - - 实例化HdfDriverEntry结构体成员。 - - 调用HDF\_INIT将HdfDriverEntry实例化对象注册到HDF框架中。 - -2. **配置属性文件:** - - 在device\_info.hcs文件中添加deviceNode描述。 - - 【可选】添加watchdog\_config.hcs器件属性文件。 - -3. **实例化Watchdog控制器对象:** - - 初始化WatchdogCntlr成员。 - - 实例化WatchdogCntlr成员WatchdogMethod。 - - >![](../public_sys-resources/icon-note.gif) **说明:** - >实例化WatchdogCntlr成员WatchdogMethod,其定义和成员说明见[接口说明](#section752964871810)。 - - -4. **驱动调试:** - - 【可选】针对新增驱动程序,建议验证驱动基本功能,例如挂载后的信息反馈,超时时间设置的成功与否等。 - - -## 开发实例 - -下方将以watchdog\_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。 - -1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf\_device\_desc.h 中定义)类型的全局变量,且moduleName要和device\_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。 - - 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 - - Watchdog驱动入口参考: - - ``` - struct HdfDriverEntry g_watchdogDriverEntry = { - .moduleVersion = 1, - .Bind = Hi35xxWatchdogBind, //见Bind参考 - .Init = Hi35xxWatchdogInit, //见Init参考 - .Release = Hi35xxWatchdogRelease, //见Release参考 - .moduleName = "HDF_PLATFORM_WATCHDOG",//【必要且与HCS文件中里面的moduleName匹配】 - }; - HDF_INIT(g_watchdogDriverEntry);//调用HDF_INIT将驱动入口注册到HDF框架中 - ``` - -2. 完成驱动入口注册之后,下一步请在device\_info.hcs文件中添加deviceNode信息,并在 watchdog\_config.hcs 中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值与核心层WatchdogCntlr 成员的默认值或限制范围有密切关系。 - - 本例只有一个Watchdog控制器,如有多个器件信息,则需要在device\_info文件增加deviceNode信息,以及在watchdog\_config文件中增加对应的器件属性。 - - - device\_info.hcs 配置参考。 - - ``` - root { - device_info { - match_attr = "hdf_manager"; - device_watchdog :: device { // 设备节点 - device0 :: deviceNode { // 驱动的DeviceNode节点 - policy = 1; // policy字段是驱动服务发布的策略,如果需要面向用户态,则为2 - priority = 20; // 驱动启动优先级 - permission = 0644; // 驱动创建设备节点权限 - moduleName = "HDF_PLATFORM_WATCHDOG"; - // 【必要】驱动名称,该字段的值必须和驱动入口结构的moduleName值一致 - serviceName = "HDF_PLATFORM_WATCHDOG_0"; - // 【必要且唯一】驱动对外发布服务的名称 - deviceMatchAttr = "hisilicon_hi35xx_watchdog_0"; - // 【必要】驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等 - } - } - } - } - ``` - - - watchdog\_config.hcs 配置参考。 - - ``` - root { - platform { - template watchdog_controller {//【必要】模板配置,继承该模板的节点如果使用模板中的默认值,则节点字段可以缺省 - id = 0; - match_attr = ""; - regBase = 0x12050000; //【必要】地址映射需要 - regStep = 0x1000; //【必要】地址映射需要 - } - controller_0x12050000 :: watchdog_controller {//【必要】是作为设备驱动私有数据匹配的关键字 - match_attr = "hisilicon_hi35xx_watchdog_0"; //【必要】必须和device_info.hcs中的deviceMatchAttr值一致 - } - //存在多个 watchdog 时【必须】添加,否则不用 - ... - } - } - ``` - -3. 完成驱动入口注册之后,最后一步就是以核心层WatchdogCntlr对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化WatchdogCntlr成员WatchdogMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。 - - 自定义结构体参考。 - - 从驱动的角度看,自定义结构体是参数和数据的载体,而且watchdog\_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,其中一些重要数值也会传递给核心层WatchdogCntlr对象,例如索引、管脚数等。 - - ``` - struct Hi35xxWatchdog { - struct WatchdogCntlr wdt; //【必要】是链接上下层的载体,具体描述见下面 - OsalSpinlock lock; - volatile unsigned char *regBase;//【必要】地址映射需要 - uint32_t phyBase; //【必要】地址映射需要 - uint32_t regStep; //【必要】地址映射需要 - }; - //WatchdogCntlr是核心层控制器结构体,其中的成员在Init函数中会被赋值 - struct WatchdogCntlr { - struct IDeviceIoService service;//驱动服务 - struct HdfDeviceObject *device; //驱动设备 - OsalSpinlock lock; //此变量在HDF核心层被调用来实现自旋锁功能 - struct WatchdogMethod *ops; //接口回调函数 - int16_t wdtId; //WDG设备的识别id - void *priv; //存储指针 - }; - ``` - - - WatchdogCntlr成员回调函数结构体WatchdogMethod的实例化,其他成员在Init和Bind函数中初始化。 - - ``` - static struct WatchdogMethod g_method = { - .getStatus = Hi35xxWatchdogGetStatus, - .start = Hi35xxWatchdogStart, - .stop = Hi35xxWatchdogStop, - .setTimeout = Hi35xxWatchdogSetTimeout, - .getTimeout = Hi35xxWatchdogGetTimeout, - .feed = Hi35xxWatchdogFeed, - }; - ``` - - - Init函数和Bind函数参考 - - 入参**:** - - HdfDeviceObject :HDF框架给每一个驱动创建的设备对象,用来保存设备相关的私有数据和服务接口。 - - 返回值**:** - - HDF\_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf\_base.h中HDF\_STATUS 定义)。 - - **表 2** Init函数和Bind函数入参和返回值 - - - - - - - - - - - - - - - - - - - - - - -

状态(值)

-

问题描述

-

HDF_ERR_INVALID_OBJECT

-

找不到 WDG 设备

-

HDF_ERR_MALLOC_FAIL

-

内存分配失败

-

HDF_ERR_IO

-

I/O 错误

-

HDF_SUCCESS

-

初始化成功

-

HDF_FAILURE

-

初始化失败

-
- - 函数说明**:** - - 初始化自定义结构体对象,初始化WatchdogCntlr成员,调用核心层WatchdogCntlrAdd函数。 - - ``` - //一般而言,Init函数需要根据入参(HdfDeviceObject对象)的属性值初始化Hi35xxWatchdog结构体的成员, - //但本例中是在bind函数中实现的 - static int32_t Hi35xxWatchdogInit(struct HdfDeviceObject *device) - { - (void)device; - return HDF_SUCCESS; - } +1. **实例化驱动入口:** + - 实例化HdfDriverEntry结构体成员。 + - 调用HDF_INIT将HdfDriverEntry实例化对象注册到HDF框架中。 + +2. **配置属性文件:** + - 在device_info.hcs文件中添加deviceNode描述。 + - 【可选】添加watchdog_config.hcs器件属性文件。 + +3. **实例化Watchdog控制器对象:** + - 初始化WatchdogCntlr成员。 + - 实例化WatchdogCntlr成员WatchdogMethod。 + > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** + > 实例化WatchdogCntlr成员WatchdogMethod,其定义和成员说明见[接口说明](#接口说明)。 + +4. **驱动调试:** + 【可选】针对新增驱动程序,建议验证驱动基本功能,例如挂载后的信息反馈,超时时间设置的成功与否等。 + + +## 开发实例 + +下方将以watchdog_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。 + +1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf_device_desc.h 中定义)类型的全局变量,且moduleName要和device_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。 + 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 + + Watchdog驱动入口参考: + + ``` + struct HdfDriverEntry g_watchdogDriverEntry = { + .moduleVersion = 1, + .Bind = Hi35xxWatchdogBind, //见Bind参考 + .Init = Hi35xxWatchdogInit, //见Init参考 + .Release = Hi35xxWatchdogRelease, //见Release参考 + .moduleName = "HDF_PLATFORM_WATCHDOG",//【必要且与HCS文件中里面的moduleName匹配】 + }; + HDF_INIT(g_watchdogDriverEntry);//调用HDF_INIT将驱动入口注册到HDF框架中 + ``` + +2. 完成驱动入口注册之后,下一步请在device_info.hcs文件中添加deviceNode信息,并在 watchdog_config.hcs 中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值与核心层WatchdogCntlr 成员的默认值或限制范围有密切关系。 + 本例只有一个Watchdog控制器,如有多个器件信息,则需要在device_info文件增加deviceNode信息,以及在watchdog_config文件中增加对应的器件属性。 + - device_info.hcs 配置参考。 + + + ``` + root { + device_info { + match_attr = "hdf_manager"; + device_watchdog :: device { // 设备节点 + device0 :: deviceNode { // 驱动的DeviceNode节点 + policy = 1; // policy字段是驱动服务发布的策略,如果需要面向用户态,则为2 + priority = 20; // 驱动启动优先级 + permission = 0644; // 驱动创建设备节点权限 + moduleName = "HDF_PLATFORM_WATCHDOG"; + // 【必要】驱动名称,该字段的值必须和驱动入口结构的moduleName值一致 + serviceName = "HDF_PLATFORM_WATCHDOG_0"; + // 【必要且唯一】驱动对外发布服务的名称 + deviceMatchAttr = "hisilicon_hi35xx_watchdog_0"; + // 【必要】驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等 + } + } + } + } + ``` + + - watchdog_config.hcs 配置参考。 + + + ``` + root { + platform { + template watchdog_controller {//【必要】模板配置,继承该模板的节点如果使用模板中的默认值,则节点字段可以缺省 + id = 0; + match_attr = ""; + regBase = 0x12050000; //【必要】地址映射需要 + regStep = 0x1000; //【必要】地址映射需要 + } + controller_0x12050000 :: watchdog_controller {//【必要】是作为设备驱动私有数据匹配的关键字 + match_attr = "hisilicon_hi35xx_watchdog_0"; //【必要】必须和device_info.hcs中的deviceMatchAttr值一致 + } + //存在多个 watchdog 时【必须】添加,否则不用 + ... + } + } + ``` + +3. 完成驱动入口注册之后,最后一步就是以核心层WatchdogCntlr对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化WatchdogCntlr成员WatchdogMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。 + - 自定义结构体参考。 + + 从驱动的角度看,自定义结构体是参数和数据的载体,而且watchdog_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,其中一些重要数值也会传递给核心层WatchdogCntlr对象,例如索引、管脚数等。 + + + ``` + struct Hi35xxWatchdog { + struct WatchdogCntlr wdt; //【必要】是链接上下层的载体,具体描述见下面 + OsalSpinlock lock; + volatile unsigned char *regBase;//【必要】地址映射需要 + uint32_t phyBase; //【必要】地址映射需要 + uint32_t regStep; //【必要】地址映射需要 + }; + //WatchdogCntlr是核心层控制器结构体,其中的成员在Init函数中会被赋值 + struct WatchdogCntlr { + struct IDeviceIoService service;//驱动服务 + struct HdfDeviceObject *device; //驱动设备 + OsalSpinlock lock; //此变量在HDF核心层被调用来实现自旋锁功能 + struct WatchdogMethod *ops; //接口回调函数 + int16_t wdtId; //WDG设备的识别id + void *priv; //存储指针 + }; + ``` + - WatchdogCntlr成员回调函数结构体WatchdogMethod的实例化,其他成员在Init和Bind函数中初始化。 + - static int32_t Hi35xxWatchdogBind(struct HdfDeviceObject *device) - { - int32_t ret; - struct Hi35xxWatchdog *hwdt = NULL; - ... - hwdt = (struct Hi35xxWatchdog *)OsalMemCalloc(sizeof(*hwdt));//Hi35xxWatchdog 结构体的内存申请 - ... - hwdt->regBase = OsalIoRemap(hwdt->phyBase, hwdt->regStep); //地址映射 - ... - hwdt->wdt.priv = (void *)device->property;//【可选】此处是将设备属性的内容赋值给priv成员,但后续没有调用 priv 成员, - // 如果需要用到priv成员,需要额外实例化WatchdogMethod的getPriv和releasePriv成员函数 - hwdt->wdt.ops = &g_method; //【必要】将实例化后的对象赋值给ops成员,就可以实现顶层调用WatchdogMethod成员函数 - hwdt->wdt.device = device; //【必要】这是为了方便HdfDeviceObject与WatchdogcCntlr相互转化 - ret = WatchdogCntlrAdd(&hwdt->wdt); //【必要】调用此函数初始化核心层结构体,返回成功信号后驱动才完全接入平台核心层 - if (ret != HDF_SUCCESS) { //不成功的话,需要释放Init函数申请的资源 - OsalIoUnmap((void *)hwdt->regBase); - OsalMemFree(hwdt); - return ret; - } - return HDF_SUCCESS; - } - ``` - - - Release函数参考 - - 入参: - - HdfDeviceObject :HDF框架给每一个驱动创建的设备对象,用来保存设备相关的私有数据和服务接口。 - - 返回值**:** - - 无。 - - 函数说明**:** - - 该函数需要在驱动入口结构体中赋值给Release,当HDF框架调用Init函数初始化驱动失败时,可以调用Release释放驱动资源。该函数中需包含释放内存和删除控制器等操作。所有强制转换获取相应对象的操作**前提**是在Init函数中具备对应赋值的操作。 - - ``` - static void Hi35xxWatchdogRelease(struct HdfDeviceObject *device) - { - struct WatchdogCntlr *wdt = NULL; - struct Hi35xxWatchdog *hwdt = NULL; - ... - wdt = WatchdogCntlrFromDevice(device);//这里会通过service成员将HdfDeviceObject转化为WatchdogCntlr - //return (device == NULL) ? NULL : (struct WatchdogCntlr *)device->service; - if (wdt == NULL) { - return; - } - WatchdogCntlrRemove(wdt); //核心层函数,实际执行wdt->device->service = NULL以及cntlr->lock的释放 - hwdt = (struct Hi35xxWatchdog *)wdt; //这里将WatchdogCntlr转化为HimciHost - if (hwdt->regBase != NULL) { //解除地址映射 - OsalIoUnmap((void *)hwdt->regBase); - hwdt->regBase = NULL; - } - OsalMemFree(hwdt); //释放厂商自定义对象占用的内存 - } - ``` + ``` + static struct WatchdogMethod g_method = { + .getStatus = Hi35xxWatchdogGetStatus, + .start = Hi35xxWatchdogStart, + .stop = Hi35xxWatchdogStop, + .setTimeout = Hi35xxWatchdogSetTimeout, + .getTimeout = Hi35xxWatchdogGetTimeout, + .feed = Hi35xxWatchdogFeed, + }; + ``` + + - Init函数和Bind函数参考 + 入参: + HdfDeviceObject :HDF框架给每一个驱动创建的设备对象,用来保存设备相关的私有数据和服务接口。 + 返回值: + + HDF_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf_base.h中HDF_STATUS 定义)。 + + **表2** Init函数和Bind函数入参和返回值 + + | 状态(值) | 问题描述 | + | -------- | -------- | + | HDF_ERR_INVALID_OBJECT | 找不到 WDG 设备 | + | HDF_ERR_MALLOC_FAIL | 内存分配失败 | + | HDF_ERR_IO | I/O 错误 | + | HDF_SUCCESS | 初始化成功 | + | HDF_FAILURE | 初始化失败 | + + 函数说明: + + 初始化自定义结构体对象,初始化WatchdogCntlr成员,调用核心层WatchdogCntlrAdd函数。 + + + ``` + //一般而言,Init函数需要根据入参(HdfDeviceObject对象)的属性值初始化Hi35xxWatchdog结构体的成员, + //但本例中是在bind函数中实现的 + static int32_t Hi35xxWatchdogInit(struct HdfDeviceObject *device) + { + (void)device; + return HDF_SUCCESS; + } + + static int32_t Hi35xxWatchdogBind(struct HdfDeviceObject *device) + { + int32_t ret; + struct Hi35xxWatchdog *hwdt = NULL; + ... + hwdt = (struct Hi35xxWatchdog *)OsalMemCalloc(sizeof(*hwdt));//Hi35xxWatchdog 结构体的内存申请 + ... + hwdt->regBase = OsalIoRemap(hwdt->phyBase, hwdt->regStep); //地址映射 + ... + hwdt->wdt.priv = (void *)device->property;//【可选】此处是将设备属性的内容赋值给priv成员,但后续没有调用 priv 成员, + // 如果需要用到priv成员,需要额外实例化WatchdogMethod的getPriv和releasePriv成员函数 + hwdt->wdt.ops = &g_method; //【必要】将实例化后的对象赋值给ops成员,就可以实现顶层调用WatchdogMethod成员函数 + hwdt->wdt.device = device; //【必要】这是为了方便HdfDeviceObject与WatchdogcCntlr相互转化 + ret = WatchdogCntlrAdd(&hwdt->wdt); //【必要】调用此函数初始化核心层结构体,返回成功信号后驱动才完全接入平台核心层 + if (ret != HDF_SUCCESS) { //不成功的话,需要释放Init函数申请的资源 + OsalIoUnmap((void *)hwdt->regBase); + OsalMemFree(hwdt); + return ret; + } + return HDF_SUCCESS; + } + ``` + - Release函数参考 + + 入参: + + HdfDeviceObject :HDF框架给每一个驱动创建的设备对象,用来保存设备相关的私有数据和服务接口。 + + 返回值: + + 无。 + + 函数说明: + + 该函数需要在驱动入口结构体中赋值给Release,当HDF框架调用Init函数初始化驱动失败时,可以调用Release释放驱动资源。该函数中需包含释放内存和删除控制器等操作。所有强制转换获取相应对象的操作前提是在Init函数中具备对应赋值的操作。 + + + ``` + static void Hi35xxWatchdogRelease(struct HdfDeviceObject *device) + { + struct WatchdogCntlr *wdt = NULL; + struct Hi35xxWatchdog *hwdt = NULL; + ... + wdt = WatchdogCntlrFromDevice(device);//这里会通过service成员将HdfDeviceObject转化为WatchdogCntlr + //return (device == NULL) ? NULL : (struct WatchdogCntlr *)device->service; + if (wdt == NULL) { + return; + } + WatchdogCntlrRemove(wdt); //核心层函数,实际执行wdt->device->service = NULL以及cntlr->lock的释放 + hwdt = (struct Hi35xxWatchdog *)wdt; //这里将WatchdogCntlr转化为HimciHost + if (hwdt->regBase != NULL) { //解除地址映射 + OsalIoUnmap((void *)hwdt->regBase); + hwdt->regBase = NULL; + } + OsalMemFree(hwdt); //释放厂商自定义对象占用的内存 + } + ``` diff --git a/zh-cn/device-dev/driver/driver-platform.md b/zh-cn/device-dev/driver/driver-platform.md index c073c4374937fc28578e4add8e06c3a6fb568ab5..54f0c53029a7a5a632b548f0f9f34564f068ef5e 100644 --- a/zh-cn/device-dev/driver/driver-platform.md +++ b/zh-cn/device-dev/driver/driver-platform.md @@ -1,31 +1,21 @@ -# 平台驱动使用 +# 平台驱动使用 -- **[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)** +- **[RTC](driver-platform-rtc-des.md)** -- **[I3C](driver-platform-i3c-des.md)** +- **[SDIO](driver-platform-sdio-des.md)** -- **[MIPI-CSI](driver-platform-mipicsi-des.md)** +- **[SPI](driver-platform-spi-des.md)** -- **[MIPI-DSI](driver-platform-mipidsi-des.md)** +- **[UART](driver-platform-uart-des.md)** -- **[PIN](driver-platform-pin-des.md)** +- **[Watchdog](driver-platform-watchdog-des.md)** -- **[PWM](driver-platform-pwm-des.md)** +- **[MIPI DSI](driver-platform-mipidsi-des.md)** -- **[RTC](driver-platform-rtc-des.md)** - -- **[SDIO](driver-platform-sdio-des.md)** - -- **[SPI](driver-platform-spi-des.md)** - -- **[UART](driver-platform-uart-des.md)** - -- **[WATCHDOG](driver-platform-watchdog-des.md)** +- **[PWM](driver-platform-pwm-des.md)** \ No newline at end of file diff --git a/zh-cn/device-dev/driver/driver.md b/zh-cn/device-dev/driver/driver.md index da3839d4de7c68822c784f3f6b1fe32c1457baae..9d5d64412e016382e82f4ea367215b730a3059b3 100644 --- a/zh-cn/device-dev/driver/driver.md +++ b/zh-cn/device-dev/driver/driver.md @@ -1,11 +1,11 @@ -# 驱动 +# 驱动 -- **[HDF驱动框架](driver-hdf.md)** -- **[平台驱动开发](driver-develop.md)** -- **[平台驱动使用](driver-platform.md)** +- **[HDF驱动框架](driver-hdf.md)** -- **[外设驱动使用](driver-peripherals.md)** +- **[平台驱动开发](driver-develop.md)** +- **[平台驱动使用](driver-platform.md)** +- **[外设驱动使用](driver-peripherals.md)** \ No newline at end of file diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001123742904.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001123742904.png new file mode 100644 index 0000000000000000000000000000000000000000..db8069cb7a0bc1dcd7906131ce87ad54cc8ea340 Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001123742904.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001147040198.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001147040198.png new file mode 100644 index 0000000000000000000000000000000000000000..6e39de8017f25a7e4cc6f51fa77ffcc9243ad818 Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001147040198.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001153947412.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001153947412.png new file mode 100644 index 0000000000000000000000000000000000000000..f2a5855dfeea0eaa8e4db38323b25858ef6a1e09 Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001153947412.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001154105768.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001154105768.png new file mode 100644 index 0000000000000000000000000000000000000000..3803784ebc2200f61b79420e52b010cad1a55eab Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001154105768.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001160652842.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001160652842.png new file mode 100644 index 0000000000000000000000000000000000000000..1b5ffbcd060a3315eb9ac48a5f7b1a95c801c24b Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001160652842.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001160653004.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001160653004.png new file mode 100644 index 0000000000000000000000000000000000000000..f84f4ebd06f7257d119b1c9a6e56fc0ab5463750 Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001160653004.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001160812804.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001160812804.png new file mode 100644 index 0000000000000000000000000000000000000000..6ac63e41108abd4776621356c3034fc52b6f436f Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001160812804.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001160971308.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001160971308.png new file mode 100644 index 0000000000000000000000000000000000000000..96f68d24918dacf9244e0ad020f2e99d77f589c4 Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001160971308.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001160971552.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001160971552.png new file mode 100644 index 0000000000000000000000000000000000000000..808e3b3197e19ec7b1183fdd974bff7090c0b362 Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001160971552.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001170262223.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001170262223.png new file mode 100644 index 0000000000000000000000000000000000000000..1fa1231040f82789982f8a9b930304022bc9b2b5 Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001170262223.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001176603944.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001176603944.png new file mode 100644 index 0000000000000000000000000000000000000000..2f2c9acd3fa5675175743f8ce39c9f8b573f758e Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001176603944.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001176603952.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001176603952.png new file mode 100644 index 0000000000000000000000000000000000000000..dbca541769d3fc274cf4bf4248b108d3e0bb7e5f Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001176603952.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001176603960.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001176603960.png new file mode 100644 index 0000000000000000000000000000000000000000..dbca541769d3fc274cf4bf4248b108d3e0bb7e5f Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001176603960.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001176603968.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001176603968.png new file mode 100644 index 0000000000000000000000000000000000000000..2f2c9acd3fa5675175743f8ce39c9f8b573f758e Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001176603968.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001176603980.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001176603980.png new file mode 100644 index 0000000000000000000000000000000000000000..2f2c9acd3fa5675175743f8ce39c9f8b573f758e Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001176603980.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001176603992.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001176603992.png new file mode 100644 index 0000000000000000000000000000000000000000..2f2c9acd3fa5675175743f8ce39c9f8b573f758e Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001176603992.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001177082386.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001177082386.png new file mode 100644 index 0000000000000000000000000000000000000000..2f2c9acd3fa5675175743f8ce39c9f8b573f758e Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001177082386.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001177082394.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001177082394.png new file mode 100644 index 0000000000000000000000000000000000000000..750455998a2e7b698ef91a5f9732b039fba7d5c1 Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001177082394.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001177082396.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001177082396.png new file mode 100644 index 0000000000000000000000000000000000000000..2f2c9acd3fa5675175743f8ce39c9f8b573f758e Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001177082396.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001177082414.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001177082414.png new file mode 100644 index 0000000000000000000000000000000000000000..750455998a2e7b698ef91a5f9732b039fba7d5c1 Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001177082414.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001177082420.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001177082420.png new file mode 100644 index 0000000000000000000000000000000000000000..2f2c9acd3fa5675175743f8ce39c9f8b573f758e Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001177082420.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001183058868.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001183058868.png new file mode 100644 index 0000000000000000000000000000000000000000..6bea2992afd00b031176998278c0bcfce0f8e843 Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001183058868.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001183218992.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001183218992.png new file mode 100644 index 0000000000000000000000000000000000000000..3766cf8117505a0d47720dcbccc1030536921bdb Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001183218992.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001192846991.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001192846991.png new file mode 100644 index 0000000000000000000000000000000000000000..6d33da5cc9efaa7d7d880623735e32a37f171dd8 Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001192846991.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001192960023.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001192960023.png new file mode 100644 index 0000000000000000000000000000000000000000..7209d111f142c3da063e0f761387c69b48725a98 Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001192960023.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001197807387.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001197807387.png new file mode 100644 index 0000000000000000000000000000000000000000..92b531d067c78063fb785c9ea802f90db1ac2e44 Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001197807387.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001198152838.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001198152838.png new file mode 100644 index 0000000000000000000000000000000000000000..0d946444c5b2014ca21110e4b73dcb6a6d4b0f18 Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001198152838.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001200092359.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001200092359.png new file mode 100644 index 0000000000000000000000000000000000000000..87b45b288d127e85f836d8673fda820f1069186b Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001200092359.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001206092753.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001206092753.png new file mode 100644 index 0000000000000000000000000000000000000000..33ca15524892ebbad53859fab710a5309e326127 Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001206092753.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001206092987.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001206092987.png new file mode 100644 index 0000000000000000000000000000000000000000..5e94b319b49153385f2cf1372a3c43aef6b834e9 Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001206092987.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001206171539.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001206171539.png new file mode 100644 index 0000000000000000000000000000000000000000..09085c82c461015a312650c0a9aad57116771e0a Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001206171539.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001206291109.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001206291109.png new file mode 100644 index 0000000000000000000000000000000000000000..8c246a7f6a67005d30808fac11172b2108bc4e2d Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001206291109.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001206291275.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001206291275.png new file mode 100644 index 0000000000000000000000000000000000000000..b876193bfd1d4dee4fd13d943593fea050cc8e39 Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001206291275.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001206291495.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001206291495.png new file mode 100644 index 0000000000000000000000000000000000000000..beda2c0154e82a787616fdfb5643fade470da175 Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001206291495.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001206372673.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001206372673.png index 4fe8c2506c044bb280a52138a9936e8d7d2e8c01..339d44368a15f4e58d7711c69f136bccdbc9d6db 100644 Binary files a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001206372673.png and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001206372673.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001206372789.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001206372789.png new file mode 100644 index 0000000000000000000000000000000000000000..b5e82f09cd764b0cd9dc835e55f8f878b77eb91e Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001206372789.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001209705336.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001209705336.png new file mode 100644 index 0000000000000000000000000000000000000000..c9661fda039f1cdf88b5df2ad9d78d8ad0d08050 Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001209705336.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001243192721.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001243192721.png new file mode 100644 index 0000000000000000000000000000000000000000..40a2c93c66002b00db0014471b46743a5d4620e8 Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001243192721.png differ diff --git a/zh-cn/device-dev/driver/figures/zh-cn_image_0000001254063099.png b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001254063099.png new file mode 100644 index 0000000000000000000000000000000000000000..59a2a2b083fcd31291011a96fa092da2da38e99c Binary files /dev/null and b/zh-cn/device-dev/driver/figures/zh-cn_image_0000001254063099.png differ diff --git a/zh-cn/device-dev/driver/public_sys-resources/icon-caution.gif b/zh-cn/device-dev/driver/public_sys-resources/icon-caution.gif new file mode 100644 index 0000000000000000000000000000000000000000..6e90d7cfc2193e39e10bb58c38d01a23f045d571 Binary files /dev/null and b/zh-cn/device-dev/driver/public_sys-resources/icon-caution.gif differ diff --git a/zh-cn/device-dev/driver/public_sys-resources/icon-danger.gif b/zh-cn/device-dev/driver/public_sys-resources/icon-danger.gif new file mode 100644 index 0000000000000000000000000000000000000000..6e90d7cfc2193e39e10bb58c38d01a23f045d571 Binary files /dev/null and b/zh-cn/device-dev/driver/public_sys-resources/icon-danger.gif differ diff --git a/zh-cn/device-dev/driver/public_sys-resources/icon-note.gif b/zh-cn/device-dev/driver/public_sys-resources/icon-note.gif new file mode 100644 index 0000000000000000000000000000000000000000..6314297e45c1de184204098efd4814d6dc8b1cda Binary files /dev/null and b/zh-cn/device-dev/driver/public_sys-resources/icon-note.gif differ diff --git a/zh-cn/device-dev/driver/public_sys-resources/icon-notice.gif b/zh-cn/device-dev/driver/public_sys-resources/icon-notice.gif new file mode 100644 index 0000000000000000000000000000000000000000..86024f61b691400bea99e5b1f506d9d9aef36e27 Binary files /dev/null and b/zh-cn/device-dev/driver/public_sys-resources/icon-notice.gif differ diff --git a/zh-cn/device-dev/driver/public_sys-resources/icon-tip.gif b/zh-cn/device-dev/driver/public_sys-resources/icon-tip.gif new file mode 100644 index 0000000000000000000000000000000000000000..93aa72053b510e456b149f36a0972703ea9999b7 Binary files /dev/null and b/zh-cn/device-dev/driver/public_sys-resources/icon-tip.gif differ diff --git a/zh-cn/device-dev/driver/public_sys-resources/icon-warning.gif b/zh-cn/device-dev/driver/public_sys-resources/icon-warning.gif new file mode 100644 index 0000000000000000000000000000000000000000..6e90d7cfc2193e39e10bb58c38d01a23f045d571 Binary files /dev/null and b/zh-cn/device-dev/driver/public_sys-resources/icon-warning.gif differ diff --git a/zh-cn/device-dev/faqs/Readme-CN.md b/zh-cn/device-dev/faqs/Readme-CN.md index dd6d4efe122a3e31ff94511db3fb603927896996..d3feae870c2ab7d34eaa629e45b4f74fbfc97412 100644 --- a/zh-cn/device-dev/faqs/Readme-CN.md +++ b/zh-cn/device-dev/faqs/Readme-CN.md @@ -1,11 +1,11 @@ -# FAQs +# faqs -- [常见问题概述](faqs-overview.md) -- [环境搭建常见问题](faqs-environment-setup.md) -- [编译构建子系统常见问题](faqs-building.md) -- [烧录常见问题](faqs-burning.md) -- [内核常见问题](faqs-kernel.md) -- [移植常见问题](faqs-porting.md) -- [启动恢复常见问题](faqs-startup.md) -- [系统应用常见问题](faqs-system-applications.md) +- [常见问题概述](faqs-overview.md) +- [环境搭建常见问题](faqs-environment-setup.md) +- [编译构建子系统常见问题](faqs-building.md) +- [烧录常见问题](faqs-burning.md) +- [内核常见问题](faqs-kernel.md) +- [移植常见问题](faqs-transplant.md) +- [启动恢复常见问题](faqs-init.md) +- [系统应用常见问题](faqs-system-using.md) diff --git a/zh-cn/device-dev/faqs/faqs-building.md b/zh-cn/device-dev/faqs/faqs-building.md index 12be2bceb835a87697cac6fb06425a3f966dfe91..b60b540bc012f6f6f031839ea4740c97c841da44 100644 --- a/zh-cn/device-dev/faqs/faqs-building.md +++ b/zh-cn/device-dev/faqs/faqs-building.md @@ -1,251 +1,214 @@ -# 编译构建子系统常见问题 +# 编译构建子系统常见问题 -- [轻量和小型系统](#section78686441462) - - [编译构建过程中,提示“usr/sbin/ninja: invalid option -- w”](#section67961431372) - - [编译构建过程中,提示“/usr/bin/ld: cannot find -lncurses”](#section199631617371) - - [编译构建过程中,提示“line 77: mcopy: command not found”](#section937435175) - - [编译构建过程中,提示“riscv32-unknown-elf-gcc: error trying to exec 'cc1': execvp: No such file or directory”](#section1115535018713) - - [编译构建过程中,提示“No module named 'Crypto'”](#section17982573813) - - [编译构建过程中,提示“xx.sh : xx unexpected operator”](#section53663205819) - - [编译构建过程中,提示“Could not find a version that satisfies the requirement six\>=1.9.0”](#section1917790845) - - [编译构建过程中,提示找不到“-lgcc”](#section141771701647) - - [编译构建过程中,提示找不到“python”](#section51781202415) - - [编译构建过程中,提示找不到“python3”](#section1917950148) +## 轻量和小型系统 -## 轻量和小型系统 -### 编译构建过程中,提示“usr/sbin/ninja: invalid option -- w” +### 编译构建过程中,提示“usr/sbin/ninja: invalid option -- w” -- **现象描述:** +- **现象描述:** + 编译失败,提示“usr/sbin/ninja: invalid option -- w”。 - 编译失败,提示“usr/sbin/ninja: invalid option -- w”。 +- **可能原因:** + 编译环境中ninja版本太低,不支持--w选项。 -- **可能原因:** +- **解决办法:** + 卸载环境中ninja和gn,按照[获取工具](../get-code/gettools-ide.md)。 - 编译环境中ninja版本太低,不支持--w选项。 -- **解决办法:** +### 编译构建过程中,提示“/usr/bin/ld: cannot find -lncurses” - 卸载环境中ninja和gn,按照[获取工具](../get-code/gettools-ide.md)。 +- **现象描述:** + 编译失败,提示“/usr/bin/ld: cannot find -lncurses”。 +- **可能原因:** + 编译环境ncurses库缺失。 -### 编译构建过程中,提示“/usr/bin/ld: cannot find -lncurses” +- **解决办法:** + + ``` + sudo apt-get install lib32ncurses5-dev + ``` -- **现象描述:** - 编译失败,提示“/usr/bin/ld: cannot find -lncurses”。 +### 编译构建过程中,提示“line 77: mcopy: command not found” -- **可能原因:** +- **现象描述:** + ​编译失败,提示“line 77: mcopy: command not found”。 - 编译环境ncurses库缺失。 +- **可能原因:** + 编译环境未安装mcopy。 -- **解决办法:** +- **解决办法:** + + ``` + ​sudo apt-get install dosfstools mtools + ``` - ``` - sudo apt-get install lib32ncurses5-dev - ``` +### 编译构建过程中,提示“riscv32-unknown-elf-gcc: error trying to exec 'cc1': execvp: No such file or directory” -### 编译构建过程中,提示“line 77: mcopy: command not found” +- **现象描述:** + 编译失败,提示“riscv32-unknown-elf-gcc: error trying to exec 'cc1': execvp: No such file or directory”。 -- **现象描述:** +- ​**可能原因:** + 当前用户对riscv编译器路径下的文件访问权限不够。 - ​编译失败,提示“line 77: mcopy: command not found”。 +- ​**解决办法:** + 查询gcc_riscv32所在目录。 + + ``` + which riscv32-unknown-elf-gcc + ``` -- **可能原因:** + 使用chmod命令修改目录权限为755。 - 编译环境未安装mcopy。 -- **解决办法:** +### 编译构建过程中,提示“No module named 'Crypto'” - ``` - ​sudo apt-get install dosfstools mtools - ``` +- **现象描述:** + 编译失败,提示“No module named 'Crypto'”。 +- **可能原因:** + python3未安装Crypto。 -### 编译构建过程中,提示“riscv32-unknown-elf-gcc: error trying to exec 'cc1': execvp: No such file or directory” +- **解决办法:** + 1. 查询Python版本号。 + + ``` + python3 --version + ``` + 2. 需使用python3.7以上版本,然后安装pycryptodome。 + + ``` + sudo pip3 install pycryptodome + ``` -- **现象描述:** - 编译失败,提示“riscv32-unknown-elf-gcc: error trying to exec 'cc1': execvp: No such file or directory”。 +### 编译构建过程中,提示“xx.sh : xx unexpected operator” -- ​**可能原因:** +- **现象描述:** + 编译失败:“xx.sh [: xx unexpected operator”。 - 当前用户对riscv编译器路径下的文件访问权限不够。 +- **可能原因:** + 编译环境shell不是bash。 -- ​**解决办法:** +- **解决办法:** + + ``` + sudo rm -rf /bin/sh + sudo ln -s /bin/bash /bin/sh + ``` - 查询gcc\_riscv32所在目录。 - ``` - which riscv32-unknown-elf-gcc - ``` +### 编译构建过程中,提示“Could not find a version that satisfies the requirement six>=1.9.0” - 使用chmod命令修改目录权限为755。 +- **现象描述** + 编译构建过程中出现以下错误: + + ``` + Could not find a version that satisfies the requirement six>=1.9.0 + ``` -### 编译构建过程中,提示“No module named 'Crypto'” +- **可能原因** + 环境中未安装合适的“six”。 -- **现象描述:** +- **解决办法** + 方法1:通过命令“pip3 install six”,在线安装。 - 编译失败,提示“No module named 'Crypto'”。 + 方法2:离线安装。 -- **可能原因:** + 通过网页[https://pypi.org/project/six/#files](https://pypi.org/project/six/#files),下载安装包。 - python3未安装Crypto。 + ![zh-cn_image_0000001251276115](figures/zh-cn_image_0000001251276115.png) -- **解决办法:** - 1. 查询Python版本号。 + 将源码放置在Linux服务器中,并安装“pip3 install six-1.14.0-py2.py3-none-any.whl”。 - ``` - python3 --version - ``` + 完成上述安装后,重新构建。 - 2. 需使用python3.7以上版本,然后安装pycryptodome。 - ``` - sudo pip3 install pycryptodome - ``` +### 编译构建过程中,提示找不到“-lgcc” +- **现象描述** + 编译构建过程中出现以下错误: + + ``` + riscv32-unknown-elf-ld: cannot find -lgcc + ``` -### 编译构建过程中,提示“xx.sh : xx unexpected operator” +- **可能原因** + 交叉编译器gcc_riscv32的PATH添加错误,如下,在"bin"后多添加了一个“/”,应该删除。 -- **现象描述:** + + ``` + ~/gcc_riscv32/bin/:/data/toolchain/ + ``` - 编译失败:“xx.sh \[: xx unexpected operator”。 +- **解决办法** + 重新修改gcc_riscv32的PATH,将多余的“/”删除。 -- **可能原因:** + + ``` + ~/gcc_riscv32/bin:/data/toolchain/ + ``` - 编译环境shell不是bash。 -- **解决办法:** +### 编译构建过程中,提示找不到“python” - ``` - sudo rm -rf /bin/sh - sudo ln -s /bin/bash /bin/sh - ``` +- **现象描述** + 编译构建过程中出现以下错误: + + ``` + -bash: /usr/bin/python: No such file or directory + ``` -### 编译构建过程中,提示“Could not find a version that satisfies the requirement six\>=1.9.0” +- **可能原因**1 + 没有装python。 -- **现象描述** +- **解决办法** + 请使用如下命令安装Python,下方以Python3.8为例。 - 编译构建过程中出现以下错误: + + ``` + sudo apt-get install python3.8 + ``` - ``` - Could not find a version that satisfies the requirement six>=1.9.0 - ``` +- **可能原因2** + usr/bin目录下没有python软链接 + ![zh-cn_image_0000001243200677](figures/zh-cn_image_0000001243200677.png) -- **可能原因** +- **解决办法** + 请运行以下命令添加软链接: - 环境中未安装合适的“six”。 + + ``` + # cd /usr/bin/ + # which python3 + # ln -s /usr/local/bin/python3 python + # python --version + ``` + 例: -- **解决办法** + ![zh-cn_image_0000001243320787](figures/zh-cn_image_0000001243320787.png) - 方法1:通过命令“pip3 install six”,在线安装。 - 方法2:离线安装 +### 编译构建过程中,提示找不到“python3” - 通过网页[https://pypi.org/project/six/\#files](https://pypi.org/project/six/#files),下载安装包。 +- **现象描述** + ![zh-cn_image_0000001251276255](figures/zh-cn_image_0000001251276255.png) - ![](figures/download-six.png) +- **可能原因** + 没有装python3。 - 将源码放置在Linux服务器中,并安装“pip3 install six-1.14.0-py2.py3-none-any.whl”。 - - 完成上述安装后,重新构建。 - - -### 编译构建过程中,提示找不到“-lgcc” - -- **现象描述** - - 编译构建过程中出现以下错误: - - ``` - riscv32-unknown-elf-ld: cannot find -lgcc - ``` - - -- **可能原因** - - 交叉编译器gcc\_riscv32的PATH添加错误,如下,在"bin"后多添加了一个“/”,应该删除。 - - ``` - ~/gcc_riscv32/bin/:/data/toolchain/ - ``` - - -- **解决办法** - - 重新修改gcc\_riscv32的PATH,将多余的“/”删除。 - - ``` - ~/gcc_riscv32/bin:/data/toolchain/ - ``` - - -### 编译构建过程中,提示找不到“python” - -- **现象描述** - - 编译构建过程中出现以下错误: - - ``` - -bash: /usr/bin/python: No such file or directory - ``` - - -- **可能原因**1 - - 没有装python。 - -- **解决办法** - - 请使用如下命令安装Python,下方以Python3.8为例。 - ``` - sudo apt-get install python3.8 - ``` - -- **可能原因2** - usr/bin目录下没有python软链接 - - ![](figures/reason-no-python-soft-link.png) - -- **解决办法** - - 请运行以下命令添加软链接: - - ``` - # cd /usr/bin/ - # which python3 - # ln -s /usr/local/bin/python3 python - # python --version - ``` - - 例: - - ![](figures/solution-add-soft-link.png) - - -### 编译构建过程中,提示找不到“python3” - -- **现象描述** - - 安装python3过程中出现以下错误: - ``` - configure: error: no acceptable C compiler found in $PATH. See 'config.log' for more details - ``` - -- **可能原因** - - 环境中未安装“gcc”。 - -- **解决办法** - - 1. 通过命令“apt-get install gcc”在线安装。 - 2. 完成后,重新安装python3。 +- **解决办法** + 请使用如下命令安装Python3。 + + ``` + sudo apt-get install python3.8 + ``` diff --git a/zh-cn/device-dev/faqs/faqs-burning.md b/zh-cn/device-dev/faqs/faqs-burning.md index ba07a0feb6a3e89be14c81638914bb930f75f92c..0a49cd6d141732e328696bbd60f76ca80fa8f9d7 100644 --- a/zh-cn/device-dev/faqs/faqs-burning.md +++ b/zh-cn/device-dev/faqs/faqs-burning.md @@ -1,129 +1,130 @@ -# 烧录常见问题 +# 烧录常见问题 -- [轻量和小型系统](#section278314413530) - - [烧写选择串口后,提示“Error: Opening COMxx: Access denied”](#section18988185615914) - - [烧写失败](#section1370982513317) - - [串口无回显](#section183421944953) - - [Windows电脑与单板网络连接失败](#section1215410450215) +## 轻量和小型系统 -## 轻量和小型系统 -### 烧写选择串口后,提示“Error: Opening COMxx: Access denied” +### 烧写选择串口后提示“Error: Opening COMxx: Access denied” -- **现象描述** +- **现象描述** + 点击烧写并选择串口后,出现Error: Opening COMxx: Access denied。 - 点击烧写并选择串口后,出现“Error: Opening COMxx: Access denied”。 + **图1** 打开串口失败图 + ![zh-cn_image_0000001243481961](figures/zh-cn_image_0000001243481961.png) - ![](figures/Failed-to-open-the-serial-port.png) +- **可能原因** + 串口已经被占用。 -- **可能原因** +- **解决办法** - 串口已经被占用。 +1. 按图依次选择下拉框,查找带有serial-xx的终端。 + -- 解决方法 + **图2** 查找是否存在占用串口的终端 + ![zh-cn_image_0000001243481989](figures/zh-cn_image_0000001243481989.png) - 检查主机中可能占用该端口的工具,关闭即可。若是当前工具占用,可按以下步骤排查并关闭: +2. 点击标号中的垃圾桶图标,关闭串口。 + + **图3** 关闭串口终端 - 1. 排查终端窗口列表,检查是否被monitor或其他终端占用。 + ![zh-cn_image_0000001243082093](figures/zh-cn_image_0000001243082093.png) - ![](figures/terminal-list.png) +3. 重新点击烧写,选择串口并开始烧写程序。 + + **图4** 重新启动烧写任务 - 2. 找到占用,点击垃圾桶图标,关闭占用。 + ![zh-cn_image_0000001198322224](figures/zh-cn_image_0000001198322224.png) -### 烧写失败 +### 烧写失败 -- **现象描述** +- **现象描述** + 点击烧写并选择串口后,出现无法烧写的情况。 - 点击烧写并选择串口后,出现无法烧写的情况。 +- **可能原因** + 安装IDE插件DevEco后未重启。 -- **可能原因** +- **解决方法** + 重启IDE。 - 安装IDE插件DevEco后未重启。 -- **解决方法** +### 串口无回显 - 重启IDE。 +- **现象描述** + 串口显示已连接,重启单板后,回车无任何回显。 +- **可能原因1** + 串口连接错误。 -### 串口无回显 +- **解决办法** + 修改串口号。 -- **现象描述** + 请查看设备管理器,确认连接单板的串口与终端中连接串口是否一致,若不一致,请按镜像运行内步骤1修改串口号。 - 串口显示已连接,重启单板后,回车无任何回显。 +- **可能原因2** + 单板U-boot被损坏。 -- **可能原因1** +- **解决办法** + 烧写U-boot。 - 串口连接错误。 + 若上述步骤依旧无法连接串口,可能由于单板U-boot损坏,按下述步骤烧写U-boot。 -- **解决办法** +1. 获取引导文件U-boot。 + > ![icon-notice.gif](public_sys-resources/icon-notice.gif) **须知:** + > 单板的U-boot文件请在开源包中获取: + > + > Hi3516DV300:device\hisilicon\hispark_taurus\sdk_liteos\uboot\out\boot\u-boot-hi3516dv300.bin + > + > Hi3518EV300:device\hisilicon\hispark_aries\sdk_liteos\uboot\out\boot\u-boot-hi3518ev300.bin - 修改串口号。 +2. 根据USB烧写步骤烧写U-boot文件。 + 按照[Hi3516系列USB烧写步骤](../quick-start/quickstart-ide-lite-steps-hi3516-burn.md)中描述的烧写方法,选择对应单板的U-boot文件进行烧写。 - 请查看设备管理器,确认连接单板的串口与终端中连接串口是否一致,若不一致,请按镜像运行修改串口号。 +3. 烧写完成后,登录串口如下图所示。 + **图5** U-boot烧写完成串口显示图 -- **可能原因2** + ![zh-cn_image_0000001243484907](figures/zh-cn_image_0000001243484907.png) - 单板U-boot被损坏。 -- **解决办法** +### Windows电脑与单板网络连接失败 - 烧写U-boot。 +- **现象描述** + 点击烧写并选择串口后,无法获取文件。 - 若上述步骤依旧无法连接串口,可能由于单板U-boot损坏,按下述步骤烧写U-boot。 + **图6** 网络不通,单板无法获取文件图 + + ![zh-cn_image_0000001198322428](figures/zh-cn_image_0000001198322428.png) +- **可能原因** + 单板网络与Windows电脑不联通。 -1. 获取引导文件U-boot。 + Windows电脑防火墙未允许Visual Studio Code联网。 - >![](../public_sys-resources/icon-notice.gif) **须知:** - >单板的U-boot文件请在开源包中获取: - >Hi3516DV300:device\\hisilicon\\hispark\_taurus\\sdk\_liteos\\uboot\\out\\boot\\u-boot-hi3516dv300.bin - >Hi3518EV300:device\\hisilicon\\hispark\_aries\\sdk\_liteos\\uboot\\out\\boot\\u-boot-hi3518ev300.bin +- **解决方法** -2. 根据USB烧写步骤烧写U-boot文件。 +1. 检查网线是否连接。 - 按照[Hi3516系列USB烧写步骤](../quick-start/quickstart-lite-steps-hi3516-burn.md)/[Hi3518系列USB烧写步骤](../quick-start/quickstart-lite-steps-hi3518-burn.md)中描述的USB烧写方法,选择对应单板的U-boot文件进行烧写。 +2. 点击Windows防火墙。 + + **图7** 网络防火墙设置图 + + ![zh-cn_image_0000001198162584](figures/zh-cn_image_0000001198162584.png) -3. 烧写完成后,登录串口如下图所示。 - - **图 1** U-boot烧写完成串口显示图 - ![](figures/U-boot烧写完成串口显示图.png "U-boot烧写完成串口显示图") - - -### Windows电脑与单板网络连接失败 - -- **现象描述** - - 点击烧写并选择串口后,无法获取文件。 - - **图 2** 网络不通,Hi3516单板无法获取文件 - ![](figures/网络不通-Hi3516单板无法获取文件.png "网络不通-Hi3516单板无法获取文件") - -- **可能原因** - - 单板网络与Windows电脑不联通。 - - Windows电脑防火墙未允许Visual Studio Code联网。 - -- **解决方法** - -1. 检查网线是否连接。 -2. 点击Windows防火墙。 - - ![](figures/hi3516-network-and-firewall-setting.png) - -3. 点击“允许应用通过防火墙”。 - - ![](figures/hi3516-firewall-and-network-protection.png) - -4. 查找Visual Studio Code应用。 - - ![](figures/hi3516-selecting-the-visual-studio-code-application.png) - -5. 勾选Visual Studio Code的专用和公用网络的访问权限。 - - ![](figures/hi3516-allowing-the-visual-studio-code-application-to-access-the-network.png) +3. 点击“允许应用通过防火墙”。 + + **图8** 防火墙和网络保护界面图 + + ![zh-cn_image_0000001198323146](figures/zh-cn_image_0000001198323146.png) +4. 查找Visual Studio Code应用。 + + **图9** 查找Visual Studio Code应用图 + + ![zh-cn_image_0000001198003232](figures/zh-cn_image_0000001198003232.png) +5. 勾选Visual Studio Code的专用和公用网络的访问权限。 + + **图10** 允许Visual Studio Code应用访问网络 + + ![zh-cn_image_0000001243084579](figures/zh-cn_image_0000001243084579.png) diff --git a/zh-cn/device-dev/faqs/faqs-environment-building.md b/zh-cn/device-dev/faqs/faqs-environment-building.md new file mode 100644 index 0000000000000000000000000000000000000000..8087e8fdf50cf86fed60c0bbdbf0caaa04752657 --- /dev/null +++ b/zh-cn/device-dev/faqs/faqs-environment-building.md @@ -0,0 +1,205 @@ +# 环境搭建常见问题 + + +## 轻量和小型系统 + + +### hb安装过程中出现乱码、段错误 + +- **现象描述** + 执行“python3 -m pip install --user ohos-build”出现乱码、段错误(segmentation fault)。 + +- **可能原因** + pip版本过低。 + +- **解决办法** + 执行如下命令升级pip。 + + + ``` + python3 -m pip install -U pip + ``` + + +### hb安装过程中提示"cannot import 'sysconfig' from 'distutils'" + +- **现象描述** + 执行“python3 -m pip install --user ohos-build”提示"cannot import 'sysconfig' from 'distutils'" + +- **可能原因** + 缺少distutils模块。 + +- **解决办法** + 执行如下命令安装。 + + + ``` + sudo apt-get install python3.8-distutils + ``` + + +### hb安装过程中提示"module 'platform' has no attribute 'linux_distribution'" + +- **现象描述** + 执行“python3 -m pip install --user ohos-build”提示"module 'platform' has no attribute 'linux_distribution'" + +- **可能原因** + python3 pip安装兼容性问题。 + +- **解决办法** + 执行如下命令重新安装pip。 + + + ``` + sudo apt remove python3-pip + curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py + python get-pip.py + ``` + + +### hb安装过程中提示"Could not find a version that satisfies the requirement ohos-build" + +- **现象描述** + 执行“python3 -m pip install --user ohos-build”提示"Could not find a version that satisfies the requirement ohos-build" + +- **可能原因** + 可能是网络环境较差导致的安装失败。 + +- **解决办法** + 1. 请检查网络连接是否正常。如果网络有问题,请修复网络问题后重新安装。 + 2. 若网络正常,请尝试指定临时pypi源的方式安装: + + ``` + python3 -m pip install -i https://pypi.tuna.tsinghua.edu.cn/simple ohos-build + ``` + + +### 安装python3过程中,提示“configure: error: no acceptable C compiler found in $PATH” + +- **现象描述** + 安装python3过程中出现以下错误: + + + ``` + configure: error: no acceptable C compiler found in $PATH. See 'config.log' for more details + ``` + +- **可能原因** + 环境中未安装“gcc”。 + +- **解决办法** + 1. 通过命令“apt-get install gcc”在线安装。 + 2. 完成后,重新安装python3。 + + +### 安装python3过程中,提示“-bash: make: command not found” + +- **现象描述** + 安装python3过程中出现以下错误: + + + ``` + -bash: make: command not found + ``` + +- **可能原因** + 环境中未安装“make”。 + +- **解决办法** + 1. 通过命令“apt-get install make”在线安装。 + 2. 完成后,重新安装python3。 + + +### 安装python3过程中,提示“zlib not available” + +- **现象描述** + 安装python3过程中出现以下错误: + + + ``` + zipimport.ZipImportError: can't decompress data; zlib not available + ``` + +- **可能原因** + 环境中未安装“zlib”。 + +- **解决办法** + 方法1:通过命令“apt-get install zlib”在线安装。 + + 方法2:如果软件源中没有该软件,请从“www.zlib.net”下载版本代码,并离线安装。 + + ![zh-cn_image_0000001198001086](figures/zh-cn_image_0000001198001086.png) + + 完成下载后,通过以下命令安装: + + + ``` + # tar xvf zlib-1.2.11.tar.gz + # cd zlib-1.2.11 + # ./configure + # make && make install + ``` + + 完成后,重新安装python3。 + + +### 编译构建过程中,提示“No module named 'Crypto'” + +- **现象描述** + 编译构建过程中出现以下错误: + + + ``` + ModuleNotFoundError: No module named 'Crypto' + ``` + +- **可能原因** + 环境中未安装“Crypto”。 + +- **解决办法** + 方法1:通过命令“pip3 install Crypto”,在线安装。 + + 方法2:离线安装。 + + 通过网页[https://pypi.org/project/pycrypto/#files](https://pypi.org/project/pycrypto/#files),下载源码。 + + ![zh-cn_image_0000001251196005](figures/zh-cn_image_0000001251196005.png) + + 将源码放置在Linux服务器中,解压,并安装“python3 setup.py install”。 + + 完成上述安装后,重新构建。 + + +### 安装kconfiglib时,遇到lsb_release错误 + +- **现象描述** + 安装kconfiglib过程中遇到如下错误打印: + + + ``` + subprocess.CalledProcessError: Command '('lsb_release', '-a')' returned non-zero exit status 1. + ``` + +- **可能原因** + lsb_release模块基于的python版本与现有python版本不一致。 + +- **解决办法** + 执行"find / -name lsb_release",找到lsb_release位置并删除,如:"sudo rm -rf /usr/bin/lsb_release"。 + + +### Linux编译服务器终端输入不识别的命令时提示“ImportError: No module named apt_pkg” + +- **现象描述** + Linux编译服务器终端输入不识别的命令时,提示"ImportError: No module named apt_pkg" + +- **可能原因** + python3 apt安装兼容性问题。 + +- **解决办法** + 执行如下命令重新安装python3-apt。 + + + ``` + sudo apt-get remove python3-apt + sudo apt-get install python3-apt + ``` diff --git a/zh-cn/device-dev/faqs/faqs-init.md b/zh-cn/device-dev/faqs/faqs-init.md new file mode 100644 index 0000000000000000000000000000000000000000..c022046407a65a823b7e069d3766b42694880a74 --- /dev/null +++ b/zh-cn/device-dev/faqs/faqs-init.md @@ -0,0 +1,58 @@ +# 启动恢复常见问题 + + +## 系统启动过程中打印“parse failed!”错误后停止启动 + +**现象描述** + +系统启动过程中,打印“[Init] InitReadCfg, parse failed! please check file /etc/init.cfg format.”错误,启动过程停止,如下图所示: + + **图1** 运行报错图 + + ![zh-cn_image_0000001200053087](figures/zh-cn_image_0000001200053087.png) + +**可能原因** + +修改init.cfg文件时,漏掉或多加了逗号或括号等,导致init.cfg文件的json格式被破坏。 + +**解决办法** + +仔细检查init.cfg文件,确保其格式符合json格式要求。 + + +## 系统启动过程未结束就自动重启,如此反复持续 + +**现象描述** + +镜像烧写完成后系统启动,启动过程未完成即自动重新启动,如此反复持续。 + +**可能原因** + +被init启动的服务都有一个叫做“importance”的属性(详见[第2章表3](../subsystems/subsys-boot-init.md)第二章节表3描述)。 + +- 当该属性为0时,表示若当前服务进程退出,init不需要重启单板。 + +- 当该属性为1时,表示若当前服务进程退出,init需要重启单板。 + +因此出现上述现象的可能原因:有“importance”属性为1的服务在每次启动的过程中都会退出(可能是进程崩溃或出错自动退出),导致init进程自动重启单板。 + +**解决办法** + +1. 需要通过日志确认崩溃或报错退出的服务,并解决其崩溃/报错的问题,然后重新烧写镜像即可。 + +2. 也可以将崩溃/报错退出的服务的“importance”属性改为0,然后重新烧写镜像,这样即使其退出,init也不会重启单板。 + + +## 参数正确的情况下调用SetParameter/GetParameter返回失败 + +**现象描述** + +在各参数正确的情况下调用SetParameter/GetParameter返回失败。 + +**可能原因** + +程序对SetParameter/GetParameter这两个接口做了权限校验,在各参数正确的情况下调用SetParameter/GetParameter返回操作失败,很有可能是调用者的uid大于1000,没有调用权限。 + +**解决办法** + +无需处理 diff --git a/zh-cn/device-dev/faqs/faqs-kernel.md b/zh-cn/device-dev/faqs/faqs-kernel.md index 54a99ff1aed4103c770e98c5295a8e4ca5c08f61..73862f268f45bd72ea12a7ddec865a15208117e9 100644 --- a/zh-cn/device-dev/faqs/faqs-kernel.md +++ b/zh-cn/device-dev/faqs/faqs-kernel.md @@ -1,12 +1,15 @@ -# 内核常见问题 +# 内核常见问题 -## 基础内核 -### LiteOS-A和LiteOS-M内核对外API的差异 +## 基础内核 + + +### LiteOS-A和LiteOS-M内核对外API的差异 基础内核API存在差异,但是LiteOS-A提供标准POSIX接口,LiteOS-M提供标准POSIX和CMSIS接口。如果要支持跨平台,三方适配建议使用POSIX等标准接口。 -### 如何分析线程栈溢出 + +### 如何分析线程栈溢出 **问题现象** @@ -14,57 +17,72 @@ **解决措施** -1. 创建xxx线程的时候成倍加大栈空间,多次尝试如果问题不复现,则说明任务栈不够,需要调整; -2. 如果成倍加大线程栈,问题依旧复现,则排查xxx线程中是否定义超大数组,或者流程是否存在递归调用; -3. 确认无前述问题,则需要排查是否存在踩内存的情况。 +1. 创建xxx线程的时候成倍加大栈空间,多次尝试如果问题不复现,则说明任务栈不够,需要调整; + +2. 如果成倍加大线程栈,问题依旧复现,则排查xxx线程中是否定义超大数组,或者流程是否存在递归调用; + +3. 确认无前述问题,则需要排查是否存在踩内存的情况。 -## 文件系统 -### Hi3516开源板以写的模式打开同一个文件失败(LiteOS-A) +## 文件系统 + + +### Hi3516开源板以写的模式打开同一个文件失败(LiteOS-A) Hi3516开源板使用FAT文件系统,不允许该操作。 -### LiteOS内核已支持哪些硬件平台 -开源版本LiteOS-A已支持Hi3516/Hi3518开发板;LiteOS-M已支持Hi3861开发板、Nucleo\_f767zi等,详细查看kernel/liteos\_m目录下的README\_zh.md文件。 +### LiteOS内核已支持哪些硬件平台 + +开源版本LiteOS-A已支持Hi3516/Hi3518开发板;LiteOS-M已支持Hi3861开发板、STM32F103、野火挑战者STM32F429IGTb、Nucleo_f767zi等,详细查看kernel/liteos_m目录下的README_zh.md文件。 + -### LiteOS内核已支持哪几款芯片架构 +### LiteOS内核已支持哪几款芯片架构 -LiteOS-M已支持risc-v、Cortex-m3\\m4\\m7\\m33、arm9、c-sky、xtensa;LiteOS-A已支持armv7-a,待支持armv8-a,请关注开源社区更新。 +LiteOS-M已支持risc-v、Cortex-m3\m4\m7\m33、arm9,待支持c-sky、xtensa;LiteOS-A已支持armv7-a,待支持armv8-a,请关注开源社区更新。 -## 三方组件 -### OpenHarmony已支持哪些三方组件 +## 三方组件 + + +### 已支持哪些三方组件 已提供mbedtls、lwip等开源组件和三方库,可以直接使用;另外提供标准的POSIX接口,可以自行适配。 -### 在OpenHarmony上使用OpenSSL,出现秘钥长度校验不正确 + +### 在上使用OpenSSL,出现秘钥长度校验不正确 OpenSSL编译选项中要注意架构类型(ARM,X86等)和系统位数(32、64位)是否选择正确。 -### setsockopt是否支持SO\_RCVBUF和SO\_SNDBUF选项 + +### setsockopt是否支持SO_RCVBUF和SO_SNDBUF选项 不支持。 -## 编译链接 -### Arm Linux开发的应用程序,OpenHarmony如何在LiteOS-A上运行 +## 编译链接 + + +### Arm Linux开发的应用程序,如何在LiteOS-A上运行 需要用开源版本提供的交叉编译器重新编译应用程序,才可以运行。 -### OpenHarmony在什么系统下编译,使用什么编译器 + +### 在什么系统下编译,使用什么编译器 LiteOS-A在linux环境进行编译,使用LLVM编译器;LiteOS-M在Linux或Windows环境进行编译,使用IAR、Keil、GCC等编译工具。 -### LiteOS-M上使用单独编译成静态库的三方组件,出现三方组件中的全局变量值不正确,或调用三方组件的函数后系统卡死 + +### LiteOS-M上使用单独编译成静态库的三方组件,出现三方组件中的全局变量值不正确,或调用三方组件的函数后系统卡死 检查三方组件编译选项中是否有-fPIE -fpie -fPIC -fpic等地址无关编译选项,如果有,则去掉,重新编译成库使用。 -### LiteOS-A生成目标可执行文件时,提示 use VFP register arguments,xxx.o does not + +### LiteOS-A生成目标可执行文件时,提示 use VFP register arguments,xxx.o does not 请确认xxx.o编译时是否添加-mfloat-abi=xxx -mcpu=xxx -mfpu=xxx编译选项,若没有,则需要添加。 -### clock\_gettime接口获取的时间打印不对 -struct timespec结构中tv\_sec为time\_t,而time\_t为long long类型,打印控制符为%lld,请确认实际打印控制符是否正确。 +### clock_gettime接口获取的时间打印不对 +struct timespec结构中tv_sec为time_t,而time_t为long long类型,打印控制符为%lld,请确认实际打印控制符是否正确。 diff --git a/zh-cn/device-dev/faqs/faqs-overview.md b/zh-cn/device-dev/faqs/faqs-overview.md index 12e11e27d7cce15fea14f6fed6869430c7ed5196..b8d662407d501f9b82d0ff8166f54f445d6433c7 100644 --- a/zh-cn/device-dev/faqs/faqs-overview.md +++ b/zh-cn/device-dev/faqs/faqs-overview.md @@ -1,138 +1,178 @@ -# 常见问题概述 +# 常见问题概述 -- [环境搭建](#section93289248249) - - [轻量和小型系统](#section197234983111) -- [编译构建子系统](#section18826114693810) - - [轻量和小型系统](#section693410399) +常见问题主要用于帮助开发者解决在开发过程中经常出现的一类问题。当前提供了如下常见问题供开发者进行查询。 -- [烧录](#section6556741113712) - - [轻量和小型系统](#section1029933713812) -- [内核](#section13741125564211) - - [基础内核](#section1723365191114) - - [文件系统](#section14523145918136) - - [芯片适配](#section141541939159) - - [三方组件](#section4988163321816) - - [编译链接](#section080219574225) +## 环境搭建 -- [移植](#section129331824154313) -- [启动恢复](#section83501764443) -- [系统服务](#section19567132114455) - - [公共基础库](#section3214181711465) - - [视觉应用常见问题](#section295651815466) - - [hdc](#section178081876506) +### 轻量和小型系统 -常见问题主要用于帮助开发者解决在开发过程中经常出现的一类问题问题。当前提供了如下常见问题供开发者进行查询。 +- [hb安装过程中出现乱码、段错误](../faqs/faqs-environment-building.md#hb安装过程中出现乱码段错误) -## 环境搭建 +- [hb安装过程中提示"cannot import 'sysconfig' from 'distutils'"](../faqs/faqs-environment-building.md#hb安装过程中提示cannot-import-sysconfig-from-distutils) -### 轻量和小型系统 +- [hb安装过程中提示"module 'platform' has no attribute 'linux_distribution'"](../faqs/faqs-environment-building.md#hb安装过程中提示module-platform-has-no-attribute-linuxdistribution) -- [安装hb过程中出现乱码、段错误](faqs-environment-setup.md#section36351051193919) -- [安装hb过程中,提示"cannot import 'sysconfig' from 'distutils'"](faqs-environment-setup.md#section48221013144011) -- [安装hb过程中,提示"module 'platform' has no attribute 'linux\_distribution'"](faqs-environment-setup.md#section8692735427) -- [安装hb过程中,提示"Could not find a version that satisfies the requirement ohos-build"](faqs-environment-setup.md#section8692735427) -- [安装python3过程中,提示“configure: error: no acceptable C compiler found in $PATH”](faqs-environment-setup.md#section870082884217) -- [安装python3过程中,提示“-bash: make: command not found”](faqs-environment-setup.md#section198707170455) -- [安装python3过程中,提示“zlib not available”](faqs-environment-setup.md#section85401445204518) -- [安装python3过程中,提示“No module named '\_ctypes'”](faqs-environment-setup.md#section12202694460) -- [安装 kconfiglib时,遇到lsb\_release错误](faqs-environment-setup.md#section5803174135115) -- [Linux编译服务器终端输入不识别的命令时提示“ImportError: No module named apt\_pkg”](faqs-environment-setup.md#section510820516515) +- [hb安装过程中提示"Could not find a version that satisfies the requirement ohos-build"](../faqs/faqs-environment-building.md#hb安装过程中提示could-not-find-a-version-that-satisfies-the-requirement-ohos-build) -## 编译构建子系统 +- [安装python3过程中,提示“configure: error: no acceptable C compiler found in $PATH”](../faqs/faqs-environment-building.md#安装python3过程中提示configure-error-no-acceptable-c-compiler-found-in-path) -### 轻量和小型系统 +- [安装python3过程中,提示“-bash: make: command not found”](../faqs/faqs-environment-building.md#安装python3过程中提示-bash-make-command-not-found) -- [编译构建过程中,提示“usr/sbin/ninja: invalid option -- w”](faqs-building.md#section67961431372) -- [编译构建过程中,提示“/usr/bin/ld: cannot find -lncurses”](faqs-building.md#section199631617371) -- [编译构建过程中,提示“line 77: mcopy: command not found”](faqs-building.md#section937435175) -- [编译构建过程中,提示“riscv32-unknown-elf-gcc: error trying to exec 'cc1': execvp: No such file or directory”](faqs-building.md#section1115535018713) -- [编译构建过程中,提示“No module named 'Crypto'”](faqs-building.md#section17982573813) -- [编译构建过程中,提示“Could not find a version that satisfies the requirement six\>=1.9.0”](faqs-building.md#section1917790845) -- [编译构建过程中,提示“Could not find a version that satisfies the requirement six\>=1.9.0”](faqs-building.md#section1917790845)” -- [编译构建过程中,提示找不到“-lgcc”](faqs-building.md#section141771701647) -- [编译构建过程中,提示找不到“python”](faqs-building.md#section51781202415) -- [编译构建过程中,提示找不到“python3”](faqs-building.md#section1917950148) +- [安装python3过程中,提示“zlib not available”](../faqs/faqs-environment-building.md#安装python3过程中提示zlib-not-available) -## 烧录 +- [编译构建过程中,提示“No module named 'Crypto'”](../faqs/faqs-environment-building.md#编译构建过程中提示no-module-named-crypto) -### 轻量和小型系统 +- [安装kconfiglib时,遇到lsb_release错误](../faqs/faqs-environment-building.md#安装kconfiglib时遇到lsbrelease错误) -- [烧写选择串口后,提示“Error: Opening COMxx: Access denied”](faqs-burning.md#section18988185615914) +- [Linux编译服务器终端输入不识别的命令时提示“ImportError: No module named apt_pkg”](../faqs/faqs-environment-building.md#linux编译服务器终端输入不识别的命令时提示importerror-no-module-named-aptpkg) -- [烧写失败](faqs-burning.md#section1370982513317) -- [串口无回显](faqs-burning.md#section183421944953) -- [Windows电脑与单板网络连接失败](faqs-burning.md#section1215410450215) -## 内核 +## 编译构建子系统 -### 基础内核 -- [LiteOS-A和LiteOS-M内核对外API的差异](faqs-kernel.md#section447571122918) -- [如何分析线程栈溢出](faqs-kernel.md#section8623141711293) +### 轻量和小型系统 -### 文件系统 +- [编译构建过程中,提示“usr/sbin/ninja: invalid option -- w”](../faqs/faqs-building.md#编译构建过程中提示usrsbinninja-invalid-option----w) -- [Hi3516开源板以写的模式打开同一个文件失败(LiteOS-A)](faqs-kernel.md#section517972255311) +- [编译构建过程中,提示“/usr/bin/ld: cannot find -lncurses”](../faqs/faqs-building.md#编译构建过程中提示usrbinld-cannot-find--lncurses) -### 芯片适配 +- [编译构建过程中,提示“line 77: mcopy: command not found”](../faqs/faqs-building.md#编译构建过程中提示line-77-mcopy-command-not-found) -- [LiteOS内核已支持哪些硬件平台](faqs-kernel.md#section868413518533) -- [LiteOS内核已支持哪几款芯片架构](faqs-kernel.md#section1131661465417) +- [编译构建过程中,提示“riscv32-unknown-elf-gcc: error trying to exec 'cc1': execvp: No such file or directory”](../faqs/faqs-building.md#编译构建过程中提示riscv32-unknown-elf-gcc-error-trying-to-exec-cc1-execvp-no-such-file-or-directory) -### 三方组件 +- [编译构建过程中,提示“No module named 'Crypto'”](../faqs/faqs-building.md#编译构建过程中提示no-module-named-crypto) -- [OpenHarmony已支持哪些三方组件](faqs-kernel.md#section74138185411) -- [在OpenHarmony上使用OpenSSL,出现秘钥长度校验不正确](faqs-kernel.md#section10564614135516) -- [setsockopt是否支持SO\_RCVBUF和SO\_SNDBUF选项](faqs-kernel.md#section2093373215556) +- [编译构建过程中,提示“xx.sh : xx unexpected operator”](../faqs/faqs-building.md#编译构建过程中提示xxsh--xx-unexpected-operator) -### 编译链接 +- [编译构建过程中,提示“Could not find a version that satisfies the requirement six>=1.9.0”](../faqs/faqs-building.md#编译构建过程中提示could-not-find-a-version-that-satisfies-the-requirement-six190) -- [Arm Linux开发的应用程序,如何在LiteOS-A上运行](faqs-kernel.md#section1164175713557) -- [OpenHarmony在什么系统下编译,使用什么编译器](faqs-kernel.md#section132287223567) -- [LiteOS-M上使用单独编译成静态库的三方组件,出现三方组件中的全局变量值不正确,或调用三方组件的函数后系统卡死](faqs-kernel.md#section15189154225619) -- [LiteOS-A生成目标可执行文件,提示 use VFP register arguments,xxx.o does not](faqs-kernel.md#section193571012578) -- [clock\_gettime接口获取的时间打印不对](faqs-kernel.md#section8973152015717) +- [编译构建过程中,提示找不到“-lgcc”](../faqs/faqs-building.md#编译构建过程中提示找不到-lgcc) -## 移植 +- [编译构建过程中,提示找不到“python”](../faqs/faqs-building.md#编译构建过程中提示找不到python) -- [如何将用户的堆内存挂载进内核](faqs-porting.md#section21471536184914) +- [编译构建过程中,提示找不到“python3”](../faqs/faqs-building.md#编译构建过程中提示找不到python3) -## 启动恢复 -- [系统启动过程中打印“parse failed!”错误后停止启动](faqs-startup.md#section835662214302) -- [系统启动过程未结束就自动重启,如此反复持续](faqs-startup.md#section3857921143117) -- [参数正确的情况下调用SetParameter/GetParameter返回失败](faqs-startup.md#section548818116328) +## 烧录 -## 系统服务 -### 公共基础库 +### 轻量和小型系统 -- [LiteOS-A内核\(Hi3516、Hi3518平台\)KV存储路径设置错误,导致KV存储运行失败](faqs-system-applications.md#section16520347131511) +- [烧写选择串口后提示“Error: Opening COMxx: Access denied”](../faqs/faqs-burning.md#烧写选择串口后提示error-opening-comxx-access-denied) -### 视觉应用常见问题 +- [烧写失败](../faqs/faqs-burning.md#烧写失败) -- [是否存在一个全局变量,所有的页面都可以访问?](faqs-system-applications.md#section187297991718) -- [如何获取dom中的元素](faqs-system-applications.md#section1833493719175) -- [如何在页面间传值?](faqs-system-applications.md#section184283812183) -- [list如何滚动到某个item?](faqs-system-applications.md#section11897734131811) -- [text支持多行吗?](faqs-system-applications.md#section5872656121814) -- [为什么控件不显示?](faqs-system-applications.md#section7397125317107) -- [如何实现页面滑动?](faqs-system-applications.md#section338794422010) -- [Left、Top为什么不生效?](faqs-system-applications.md#section2597193611217) -- [动态绑定为什么不生效?](faqs-system-applications.md#section6939050172115) -- [如何实现相对定位和绝对定位?](faqs-system-applications.md#section5547311192215) -- [如何控制控件的显示与隐藏?](faqs-system-applications.md#section16107113352213) -- [使用Margin时,有什么注意事项?](faqs-system-applications.md#section1524910142314) -- [使用事件订阅时,有什么注意事项?](faqs-system-applications.md#section1537132012231) -- [使用动态绑定时,有什么注意事项?](faqs-system-applications.md#section96561452236) -- [swiper loop属性如何生效?](faqs-system-applications.md#section690166112414) -- [使用数组时,有什么注意事项?](faqs-system-applications.md#section1554552822414) +- [串口无回显](../faqs/faqs-burning.md#串口无回显) -### hdc +- [Windows电脑与单板网络连接失败](../faqs/faqs-burning.md#windows电脑与单板网络连接失败) -- [hdc\_std连接不到设备](faqs-system-applications.md#section1965012223257) -- [hdc\_std运行不了](faqs-system-applications.md#section1157575212515) +## 内核 + + +### 基础内核 + +- [LiteOS-A和LiteOS-M内核对外API的差异](../faqs/faqs-kernel.md#liteos-a和liteos-m内核对外api的差异) + +- [如何分析线程栈溢出](../faqs/faqs-kernel.md#如何分析线程栈溢出) + + +### 文件系统 + +- [Hi3516开源板以写的模式打开同一个文件失败(LiteOS-A)](../faqs/faqs-kernel.md#hi3516开源板以写的模式打开同一个文件失败liteos-a) + + +### 芯片适配 + +- [LiteOS内核已支持哪些硬件平台](../faqs/faqs-kernel.md#liteos内核已支持哪些硬件平台) + +- [LiteOS内核已支持哪几款芯片架构](../faqs/faqs-kernel.md#liteos内核已支持哪几款芯片架构) + + +### 三方组件 + +- [HarmonyOSOpenHarmony已支持哪些三方组件](../faqs/faqs-kernel.md#harmonyosopenharmony已支持哪些三方组件) + +- [在HarmonyOSOpenHarmony上使用OpenSSL,出现秘钥长度校验不正确](../faqs/faqs-kernel.md#在harmonyosopenharmony上使用openssl出现秘钥长度校验不正确) + +- [setsockopt是否支持SO_RCVBUF和SO_SNDBUF选项](../faqs/faqs-kernel.md#setsockopt是否支持sorcvbuf和sosndbuf选项) + + +### 编译链接 + +- [Arm Linux开发的应用程序,HarmonyOSOpenHarmony如何在LiteOS-A上运行](../faqs/faqs-kernel.md#arm-linux开发的应用程序harmonyosopenharmony如何在liteos-a上运行) + +- [HarmonyOSOpenHarmony在什么系统下编译,使用什么编译器](../faqs/faqs-kernel.md#harmonyosopenharmony在什么系统下编译使用什么编译器)[HarmonyOSOpenHarmony在什么系统下编译,使用什么编译器](../faqs/faqs-kernel.md#harmonyosopenharmony在什么系统下编译使用什么编译器) + +- [LiteOS-M上使用单独编译成静态库的三方组件,出现三方组件中的全局变量值不正确,或调用三方组件的函数后系统卡死](../faqs/faqs-kernel.md#liteos-m上使用单独编译成静态库的三方组件出现三方组件中的全局变量值不正确或调用三方组件的函数后系统卡死) + +- [LiteOS-A生成目标可执行文件时,提示 use VFP register arguments,xxx.o does not](../faqs/faqs-kernel.md#liteos-a生成目标可执行文件时提示-use--vfp-register-argumentsxxxo-does-not) + +- [clock_gettime接口获取的时间打印不对](../faqs/faqs-kernel.md#clockgettime接口获取的时间打印不对) + + +## 移植 + +- [如何将用户的堆内存挂载进内核](../faqs/faqs-transplant.md#如何将用户的堆内存挂载进内核) + + +## 启动恢复 + +- [系统启动过程中打印“parse failed!”错误后停止启动](../faqs/faqs-init.md#系统启动过程中打印parse-failed错误后停止启动) + +- [系统启动过程未结束就自动重启,如此反复持续](../faqs/faqs-init.md#系统启动过程未结束就自动重启如此反复持续) + +- [参数正确的情况下调用SetParameter/GetParameter返回失败](../faqs/faqs-init.md#参数正确的情况下调用setparametergetparameter返回失败) + + +## 系统服务 + + +### 公共基础库 + +- [1.LiteOS-A内核(Hi3516、Hi3518平台)KV存储路径设置错误,导致KV存储运行失败](../faqs/faqs-system-using.md#1liteos-a内核hi3516hi3518平台kv存储路径设置错误导致kv存储运行失败) + + +### 视觉应用常见问题 + +- [是否存在一个全局变量,所有的页面都可以访问?](../faqs/faqs-system-using.md#是否存在一个全局变量所有的页面都可以访问) + +- [如何获取dom中的元素](../faqs/faqs-system-using.md#如何获取dom中的元素) + +- [如何在页面间传值?](../faqs/faqs-system-using.md#如何在页面间传值) + +- [list如何滚动到某个item?](../faqs/faqs-system-using.md#list如何滚动到某个item) + +- [text支持多行吗?](../faqs/faqs-system-using.md#text支持多行吗) + +- [为什么控件不显示?](../faqs/faqs-system-using.md#为什么控件不显示) + +- [如何实现页面滑动?](../faqs/faqs-system-using.md#如何实现页面滑动) + +- [Left、Top为什么不生效?](../faqs/faqs-system-using.md#lefttop为什么不生效) + +- [动态绑定为什么不生效?](../faqs/faqs-system-using.md#动态绑定为什么不生效) + +- [如何实现相对定位和绝对定位?](../faqs/faqs-system-using.md#如何实现相对定位和绝对定位) + +- [如何控制控件的显示与隐藏?](../faqs/faqs-system-using.md#如何控制控件的显示与隐藏) + +- [使用Margin时,有什么注意事项?](../faqs/faqs-system-using.md#使用margin时有什么注意事项) + +- [使用事件订阅时,有什么注意事项?](../faqs/faqs-system-using.md#使用事件订阅时有什么注意事项) + +- [使用动态绑定时,有什么注意事项?](../faqs/faqs-system-using.md#使用动态绑定时有什么注意事项) + +- [swiper loop属性如何生效?](../faqs/faqs-system-using.md#swiper-loop属性如何生效) + +- [使用数组时,有什么注意事项?](../faqs/faqs-system-using.md#使用数组时有什么注意事项) + + +### hdc + +- [hdc_std连接不到设备](../faqs/faqs-system-using.md#hdcstd连接不到设备) + +- [hdc_std运行不了](../faqs/faqs-system-using.md#hdcstd运行不了) diff --git a/zh-cn/device-dev/faqs/faqs-system-using.md b/zh-cn/device-dev/faqs/faqs-system-using.md new file mode 100644 index 0000000000000000000000000000000000000000..0f22238e7f1c4dba9d383ef68910e5b1debcbd12 --- /dev/null +++ b/zh-cn/device-dev/faqs/faqs-system-using.md @@ -0,0 +1,201 @@ +# 系统应用常见问题 + + + + +## 公共基础库常见问题 + + +### 1.LiteOS-A内核(Hi3516、Hi3518平台)KV存储路径设置错误,导致KV存储运行失败 + +**现象描述** + +LiteOS-A内核(Hi3516、Hi3518平台)直接调用KV存储提供的接口,各参数正常的情况下,编译可执行程序运行失败。 + +**可能原因** + +直接运行编译出的可执行文件,没有将程序基于AbilityKit转换成应用,不能由BMS在应用安装时正确设置应用数据存储路径,导致KV存储运行失败。 + +**解决办法** + +显示调用KV存储的UtilsSetEnv接口,设置数据存储路径。 + + +``` +UtilsSetEnv("/storage/com.example.kv"); +``` + + +## 视觉应用常见问题 + + +### 是否存在一个全局变量,所有的页面都可以访问? + +当前框架中不存在所有Page都可以访问的全局变量。 + + +### 如何获取dom中的元素 + +通过ref属性获取dom中的元素,详细示例如下图所示;获取的元素只能使用它的方法,不能改变属性。 + + +``` + +
+ + +
+ +/* index.js */ +export default { + data: { + images:[ + {src:"common/frame1.png"}, + {src:"common/frame2.png"}, + {src:"common/frame3.png"} + ] + }, + handleClick(){ + //通过$refs属性获取对应的组件,在hml中,组件的ref属性要设置为animator + const animator = this.$refs.animator; + const state = animator.getState(); + if(state == "paused"){ + animator.resume(); + }else if(state == "stopped"){ + animator.start(); + }else{ + animator.pause(); + } + } +} +``` + + +### 如何在页面间传值? + +通过router.replace方法中的params参数来传递,参考代码如下: + +第一个页面传递数据: + + +``` +router.replace({ + uri:'pages/detail/detail', //要跳转的页面uri + params:{transferData:this.data} //传递的数据,数据个数和名称开发者自己定义, +}); +``` + +第二个界面接受数据: + + +``` +onInit(){ + const data = this.transferData; //在onInit函数中接受传递的数据 +} +``` + + +### list如何滚动到某个item? + +通过list的scrollTo方法滚动到指定的item,参数是目标item的index。Index参数可以通过scrollend事件获取或者开发者指定。 + + +### text支持多行吗? + +text支持多行。通过回车键换行或者是不设置text的高度属性,由控件自动根据内容换行。 + + +### 为什么控件不显示? + +**现象描述** + +开发者在hml文件中添加的控件无法显示 + +**可能原因** + +- 未设置width和height值; + +- 样式设置错误。 + +**处理步骤** + +(1)检查是否设置width和height值,组件必须显式设置width和height值; + +(2)检查组件的样式设置是否正确。 + + +### 如何实现页面滑动? + +实现页面滑动目前有三种方式:scroll(根组件大小超过屏幕的大小即自动实现scroll效果)、list、swiper。开发者可以参考开发文档查看三者的区别,并加以使用。 + + +### Left、Top为什么不生效? + +除根节点外,Left、Top配合Stack组件使用才有效果。 + + +### 动态绑定为什么不生效? + +在进行绑定时,必须先将要绑定的对象或者对象的属性进行定义,不能先绑定后定义 + + +### 如何实现相对定位和绝对定位? + +使用div、stack(top left属性)来实现相对和绝对定位。 + + +### 如何控制控件的显示与隐藏? + +通过display、show和if来控制控件的显示与隐藏。区别在于:if为false时,组件会从VDOM中移除,而show仅是渲染时不可见,组件依然存在于VDOM中。 + + +### 使用Margin时,有什么注意事项? + +Stack组件不支持其子组件设置margin属性。 + + +### 使用事件订阅时,有什么注意事项? + +在应用运行期间只存在一个page,所以router.replace跳转是先销毁前一个页面,然后在新创建一个界面。因此,如果涉及到事件订阅的页面,每次页面创建时要进行事件订阅,跳转离开界面前取消事件订阅。 + + +### 使用动态绑定时,有什么注意事项? + +过多的动态绑定会消耗较多的内存,若非业务需要,尽量不要使用太多的动态绑定。 + + +### swiper loop属性如何生效? + +去掉第一个组件或者去掉最后一个组件,剩余的长度大于swiper长度,loop生效。 + + +### 使用数组时,有什么注意事项? + +数组元素不宜过多,尽量避免对大数组进行频繁操作。 + + +## hdc类问题 + + +### hdc_std连接不到设备 + +- **现象描述** + 执行 "hdc_std list targets"命令后结果为:[Empty] + +- **解决方法** + 1. 设备没有被识别: + 在设备管理器中查看是否有hdc设备,在通用串行总线设备中会有“HDC Device”信息。如果没有,hdc无法连接。此时需要断开并重联PC和OpenHarmony设备之间的USB连接,或者烧写最新的镜像。 + 2. hdc_std工作异常: + 可以执行"hdc kill"或者"hdc start -r"杀掉hdc服务或者重启hdc服务,然后再执行hdc list targets查看是否已经可以获取设备信息。 + 3. hdc_std与设备不匹配: + 如果设备烧写的是最新镜像,hdc_std也需要使用最新版本。 + + +### hdc_std运行不了 + +- **现象描述** + 点击hdc_std.exe文件无法运行。 + +- **解决方法** + hdc_std.exe不需要安装,直接放到磁盘上就能使用,也可以添加到环境变量中。通过打开cmd执行hdc_std命令直接使用。 + diff --git a/zh-cn/device-dev/faqs/faqs-transplant.md b/zh-cn/device-dev/faqs/faqs-transplant.md new file mode 100644 index 0000000000000000000000000000000000000000..6b52f372889ae7b0f5cedf04fcd74cfea85e8eed --- /dev/null +++ b/zh-cn/device-dev/faqs/faqs-transplant.md @@ -0,0 +1,18 @@ +# 移植常见问题 + + +## 如何将用户的堆内存挂载进内核 + +- 内核堆内存配置的相关宏如下,用户可根据实际情况,在target_config.h中配置: + + **表1** 内核堆内存配置相关宏 + +| 宏名称 | 描述 | +| -------- | -------- | +| LOSCFG_SYS_EXTERNAL_HEAP | 这个宏决定系统是使用内核的内部堆内存还是用户的堆内存,默认为0(即使用内部的堆内存),大小为0x10000;如果用户需要基于外部的堆内存,那么可以将该宏设置为1。 | +| LOSCFG_SYS_HEAP_ADDR | 内核堆内存的起始地址。 | +| LOSCFG_SYS_HEAP_SIZE | 内核堆内存的大小,即LOSCFG_SYS_HEAP_ADDR指定的内存块大小。 | + +- 注意事项: + +指定的堆内存范围务必保证没有其他模块使用,避免踩内存,破坏堆内存功能。 diff --git a/zh-cn/device-dev/faqs/faqs.md b/zh-cn/device-dev/faqs/faqs.md new file mode 100644 index 0000000000000000000000000000000000000000..a851fcc0fcdd0894e56dbb92f0b491c660803c05 --- /dev/null +++ b/zh-cn/device-dev/faqs/faqs.md @@ -0,0 +1,19 @@ +# FAQ + + + +- **[常见问题概述](faqs-overview.md)** + +- **[环境搭建常见问题](faqs-environment-building.md)** + +- **[编译构建子系统常见问题](faqs-building.md)** + +- **[烧录常见问题](faqs-burning.md)** + +- **[内核常见问题](faqs-kernel.md)** + +- **[移植常见问题](faqs-transplant.md)** + +- **[启动恢复常见问题](faqs-init.md)** + +- **[系统应用常见问题](faqs-system-using.md)** \ No newline at end of file diff --git a/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001198001086.png b/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001198001086.png new file mode 100644 index 0000000000000000000000000000000000000000..3b7f6f4766c54f6ca1e0057fc8f869785cc63e56 Binary files /dev/null and b/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001198001086.png differ diff --git a/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001198003232.png b/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001198003232.png new file mode 100644 index 0000000000000000000000000000000000000000..c735ae362e184083329cdf710289a169ad5625d4 Binary files /dev/null and b/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001198003232.png differ diff --git a/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001198162584.png b/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001198162584.png new file mode 100644 index 0000000000000000000000000000000000000000..88cba0537b5431aa266364abbe19162130f4e3ca Binary files /dev/null and b/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001198162584.png differ diff --git a/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001198322224.png b/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001198322224.png new file mode 100644 index 0000000000000000000000000000000000000000..208a4fbace342514f59f0000c4d50f5dc9321f0f Binary files /dev/null and b/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001198322224.png differ diff --git a/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001198322428.png b/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001198322428.png new file mode 100644 index 0000000000000000000000000000000000000000..548e03da4b76123cb67d41cbd1de4a0f33f5ef4b Binary files /dev/null and b/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001198322428.png differ diff --git a/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001198323146.png b/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001198323146.png new file mode 100644 index 0000000000000000000000000000000000000000..775ce6fe99d4894b39f2bdd613097dcaf11a37b2 Binary files /dev/null and b/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001198323146.png differ diff --git a/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001200053087.png b/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001200053087.png new file mode 100644 index 0000000000000000000000000000000000000000..015c38ba5516395527bcf6715535238f02b2bad9 Binary files /dev/null and b/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001200053087.png differ diff --git a/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001243082093.png b/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001243082093.png new file mode 100644 index 0000000000000000000000000000000000000000..0c1f60638087d0fe56127f2f842244355afad85f Binary files /dev/null and b/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001243082093.png differ diff --git a/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001243084579.png b/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001243084579.png new file mode 100644 index 0000000000000000000000000000000000000000..afc9028fbb61db82e6f1384032bb32f56ed2ec35 Binary files /dev/null and b/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001243084579.png differ diff --git a/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001243200677.png b/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001243200677.png new file mode 100644 index 0000000000000000000000000000000000000000..b6bc36af5339ea5a4f67640e69836965b3776e17 Binary files /dev/null and b/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001243200677.png differ diff --git a/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001243320787.png b/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001243320787.png new file mode 100644 index 0000000000000000000000000000000000000000..9284df45bb1415d84f0325df85b4eb5c223281e8 Binary files /dev/null and b/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001243320787.png differ diff --git a/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001243481961.png b/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001243481961.png new file mode 100644 index 0000000000000000000000000000000000000000..0eee1bbff2e54816d6be05f7f3972a83f615884d Binary files /dev/null and b/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001243481961.png differ diff --git a/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001243481989.png b/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001243481989.png new file mode 100644 index 0000000000000000000000000000000000000000..cfa0ceb21f5a11d459b93721f512309c9d6da2ac Binary files /dev/null and b/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001243481989.png differ diff --git a/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001243484907.png b/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001243484907.png new file mode 100644 index 0000000000000000000000000000000000000000..ad4fd618860ca9f79e9bdc39436c3b2f9cdb72de Binary files /dev/null and b/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001243484907.png differ diff --git a/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001251196005.png b/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001251196005.png new file mode 100644 index 0000000000000000000000000000000000000000..527fe8b9836daf35c8300e0e84bdb2ca390f85a5 Binary files /dev/null and b/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001251196005.png differ diff --git a/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001251276115.png b/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001251276115.png new file mode 100644 index 0000000000000000000000000000000000000000..39ae26ac8f3254d023d6b90a9f9bb8a8ff0c940b Binary files /dev/null and b/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001251276115.png differ diff --git a/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001251276255.png b/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001251276255.png new file mode 100644 index 0000000000000000000000000000000000000000..ff9105c313d5755f140920bbfc2399e3ccb5e2f5 Binary files /dev/null and b/zh-cn/device-dev/faqs/figures/zh-cn_image_0000001251276255.png differ diff --git a/zh-cn/device-dev/faqs/public_sys-resources/icon-caution.gif b/zh-cn/device-dev/faqs/public_sys-resources/icon-caution.gif new file mode 100644 index 0000000000000000000000000000000000000000..6e90d7cfc2193e39e10bb58c38d01a23f045d571 Binary files /dev/null and b/zh-cn/device-dev/faqs/public_sys-resources/icon-caution.gif differ diff --git a/zh-cn/device-dev/faqs/public_sys-resources/icon-danger.gif b/zh-cn/device-dev/faqs/public_sys-resources/icon-danger.gif new file mode 100644 index 0000000000000000000000000000000000000000..6e90d7cfc2193e39e10bb58c38d01a23f045d571 Binary files /dev/null and b/zh-cn/device-dev/faqs/public_sys-resources/icon-danger.gif differ diff --git a/zh-cn/device-dev/faqs/public_sys-resources/icon-note.gif b/zh-cn/device-dev/faqs/public_sys-resources/icon-note.gif new file mode 100644 index 0000000000000000000000000000000000000000..6314297e45c1de184204098efd4814d6dc8b1cda Binary files /dev/null and b/zh-cn/device-dev/faqs/public_sys-resources/icon-note.gif differ diff --git a/zh-cn/device-dev/faqs/public_sys-resources/icon-notice.gif b/zh-cn/device-dev/faqs/public_sys-resources/icon-notice.gif new file mode 100644 index 0000000000000000000000000000000000000000..86024f61b691400bea99e5b1f506d9d9aef36e27 Binary files /dev/null and b/zh-cn/device-dev/faqs/public_sys-resources/icon-notice.gif differ diff --git a/zh-cn/device-dev/faqs/public_sys-resources/icon-tip.gif b/zh-cn/device-dev/faqs/public_sys-resources/icon-tip.gif new file mode 100644 index 0000000000000000000000000000000000000000..93aa72053b510e456b149f36a0972703ea9999b7 Binary files /dev/null and b/zh-cn/device-dev/faqs/public_sys-resources/icon-tip.gif differ diff --git a/zh-cn/device-dev/faqs/public_sys-resources/icon-warning.gif b/zh-cn/device-dev/faqs/public_sys-resources/icon-warning.gif new file mode 100644 index 0000000000000000000000000000000000000000..6e90d7cfc2193e39e10bb58c38d01a23f045d571 Binary files /dev/null and b/zh-cn/device-dev/faqs/public_sys-resources/icon-warning.gif differ diff --git a/zh-cn/device-dev/get-code/figure/zh-cn_image_0000001153508656.png b/zh-cn/device-dev/get-code/figure/zh-cn_image_0000001153508656.png new file mode 100644 index 0000000000000000000000000000000000000000..bd2829efdc6d710559efe4650ddcba6b954b525e Binary files /dev/null and b/zh-cn/device-dev/get-code/figure/zh-cn_image_0000001153508656.png differ diff --git a/zh-cn/device-dev/get-code/figure/zh-cn_image_0000001167734854.png b/zh-cn/device-dev/get-code/figure/zh-cn_image_0000001167734854.png new file mode 100644 index 0000000000000000000000000000000000000000..a4fa09ee58922bc9b182ac688ed4553b211c452c Binary files /dev/null and b/zh-cn/device-dev/get-code/figure/zh-cn_image_0000001167734854.png differ diff --git a/zh-cn/device-dev/get-code/figure/zh-cn_image_0000001167743458.png b/zh-cn/device-dev/get-code/figure/zh-cn_image_0000001167743458.png new file mode 100644 index 0000000000000000000000000000000000000000..889adfe235359b5ab438ff87afb37ef4d1cf2ad9 Binary files /dev/null and b/zh-cn/device-dev/get-code/figure/zh-cn_image_0000001167743458.png differ diff --git a/zh-cn/device-dev/get-code/figure/zh-cn_image_0000001168212170.png b/zh-cn/device-dev/get-code/figure/zh-cn_image_0000001168212170.png new file mode 100644 index 0000000000000000000000000000000000000000..d98c83b3ead8e863b4db1da755b4e743afd62f46 Binary files /dev/null and b/zh-cn/device-dev/get-code/figure/zh-cn_image_0000001168212170.png differ diff --git a/zh-cn/device-dev/get-code/gettools-acquire.md b/zh-cn/device-dev/get-code/gettools-acquire.md index 14104510ac85970efd8c54889a427ef814acf862..4cb587d8b713e8042e802f7d32f7f46be97f70ea 100644 --- a/zh-cn/device-dev/get-code/gettools-acquire.md +++ b/zh-cn/device-dev/get-code/gettools-acquire.md @@ -1,230 +1,195 @@ -# Docker编译环境 +# Docker编译环境 -## Docker环境介绍 + +## Docker环境介绍 OpenHarmony为开发者提供了两种Docker环境,以帮助开发者快速完成复杂的开发环境准备工作。两种Docker环境及适用场景如下: -- 独立Docker环境:适用于直接基于Ubuntu、Windows操作系统平台进行版本编译的场景。 -- 基于HPM的Docker环境:适用于使用HPM工具进行发行版编译的场景。 - -**表 1** Docker镜像介绍 - - - - - - - - - - - - - - - - - - - - - -

Docker环境

-

系统类型

-

运行平台

-

Docker镜像仓库

-

标签

-

独立 Docker环境

-

轻量和小型系统

-

Ubuntu/Windows

-

swr.cn-south-1.myhuaweicloud.com/openharmony-docker/openharmony-docker

-

1.0.0

-

HPM Docker环境

-

轻量和小型系统

-

Ubuntu/Windows

-

swr.cn-south-1.myhuaweicloud.com/openharmony-docker/openharmony-docker

-

0.0.3

-
- - - - - - - - -## 环境准备 +- 独立Docker环境:适用于直接基于Ubuntu、Windows操作系统平台进行版本编译的场景。 -在使用docker环境前需要先完成以下操作: +- 基于HPM的Docker环境:适用于使用HPM工具进行发行版编译的场景。 -1. 安装Docker,Docker安装请参考[官方指导](https://docs.docker.com/engine/install/)。 -2. 获取OpenHarmony源码,请参考[获取源码](sourcecode-acquire.md)。 + **表1** Docker镜像介绍 - >![](../public_sys-resources/icon-note.gif) **说明:** - >HPM Docker环境无需单独获取源码。 +| 系统类型 | 运行平台 | Docker镜像仓库 | 标签 | +| -------- | -------- | -------- | -------- | +| 轻量和小型系统(独立Docker环境) | Ubuntu/Windows | swr.cn-south-1.myhuaweicloud.com/openharmony-docker/openharmony-docker | 1.0.0 | +| 标准系统(独立Docker环境) | Ubuntu | swr.cn-south-1.myhuaweicloud.com/openharmony-docker/openharmony-docker-standard | 1.0.0 | +| 轻量和小型系统(HPM Docker环境) | Ubuntu/Windows | swr.cn-south-1.myhuaweicloud.com/openharmony-docker/openharmony-docker | 0.0.3 | -## 独立Docker环境 +## 环境准备 -OpenHarmony的Docker镜像托管在[HuaweiCloud SWR](https://console.huaweicloud.com/swr/?region=cn-south-1#/app/warehouse/warehouseMangeDetail/goldensir/openharmony-docker/openharmony-docker?type=ownImage)上。开发者可以通过该镜像在很大程度上简化编译前的环境配置。下文将介绍具体使用步骤。 +在使用docker环境前需要先完成以下操作: -### 搭建Docker环境-轻量系统类设备(参考内存≥128KB)和小型系统类设备(参考内存≥1MB) +1. 安装Docker,Docker安装请参考[官方指导](https://docs.docker.com/engine/install/)。 -1. 获取Docker镜像。 +2. 获取OpenHarmony源码,请参考[获取源码](https://device.harmonyos.com/cn/docs/documentation/guide/sourcecode-acquire-0000001050769927)。 + > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** + > HPM Docker环境无需单独获取源码。 - ``` - docker pull swr.cn-south-1.myhuaweicloud.com/openharmony-docker/openharmony-docker:1.0.0 - ``` -2. 进入OpenHarmony代码根目录执行如下命令,从而进入Docker构建环境。 +## 独立Docker环境 - ubuntu下执行: +OpenHarmony的Docker镜像托管在[HuaweiCloud SWR](https://console.huaweicloud.com/swr/?region=cn-south-1#/app/warehouse/warehouseMangeDetail/goldensir/openharmony-docker/openharmony-docker?type=ownImage)上。开发者可以通过该镜像在很大程度上简化编译前的环境配置。下文将介绍具体使用步骤。 - ``` - docker run -it -v $(pwd):/home/openharmony swr.cn-south-1.myhuaweicloud.com/openharmony-docker/openharmony-docker:1.0.0 - ``` +### 搭建Docker环境(轻量系统和小型系统) - windows下执行(假设源码目录为D:\\OpenHarmony): +1. 获取Docker镜像。 + + ``` + docker pull swr.cn-south-1.myhuaweicloud.com/openharmony-docker/openharmony-docker:1.0.0 + ``` - ``` - docker run -it -v D:\OpenHarmony:/home/openharmony swr.cn-south-1.myhuaweicloud.com/openharmony-docker/openharmony-docker:1.0.0 - ``` +2. 进入源码根目录执行如下命令,从而进入Docker构建环境。 + ubuntu下执行: + + ``` + docker run -it -v $(pwd):/home/openharmony swr.cn-south-1.myhuaweicloud.com/openharmony-docker/openharmony-docker:1.0.0 + ``` + windows下执行(假设源码目录为D:\OpenHarmony): -### 编译源码-轻量系统类设备(参考内存≥128KB)和小型系统类设备(参考内存≥1MB) + + ``` + docker run -it -v D:\OpenHarmony:/home/openharmony swr.cn-south-1.myhuaweicloud.com/openharmony-docker/openharmony-docker:1.0.0 + ``` -通过如下编译脚本启动轻量系统类设备(参考内存≥128KB)和小型系统类设备(参考内存≥1MB)的编译。下文以Hi3516平台为例说明具体编译步骤。 +### 编译源码(轻量系统和小型系统) -设置编译路径,选择当前路径。 +通过如下编译脚本启动轻量系统类设备(参考内存≥128KiB)和小型系统类设备(参考内存≥1MiB)的编译。下文以Hi3516平台为例说明具体编译步骤。 + 设置编译路径,选择当前路径。 + ``` hb set + . ``` -**图 1** 设置编译界面 -![](figure/设置编译界面.png "设置编译界面") - ->![](../public_sys-resources/icon-note.gif) **说明:** ->当前开发板平台和编译界面的对应关系如下: ->- Hi3861:wifiiot\_hispark\_pegasus@hisilicon ->- Hi3516:ipcamera\_hispark\_taurus@hisilicon ->- Hi3518:ipcamera\_hispark\_aries@hisilicon - -1. 选择ipcamera\_hispark\_taurus@hisilicon并回车。 -2. 执行编译。 - - ``` - hb build -f - ``` + **图1** 设置编译界面 -3. 查看编译结果。 + ![zh-cn_image_0000001153508656](figures/zh-cn_image_0000001153508656.png) - 编译结果文件生成在out/hispark\_taurus/ipcamera\_hispark\_taurus目录下。 +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> 当前开发板平台和编译界面的对应关系如下: +> +> - Hi3861:wifiiot_hispark_pegasus\@hisilicon +> +> - Hi3516:ipcamera_hispark_taurus\@hisilicon +> +> - Hi3518:ipcamera_hispark_aries\@hisilicon +1. 选择ipcamera_hispark_taurus\@hisilicon并回车。 -### 搭建Docker环境-标准系统类设备(参考内存≥128MB) +2. 执行编译。 + + ``` + hb build -f + ``` -1. 获取Docker镜像。 +3. 查看编译结果。 + 编译结果文件生成在out/hispark_taurus/ipcamera_hispark_taurus目录下。 - ``` - docker pull swr.cn-south-1.myhuaweicloud.com/openharmony-docker/openharmony-docker:1.0.0 - ``` +### 搭建Docker环境(标准系统) -2. 进入OpenHarmony代码根目录执行如下命令,从而进入Docker构建环境。 +1. 获取Docker镜像。 + + ``` + docker pull swr.cn-south-1.myhuaweicloud.com/openharmony-docker/openharmony-docker-standard:1.0.0 + ``` - ``` - docker run -it -v $(pwd):/home/openharmony swr.cn-south-1.myhuaweicloud.com/openharmony-docker/openharmony-docker:1.0.0 - ``` +2. 进入源码根目录执行如下命令,从而进入Docker构建环境。 + + ``` + docker run -it -v $(pwd):/home/openharmony swr.cn-south-1.myhuaweicloud.com/openharmony-docker/openharmony-docker-standard:1.0.0 + ``` +### 编译源码(标准系统) -### 编译源码-标准系统类设备(参考内存≥128MB) - -通过如下编译脚本启动标准系统类设备(参考内存≥128MB)的编译。 - + 通过如下编译脚本启动标准系统类设备(参考内存≥128MB)的编译。 + ``` ./build.sh --product-name {product_name} --ccache ``` -\{product\_name\}为当前版本支持的平台。比如:Hi3516DV300和rk3568等。 +{product_name}为当前版本支持的平台。比如:Hi3516DV300和rk3568等。 编译所生成的文件都归档在out/{device_name}/目录下,结果镜像输出在 out/{device_name}/packages/phone/images/ 目录下。 ->![](../public_sys-resources/icon-note.gif) **说明:** ->退出Docker执行exit命令即可。 +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> 退出Docker执行exit命令即可。 -## 基于HPM的Docker环境 -docker\_dist是一个[HPM](https://hpm.harmonyos.com/)系统中的模板组件,能够帮助用户快速初始化HPM工程,利用docker镜像来快速编译OpenHarmony发行版,在很大程度上简化了编译前的环境配置。开发者在配置好Ubuntu和[hpm-cli](../hpm-part/hpm-part-development.md)开发环境后,可以通过以下步骤来使用我们提供的Docker环境。 +## 基于HPM的Docker环境 -### 搭建Docker环境 +docker_dist是一个[HPM](https://hpm.harmonyos.com/)系统中的模板组件,能够帮助用户快速初始化HPM工程,利用docker镜像来快速编译OpenHarmony发行版,在很大程度上简化了编译前的环境配置。开发者在配置好Ubuntu和[hpm-cli](https://device.harmonyos.com/cn/docs/documentation/guide/hpm-part-development-install-0000001178291102)开发环境后,可以通过以下步骤来使用我们提供的Docker环境。 -1. 初始化安装模板。在任意工作目录中执行以下命令。 - ``` - hpm init -t @ohos/docker_dist - ``` +### 搭建Docker环境 -2. 修改publishAs。 +1. 初始化安装模板。在任意工作目录中执行以下命令。 + + ``` + hpm init -t @ohos/docker_dist + ``` - 因为获取到的是模板类型的包,要把包的类型改为需要的类型。 在当前目录下打开bundle.json文件,把"publishAs"字段的值由"template"改为"distribution"。 +2. 修改publishAs。 + 因为获取到的是模板类型的包,要把包的类型改为需要的类型。 在当前目录下打开bundle.json文件,把"publishAs"字段的值由"template"改为"distribution"。 -### 获取及编译源码 +### 获取及编译源码 执行编译。自动安装docker只能在Ubuntu环境下执行,如果其他环境,需要用户自行安装docker,然后拉取镜像,执行编译。 -- **自动安装docker(Ubuntu环境)** - - 以下命令可以帮助用户自动安装docker, 拉取镜像,并且在容器中开始运行对应解决方案的拉取和编译。 - - **方式一:** - - 命令后接参数指定解决方案,格式如下: - - ``` - hpm run docker solution={product} - ``` - - \{product\}为需编译的解决方案,如:@ohos/hispark\_taurus、@ohos/hispark\_aries、@ohos/hispark\_pegasus。 - - **方式二:** - - 设置环境变量来选择解决方案,再执行编译命令。 - - 1. 选择解决方案。 - - ``` - export solution={product} - ``` - - \{product\}为需编译的解决方案,如:@ohos/hispark\_taurus、@ohos/hispark\_aries、@ohos/hispark\_pegasus。 - - 2. 获取源码及执行编译。 - - ``` - hpm run docker - ``` - - 以上两种方式以@ohos/hispark\_taurus为例,执行成功结果如下: - - ``` - ...... - ohos ipcamera_hispark_taurus build success! - @ohos/hispark_taurus: distribution building completed. - ``` - - -- **自行安装docker(非Ubuntu环境)** - - 自行安装docker相关操作如下: - - ``` - # 拉取镜像 - docker pull swr.cn-south-1.myhuaweicloud.com/openharmony-docker/openharmony-docker:0.0.3# linux环境下的编译 - hpm run distWithDocker solution={product} - # windows下的编译,需要配置gitbash - hpm config set shellPath "gitbash路径" - hpm run distWithDocker solution={product} - ``` - +- **自动安装docker(Ubuntu环境)** + 以下命令可以帮助用户自动安装docker, 拉取镜像,并且在容器中开始运行对应解决方案的拉取和编译。 + + **方式一:** + + 命令后接参数指定解决方案,格式如下: + + + ``` + hpm run docker solution={product} + ``` + + {product}为需编译的解决方案,如:\@ohos/hispark_taurus、\@ohos/hispark_aries、\@ohos/hispark_pegasus。 + + **方式二:** + + 设置环境变量来选择解决方案,再执行编译命令。 + + 1. 选择解决方案。 + + ``` + export solution={product} + ``` + + {product}为需编译的解决方案,如:\@ohos/hispark_taurus、\@ohos/hispark_aries、\@ohos/hispark_pegasus。 + 2. 获取源码及执行编译。 + + ``` + hpm run docker + ``` + + 以上两种方式以\@ohos/hispark_taurus为例,执行成功结果如下: + + ``` + ...... + ohos ipcamera_hispark_taurus build success! + @ohos/hispark_taurus: distribution building completed. + ``` + +- **自行安装docker(非Ubuntu环境)** + 自行安装docker相关操作如下: + + + ``` + # 拉取镜像 + docker pull swr.cn-south-1.myhuaweicloud.com/openharmony-docker/openharmony-docker:0.0.3# linux环境下的编译 + hpm run distWithDocker solution={product} + # windows下的编译,需要配置gitbash + hpm config set shellPath "gitbash路径" + hpm run distWithDocker solution={product} + ``` diff --git a/zh-cn/device-dev/get-code/gettools-ide.md b/zh-cn/device-dev/get-code/gettools-ide.md index c4f0930b51bd474eec753c7766ff1c20384ee936..6687462b29f9703bf4bc7d79e530dc594d142dc0 100644 --- a/zh-cn/device-dev/get-code/gettools-ide.md +++ b/zh-cn/device-dev/get-code/gettools-ide.md @@ -1,10 +1,8 @@ # IDE - ## 获取设备开发工具(HUAWEI DevEco Device Tool) -HUAWEI DevEco Device Tool是OpenHarmony面向智能设备开发者提供的一站式集成开发环境,支持OpenHarmony的组件按需定制,支持代码编辑、编译、烧录、调试等功能,支持C/C++语言,以插件的形式部署在Visual Studio Code上。具体可参见[获取工具](https://device.harmonyos.com/cn/ide)和[工具使用指南](https://device.harmonyos.com/cn/docs/ide/user-guides/service_introduction-0000001050166905)。 - +HUAWEI DevEco Device Tool是OpenHarmony面向智能设备开发者提供的一站式集成开发环境,支持OpenHarmony的组件按需定制,支持代码编辑、编译、烧录、调试等功能,支持C/C++语言,以插件的形式部署在Visual Studio Code上。具体可参见[获取工具](https://device.harmonyos.com/cn/ide)和[工具使用指南](https://device.harmonyos.com/cn/docs/ide/user-guides/service_introduction-0000001050166905)**。** ## 获取应用开发工具(HUAWEI DevEco Studio) diff --git a/zh-cn/device-dev/get-code/public_sys-resources/icon-caution.gif b/zh-cn/device-dev/get-code/public_sys-resources/icon-caution.gif new file mode 100644 index 0000000000000000000000000000000000000000..6e90d7cfc2193e39e10bb58c38d01a23f045d571 Binary files /dev/null and b/zh-cn/device-dev/get-code/public_sys-resources/icon-caution.gif differ diff --git a/zh-cn/device-dev/get-code/public_sys-resources/icon-danger.gif b/zh-cn/device-dev/get-code/public_sys-resources/icon-danger.gif new file mode 100644 index 0000000000000000000000000000000000000000..6e90d7cfc2193e39e10bb58c38d01a23f045d571 Binary files /dev/null and b/zh-cn/device-dev/get-code/public_sys-resources/icon-danger.gif differ diff --git a/zh-cn/device-dev/get-code/public_sys-resources/icon-note.gif b/zh-cn/device-dev/get-code/public_sys-resources/icon-note.gif new file mode 100644 index 0000000000000000000000000000000000000000..6314297e45c1de184204098efd4814d6dc8b1cda Binary files /dev/null and b/zh-cn/device-dev/get-code/public_sys-resources/icon-note.gif differ diff --git a/zh-cn/device-dev/get-code/public_sys-resources/icon-notice.gif b/zh-cn/device-dev/get-code/public_sys-resources/icon-notice.gif new file mode 100644 index 0000000000000000000000000000000000000000..86024f61b691400bea99e5b1f506d9d9aef36e27 Binary files /dev/null and b/zh-cn/device-dev/get-code/public_sys-resources/icon-notice.gif differ diff --git a/zh-cn/device-dev/get-code/public_sys-resources/icon-tip.gif b/zh-cn/device-dev/get-code/public_sys-resources/icon-tip.gif new file mode 100644 index 0000000000000000000000000000000000000000..93aa72053b510e456b149f36a0972703ea9999b7 Binary files /dev/null and b/zh-cn/device-dev/get-code/public_sys-resources/icon-tip.gif differ diff --git a/zh-cn/device-dev/get-code/public_sys-resources/icon-warning.gif b/zh-cn/device-dev/get-code/public_sys-resources/icon-warning.gif new file mode 100644 index 0000000000000000000000000000000000000000..6e90d7cfc2193e39e10bb58c38d01a23f045d571 Binary files /dev/null and b/zh-cn/device-dev/get-code/public_sys-resources/icon-warning.gif differ diff --git a/zh-cn/device-dev/get-code/sourcecode-acquire.md b/zh-cn/device-dev/get-code/sourcecode-acquire.md index 739814e4d8fcace75178a12d2f8cef1edcfe9c23..d6c7e8a2aee71da468cddf88e75187e0a4e0e27d 100644 --- a/zh-cn/device-dev/get-code/sourcecode-acquire.md +++ b/zh-cn/device-dev/get-code/sourcecode-acquire.md @@ -1,339 +1,208 @@ -# 获取源码 +# 获取源码 -## OpenHarmony介绍 + +## OpenHarmony介绍 OpenHarmony是由开放原子开源基金会(OpenAtom Foundation)孵化及运营的开源项目,目标是面向全场景、全连接、全智能时代,搭建一个智能终端设备操作系统的框架和平台,促进万物互联产业的繁荣发展。 + + 开源代码仓库地址:[https://openharmony.gitee.com](https://openharmony.gitee.com)。 -## 获取源码概述 -OpenHarmony当前为开发者提供了以下4种获取源码的方式,开发者可根据业务诉求选用合适的方式获取源码: +## 获取源码概述 -- **获取方式1**:从码云代码仓库获取。通过repo或git工具从代码仓库中下载,此方式可获取最新代码。 -- **获取方式2**:通过[DevEco Marketplace](https://repo.harmonyos.com/#/cn/home)网站获取。访问[DevEco Marketplace](https://repo.harmonyos.com/#/cn/home)网站,查找满足需求的开源发行版,直接下载(或者定制后下载),再通过hpm-cli命令工具将所需的组件及工具链下载、安装到本地。 -- **获取方式3**:从镜像站点下载归档后的发行版压缩文件。如果要获取旧版本的源码,也可通过此方式获取,此方式下载速度较快。 -- **获取方式4**:从github代码仓库获取。通过repo或git工具从代码仓库中下载,此方式可获取最新代码。 +本文档将介绍如何获取OpenHarmony源码并说明OpenHarmony的源码目录结构。OpenHarmony的代码以[组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/hpm-part/Readme-CN.md)的形式开放,开发者可以通过如下其中一种方式获取: -## 获取方式1:从码云仓库获取 +- **获取方式1**:从码云代码仓库获取。通过repo或git工具从代码仓库中下载,此方式可获取最新代码。 -### 适用场景 +- **获取方式2**:通过[DevEco Marketplace](https://repo.harmonyos.com/#/cn/home)网站获取。访问[DevEco Marketplace](https://repo.harmonyos.com/#/cn/home)网站,查找满足需求的开源发行版,直接下载(或者定制后下载),再通过hpm-cli命令工具将所需的组件及工具链下载、安装到本地。 -- 基于OpenHarmony的稳定分支建立自己的基线,分发下游客户。 +- **获取方式3**:从镜像站点下载归档后的发行版压缩文件。如果要获取旧版本的源码,也可通过此方式获取,此方式下载速度较快。 -- 已经完成自身软件与OpenHarmony的对接,需要进行OpenHarmony官方认证。 +- **获取方式4**:从github代码仓库获取。通过repo或git工具从代码仓库中下载,此方式可获取最新代码。 -- 芯片/模组/app通过OpenHarmony官方认证后,贡献代码到OpenHarmony社区。 -- 修复OpenHarmony的问题。 +## 获取方式1:从码云仓库获取 -- 学习OpenHarmony的源码。 +### 适用场景 -### 前提条件 +- 基于OpenHarmony的稳定分支建立自己的基线,分发下游客户。 -1. 注册码云gitee帐号。 -2. 注册码云SSH公钥,请参考[码云帮助中心](https://gitee.com/help/articles/4191)。 -3. 安装[git客户端](https://git-scm.com/book/zh/v2/%E8%B5%B7%E6%AD%A5-%E5%AE%89%E8%A3%85-Git)和[git-lfs](https://gitee.com/vcs-all-in-one/git-lfs?_from=gitee_search#downloading)并配置用户信息。 +- 已经完成自身软件与OpenHarmony的对接,需要进行OpenHarmony官方认证。 - ``` - git config --global user.name "yourname" - git config --global user.email "your-email-address" - git config --global credential.helper store - ``` +- 芯片/模组/app通过OpenHarmony官方认证后,贡献代码到OpenHarmony社区。 -4. 安装码云repo工具,可以执行如下命令。 +- 修复OpenHarmony的问题。 - ``` - curl https://gitee.com/oschina/repo/raw/fork_flow/repo-py3 -o /usr/local/bin/repo #如果没有权限,可下载至其他目录,并将其配置到环境变量中 - chmod a+x /usr/local/bin/repo - pip3 install -i https://repo.huaweicloud.com/repository/pypi/simple requests - ``` +- 学习OpenHarmony的源码。 -### 操作步骤 +### 前提条件 +1. 注册码云gitee帐号。 ->![](../public_sys-resources/icon-note.gif) **说明:** ->Master主干为开发分支,开发者可通过Master主干获取最新特性。发布版本代码相对比较稳定,开发者可基于发布版本代码进行商用功能开发。 +2. 注册码云SSH公钥,请参考[码云帮助中心](https://gitee.com/help/articles/4191)。 -- **OpenHarmony主干代码获取** +3. 安装[git客户端](https://git-scm.com/book/zh/v2/%E8%B5%B7%E6%AD%A5-%E5%AE%89%E8%A3%85-Git)和[git-lfs](https://gitee.com/vcs-all-in-one/git-lfs?_from=gitee_search#downloading)并配置用户信息。 + + ``` + git config --global user.name "yourname" + git config --global user.email "your-email-address" + git config --global credential.helper store + ``` - 方式一(推荐):通过repo + ssh下载(需注册公钥,请参考[码云帮助中心](https://gitee.com/help/articles/4191))。 +4. 安装码云repo工具,可以执行如下命令。 + + ``` + curl -s https://gitee.com/oschina/repo/raw/fork_flow/repo-py3 > /usr/local/bin/repo #如果没有权限,可下载至其他目录,并将其配置到环境变量中 + chmod a+x /usr/local/bin/repo + pip3 install -i https://repo.huaweicloud.com/repository/pypi/simple requests + ``` - ``` - repo init -u git@gitee.com:openharmony/manifest.git -b master --no-repo-verify - repo sync -c - repo forall -c 'git lfs pull' - ``` - 方式二:通过repo + https下载。 +### 操作步骤 - ``` - repo init -u https://gitee.com/openharmony/manifest.git -b master --no-repo-verify - repo sync -c - repo forall -c 'git lfs pull' - ``` -- **OpenHarmony发布版本代码获取** +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> Master主干为开发分支,开发者可通过Master主干获取最新特性。发布版本代码相对比较稳定,开发者可基于发布版本代码进行商用功能开发。 - OpenHarmony发布版本获取源码方式请参考[Release-Notes](../../release-notes/Readme.md)。 +- **OpenHarmony主干代码获取** + + 方式一(推荐):通过repo + ssh下载(需注册公钥,请参考[码云帮助中心](https://gitee.com/help/articles/4191))。 + + ``` + repo init -u git@gitee.com:openharmony/manifest.git -b master --no-repo-verify + repo sync -c + repo forall -c 'git lfs pull' + ``` + 方式二:通过repo + https下载。 -## 获取方式2:从DevEco Marketplace获取 + + ``` + repo init -u https://gitee.com/openharmony/manifest.git -b master --no-repo-verify + repo sync -c + repo forall -c 'git lfs pull' + ``` -### 适用场景 +- **OpenHarmony发布版本代码获取** -对于刚接触OpenHarmony的新用户,希望能够参考一些示例解决方案从而进行快速开发。可以在[DevEco Marketplace](https://repo.harmonyos.com/#/cn/home)网站获取下载开源发行版,也可以在开源发行版的基础上定制(添加或删除组件)。然后通过包管理器命令行工具(hpm-cli)将需要的组件及相关的编译工具链全部下载、安装到本地。 + OpenHarmony发布版本获取源码方式请参考[Release-Notes](https://gitee.com/openharmony/docs/blob/master/zh-cn/release-notes/Readme.md)。 -### 前提条件 -先要在本地安装Node.js和hpm命令行工具,安装步骤如下: +## 获取方式2:从DevEco Marketplace获取 -1. 安装Node.js。 - 官网下载并在本地安装Node.js. +### 适用场景 - [Node.js](https://nodejs.org/) 版本需不低于12.x \(包含npm 6.14.4\),推荐安装LTS版本。 +对于刚接触OpenHarmony的新用户,希望能够参考一些示例解决方案从而进行快速开发。可以在[DevEco Marketplace](https://repo.harmonyos.com/#/cn/home)网站获取下载开源发行版,也可以在开源发行版的基础上定制(添加或删除组件)。然后通过包管理器命令行工具(hpm-cli)将需要的组件及相关的编译工具链全部下载、安装到本地。 -2. 通过Node.js自带的npm安装hpm命令行工具。 - 打开CMD,执行以下命令: +### 前提条件 - ``` - npm install -g @ohos/hpm-cli - ``` +先要在本地安装Node.js和hpm命令行工具,安装步骤如下: -3. 安装完成后执行如下命令,显示hpm版本,即安装成功。 +1. 安装Node.js。 + 官网下载并在本地安装Node.js. - ``` - hpm -V 或 hpm --version - ``` + [Node.js](https://nodejs.org/)版本需不低于12.x (包含npm 6.14.4),推荐安装LTS版本。 -4. 如果升级hpm的版本,请执行如下命令: +2. 通过Node.js自带的npm安装hpm命令行工具。 + 打开CMD,执行以下命令: + + ``` + npm install -g @ohos/hpm-cli + ``` - ``` - npm update -g @ohos/hpm-cli - ``` +3. 安装完成后执行如下命令,显示hpm版本,即安装成功。 + + ``` + hpm -V 或 hpm --version + ``` +4. 如果升级hpm的版本,请执行如下命令: + + ``` + npm update -g @ohos/hpm-cli + ``` -### 操作步骤 -1. 查找发行版。 - 1. 访问[DevEco Marketplace](https://repo.harmonyos.com/#/cn/home),设定搜索的对象为“设备组件“,并在左侧边栏选择“开源发行版“,如下图所示。 - 2. 在搜索框输入关键字搜索,如“摄像头”。 - 3. 结果中显示与关键字匹配的发行版,可以进一步根据组件类别等过滤条件(如:适配的开发板,内核)精确筛选。 - 4. 查找合适的发行版,点击查看发行版的详情介绍。 +### 操作步骤 - **图 1** 包管理 - ![](figure/包管理.png "包管理") +1. 查找发行版。 + 1. 访问[DevEco Marketplace](https://repo.harmonyos.com/#/cn/home),设定搜索的对象为设备组件,并在左侧边栏选择开源发行版,如下图所示。 + 2. 在搜索框输入关键字搜索,如“摄像头”。 + 3. 结果中显示与关键字匹配的发行版,可以进一步根据组件类别等过滤条件(如:适配的开发板,内核)精确筛选。 + 4. 查找合适的发行版,点击查看发行版的详情介绍。 -2. 了解发行版详情。 + **图1** 包管理 - 1. 仔细阅读发行版的说明信息,以了解使用场景、特性、组件构成、使用方法以及如何进行定制化,如下图所示。 - 2. 点击「直接下载」,将发行版下载到本地。 - 3. 点击「定制组件」,将对发行版包含的组件进行定制(添加/删除)。 + ![zh-cn_image_0000001168212170](figures/zh-cn_image_0000001168212170.png) - **图 2** 发行版示例 - ![](figure/发行版示例.png "发行版示例") +2. 了解发行版详情。 + 1. 仔细阅读发行版的说明信息,以了解使用场景、特性、组件构成、使用方法以及如何进行定制化,如下图所示。 + 2. 点击「直接下载」,将发行版下载到本地。 + 3. 点击「定制组件」,将对发行版包含的组件进行定制(添加/删除)。 -3. 定制组件。 - 1. 进入发行版的定制页面,如下图所示。 - 2. 通过关闭开关移除可选组件,或者通过“添加组件”增加新的组件。 - 3. 在右边填写您的项目基本信息,包括名称、版本、描述等信息。 - 4. 点击“下载“,系统会根据您的选择,生成相应的OpenHarmony代码结构文件\(如my\_cust\_dist.zip\),保存至本地文件。 + **图2** 发行版示例 - **图 3** 组件定制 - ![](figure/组件定制.png "组件定制") + ![zh-cn_image_0000001167734854](figures/zh-cn_image_0000001167734854.png) -4. 安装组件。 - 1. 解压下载的压缩文件,用命令行工具CMD(Linux下的Shell终端)。 - 2. 在解压后的文件目录下执行hpm install指令,系统会自动下载并安装组件。安装窗口显示“Install sucessful”表示组件下载及安装成功。 - 3. 下载的组件将保存在工程目录下的ohos\_bundles文件夹中(部分组件安装后会将源码复制到指定目录下)。 +3. 定制组件。 + 1. 进入发行版的定制页面,如下图所示。 + 2. 通过关闭开关移除可选组件,或者通过“添加组件”增加新的组件。 + 3. 在右边填写您的项目基本信息,包括名称、版本、描述等信息。 + 4. 点击下载,系统会根据您的选择,生成相应的OpenHarmony代码结构文件(如my_cust_dist.zip),保存至本地文件。 + **图3** 组件定制 -## 获取方式3:从镜像站点获取 + ![zh-cn_image_0000001167743458](figures/zh-cn_image_0000001167743458.png) + +4. 安装组件。 + 1. 解压下载的压缩文件,用命令行工具CMD(Linux下的Shell终端)。 + 2. 在解压后的文件目录下执行hpm install指令,系统会自动下载并安装组件。安装窗口显示“Install successful”表示组件下载及安装成功。 + 3. 下载的组件将保存在工程目录下的ohos_bundles文件夹中(部分组件安装后会将源码复制到指定目录下)。 + + +## 获取方式3:从镜像站点获取 为了获得更好的下载性能,您可以选择从以下站点的镜像库获取源码或者对应的解决方案。 -本部分只提供OpenHarmony LTS最新版本和最新发布版本的源码获取方式, 其他版本获取源码方式以及具体版本信息请参考[Release-Notes](../../release-notes/Readme.md)。 - -**表 1** 获取源码路径 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

LTS版本源码

-

版本信息

-

下载站点

-

SHA256校验码

-

全量代码(标准、轻量和小型系统)

-

3.0

-

站点

-

SHA256校验码

-

标准系统解决方案(二进制)

-

3.0

-

站点

-

SHA256校验码

-

Hi3861解决方案(二进制)

-

3.0

-

站点

-

SHA256校验码

-

Hi3518解决方案(二进制)

-

3.0

-

站点

-

SHA256校验码

-

Hi3516解决方案-LiteOS(二进制)

-

3.0

-

站点

-

SHA256校验码

-

Hi3516解决方案-Linux(二进制)

-

3.0

-

站点

-

SHA256校验码

-

RELEASE-NOTES

-

3.0

-

站点

-

-

-

最新发布版本源码

-

版本信息

-

下载站点

-

SHA256校验码

-

全量代码Release版本(标准、轻量和小型系统)

-

3.1 Release

-

站点

-

SHA256校验码

-

Hi3516标准系统解决方案(二进制)

-

3.1 Release

-

站点

-

SHA256校验码

-

RK3568标准系统解决方案(二进制)

-

3.1 Release

-

站点

-

SHA256校验码

-

Hi3861解决方案(二进制)

-

3.1 Release

-

站点

-

SHA256校验码

-

Hi3516解决方案-LiteOS(二进制)

-

3.1 Release

-

站点

-

SHA256校验码

-

Hi3516解决方案-Linux(二进制)

-

3.1 Release

-

站点

-

SHA256校验码

-

RELEASE-NOTES

-

3.1 Release

-

站点

-

-

-

编译工具链

-

版本信息

-

下载站点

-

SHA256校验码

-

编译工具链获取清单

-

-

-

站点

-

-

-
- -## 获取方式4:从github镜像仓库获取 - ->![](../public_sys-resources/icon-note.gif) **说明:** +本部分只提供OpenHarmony LTS最新版本和最新发布版本的源码获取方式, 其他版本获取源码方式以及具体版本信息请参考[Release-Notes](https://gitee.com/openharmony/docs/blob/master/zh-cn/release-notes/Readme.md)。 + + **表1** 获取源码路径 + +| **LTS版本源码** | **版本信息** | **下载站点** | **SHA256校验码** | +| -------- | -------- | -------- | -------- | +| 全量代码(标准、轻量和小型系统) | 3.0 | [站点](https://repo.huaweicloud.com/harmonyos/os/3.0/code-v3.0-LTS.tar.gz) | [SHA256校验码](https://repo.huaweicloud.com/harmonyos/os/3.0/code-v3.0-LTS.tar.gz.sha256) | +| 标准系统解决方案(二进制) | 3.0 | [站点](https://repo.huaweicloud.com/harmonyos/os/3.0/standard.tar.gz) | [SHA256校验码](https://repo.huaweicloud.com/harmonyos/os/3.0/standard.tar.gz.sha256) | +| Hi3861解决方案(二进制) | 3.0 | [站点](https://repo.huaweicloud.com/harmonyos/os/3.0/hispark_pegasus.tar.gz) | [SHA256校验码](https://repo.huaweicloud.com/harmonyos/os/3.0/hispark_pegasus.tar.gz.sha256) | +| Hi3518解决方案(二进制) | 3.0 | [站点](https://repo.huaweicloud.com/harmonyos/os/3.0/hispark_aries.tar.gz) | [SHA256校验码](https://repo.huaweicloud.com/harmonyos/os/3.0/hispark_aries.tar.gz.sha256) | +| Hi3516解决方案-LiteOS(二进制) | 3.0 | [站点](https://repo.huaweicloud.com/harmonyos/os/3.0/hispark_taurus.tar.gz) | [SHA256校验码](https://repo.huaweicloud.com/harmonyos/os/3.0/hispark_taurus.tar.gz.sha256) | +| Hi3516解决方案-Linux(二进制) | 3.0 | [站点](https://repo.huaweicloud.com/harmonyos/os/3.0/hispark_taurus_linux.tar.gz) | [SHA256校验码](https://repo.huaweicloud.com/harmonyos/os/3.0/hispark_taurus_linux.tar.gz.sha256) | +| RELEASE-NOTES | 3.0 | [站点](https://gitee.com/openharmony/docs/blob/OpenHarmony-3.0-LTS/zh-cn/release-notes/OpenHarmony-v3.0-LTS.md) | - | +| **最新发布版本源码** | **版本信息** | **下载站点** | **SHA256校验码** | +| 全量代码Release版本(标准、轻量和小型系统) | 3.1 Release | [站点](https://repo.huaweicloud.com/harmonyos/os/3.1-Release/code-v3.1-Release.tar.gz) | [SHA256校验码](https://repo.huaweicloud.com/harmonyos/os/3.1-Release/code-v3.1-Release.tar.gz.sha256) | +| Hi3516标准系统解决方案(二进制) | 3.1 Release | [站点](https://repo.huaweicloud.com/harmonyos/os/3.1-Release/standard_hi3516.tar.gz) | [SHA256校验码](https://repo.huaweicloud.com/harmonyos/os/3.1-Release/standard_hi3516.tar.gz.sha256) | +| RK3568标准系统解决方案(二进制) | 3.1 Release | [站点](https://repo.huaweicloud.com/harmonyos/os/3.1-Release/standard_rk3568.tar.gz) | [SHA256校验码](https://repo.huaweicloud.com/harmonyos/os/3.1-Release/standard_rk3568.tar.gz.sha256) | +| Hi3861解决方案(二进制) | 3.1 Release | [站点](https://repo.huaweicloud.com/harmonyos/os/3.1-Release/hispark_pegasus.tar.gz) | [SHA256校验码](https://repo.huaweicloud.com/harmonyos/os/3.1-Release/hispark_pegasus.tar.gz.sha256) | +| Hi3516解决方案-LiteOS(二进制) | 3.1 Release | [站点](https://repo.huaweicloud.com/harmonyos/os/3.1-Release/hispark_taurus.tar.gz) | [SHA256校验码](https://repo.huaweicloud.com/harmonyos/os/3.1-Release/hispark_taurus.tar.gz.sha256) | +| Hi3516解决方案-Linux(二进制) | 3.1 Release | [站点](https://repo.huaweicloud.com/harmonyos/os/3.1-Release/hispark_taurus_linux.tar.gz) | [SHA256校验码](https://repo.huaweicloud.com/harmonyos/os/3.1-Release/hispark_taurus_linux.tar.gz.sha256) | +| RELEASE-NOTES | 3.1 Release | [站点](https://gitee.com/openharmony/docs/tree/OpenHarmony-3.1-Release/zh-cn/release-notes/OpenHarmony-v3.1-Release.md) | - | +| **编译工具链** | **版本信息** | **下载站点** | **SHA256校验码** | +| 编译工具链获取清单 | - | [站点](https://repo.huaweicloud.com/harmonyos/os/2.0/tool_chain/) | - | + + +## 获取方式4:从github镜像仓库获取 + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** > 镜像仓库每日23:00(UTC +8:00)同步。 方式一(推荐):通过repo + ssh下载(需注册公钥,请参考[GitHub帮助中心](https://docs.github.com/en/github/authenticating-to-github/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account))。 + ``` repo init -u git@github.com:openharmony/manifest.git -b master --no-repo-verify repo sync -c @@ -342,94 +211,33 @@ repo forall -c 'git lfs pull' 方式二:通过repo + https下载。 + ``` repo init -u https://github.com/openharmony/manifest.git -b master --no-repo-verify repo sync -c repo forall -c 'git lfs pull' ``` -## 源码目录简介 + +## 源码目录简介 下表是OpenHarmony源码目录: -**表 2** 源码目录 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

目录名

-

描述

-

applications

-

应用程序样例,包括camera等

-

base

-

基础软件服务子系统集&硬件服务子系统集

-

build

-

组件化编译、构建和配置脚本

-

docs

-

说明文档

-

domains

-

增强软件服务子系统集

-

drivers

-

驱动子系统

-

foundation

-

系统基础能力子系统集

-

kernel

-

内核子系统

-

prebuilts

-

编译器及工具链子系统

-

test

-

测试子系统

-

third_party

-

开源第三方组件

-

utils

-

常用的工具集

-

vendor

-

厂商提供的软件

-

build.py

-

编译脚本文件

-
+ **表2** 源码目录 + +| 目录名 | 描述 | +| -------- | -------- | +| applications | 应用程序样例,包括camera等 | +| base | 基础软件服务子系统集&硬件服务子系统集 | +| build | 组件化编译、构建和配置脚本 | +| docs | 说明文档 | +| domains | 增强软件服务子系统集 | +| drivers | 驱动子系统 | +| foundation | 系统基础能力子系统集 | +| kernel | 内核子系统 | +| prebuilts | 编译器及工具链子系统 | +| test | 测试子系统 | +| third_party | 开源第三方组件 | +| utils | 常用的工具集 | +| vendor | 厂商提供的软件 | +| build.py | 编译脚本文件 | diff --git "a/\357\274\201" "b/\357\274\201" new file mode 100644 index 0000000000000000000000000000000000000000..145356f1c64caf99afd1b38bdd6c23ebaf6fe268 --- /dev/null +++ "b/\357\274\201" @@ -0,0 +1,7 @@ +Signed-off-by: duangavin123 +Merge branch 'master' of https://gitee.com/duangavin123_admin/docs_1 +# Please enter a commit message to explain why this merge is necessary, +# especially if it merges an updated upstream into a topic branch. +# +# Lines starting with '#' will be ignored, and an empty message aborts +# the commit.