当前位置: 首页 > article >正文

OpenHarmony-4.GPIO驱动

  • GPIO

1.功能简介

  GPIO(General-purpose input/output)即通用型输入输出。GPIO又俗称为I/O口,I指的是输入(in),O指的是输出(out)。可以通过软件来控制其输入和输出,即I/O控制。通常,GPIO控制器通过分组的方式管理所有GPIO管脚,每组GPIO有一个或多个寄存器与之关联,通过读写寄存器完成对GPIO管脚的操作。

  • GPIO输入

    输入是检测各个引脚上的电平状态,高电平或者低电平状态。常见的输入模式有:模拟输入、浮空输入、上拉输入、下拉输入。

  • GPIO输出

    输出是当需要控制引脚电平的高低时需要用到输出功能。常见的输出模式有:开漏输出、推挽输出、复用开漏输出、复用推挽输出。

  GPIO接口定义了操作GPIO管脚的标准方法集合,包括:

  • 设置、获取管脚方向:方向可以是输入或者输出(暂不支持高阻态)。

  • 读、写管脚电平值:电平值可以是低电平或高电平。

  • 设置、取消管脚中断服务函数:设置一个管脚的中断响应函数,以及中断触发方式。取消一个管脚的中断服务函数。

  • 使能、禁止管脚中断:禁止或使能管脚中断。

1.1.运作机制

  在HDF框架中,同类型设备对象较多时(可能同时存在十几个同类型配置器),若采用独立服务模式,则需要配置更多的设备节点,且相关服务会占据更多的内存资源。相反,采用统一服务模式可以使用一个设备服务作为管理器,统一处理所有同类型对象的外部访问(这会在配置文件中有所体现),实现便捷管理和节约资源的目的。GPIO模块接口适配模式采用统一服务模式:
在这里插入图片描述
  在统一模式下,所有的控制器都被核心层统一管理,并由核心层统一发布一个服务供接口层,因此这种模式下驱动无需再为每个控制器发布服务。

  GPIO模块各分层作用:

  • 接口层提供操作GPIO管脚的标准方法。

  • 核心层主要提供GPIO管脚资源匹配,GPIO管脚控制器的添加、移除以及管理的能力,通过钩子函数与适配层交互,供芯片厂家快速接入HDF框架。

  • 适配层主要是将钩子函数的功能实例化,实现具体的功能。

1.2.接口层

  GPIO模块提供的主要接口:

  • drivers/hdf_core/framework/include/platform/gpio_if.h

在这里插入图片描述

  以gpio_stm32f4xx为例:

GpioRead
	-> GpioCntlrRead
		-> cntlr->ops->read 调用哪里?
			-> LL_GPIO_ReadInputPin

  GpioRead代码分析:

drivers_hdf_core/framework/support/platform/src/gpio/gpio_if.c
int32_t GpioRead(uint16_t gpio, uint16_t *val)
{
    int32_t ret;
    struct GpioCntlr *cntlr = GpioCntlrGetByGpio(gpio);

    ret = GpioCntlrRead(cntlr, GpioCntlrGetLocal(cntlr, gpio), val);

    GpioCntlrPut(cntlr);
    return ret;
}

drivers_hdf_core/framework/support/platform/src/gpio/gpio_core.c:
int32_t GpioCntlrRead(struct GpioCntlr *cntlr, uint16_t local, uint16_t *val)
{
    ...
    return cntlr->ops->read(cntlr, local, val);  //调用注册的gpio_stm32f4xx控制器ops接口对应的read函数,即g_GpioCntlrMethod->GpioDevRead
}

  gpio_stm32f4xx驱动:

  • drivers_hdf_core/adapter/platform/gpio/gpio_stm32f4xx.c
struct HdfDriverEntry g_GpioDriverEntry = {
    .moduleVersion = 1,
    .moduleName = "ST_GPIO_MODULE_HDF",
    .Init = GpioDriverInit,
    .Release = GpioDriverRelease,
};
HDF_INIT(g_GpioDriverEntry);

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

    ret = PlatformDeviceBind(&g_stmGpioCntlr.device, device);
    gpioCntlr = GpioCntlrFromHdfDev(device);
    ret = AttachGpioDevice(gpioCntlr, device); /* GpioCntlr add GpioDevice to priv */
  
    gpioCntlr->ops = &g_GpioCntlrMethod;  //注册的ops接口
    ret = GpioCntlrAdd(gpioCntlr);
    return HDF_SUCCESS;
}

/* 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,
};

static int32_t GpioDevRead(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t *val)
{
    (void)cntlr;
    uint16_t realPin = g_gpioPinsMap[gpio].realPin;
    uint32_t pinReg = g_stmRealPinMaps[realPin];
    uint16_t value = 0;

    GPIO_TypeDef* gpiox = g_gpioxMaps[g_gpioPinsMap[gpio].group];
    value = LL_GPIO_ReadInputPin(gpiox, pinReg);  //调用ll库对应的函数接口
    *val = value;

    return HDF_SUCCESS;
}

1.3.核心层

  • drivers_hdf_core/adapter/platform/gpio/gpio_stm32f4xx.c

  gpio_stm32f4xx驱动初始化:

struct HdfDriverEntry g_GpioDriverEntry = {
    .moduleVersion = 1,
    .moduleName = "ST_GPIO_MODULE_HDF",
    .Init = GpioDriverInit,
    .Release = GpioDriverRelease,
};
HDF_INIT(g_GpioDriverEntry);

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

    ret = PlatformDeviceBind(&g_stmGpioCntlr.device, device);
    gpioCntlr = GpioCntlrFromHdfDev(device);
    ret = AttachGpioDevice(gpioCntlr, device); /* GpioCntlr add GpioDevice to priv */

    gpioCntlr->ops = &g_GpioCntlrMethod; /* register callback */
    ret = GpioCntlrAdd(gpioCntlr);
    return HDF_SUCCESS;
}

  GpioDriverInit 函数主要工作:

  • 绑定GpioCntlr和HdfDeviceObject;
  • 调用GpioCntlrAdd将gpioCntlr 注册到PlatformManager进行管理。
    GpioCntlrAdd -> PlatformDeviceAdd->PlatformManagerAddDevice

1.4.开发步骤

  GPIO标准API通过GPIO管脚号来操作指定管脚,使用GPIO的一般流程如图所示。

图 2 GPIO使用流程图
1.3.1.确定GPIO管脚号

  两种方式获取管脚号:

  • 根据SOC芯片规则进行计算、通过管脚别名获取
    不同SOC芯片由于其GPIO控制器型号、参数、以及控制器驱动的不同,GPIO管脚号的换算方式不一样。
  • 通过管脚别名获取
    调用接口GpioGetByName进行获取,入参是该管脚的别名,接口返回值是管脚的全局ID。

1.3.2.设置GPIO管脚中断

  为一个GPIO管脚设置中断响应程序,使用如下函数:

int32_t GpioSetIrq(uint16_t gpio, uint16_t mode, GpioIrqFunc func, void *arg);

  以hdf_key 驱动为例:

SetupKeyIrq
   ->GpioSetIrq
drivers_hdf_core/framework/model/input/driver/hdf_key.c:
static int32_t KeyInit(KeyDriver *keyDrv)
{
    int32_t ret = SetupKeyIrq(keyDrv);
    CHECK_RETURN_VALUE(ret);
    return HDF_SUCCESS;
}

static int32_t SetupKeyIrq(KeyDriver *keyDrv)
{
    uint16_t intGpioNum = keyDrv->keyCfg->gpioNum;
    uint16_t irqFlag = keyDrv->keyCfg->irqFlag;
    int32_t ret = GpioSetDir(intGpioNum, GPIO_DIR_IN);

    ret = GpioSetIrq(intGpioNum, irqFlag | GPIO_IRQ_USING_THREAD, KeyIrqHandle, keyDrv);
    ret = GpioEnableIrq(intGpioNum);

    return HDF_SUCCESS;
}

GpioSetIrq 函数调用:

GpioSetIrq 
     -> GpioCntlrSetIrq
     	-> GpioIrqRecordCreate
     		-> cntlr->ops->setIrq
     			-> GpioDevSetIrq  //gpio_stm32f4xx.c

代码实现:

drivers_hdf_core/framework/support/platform/src/gpio/gpio_if.c
int32_t GpioSetIrq(uint16_t gpio, uint16_t mode, GpioIrqFunc func, void *arg)
{
    int32_t ret;
    struct GpioCntlr *cntlr = GpioCntlrGetByGpio(gpio);

    ret = GpioCntlrSetIrq(cntlr, GpioCntlrGetLocal(cntlr, gpio), mode, func, arg);

    GpioCntlrPut(cntlr);
    return ret;
}

int32_t GpioCntlrSetIrq(struct GpioCntlr *cntlr, uint16_t local, uint16_t mode, GpioIrqFunc func, void *arg)
{
    int32_t ret;
    struct GpioInfo *ginfo = NULL;
    struct GpioIrqRecord *irqRecord = NULL;

    ginfo = &cntlr->ginfos[local];
    ret = GpioIrqRecordCreate(ginfo, mode, func, arg, &irqRecord);
    ret = GpioCntlrSetIrqInner(ginfo, irqRecord);
    return ret;
}

static int32_t GpioCntlrSetIrqInner(struct GpioInfo *ginfo, struct GpioIrqRecord *irqRecord)
{
    int32_t ret;
    uint16_t local = GpioInfoToLocal(ginfo);
    struct GpioCntlr *cntlr = ginfo->cntlr;
    ...
    ginfo->irqRecord = irqRecord;
   
    ret = cntlr->ops->setIrq(cntlr, local, irqRecord->mode);
    return ret;
}

drivers_hdf_core/adapter/platform/gpio/gpio_stm32f4xx.c
struct GpioMethod g_GpioCntlrMethod = {
     ...
    .setIrq = GpioDevSetIrq,
    ...
};

static int32_t GpioDevSetIrq(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t mode)
{
    (void)cntlr;
    uint16_t realPin = g_gpioPinsMap[gpio].realPin;
    uint32_t pinReg = g_stmRealPinMaps[realPin];

    if (mode == OSAL_IRQF_TRIGGER_RISING) {
        g_gpioExitCfg[gpio].trigger = LL_EXTI_TRIGGER_RISING;
    } else if (mode == OSAL_IRQF_TRIGGER_FALLING) {
        g_gpioExitCfg[gpio].trigger = LL_EXTI_TRIGGER_FALLING;
    } else {
        HDF_LOGE("%s %d, error mode:%d", __func__, __LINE__, mode);
        return HDF_ERR_NOT_SUPPORT;
    }

    return HDF_SUCCESS;
}

refer to

  • git clone https://gitee.com/openharmony/drivers_hdf_core.git
  • http://docs.openharmony.cn/pages/v4.1/zh-cn/device-dev/driver/driver-platform-gpio-des.md/

http://www.kler.cn/a/428452.html

相关文章:

  • 【Compose multiplatform教程】01 创建你的多平台项目 <官网搬运>
  • 多线程编程:线程间的同步与通信
  • 《向量数据库指南》——Mlivus Cloud:OPPO的向量数据库选型秘籍
  • AGameModeBase和游戏模式方法
  • 03、Node.js安装及环境配置
  • 如何在自动化安全测试中,实现多工具集成与数据融合,以提高对Spring Boot应用程序安全漏洞的检测效率与准确性?
  • C++(十一)
  • Spring Security集成JWT
  • 【数学建模】论文排版教程
  • Linix学习一
  • Qt中实现可视化界面的TCP SYN扫描(改进版)
  • Lumos学习王佩丰Excel第二十讲:图表基础
  • 黑马程序员Java项目实战《苍穹外卖》Day09
  • Java集合(三)- Stack Queue
  • 如何用python获取图像
  • ADI的DSP用CCES来调试,仿真器TEST第一步“Opening Emulator Interface”报错,解决办法。
  • Chrome 中小于 12px 文字的实现方式与应用场景详解
  • 机器学习周报(12.2-12.8)
  • C# NLog 配置ElasticSearch
  • 【JAVA】Java高级:Spring框架与Java EE—Spring框架概述(控制反转、依赖注入)