江西建设推广网站,竞价外包推广,全能浏览器,自己做第一个网站往期知识点记录#xff1a; 鸿蒙#xff08;HarmonyOS#xff09;应用层开发#xff08;北向#xff09;知识点汇总 鸿蒙#xff08;OpenHarmony#xff09;南向开发保姆级知识点汇总~ 持续更新中……
概述
功能简介
PIN即管脚控制器#xff0c;用于统一管理各SoC的…往期知识点记录 鸿蒙HarmonyOS应用层开发北向知识点汇总 鸿蒙OpenHarmony南向开发保姆级知识点汇总~ 持续更新中……
概述
功能简介
PIN即管脚控制器用于统一管理各SoC的管脚资源对外提供管脚复用功能。
基本概念
PIN是一个软件层面的概念目的是为了统一对各SoC的PIN管脚进行管理对外提供管脚复用功能配置PIN管脚的电气特性。
SoCSystem on Chip
系统级芯片又称作片上系统通常是面向特定用途将微处理器、模拟IP核、数字IP核和存储器集成在单一芯片的标准产品。
管脚复用
由于芯片自身的引脚数量有限无法满足日益增多的外接需求。此时可以通过软件层面的寄存器设置让引脚工作在不同的状态从而实现相同引脚完成不同功能的目的。
运作机制
在HDF框架中同类型设备对象较多时可能同时存在十几个同类型配置器若采用独立服务模式则需要配置更多的设备节点且相关服务会占据更多的内存资源。相反采用统一服务模式可以使用一个设备服务作为管理器统一处理所有同类型对象的外部访问这会在配置文件中有所体现实现便捷管理和节约资源的目的。PIN模块接口适配模式采用统一服务模式如图1所示。
在统一模式下所有的控制器都被核心层统一管理并由核心层统一发布一个服务供接口层因此这种模式下驱动无需再为每个控制器发布服务。
PIN模块各分层作用 接口层提供获取PIN管脚、设置PIN管脚推拉方式、获取PIN管脚推拉方式、设置PIN管脚推拉强度、获取PIN管脚推拉强度、设置PIN管脚功能、获取PIN管脚功能、释放PIN管脚的接口。 核心层主要提供PIN管脚资源匹配PIN管脚控制器的添加、移除以及管理的能力通过钩子函数与适配层交互。 适配层主要是将钩子函数的功能实例化实现具体的功能。
图 1 统一服务模式结构图 约束与限制
PIN模块目前只支持小型系统LiteOS-A内核。
开发指导
场景介绍
PIN模块主要用于管脚资源管理。在各SoC对接HDF框架时需要来适配PIN驱动。下文将介绍如何进行PIN驱动适配。
接口说明
为了保证上层在调用PIN接口时能够正确的操作PIN管脚核心层在//drivers/hdf_core/framework/support/platform/include/pin/pin_core.h中定义了以下钩子函数驱动适配者需要在适配层实现这些函数的具体功能并与钩子函数挂接从而完成适配层与核心层的交互。
PinCntlrMethod定义
struct PinCntlrMethod {int32_t (*SetPinPull)(struct PinCntlr *cntlr, uint32_t index, enum PinPullType pullType);int32_t (*GetPinPull)(struct PinCntlr *cntlr, uint32_t index, enum PinPullType *pullType);int32_t (*SetPinStrength)(struct PinCntlr *cntlr, uint32_t index, uint32_t strength);int32_t (*GetPinStrength)(struct PinCntlr *cntlr, uint32_t index, uint32_t *strength);int32_t (*SetPinFunc)(struct PinCntlr *cntlr, uint32_t index, const char *funcName);int32_t (*GetPinFunc)(struct PinCntlr *cntlr, uint32_t index, const char **funcName);
};
c表 1 PinCntlrMethod成员的钩子函数功能说明
成员函数入参出参返回值功能SetPinPullcntlr结构体指针核心层PIN控制器indexuint32_t类型变量管脚索引号pullType枚举常量PIN管脚推拉方式无HDF_STATUS相关状态PIN设置管脚推拉方式GetPinPullcntlr结构体指针核心层PIN控制器indexuint32_t类型变量管脚索引号pullType枚举常量指针传出获取的PIN管脚推拉方式HDF_STATUS相关状态PIN获取管脚推拉方式SetPinStrengthcntlr结构体指针核心层PIN控制器indexuint32_t类型变量管脚索引号strengthuint32_t变量PIN推拉强度无HDF_STATUS相关状态PIN设置推拉强度GetPinStrengthcntlr结构体指针核心层PIN控制器indexuint32_t类型变量管脚索引号strengthuint32_t变量指针传出获取的PIN推拉强度HDF_STATUS相关状态PIN获取推拉强度SetPinFunccntlr结构体指针核心层PIN控制器indexuint32_t类型变量管脚索引号funcNamechar指针常量传入PIN管脚功能无HDF_STATUS相关状态PIN设置管脚功能GetPinFunccntlr结构体指针核心层PIN控制器indexuint32_t类型变量管脚索引号funcNamechar双重指针常量传出获取的PIN管脚功能HDF_STATUS相关状态PIN获取管脚功能
开发步骤
PIN模块适配HDF框架包含以下四个步骤 实例化驱动入口 配置属性文件 实例化PIN控制器对象 驱动调试
开发实例
下方将基于Hi3516DV300开发板以//device/soc/hisilicon/common/platform/pin/pin_hi35xx.c驱动为示例展示需要驱动适配者提供哪些内容来完整实现设备功能。
实例化驱动入口
驱动入口必须为HdfDriverEntry在hdf_device_desc.h中定义类型的全局变量且moduleName要和device_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总形成一个类似数组的段地址空间方便上层调用。
一般在加载驱动时HDF会先调用Bind函数再调用Init函数加载该驱动。当Init调用异常时HDF框架会调用Release释放驱动资源并退出。
PIN驱动入口开发参考 static struct HdfDriverEntry g_hi35xxPinDriverEntry {.moduleVersion 1,.Bind Hi35xxPinBind, // PIN不需要实现Bind本例是一个空实现驱动适配者可根据自身需要添加相关操作.Init Hi35xxPinInit, // 挂接PIN模块Init实例化.Release Hi35xxPinRelease, // 挂接PIN模块Release实例化.moduleName hi35xx_pin_driver, // 【必要且与HCS文件中里面的moduleName匹配】};HDF_INIT(g_hi35xxPinDriverEntry); // 调用HDF_INIT将驱动入口注册到HDF框架中c配置属性文件 完成驱动入口注册之后需要在device_info.hcs文件中添加deviceNode信息deviceNode信息与驱动入口注册相关。本例以两个PIN控制器为例如有多个器件信息则需要在device_info.hcs文件增加对应的deviceNode信息以及在gpio_config.hcs文件中增加对应的器件属性。器件属性值对于驱动适配者的驱动实现以及核心层PinCntlr相关成员的默认值或限制范围有密切关系比如控制器号控制器管脚数量、管脚等,需要在pin_config.hcs中配置器件属性。
统一服务模式的特点是device_info.hcs文件中第一个设备节点必须为PIN管理器其各项参数如表2所示
表 2 device_info.hcs节点参数说明
成员名值policy驱动服务发布的策略PIN管理器具体配置为2表示驱动对内核态和用户态都发布服务
| priority | 驱动启动优先级0-200值越大优先级越低。PIN管理器具体配置为8 |
| permission | 驱动创建设备节点权限PIN管理器具体配置为0664 |
| moduleName | 驱动名称PIN管理器固定为HDF_PLATFORM_PIN_MANAGER |
| serviceName | 驱动对外发布服务的名称PIN管理器服务名设置为HDF_PLATFORM_PIN_MANAGER |
| deviceMatchAttr | 驱动私有数据匹配的关键字PIN管理器没有使用可忽略 |device_info.hcs 配置参考 在//vendor/hisilicon/hispark_taurus/hdf_config/device_info/device_info.hcs文件中添加deviceNode描述。 root {device_info {platform :: host {hostName platform_host;priority 50;device_pin :: device {device0 :: deviceNode { // 用于统一管理PIN并发布服务policy 2; // 2用户态可见1内核态可见0不需要发布服务。priority 8; // 启动优先级permission 0644; // 创建设备节点权限moduleName HDF_PLATFORM_PIN_MANAGER;serviceName HDF_PLATFORM_PIN_MANAGER;}device1 :: deviceNode { // 为每一个PIN控制器配置一个HDF设备节点存在多个时必须添加否则不用。policy 0;priority 10; // 驱动启动优先级permission 0644; // 驱动创建设备节点权限moduleName hi35xx_pin_driver; // 【必要】用于指定驱动名称需要与期望的驱动Entry中的moduleName一致。deviceMatchAttr hisilicon_hi35xx_pin_0; // 【必要】用于配置控制器私有数据要与pin_config.hcs中对应控制器保持一致具体的控制器信息在pin_config.hcs中。}device2 :: deviceNode {policy 0;priority 10;permission 0644;moduleName hi35xx_pin_driver;deviceMatchAttr hisilicon_hi35xx_pin_1;}...... // 如果存在多个PIN控制器时【必须】添加节点否则不用 }}}}cpin_config.hcs配置参考 在//device/soc/hisilicon/hi3516dv300/sdk_liteos/hdf_config/pin/pin_config.hcs文件配置器件属性其中配置参数如下 root {platform {pin_config_hi35xx {template pin_controller { // 【必要】配置模板配如果下面节点使用时继承该模板则节点中未声明的字段会使用该模板中的默认值。number 0; // 【必要】PIN控制器号regStartBasePhy 0; // 【必要】寄存器物理基地址起始地址regSize 0; // 【必要】寄存器位宽pinCount 0; // 【必要】管脚数量match_attr ;template pin_desc {pinName ; // 【必要】管脚名称init 0; // 【必要】寄存器默认值F0 ; // 【必要】功能0F1 ; // 功能1F2 ; // 功能2F3 ; // 功能3F4 ; // 功能4F5 ; // 功能5}}controller_0 :: pin_controller {number 0;regStartBasePhy 0x10FF0000;regSize 0x48;pinCount 18;match_attr hisilicon_hi35xx_pin_0;T1 :: pin_desc {pinName T1;init 0x0600;F0 EMMC_CLK;F1 SFC_CLK;F2 SFC_BOOT_MODE;}...... // 对应管脚控制器下的每个管脚按实际添加。}...... // 每个管脚控制器对应一个控制器节点如存在多个PIN控制器请依次添加对应的控制器节点。}}}c需要注意的是新增pin_config.hcs配置文件后必须在产品对应的hdf.hcs文件中将其包含如下语句所示否则配置文件无法生效。 #include ../../../../device/soc/hisilicon/hi3516dv300/sdk_liteos/hdf_config/pin/pin_config.hcs // 配置文件相对路径c实例化PIN控制器对象
完成配置属性文件之后下一步就是以核心层PinCntlr对象的初始化为核心包括驱动适配者自定义结构体传递参数和数据实例化PinCntlr成员PinCntlrMethod让用户可以通过接口来调用驱动底层函数实现HdfDriverEntry成员函数Bind、Init、Release。
驱动适配者自定义结构体参考
从驱动的角度看自定义结构体是参数和数据的载体而且pin_config.hcs文件中的数值会被HDF读入并通过DeviceResourceIface来初始化结构体成员一些重要数值也会传递给核心层对象。
在Hi35xxPinCntlrInit函数中对PinCntlr成员进行初始化操作。 // 驱动适配者自定义管脚描述结构体struct Hi35xxPinDesc {const char *pinName; // 管脚名uint32_t init; // 初始化值uint32_t index; // 管脚索引int32_t pullType; // 管脚推拉方式int32_t strength; // 管脚推拉强度const char *func[HI35XX_PIN_FUNC_MAX]; // 管脚功能名字符串数组};// 驱动适配者自定义结构体struct Hi35xxPinCntlr {struct PinCntlr cntlr; // 是核心层控制对象具体描述见下面struct Hi35xxPinDesc *desc; // 驱动适配者自定义管脚描述结构体指针volatile unsigned char *regBase; // 寄存器映射地址uint16_t number; // 管脚控制器编号uint32_t regStartBasePhy; // 寄存器物理基地址起始地址uint32_t regSize; // 寄存器位宽uint32_t pinCount; // 管脚数量};// PinCntlr是核心层控制器结构体其中的成员在Init函数中会被赋值。struct PinCntlr {struct IDeviceIoService service; // 驱动服务struct HdfDeviceObject *device; // 驱动设备对象struct PinCntlrMethod *method; // 钩子函数struct DListHead node; // 链表节点OsalSpinlock spin; // 自旋锁uint16_t number; // 管脚控制器编号uint16_t pinCount; // 管脚数量struct PinDesc *pins; // 管脚资源void *priv; // 私有数据};// PIN管脚控制器初始化static int32_t Hi35xxPinCntlrInit(struct HdfDeviceObject *device, struct Hi35xxPinCntlr *hi35xx){struct DeviceResourceIface *drsOps NULL;int32_t ret;// 从hcs文件读取管脚控制器相关属性drsOps DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);if (drsOps NULL || drsOps-GetUint32 NULL || drsOps-GetUint16 NULL) {HDF_LOGE(%s: invalid drs ops fail!, __func__);return HDF_FAILURE;}ret drsOps-GetUint16(device-property, number, hi35xx-number, 0);if (ret ! HDF_SUCCESS) {HDF_LOGE(%s: read number failed, __func__);return ret;}if (hi35xx-number HI35XX_PIN_MAX_NUMBER) {HDF_LOGE(%s: invalid number:%u, __func__, hi35xx-number);return HDF_ERR_INVALID_PARAM;}ret drsOps-GetUint32(device-property, regStartBasePhy, hi35xx-regStartBasePhy, 0);if (ret ! HDF_SUCCESS) {HDF_LOGE(%s: read regStartBasePhy failed, __func__);return ret;}ret drsOps-GetUint32(device-property, regSize, hi35xx-regSize, 0);if (ret ! HDF_SUCCESS) {HDF_LOGE(%s: read regSize failed, __func__);return ret;}ret drsOps-GetUint32(device-property, pinCount, hi35xx-pinCount, 0);if (ret ! HDF_SUCCESS) {HDF_LOGE(%s: read pinCount failed, __func__);return ret;}if (hi35xx-pinCount PIN_MAX_CNT_PER_CNTLR) {HDF_LOGE(%s: invalid number:%u, __func__, hi35xx-number);return HDF_ERR_INVALID_PARAM;}// 将读取的值赋值给管脚控制器的成员完成管脚控制器初始化。hi35xx-cntlr.pinCount hi35xx-pinCount;hi35xx-cntlr.number hi35xx-number;hi35xx-regBase OsalIoRemap(hi35xx-regStartBasePhy, hi35xx-regSize); // 管脚控制器映射if (hi35xx-regBase NULL) {HDF_LOGE(%s: remap Pin base failed, __func__);return HDF_ERR_IO;}hi35xx-desc (struct Hi35xxPinDesc *)OsalMemCalloc(sizeof(struct Hi35xxPinDesc) * hi35xx-pinCount);if (hi35xx-desc NULL) {HDF_LOGE(%s: memcalloc hi35xx desc failed, __func__);return HDF_ERR_MALLOC_FAIL;}hi35xx-cntlr.pins (struct PinDesc *)OsalMemCalloc(sizeof(struct PinDesc) * hi35xx-pinCount);if (hi35xx-desc NULL) {HDF_LOGE(%s: memcalloc hi35xx cntlr pins failed, __func__);return HDF_ERR_MALLOC_FAIL;}return HDF_SUCCESS;}cPinCntlr成员钩子函数结构体PinCntlrMethod的实例化。 static struct PinCntlrMethod g_method {.SetPinPull Hi35xxPinSetPull, // 设置推拉方式.GetPinPull Hi35xxPinGetPull, // 获取推拉方式.SetPinStrength Hi35xxPinSetStrength, // 设置推拉强度.GetPinStrength Hi35xxPinGetStrength, // 获取推拉强度.SetPinFunc Hi35xxPinSetFunc, // 设置管脚功能.GetPinFunc Hi35xxPinGetFunc, // 获取管脚功能};cInit函数开发参考
入参
HdfDeviceObjectHDF框架给每一个驱动创建的设备对象用来保存设备相关的私有数据和服务接口。
返回值
HDF_STATUS相关状态表3为部分展示如需使用其他状态可参考//drivers/hdf_core/interfaces/inner_api/utils/hdf_base.h中HDF_STATUS定义。
表 3 HDF_STATUS相关状态说明
状态(值)问题描述HDF_ERR_INVALID_OBJECT控制器对象非法HDF_ERR_MALLOC_FAIL内存分配失败HDF_ERR_INVALID_PARAM参数非法HDF_ERR_IOI/O 错误HDF_SUCCESS初始化成功HDF_FAILURE初始化失败
函数说明
初始化自定义结构体对象和PinCntlr成员并通过调用核心层PinCntlrAdd函数挂载PIN控制器。 static int32_t Hi35xxPinReadFunc(struct Hi35xxPinDesc *desc, const struct DeviceResourceNode *node, struct DeviceResourceIface *drsOps){int32_t ret;uint32_t funcNum 0;// 从hcs中读取管脚控制器子节点管脚功能名ret drsOps-GetString(node, F0, desc-func[funcNum], NULL);if (ret ! HDF_SUCCESS) {HDF_LOGE(%s: read F0 failed, __func__);return ret;}funcNum;ret drsOps-GetString(node, F1, desc-func[funcNum], NULL);if (ret ! HDF_SUCCESS) {HDF_LOGE(%s: read F1 failed, __func__);return ret;}funcNum;......return HDF_SUCCESS;}static int32_t Hi35xxPinParsePinNode(const struct DeviceResourceNode *node, struct Hi35xxPinCntlr *hi35xx, int32_t index){int32_t ret;struct DeviceResourceIface *drsOps NULL;// 从hcs中读取管脚控制器子节点管脚相关属性drsOps DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);if (drsOps NULL || drsOps-GetUint32 NULL || drsOps-GetString NULL) {HDF_LOGE(%s: invalid drs ops fail!, __func__);return HDF_FAILURE;}ret drsOps-GetString(node, pinName, hi35xx-desc[index].pinName, NULL);if (ret ! HDF_SUCCESS) {HDF_LOGE(%s: read pinName failed, __func__);return ret;}...ret Hi35xxPinReadFunc(hi35xx-desc[index], node, drsOps);if (ret ! HDF_SUCCESS) {HDF_LOGE(%s:Pin read Func failed, __func__);return ret;}hi35xx-cntlr.pins[index].pinName hi35xx-desc[index].pinName;hi35xx-cntlr.pins[index].priv (void *)node;......return HDF_SUCCESS;}static int32_t Hi35xxPinInit(struct HdfDeviceObject *device){......struct Hi35xxPinCntlr *hi35xx NULL;......ret Hi35xxPinCntlrInit(device, hi35xx); // 管脚控制器初始化......DEV_RES_NODE_FOR_EACH_CHILD_NODE(device-property, childNode) { // 遍历管脚控制器的每个子节点ret Hi35xxPinParsePinNode(childNode, hi35xx, index); // 解析子节点......}hi35xx-cntlr.method g_method; // PinCntlrMethod实例化实例化对象的挂载ret PinCntlrAdd(hi35xx-cntlr); // 添加控制器if (ret ! HDF_SUCCESS) {HDF_LOGE(%s: add Pin cntlr: failed, __func__);ret HDF_FAILURE;}return HDF_SUCCESS;}cRelease函数开发参考
入参
HdfDeviceObjectHDF框架给每一个驱动创建的设备对象用来保存设备相关的私有数据和服务接口。
返回值 无。
函数说明
释放内存和删除控制器该函数需要在驱动入口结构体中赋值给Release接口。当HDF框架调用Init函数初始化驱动失败时可以调用Release释放驱动资源。 static void Hi35xxPinRelease(struct HdfDeviceObject *device){int32_t ret;uint16_t number;struct PinCntlr *cntlr NULL;struct Hi35xxPinCntlr *hi35xx NULL;struct DeviceResourceIface *drsOps NULL;if (device NULL || device-property NULL) {HDF_LOGE(%s: device or property is null, __func__);return;}// 从hcs文件中读取管脚控制器编号drsOps DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);if (drsOps NULL || drsOps-GetUint32 NULL || drsOps-GetString NULL) { HDF_LOGE(%s: invalid drs ops, __func__);return;}ret drsOps-GetUint16(device-property, number, number, 0);if (ret ! HDF_SUCCESS) {HDF_LOGE(%s: read cntlr number failed, __func__);return;}cntlr PinCntlrGetByNumber(number); // 通过管脚控制器编号获取管脚控制器PinCntlrRemove(cntlr);hi35xx (struct Hi35xxPinCntlr *)cntlr;if (hi35xx ! NULL) {if (hi35xx-regBase ! NULL) {OsalIoUnmap((void *)hi35xx-regBase);}OsalMemFree(hi35xx);}}c驱动调试 【可选】针对新增驱动程序建议验证驱动基本功能例如挂载后的信息反馈PIN管脚设置推拉方式、推拉强度等。
最后
经常有很多小伙伴抱怨说不知道学习鸿蒙开发哪些技术不知道需要重点掌握哪些鸿蒙应用开发知识点
为了能够帮助到大家能够有规划的学习这里特别整理了一套纯血版鸿蒙HarmonyOS Next全栈开发技术的学习路线包含了鸿蒙开发必掌握的核心知识要点内容有ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、WebGL、元服务、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、OpenHarmony驱动开发、系统定制移植等等鸿蒙HarmonyOS NEXT技术知识点。 《鸿蒙 (Harmony OS)开发学习手册》共计892页:https://gitcode.com/HarmonyOS_MN/733GH/overview
如何快速入门
1.基本概念 2.构建第一个ArkTS应用 3.…… 鸿蒙开发面试真题含参考答案: 《OpenHarmony源码解析》:
搭建开发环境Windows 开发环境的搭建Ubuntu 开发环境搭建Linux 与 Windows 之间的文件共享……系统架构分析构建子系统启动流程子系统分布式任务调度子系统分布式通信子系统驱动子系统…… OpenHarmony 设备开发学习手册:https://gitcode.com/HarmonyOS_MN/733GH/overview