鸿蒙OpenHarmony HDF 驱动开发

本文详细介绍了HDF驱动框架,包括其功能、加载方式、驱动开发步骤,特别是以GPIO驱动为例,阐述了驱动程序的接口实现。重点讲解了驱动配置,如何使用HCS管理和驱动的启动策略。
摘要由CSDN通过智能技术生成

请添加图片描述

最近忙于适配OpenHarmonyOS LiteOS-M 平台,已经成功实践适配平台GD32F407、STM32F407、STM32G474板卡,LiteOS适配已经算是有实际经验了。
但是,鸿蒙代码学习进度慢下来了。还是得不断学习理论知识丰富自己的认知。接下来时间要把HDF驱动框架熟悉,完善南向开发技术点。

一、概述

HDF(Hardware Driver Foundation)驱动框架,为驱动开发者提供驱动框架能力,包括驱动加载、驱动服务管理、驱动消息机制和配置管理。并以组件化驱动模型作为核心设计思路,让驱动开发和部署更加规范,旨在构建统一的驱动架构平台,为驱动开发者提供更精准、更高效的驱动管理的开发环境,力求做到一次开发,多系统部署。

HDF支持两种加载方式:

  • 按需加载, HDF框架支持驱动在系统后动过程中默认加载,或者在系统后动之后动态加载。
  • 按序加载, HDF框架支持驱动在系统启动的过程中按照驱动的优先级进行加载。

驱动开发步骤:

  1. 驱动程序实现,包含驱动业务代码和驱动入口注册到HDF框架。
  2. 驱动编译,将业务代码进行编译,同时将结果编译进内核。
  3. 驱动配置,HDF使用HCS作为配置描述源码驱动配置包含两部分HDF框架定义的驱动设备描述和驱动的私有配置信息。

二、HDF驱动框架

HDF驱动框架主要包含三部分:

  • 1、驱动程序部分----完成驱动的功能逻辑。
  • 2、驱动配置信息----指示驱动的加载信息内容。
  • 3、驱动资源配置----配置驱动的硬件配置信息。

三、驱动程序

驱动程序主要是完成驱动功能的逻辑代码,轻量内核LiteOS-M驱动程序代码路径为:drivers/hdf_core/adapter/platform 。
SDK源码使用drivers/hdf_core/adapter/platform目录,放置适配LiteOS-M各个平台驱动程序。

drivers/hdf_core/adapter/platform
├── BUILD.gn
├── can
├── gpio
├── i2c
├── mipi_dsi
├── pwm
├── spi
├── uart
└── watchdog

这里以LiteOS-M GPIO HDF驱动为例,对于开发者首先看到的是驱动入口部分,驱动入口通过结构体DriverEntry进行描述。其中主要包含Bind, Init 和Release三个接口。

/* HdfDriverEntry definitions */
//struct HdfDriverEntry定义在:drivers/hdf_core/interfaces/inner_api/host/shared/hdf_device_desc.h
struct HdfDriverEntry g_GpioDriverEntry = {
    .moduleVersion = 1,
    .moduleName = "ST_GPIO_MODULE_HDF", // 职责:与hdf hcs结点moduleName进行匹配
    .Bind = GpioDriverBind,             // 职责:绑定驱动对外提供的服务接口到HDF
    .Init = GpioDriverInit,             // 职责:初始化驱动自身的业务
    .Release = GpioDriverRelease,       // 职责:释放驱动资源,发生异常时也会调用
};
HDF_INIT(g_GpioDriverEntry);            //注册到HDF框架中

Bind接口描述:该接口的作用主要是完成驱动设备和设备服务接口的bind动作。

static int32_t GpioDriverBind(struct HdfDeviceObject *device)
{
    if (device == NULL) {
        HDF_LOGE("device object is NULL\n");
        return HDF_FAILURE;
    }

    return HDF_SUCCESS;
}

Init接口描述:当框架完成设备绑定动作后,就开始调用驱动初始化接口,初始化成功后,驱动框架根据配置文件决定是对外创建设备服务接口,还是接口只对当前服务可见。如果Init初始化失败,驱动框架就会主动释放创建的设备接口等信息。

static int32_t GpioDriverInit(struct HdfDeviceObject *device)
{
    int32_t ret;
    struct GpioCntlr *gpioCntlr = NULL;

    if (device == NULL) {
        HDF_LOGE("%s: device is NULL", __func__);
        return HDF_ERR_INVALID_PARAM;
    }

    ret = PlatformDeviceBind(&g_stmGpioCntlr.device, device);   //绑定设备对象
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%s: bind hdf device failed:%d", __func__, ret);
        return ret;
    }

    gpioCntlr = GpioCntlrFromHdfDev(device);                    //获取gpio控制器
    if (gpioCntlr == NULL) {
        HDF_LOGE("GpioCntlrFromHdfDev fail\r\n");
        return HDF_DEV_ERR_NO_DEVICE_SERVICE;
    }

    ret = AttachGpioDevice(gpioCntlr, device);                  /* GpioCntlr add GpioDevice to priv */
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("AttachGpioDevice fail\r\n");
        return HDF_DEV_ERR_ATTACHDEV_FAIL;
    }

    gpioCntlr->ops = &g_GpioCntlrMethod;                        /* 绑定控制器控制方法 */
    ret = GpioCntlrAdd(gpioCntlr);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("GpioCntlrAdd fail %d\r\n", gpioCntlr->start);
        return HDF_FAILURE;
    }

    return HDF_SUCCESS;
}

gpio控制器方法实现。

/* GpioMethod definitions */
struct GpioMethod g_GpioCntlrMethod = {
    .request = NULL,
    .release = NULL,
    .write = GpioDevWrite,
    .read = GpioDevRead,
    .setDir = GpioDevSetDir,
    .getDir = GpioDevGetDir,
    .toIrq = NULL,
    .setIrq = GpioDevSetIrq,
    .unsetIrq = GpioDevUnSetIrq,
    .enableIrq = GpioDevEnableIrq,
    .disableIrq = GpioDevDisableIrq,
};

Release接口描述:当用户需要卸载驱动时,驱动框架先通过该接口通知驱动程序释放资源,然后再释放其他内部资源。

static void GpioDriverRelease(struct HdfDeviceObject *device)
{
    struct GpioCntlr *gpioCntlr = NULL;

    if (device == NULL) {
        HDF_LOGE("%s: device is NULL", __func__);
        return;
    }

    gpioCntlr = GpioCntlrFromHdfDev(device);
    if (gpioCntlr == NULL) {
        HDF_LOGE("%s: host is NULL", __func__);
        return;
    }

    gpioCntlr->count = 0;
}

四、驱动配置

HCS(HDF Configuration Source)是HDF驱动框架的配置描述源码,内容以Key-Value为主要形式。它实现了配置代码与驱动代码解耦,便于开发者进行配置管理。

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

设备描述信息

HDF框架加载驱动所需要的信息来源于HDF框架定义的驱动设备描述,因此基于HDF框架开发的驱动必须要在HDF框架定义的device_info.hcs配置文件中添加对应的设备描述。


root {
    module = "navy,stm32g474";
    device_info {
        match_attr = "hdf_manager";
        template host {
            hostName = "";
            priority = 100;
            template device {
                template deviceNode {
                    policy = 0;
                    priority = 100;
                    preload = 0;
                    permission = 0664;
                    moduleName = "";
                    serviceName = "";
                    deviceMatchAttr = "";
                }
            }
        }
        platform :: host {
            hostName = "platform_host";                             // 容器名称
            priority = 50;                                          // 容器启动优先级
            device_gpio :: device {
                gpio0 :: deviceNode {
                    policy = 0;                                     // 详见ServicePolicy
                    priority = 60;                                  // 驱动启动优先级
                    permission = 0644;                              // 驱动创建设备节点权限
                    moduleName = "ST_GPIO_MODULE_HDF";              // 【必要】用于指定驱动名称,需要与期望的驱动Entry中的moduleName一致
                    serviceName = "HDF_PLATFORM_GPIO";              // 服务名称
                    deviceMatchAttr = "gpio_config";                // 【必要】用于配置控制器私有数据,要与gpio_config.hcs中对应控制器保持一致,其他控制器信息也在文件中
                }
            }
            device_xxx  ::  device {
                xxx ::  deviceNode {
                    ...
                }
            }
        }
        misc    :: host {
            hostName = "misc_host";
            priority = 100;
            xxx :: device {
                xxx ::  deviceNode {
                    ...
                }
            }
        }

    }
}

其中,
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;

驱动私有配置信息

#include "default_device_info.hcs"
root {
    platform {
        gpio_config {
            match_attr = "gpio_config";                 // 【必要】必须和device_info.hcs中的deviceMatchAttr值一致
            pin =       [ 0, 1, 2, 3,  4, 5, 6];        // pin index when register to hdf framework 0-3 spi flash gpio 4-5 uart1 
            realPin =   [ 5, 5, 4, 15, 6, 7, 13];       // pin number in stm32 led2 pe5, led3 pe6,
            group =     [ 0, 1, 1, 0,  1, 1, 2];        // group of gpio 0:GPIOA 1:GPIOB 2:GPIOC 3:GPIOD 4:GPIOE 5: GPIOF 6:GPIOG 7:GPIOH 8:GPIOI
            mode =      [ 2, 2, 2 ,1,  2, 2, 1];        // 0: input 1: output 2:alternate 3:analog  
            speed =     [ 3, 3, 3, 3,  3, 3, 0];        // 0: low 1: middle 2:high 3:very_high
            pull =      [ 0, 0, 0, 0,  1, 1, 1];        // 0: nopull 1:up 2:down
            pinNum = 7;
            output =    [ 0, 0, 0, 0,  0, 0, 0];        // 0:pushpull 1:opendrain
            alternate = [ 5, 5, 5, 0,  7, 7, 0];

        }
        ...
    }
    ...
}

HDF框架将一类设备驱动放在同一个Host(设备容器)里面,用于管理一组设备的启动加载等过程。在划分Host时,驱动程序是部署在一个Host还是部署在不同的Host,主要考虑驱动程序之间是否存在耦合性,如果两个驱动程序之间存在依赖,可以考虑将这部分驱动程序部署在一个Host里面,否则部署到独立的Host中是更好的选择。Device对应一个真实的物理设备。DeviceNode是设备的一个部件,Device至少有一个DeviceNode。每个DeviceNode可以发布一个设备服务。驱动即驱动程序,每个DevicdNode唯一对应一个驱动,实现和硬件的功能交互。HDF驱动模型如下图所示:
请添加图片描述

到此基础的HDF驱动开发流程结束。

坚持就有收获

请添加图片描述

  • 27
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
openharmony hdf适配是指在openharmony操作系统中,使用hdf框架进行硬件设备的适配。hdf是一种硬件设备抽象层的开发框架,可以帮助开发者简化硬件设备的驱动开发工作。 在openharmony系统中,不同的硬件设备需要与操作系统进行交互,以实现功能的完整性。而hdf框架的作用就是通过提供一系列接口和函数,使不同硬件设备的驱动程序能够与openharmony系统进行交互和通信。 通过使用hdf框架进行适配,可以实现如下优点: 1. 硬件设备的抽象化:hdf框架提供了一系列标准化接口,可以将硬件设备的具体实现进行抽象化,使得不同的硬件设备能够使用相同的接口进行访问和控制。 2. 简化开发工作:使用hdf框架可以避免开发者直接与底层硬件进行交互,减少了开发工作的复杂性。开发者只需要通过hdf的接口函数进行调用和操作,就能够完成硬件设备的驱动开发。 3. 提高代码的可重用性:hdf框架提供了一套通用的接口,这些接口可以在不同的硬件设备之间进行共享和复用。这样一来,当需要适配新的硬件设备时,只需要实现部分适配层的代码即可,大大提高了代码的可重用性。 4. 方便维护和升级:通过使用hdf框架进行适配,系统维护和升级变得更加方便。当需要对硬件设备进行维护或者升级时,只需要修改hdf框架的适配代码,而不需要修改原始的驱动程序。 总之,openharmony hdf适配的目的在于简化硬件设备的驱动开发工作,提高代码的可重用性和系统的维护性。通过使用hdf框架,开发者可以更加方便地实现不同硬件设备的适配,为用户提供更加稳定和高效的系统体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

攻下一城

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值