#2020征文-开发板# 用鸿蒙开发AI应用(五)HDF 驱动补光灯 原创 精华
前言
上一篇,我们在鸿蒙上运行了第一个程序,这一篇我们来编写一个驱动开启摄像头的红外补光灯,顺便熟悉一下鸿蒙上的 HDF 驱动开发。
硬件准备
先查一下原理图(具体可参考第一篇的硬件资料),找到红外灯的 IO 口编号,GPIO5_1。
HDF 驱动开发
1. 简介
HDF(OpenHarmony Driver Foundation)驱动框架,为驱动开发者提供驱动框架能力,包括驱动加载、驱动服务管理和驱动消息机制。旨在构建统一的驱动架构平台,为驱动开发者提供更精准、更高效的开发环境,力求做到一次开发,多系统部署。
HDF框架以组件化的驱动模型作为核心设计思路,为开发者提供更精细化的驱动管理,让驱动开发和部署更加规范。HDF框架将一类设备驱动放在同一个host里面,驱动内部实现开发者也可以将驱动功能分层独立开发和部署,支持一个驱动多个node,HDF框架管理驱动模型如下图所示:
2. 驱动框架
2.1 驱动框架实现
在 huawei/hdf 目录下新建一个文件夹 led, 然后在其中新建一个源文件 led.c。
2.2 驱动入口注册到HDF框架
3. 驱动编译
在 huawei/hdf/led 目录下新建编译文件 Makefile
这里的hdf_led_driver为驱动文件名,注意对应关系。
4. 编译结果链接到内核镜像
修改 huawei/hdf/hdf_vendor.mk 文件,添加以下代码
填入驱动文件名和源码路径。
5. 驱动配置
驱动配置包含两部分,HDF框架定义的驱动设备描述和驱动的私有配置信息。
5.1 驱动设备描述(必选)
HDF框架加载驱动所需要的信息来源于HDF框架定义的驱动设备描述。
修改 vendor/hisi/hi35xx/hi3516dv300/config/device_info/device_info.hcs配置文件,添加驱动的设备描述。
其中,moduleName、serviceName和deviceMatchAttr 都比较重要,分布链接到源码的不同位置,我这里都分开命名,便于理解。
5.2 驱动私有配置信息(可选)
如果驱动有私有配置,则可以添加一个驱动的配置文件,用来填写一些驱动的默认配置信息,HDF框架在加载驱动的时候,会将对应的配置信息获取并保存在HdfDeviceObject 中的property里面,通过Bind和Init(参考驱动开发)传递给驱动。
在 vendor/hisi/hi35xx/hi3516dv300/config/ 目录下新建一个文件夹 led, 然后在其中新建一个源文件 led_config.hcs, 填入以下代码。
配置信息定义之后,需要将该配置文件添加到板级配置入口文件hdf.hcs。
5.3 板级配置(可选)
修改 vendor/hisi/hi35xx/hi3516dv300/config/hdf.hcs文件,添加代码
6. 驱动消息机制管理
当用户态应用和内核态驱动需要交互时,可以使用HDF框架的消息机制来实现。用消息管理可以在用户态和内核态之间架起桥梁,这为我们之后的APP提供了操控底层设备功能的能力。
这里我们在用户态实现一个简单的消息机制,内核态接受到消息后,翻转摄像头两侧的红外补光灯。
6.1 配置服务策略
HDF框架定了驱动对外发布服务的策略,是由配置文件中的policy字段来控制。
我们将驱动配置信息中服务策略policy字段设置为2,在之前的设备描述文件device_info.hcs里已经配置好了。
6.2 实现服务
在第2章,我们实现了一个空的驱动框架,现在继续实现内核态的消息服务接口。
编辑 huawei/hdf/led/led.c, 实现服务基类成员IDeviceIoService中的Dispatch方法。收到用户态发来的命令后,操作LED设备,然后将返回值通过reply传回,最后再将收到的命令回传给用户态程序。
修改 HdfLedDriverBind函数,将服务绑定到框架。
7. 业务代码
内核态核心功能,就简单实现一个每调用一次,就翻转一下LED状态的CtrlLED函数。这里mode为 -1 时为翻转,也可以直接指定高电平或低电平来开关,方便后续扩展。
其中Hi3516DV300的控制器管理12组GPIO管脚,每组8个。
GPIO号 = GPIO组索引(0~11)* 每组GPIO管脚数(8) + 组内偏移。
那么GPIO5_1的GPIO号 = 5 * 8 +1 = 41。
同理,GPIO2_3、GPIO3_4和蜂鸣器组件等等通用IO设备也能相应控制,可以尽情发挥想象力了。
8. 配置Kconfig
在`vendor/huawei/hdf/led/`下,新建一个目录`driver`,再在其下新建`Kconfig`文件。
将其链接到板级Kconfig中,在vendor/huawei/hdf/Kconfig增加
好了,内核态的程序基本都搞定了。
9. 用户态程序
我们开始写个主程序通过消息机制来与内核态交互。
新建applications/sample/camera/myApp/my_led_app.c源文件:
9.1 定义参数
led_service为服务名称,需要与之前定义的匹配;LED_WRITE_READ为命令标识,用户态和内核态通过这个来标识消息类型。
9.2 发送消息
先实现一个发送消息的函数SendEvent,发送字符串命令后,收回内核态reply中操作设备后的返回值,放入replyData中打印出来。这里操作成功返回0。
9.3 设置回调
收到内核态发来的字符串,简单打印一下。
9.4 主程序
先构造一个服务,通过服务名称,绑定到对应的驱动。然后设置监听,等待来自内核的消息。最后每隔1秒发出一条翻转LED的指令。
9.5 配置BUILD.gn
在 drivers/hdf/lite/manager/BUILD.gn里增加以下代码,生成led_app应用。
10. 编译和烧录
由于这次我们要用到`HDF`框架,需要用到的组件比较多,简单复制一个`build\lite\product\ipcamera_hi3516dv300.json`改名为`my_hi3516dv300`即可。
编译和烧录的过程参考前文,这里不再赘述了。顺利的话,启动程序就能看见LED欢快的闪烁了。
红外光在肉眼下不太显眼,在镜头下比较亮些,照度范围很大,后续再测一下夜视补光的效果。
总结
驱动开发涉及到文件和配置比较多,关系也比较纷繁,而且分散在各个目录。
这里列出主要文件再梳理一下:
大致上分三个部分,内核态、用户态和驱动配置。
1. 内核态
首先由led.c生成名为led_service的服务,以g_ledDriverEntry结构注册到HCS框架。编译成hdf_led_driver驱动,通过 huawei/hdf/hdf_vendor.mk链接到内核镜像中。
通过 HdfLedDriverBind函数将led_driver模块绑定到框架,IDeviceIoService中的Dispatch方法来处理来自用户态消息。
2. 用户态
用户态以HdfIoServiceBind通过服务名led_service来找到相应的驱动,用HdfSbufWriteString来发送消息,serv->dispatcher->Dispatch来接收返回值,通过HdfDeviceRegisterEventListener设置监听,来获取内核态主动发送的消息。
3. 驱动配置
以模块名led_driver找到注册到HCS框架的驱动程序(内核侧的别名);
以服务名led_service,暴露给用户态程序或内核态程序调用(用户侧的别名);
以led_config链接驱动私有配置文件。两个别名双向解绑,最后通过配置文件来进行耦合,保证了灵活性。这种设计在分布式的场合中,会有比较大的便利性。
资料下载
下一篇预告
本期主要介绍了一下HDF的驱动开发,界面部分碍于篇幅留在下一篇介绍了,
敬请期待...
哎哟。还可以哦。
干货满满
请问你的代码是code-2.0-canary吗?
main函数在哪个.c文件中?
大神,你的资料在哪里下载啊?