GPIO设备驱动程序开发指南

更正文档

1. 前言

本文介绍如何编写符合AliOS Things标准的GPIO控制器设备驱动程序。

2. 头文件

在程序中使用本文提及的功能应包含头文件aos/gpioc_core.h

3. 数据结构

AliOS Things提供GPIO控制器设备的抽象基础结构:

typedef struct aos_gpioc aos_gpioc_t;

采用结构体嵌套的方式从基础结构派生出具体的硬件结构,注意基础结构之后应紧接aos_gpioc_pin_t类型数组。派生类型应包含具体硬件操作所需的各种变量。例如:

#define GPIOC_ABC_NUM_PINS 32

typedef struct {
    aos_gpioc_t gpioc;
    aos_gpioc_pin_t pins[GPIOC_ABC_NUM_PINS];
    /* private data */
    void *reg_base;
    int irq_num;
} gpioc_abc_t;

使用宏aos_container_of实现从基础结构指针到派生结构指针的转换。例如:

aos_gpioc_t *gpioc_dev = foo();
gpioc_abc_t *gpioc_abc = aos_container_of(gpioc_dev, gpioc_abc_t, gpioc);

4. 注册及注销

4.1. 注册

AliOS Things提供如下函数用于注册GPIO master设备:

aos_status_t aos_gpioc_register(aos_gpioc_t *gpioc);

调用注册函数之前,BSP开发者应自行分配一个aos_gpioc_t类型或其派生类型的变量并对包含的如下变量赋值:

  • dev.iduint32_t类型,表示该设备的ID。不同GPIO控制器设备不能拥有相同的ID。

  • opsconst aos_gpioc_ops_t *类型,指向一组面向硬件的回调函数:

typedef struct {
    void (*unregister)(aos_gpioc_t *gpioc);
    aos_status_t (*set_mode)(aos_gpioc_t *gpioc, uint32_t pin);
    void (*enable_irq)(aos_gpioc_t *gpioc, uint32_t pin);
    void (*disable_irq)(aos_gpioc_t *gpioc, uint32_t pin);
    int (*get_value)(aos_gpioc_t *gpioc, uint32_t pin);
    void (*set_value)(aos_gpioc_t *gpioc, uint32_t pin);
} aos_gpioc_ops_t;

  • num_pinsuint32_t类型,表示该设备包含的GPIO pin数目。

调用注册函数之前,BSP开发者应初始化派生类型中的私有变量,并执行具体硬件相关的初始化工作(例如映射寄存器地址等)。

4.2. 注销

AliOS Things提供如下函数用于注销GPIO控制器设备:

aos_status_t aos_gpioc_unregister(uint32_t id);

调用此函数之后,BSP开发者可回收相关联的aos_gpioc_t类型或其派生类型的变量。

5. 回调函数

驱动程序应实现aos_gpioc_ops_t定义的一组面向硬件的回调函数。

5.1. unregister

void (*unregister)(aos_gpioc_t *gpioc);

unregister回调函数在设备注销时被调用,可在该函数中执行具体硬件相关的反初始化工作(例如解除寄存器地址映射等)。

5.2. set_mode

aos_status_t (*set_mode)(aos_gpioc_t *gpioc, uint32_t pin);

set_mode回调函数在修改GPIO控制器设备上某个pin的模式时被调用,驱动程序应在该函数中根据新模式修改硬件状态。修改成功后返回0;失败时应返回errno(负值),且驱动程序应将硬件状态恢复到此函数被调用之前的状态。

set_mode回调函数可访问gpioc->pins[pin].mode变量获取被操作的pin的新模式。该变量是uint32_t类型,可包含如下字段,各字段使用按位或运算连接:

  • 方向,掩码为AOS_GPIO_DIR_MASK,取值必须为以下当中的一个:

  • AOS_GPIO_DIR_NONE:表示该pin不作为GPIO使用,可能让出pin mux,具体由驱动程序实现决定。

  • AOS_GPIO_DIR_INPUT:表示该pin作为输入。

  • AOS_GPIO_DIR_OUTPUT:表示该pin作为输出。

  • 输入配置,只在该pin作为输入时有意义,掩码为AOS_GPIO_INPUT_CFG_MASK,取值必须为以下当中的一个:

  • AOS_GPIO_INPUT_CFG_DEFAULT:表示输入配置为默认模式,具体由驱动程序实现,一般为最常用模式或硬件支持的唯一模式。

  • AOS_GPIO_INPUT_CFG_HI:表示输入配置为浮空模式。

  • AOS_GPIO_INPUT_CFG_PU:表示输入配置为上拉模式。

  • AOS_GPIO_INPUT_CFG_PD:表示输入配置为下拉模式。

  • 中断触发模式。注意set_mode回调函数只能设置硬件中断模式但不能使能中断。只在该pin作为输入时有意义,掩码为AOS_GPIO_IRQ_TRIG_MASK,取值必须为以下当中的一个:

  • AOS_GPIO_IRQ_TRIG_NONE:表示不触发中断。

  • AOS_GPIO_IRQ_TRIG_EDGE_RISING:表示上升沿触发中断。

  • AOS_GPIO_IRQ_TRIG_EDGE_FALLING:表示下降沿触发中断。

  • AOS_GPIO_IRQ_TRIG_EDGE_BOTH:表示上升沿和下降沿都触发中断。

  • AOS_GPIO_IRQ_TRIG_LEVEL_LOW:表示低电平触发中断。

  • AOS_GPIO_IRQ_TRIG_LEVEL_HIGH:表示高电平触发中断。

  • 输出配置,只在该pin作为输出时有意义,掩码为AOS_GPIO_OUTPUT_CFG_MASK,取值必须为以下当中的一个:

  • AOS_GPIO_OUTPUT_CFG_DEFAULT:表示输出配置为默认模式,具体由驱动程序实现,一般为最常用模式或硬件支持的唯一模式。

  • AOS_GPIO_OUTPUT_CFG_PP:表示输出配置为推挽模式。

  • AOS_GPIO_OUTPUT_CFG_ODNP:表示输出配置为开漏无上拉模式。

  • AOS_GPIO_OUTPUT_CFG_ODPU:表示输出配置为开漏上拉模式。

  • 输出初始电平,只在该pin作为输出时有意义,掩码为AOS_GPIO_OUTPUT_INIT_MASK,取值必须为以下当中的一个:

  • AOS_GPIO_OUTPUT_INIT_LOW:表示输出低电平。

  • AOS_GPIO_OUTPUT_INIT_HIGH:表示输出高电平。

5.3. enable_irq

void (*enable_irq)(aos_gpioc_t *gpioc, uint32_t pin);

enable_irq回调函数在使能某个pin的中断时被调用,驱动程序应在该函数中将硬件配置为使能该pin的中断。这里的使能中断是指GPIO控制器级别而非中断控制器级别。

5.4. disable_irq

void (*disable_irq)(aos_gpioc_t *gpioc, uint32_t pin);

disable_irq回调函数在禁用某个pin的中断时被调用,驱动程序应在该函数中将硬件配置为禁用该pin的中断。这里的禁用中断是指GPIO控制器级别而非中断控制器级别。

5.5 get_value

int (*get_value)(aos_gpioc_t *gpioc, uint32_t pin);

get_value回调函数在获取某个pin的输入电平时被调用,驱动程序应在该函数中从硬件获取输入电平。输入电平为低电平时返回0,为高电平时返回1。

5.5 set_value

void (*set_value)(aos_gpioc_t *gpioc, uint32_t pin);

set_value回调函数在设置某个pin的输出电平时被调用,驱动函数应在该函数中向硬件配置输出电平。gpioc->pins[pin].value变量表示被输出的电平,0表示低电平,1表示高电平。

6. 中断处理

在GPIO控制器硬件中断处理程序中调用宏aos_gpioc_hard_irq_handler来触发中断处理流程。

aos_gpioc_hard_irq_handler(gpioc, pin, polarity)

polarity是获取双沿触发中断极性的表达式,若本次是上升沿触发则表达式的值应为true,否则为falsepolarity表达式只有在中断模式为双沿触发时才会被求值。