目录:

前言

硬件准备

HDF 驱动开发

总结

前言
上一篇,我们在鸿蒙上运行了第一个程序,这一篇我们来编写一个驱动开启摄像头的红外补光灯,顺便熟悉一下鸿蒙上的 HDF 驱动开发。

硬件准备
先查一下原理图(具体可参考第一篇的硬件资料),找到红外灯的 IO 口编号,GPIO5_1。

HDF 驱动开发
1. 简介
HDF(OpenHarmony Driver Foundation)驱动框架,为驱动开发者提供驱动框架能力,包括驱动加载、驱动服务管理和驱动消息机制。旨在构建统一的驱动架构平台,为驱动开发者提供更精准、更高效的开发环境,力求做到一次开发,多系统部署。

HDF框架以组件化的驱动模型作为核心设计思路,为开发者提供更精细化的驱动管理,让驱动开发和部署更加规范。HDF框架将一类设备驱动放在同一个host里面,驱动内部实现开发者也可以将驱动功能分层独立开发和部署,支持一个驱动多个node,HDF框架管理驱动模型如下图所示:

2. 驱动框架
2.1 驱动框架实现
在 huawei/hdf 目录下新建一个文件夹 led, 然后在其中新建一个源文件 led.c。

#include "hdf_device_desc.h"  // HDF框架对驱动开放相关能力接口的头文件
#include "hdf_log.h" // HDF 框架提供的日志接口头文件 #define HDF_LOG_TAG led_driver // 打印日志所包含的标签,如果不定义则用默认定义的HDF_TAG标签 //驱动对外提供的服务能力,将相关的服务接口绑定到HDF框架
int32_t HdfLedDriverBind(struct HdfDeviceObject *deviceObject)
{
HDF_LOGD("Led driver bind success");
return 0;
} // 驱动自身业务初始的接口
int32_t HdfLedDriverInit(struct HdfDeviceObject *deviceObject)
{
if (deviceObject == NULL) {
HDF_LOGE("Led driver Init failed!");
return HDF_ERR_INVALID_OBJECT;
}
HDF_LOGD("Led driver Init success");
return HDF_SUCCESS;
} // 驱动资源释放的接口
void HdfLedDriverRelease(struct HdfDeviceObject *deviceObject)
{
if (deviceObject == NULL) {
HDF_LOGE("Led driver release failed!");
return;
} HDF_LOGD("Led driver release success");
return;
}

2.2 驱动入口注册到HDF框架

// 定义驱动入口的对象,必须为HdfDriverEntry(在hdf_device_desc.h中定义)类型的全局变量
struct HdfDriverEntry g_ledDriverEntry = {
.moduleVersion = 1,
.moduleName = "led_driver",
.Bind = HdfLedDriverBind,
.Init = HdfLedDriverInit,
.Release = HdfLedDriverRelease,
}; // 调用HDF_INIT将驱动入口注册到HDF框架中,在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动,当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
HDF_INIT(g_ledDriverEntry);

3. 驱动编译

在 huawei/hdf/led 目录下新建编译文件 Makefile

include $(LITEOSTOPDIR)/../../drivers/hdf/lite/lite.mk  #导入hdf预定义内容,必需

MODULE_NAME := hdf_led_driver  #生成的结果文件
LOCAL_SRCS += led.c #本驱动的源代码文件
LOCAL_INCLUDE := ./include #本驱动的头文件目录
LOCAL_CFLAGS += -fstack-protector-strong -Wextra -Wall -Werror #自定义的编译选项
include $(HDF_DRIVER) #导入模板makefile完成编译

这里的hdf_led_driver为驱动文件名,注意对应关系。

4. 编译结果链接到内核镜像

修改 huawei/hdf/hdf_vendor.mk 文件,添加以下代码

LITEOS_BASELIB += -lhdf_led_driver  #链接生成的静态库
LIB_SUBDIRS += $(VENDOR_HDF_DRIVERS_ROOT)/led #驱动代码Makefile的目录

填入驱动文件名和源码路径。

5. 驱动配置

驱动配置包含两部分,HDF框架定义的驱动设备描述和驱动的私有配置信息。

5.1 驱动设备描述(必选)
HDF框架加载驱动所需要的信息来源于HDF框架定义的驱动设备描述。

修改 vendor/hisi/hi35xx/hi3516dv300/config/device_info/device_info.hcs配置文件,添加驱动的设备描述。

platform :: host {
hostName = "platform_host"; // host名称,host节点是用来存放某一类驱动的容器
priority = 50; // host启动优先级(0-200),值越大优先级越低,建议默认配100,优先级相同则不保证host的加载顺序 device_led :: device { // led设备节点
device0 :: deviceNode { // led驱动的DeviceNode节点
policy = 2; // policy字段是驱动服务发布的策略,在驱动服务管理章节有详细介绍
priority = 100; // 驱动启动优先级(0-200),值越大优先级越低,建议默认配100,优先级相同则不保证device的加载顺序
preload = 0; // 驱动按需加载字段
permission = 0666; // 驱动创建设备节点权限
moduleName = "led_driver"; // 驱动名称,该字段的值必须和驱动入口结构的moduleName值一致
serviceName = "led_service"; // 驱动对外发布服务的名称,必须唯一
deviceMatchAttr = "led_config"; // 驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等
}
}

其中,moduleName、serviceName和deviceMatchAttr 都比较重要,分布链接到源码的不同位置,我这里都分开命名,便于理解。

5.2 驱动私有配置信息(可选)
如果驱动有私有配置,则可以添加一个驱动的配置文件,用来填写一些驱动的默认配置信息,HDF框架在加载驱动的时候,会将对应的配置信息获取并保存在HdfDeviceObject 中的property里面,通过Bind和Init(参考驱动开发)传递给驱动。

在 vendor/hisi/hi35xx/hi3516dv300/config/ 目录下新建一个文件夹 led, 然后在其中新建一个源文件 led_config.hcs, 填入以下代码。

root {
LedDriverConfig {
led_version = 1;
match_attr = "led_config"; //该字段的值必须和device_info.hcs中的deviceMatchAttr值一致
}
}

配置信息定义之后,需要将该配置文件添加到板级配置入口文件hdf.hcs。

5.3 板级配置(可选)
修改 vendor/hisi/hi35xx/hi3516dv300/config/hdf.hcs文件,添加代码

#include "device_info/device_info.hcs"
#include "led/led_config.hcs"

6. 驱动消息机制管理

当用户态应用和内核态驱动需要交互时,可以使用HDF框架的消息机制来实现。用消息管理可以在用户态和内核态之间架起桥梁,这为我们之后的APP提供了操控底层设备功能的能力。

这里我们在用户态实现一个简单的消息机制,内核态接受到消息后,翻转摄像头两侧的红外补光灯。

6.1 配置服务策略
HDF框架定了驱动对外发布服务的策略,是由配置文件中的policy字段来控制。

typedef enum {
/* 驱动不提供服务 */
SERVICE_POLICY_NONE = 0,
/* 驱动对内核态发布服务 */
SERVICE_POLICY_PUBLIC = 1,
/* 驱动对内核态和用户态都发布服务 */
SERVICE_POLICY_CAPACITY = 2,
/* 驱动服务不对外发布服务,但可以被订阅 */
SERVICE_POLICY_FRIENDLY = 3,
/* 驱动私有服务不对外发布服务,也不能被订阅 */
SERVICE_POLICY_PRIVATE = 4,
/* 错误的服务策略 */
SERVICE_POLICY_INVALID
} ServicePolicy;

我们将驱动配置信息中服务策略policy字段设置为2,在之前的设备描述文件device_info.hcs里已经配置好了。

6.2 实现服务
在第2章,我们实现了一个空的驱动框架,现在继续实现内核态的消息服务接口。

编辑 huawei/hdf/led/led.c, 实现服务基类成员IDeviceIoService中的Dispatch方法。收到用户态发来的命令后,操作LED设备,然后将返回值通过reply传回,最后再将收到的命令回传给用户态程序。

// Dispatch是用来处理用户态发下来的消息
int32_t LedDriverDispatch(struct HdfDeviceIoClient *client, int cmdCode, struct HdfSBuf *data, struct HdfSBuf *reply)
{
int32_t result = HDF_FAILURE;
HDF_LOGE("Led driver dispatch");
if (client == NULL || client->device == NULL)
{
HDF_LOGE("Led driver device is NULL");
return HDF_ERR_INVALID_OBJECT;
} switch (cmdCode)
{
case LED_WRITE_READ:
const char *recv = HdfSbufReadString(data);
if (recv != NULL)
{
HDF_LOGI("recv: %s", recv);
result = CtlLED(-1); # 操作设备
// CtlLED(GPIO_VAL_HIGH);
if (!HdfSbufWriteInt32(reply, result))
{
HDF_LOGE("replay is fail");
}
return HdfDeviceSendEvent(client->device, cmdCode, data);
}
break; default:
break;
}
return result;
}

修改 HdfLedDriverBind函数,将服务绑定到框架。

//驱动对外提供的服务能力,将相关的服务接口绑定到HDF框架
int32_t HdfLedDriverBind(struct HdfDeviceObject *deviceObject)
{
if (deviceObject == NULL)
{
HDF_LOGE("Led driver bind failed!");
return HDF_ERR_INVALID_OBJECT;
}
static struct IDeviceIoService ledDriver = {
.Dispatch = LedDriverDispatch,
};
deviceObject->service = (struct IDeviceIoService *)(&ledDriver);
HDF_LOGD("Led driver bind success");
return HDF_SUCCESS;
}

7. 业务代码
内核态核心功能,就简单实现一个每调用一次,就翻转一下LED状态的CtrlLED函数。这里mode为 -1 时为翻转,也可以直接指定高电平或低电平来开关,方便后续扩展。

其中Hi3516DV300的控制器管理12组GPIO管脚,每组8个。

GPIO号 = GPIO组索引(0~11)* 每组GPIO管脚数(8) + 组内偏移。

那么GPIO5_1的GPIO号 = 5 * 8 +1 = 41。

static int32_t CtlLED(int mode)
{
int32_t ret;
uint16_t valRead;
/* LED的GPIO管脚号 */
uint16_t gpio = 5 * 8 + 1; // 红外补光灯
// uint16_t gpio = 2 * 8 + 3; // 绿色指示灯
// uint16_t gpio = 3 * 8 + 4; // 红色指示灯 /* 将GPIO管脚配置为输出 */
ret = GpioSetDir(gpio, GPIO_DIR_OUT);
if (ret != 0)
{
HDF_LOGE("GpioSerDir: failed, ret %d\n", ret);
return ret;
} if (mode == -1)
{
// 翻转输出口
(void)GpioRead(gpio, &valRead);
ret = GpioWrite(gpio, (valRead == GPIO_VAL_LOW) ? GPIO_VAL_HIGH : GPIO_VAL_LOW);
}
else
{
ret = GpioWrite(gpio, mode);
} if (ret != 0)
{
HDF_LOGE("GpioWrite: failed, ret %d\n", ret);
return ret;
}
return ret;
}

同理,GPIO2_3、GPIO3_4和蜂鸣器组件等等通用IO设备也能相应控制,可以尽情发挥想象力了。

8. 配置Kconfig

在`vendor/huawei/hdf/led/`下,新建一个目录`driver`,再在其下新建`Kconfig`文件。

config LOSCFG_DRIVERS_HDF_PLATFORM_LED
bool "Enable HDF LED driver"
default n
depends on LOSCFG_DRIVERS_HDF_PLATFORM
help
Answer Y to enable HDF LED driver.

将其链接到板级Kconfig中,在vendor/huawei/hdf/Kconfig增加

source "../../vendor/huawei/hdf/led/driver/Kconfig"

好了,内核态的程序基本都搞定了。

查看更多章节>>>

作者:bluishfish
想了解更多内容,请访问: 51CTO和华为官方战略合作共建的鸿蒙技术社区https://harmonyos.51cto.com/

#2020征文-开发板# 用鸿蒙开发AI应用(五)HDF 驱动补光灯的更多相关文章

  1. #2020征文-开发板# 用鸿蒙开发AI应用(一)硬件篇

    目录: 前言 开发板简介 产品特色及功能 产品参数 各个主板功能简介 Hi3516DV300 芯片手册 前言鸿蒙2.0的系统刚开源出来,华为志在打造1+8+N万物互联的全场景智慧生活,不仅是国产操作系 ...

  2. #2020征文-开发板# 用鸿蒙开发AI应用(二)系统篇

    目录: 前言 安装虚拟机 安装 Ubuntu 设置共享文件夹 前言上回说到,我们在一块 HarmonyOS HiSpark AI Camera 开发板,并将其硬件做了一下解读和组装.要在其上编译鸿蒙系 ...

  3. #2020征文-开发板# 用鸿蒙开发AI应用(三)软件篇

    目录: 前言 HarmonyOS 简介 DevEco Device Tool(windows下) 获取源码(切换到ubuntu) 烧录程序(切换回windows) 前言上一篇,我们在 Win10 上用 ...

  4. iTOP-4418开发板和6818开发板-第五路串口介绍

    iTOP-4418开发板和6818开发板 的除去默认 4 个串口的配置和用法. 4418 的开发板最多支持 5 路串口,如下图所示,4418 的 datasheet.   6818 的开发板最多支持 ...

  5. #2020征文-开发板#使用Python开发鸿蒙应用--2021.01.07直播图文

    写在前面: 每年的过年前夕,手中的项目一定会告急...而自己又缺乏三头六臂七十二变等特技,所以只能在鸿蒙社区先消失一阵子了.今天再看社区的帖子,发现大家的进步可不一般,各种案例示例层出不穷,一片欣欣向 ...

  6. ESP-EYE V2.1 开发板 WINDOWS 10 开发入门

    准备工作 1 × ESP-EYE V2.1 开发板 1 × Micro USB B 电缆 1 × PC(Windows10) 简介 ESP-EYE 是一款面向人脸识别和语音识别市场的开发板,搭载 ES ...

  7. 基于讯为4412开发板的Android开发流程

    讯为4412开发板  使用三星2410芯片,基于arm9架构,由于自己电脑硬件的局限,只能跑Android4.0.3系统. 1.Uboot这个直接使用官方镜像烧写就可以了,一般情况不用去重复烧写. 略 ...

  8. 嵌入式开发板iTOP4412学习开发板

    网站:http://www.topeetboard.com 淘宝:https://item.taobao.com/item.htm?_u=okcahs0f42a&id=38712193806 ...

  9. 【分享】4412开发板-嵌入式Linux开发须要掌握的基础知识和技能

    本文转自迅为电子论坛:http://www.topeetboard.com 1.Linux 基础 安装Linux操作系统 Linux文件系统 Linux经常使用命令 Linux启动过程具体解释 熟悉L ...

随机推荐

  1. 题解-洛谷P4229 某位歌姬的故事

    题面 洛谷P4229 某位歌姬的故事 \(T\) 组测试数据.有 \(n\) 个音节,每个音节 \(h_i\in[1,A]\),还有 \(m\) 个限制 \((l_i,r_i,g_i)\) 表示 \( ...

  2. 计算机语言与JAVA的发展

    计算机语言与JAVA的发展 第一代语言 2进制 第二代语言 汇编语言 解决人类无法读懂的问题 指令替代二进制 目前应用 逆向工程 机器人 病毒 第三代语言 摩尔定律 性能提升愈来愈慢 高级语言 面向过 ...

  3. Java并发编程的艺术(七)——线程间的通信

    为什么需要线程间通信 让线程之间合作,提高运行效率. volatile和synchronized关键字 实现原理 这两个方式都是采用共享内存的方式进行通信,通过同步机制保证数据可见性和排他性. 特点 ...

  4. SpringBoot快速入门(理论篇)

    说在最前 此篇文章,为Spring Boot理论骗,所谓的理论篇就是几乎不会出现代码,只介绍一些理论知识,这些理论知识对你你以后快速上手Spring Boot有非常大的用处! 什么是Spring Bo ...

  5. 可选链plugin-proposal-optional-chaining的使用(优化)

    第一步 安装 npm install --save-dev @babel/plugin-proposal-optional-chaining 然后在.babelrc.js文件夹里进行配置 plugin ...

  6. jenkins+ant+jmeter实现自动化集成(详解)

    jenkins+ant+jmeter实现自动化集成 for window 一.jmeter 1.jmeter安装 二.ant 1.ant安装 三.ant运行 jmeter脚本 1.配置 四.jenki ...

  7. Exception in thread "main" java.lang.RuntimeException: java.lang.RuntimeException: Unable to instantiate org.apache.hadoop.hive.metastore.HiveMetaStoreClient

    hive安装时遇到的问题 解压后指定了hive-env.sh文件的Hadoop_home  & hive_conf 两个参数后,先直接bin/hive 用Derby数据库启动一下,然后再配置其 ...

  8. 云原生时代,Java的危与机(周志明)

    说明 本篇文章是转载自周志明老师的文章,链接地址:https://www.infoq.cn/article/RQfWw2R2ZpYQiOlc1WBE 今天,25 岁的 Java 仍然是最具有统治力的编 ...

  9. react第X单元(redux)

    第X单元(redux) #课程目标 理解redux解决的问题,理解redux的工作原理 熟练掌握redux的api 熟练掌握redux和react组件之间的通信(react-redux) 把redux ...

  10. Flink相对于Spark的优点

    Flink相对于Spark的优点 容错 Flink 基于两阶段提交实现了精确的一次处理语义. Spark Streaming 只能做到不丢数据,但是有重复. 反压 Flink 在数据传输过程中使用了分 ...