AliOS Things 硬件抽象层(HAL)对接系列1 — GPIO driver porting

HAL层(Hardware abstraction layer 硬件抽象层) 的目的是为了屏蔽底层不同芯片平台的差异,从而使驱动层上面的软件不会随芯片平台而改变。AliOS Things定义了全面的HAL抽象层,这个系列主要介绍AliOS ThingsHAL层与不同芯片平台对接的poring要点,并举例说明。

Hal 对接系列1 —— Gpio driver porting

一. 接口定义说明

gpio 对外接口定义在 include/hal/soc下面,接口函数主要有以下几个:

int32_t hal_gpio_init(gpio_dev_t *gpio)
int32_t hal_gpio_output_high(gpio_dev_t *gpio);
int32_t hal_gpio_output_low(gpio_dev_t *gpio);
int32_t hal_gpio_output_toggle(gpio_dev_t *gpio);
int32_t hal_gpio_input_get(gpio_dev_t *gpio, uint32_t *value);
int32_t hal_gpio_enable_irq(gpio_dev_t *gpio, gpio_irq_trigger_t trigger, gpio_irq_handler_t handler, void *arg);
int32_t hal_gpio_disable_irq(gpio_dev_t *gpio);
int32_t hal_gpio_clear_irq(gpio_dev_t *gpio);
int32_t hal_gpio_finalize(gpio_dev_t *gpio)

其中,结构体gpio_dev_t 定义为:

typedef struct {
    uint8_t       port;           /* gpio port */
    gpio_config_t config;  /* gpio config */
    void         *priv;           /* priv data */
} gpio_dev_t;

接口函数的含义清晰明了,这里用户有两种方式可以调用驱动:

  1. 直接调用接口函数,常用于对gpio驱动的二次封装,如在lcd驱动中调用gpio进行相关操作;
  2. 通过vfs虚拟文件系统进行操作,即使用open, read, write, ioctl等标准接口进行。

二. 接口使用说明

二者调用方式在hal层没有显著区别。以第一种为例:
调用gpio驱动时,首先定义
gpio_dev_t gpio_1 = {KEY_1, OUTPUT, &value}
即使用gpio 的输出功能,可以使用

hal_gpio_output_high(&gpio_1);
hal_gpio_output_low(& gpio_1);
hal_gpio_output_toggle(& gpio_1);

等接口函数操作gpio输出高、低电平或者反转电平。

gpio_dev_t gpio_2 = {KEY_2, INPUT, NULL}
即使用gpio的输入功能,可以使用
hal_gpio_input_get(&gpio_2 , uint32_t *value)
等接口函数操作读取gpio电平值;

gpio_dev_t gpio_3 = {KEY_3, IRQ_MODE, &value}
即使用gpio的输入中断功能,value值为上升沿、下降沿和边沿触发三种模式,
可以使用

hal_gpio_enable_irq(&gpio_3, gpio_irq_trigger_t trigger,                                 
                    gpio_irq_handler_t handler, void *arg);

进行中断初始化,用户还需要自行提供中断处理函数handler,定义如下:
typedef void (gpio_irq_handler_t)(void arg);

具体的操作示例,可以参考aos/example/peri_deiver_test_developerkit/peri_test.c

三. HAL层对接要点

HAL层需要严格按照位于include/hal/soc/gpio.h的实现进行对接, 新建两个文件hal_gpio_xxx.c和hal_gpio_xxx.h,将封装层代码放到这两个文件中,实现上面列出的接口函数。

hal_gpio_init是gpio初始化,不同系列芯片的初始化方式差异较大,我们往往无法直接调用芯片厂商的初始化函数,此时需要对接口进行一些转换以对接芯片厂商的驱动。举例说明。

ST系列:
我们最终需要的gpio初始化接口即:int32_t hal_gpio_init(gpio_dev_t *gpio)
ST系列芯片驱动的gpio初始化接口为:void HAL_GPIO_Init(GPIO_TypeDef GPIOx, GPIO_InitTypeDef GPIO_Init)
其中的结构体GPIO_TypeDef 、GPIO_InitTypeDef 为ST芯片专用的驱动结构体定义,
对接ST系列的gpio驱动时,需要手动对上述结构体进行定义,以满足继续调用ST的驱动的要求:
定义
GPIO_TypeDef *GPIOx;
GPIO_InitTypeDef GPIO_InitStruct;

/伪代码举例/
get_gpio_group(gpio, &GPIOx) 来获取GPIOx
gpio_para_transform(gpio, &GPIO_InitStruct); 来获取 GPIO_InitStruct
(get_gpio_group 和 gpio_para_transform 等函数的实现要点:根据GPIO_TypeDef 和GPIO_InitTypeDef 结构体的定义将 gpio_dev_t 实现转换 ,具体可参考ST驱动源码)
有了GPIOx 和 GPIO_InitStruct,进一步调用ST提供gpio初始化函数 HAL_GPIO_Init

再以NRF系列芯片为例:
NRF系列芯片驱动的gpio初始化接口为:ret_code_t renrf_drv_gpiote_init(void)
对接该系列hal层时,可以直接调用底层驱动,需要注意的是,NRF的gpio初始化分
输入gpio的初始化和输出gpio的初始化,即:

ret_code_t  nrf_drv_gpiote_out_init(nrf_drv_gpiote_pin_t pin,
                nrf_drv_gpiote_out_config_t const * p_config);

ret_code_t  nrf_drv_gpiote_in_init(nrf_drv_gpiote_pin_t  pin,
                 nrf_drv_gpiote_in_config_t const * p_config,
                 nrf_drv_gpiote_evt_handler_t  evt_handler);

这里的 nrf_drv_gpiote_pin_t 、nrf_drv_gpiote_out_config_t 、nrf_drv_gpiote_in_config_t 等结构体定义也是NRF系列专用,对接该系列的gpio驱动时,需要手动对上述结构体进行定义,如:

static nrf_drv_gpiote_out_config_t out_config = GPIOTE_CONFIG_OUT_SIMPLE(false);
static nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_TOGGLE(true);

int32_t hal_gpio_init(gpio_dev_t *gpio)
{
    int32_t ret = -1;

    if (!nrf_drv_gpiote_is_init()) {
        ret = nrf_drv_gpiote_init();
         if (ret != NRF_SUCCESS)
            return NRF_ERROR_INTERNAL;
    }

    switch (gpio->config) {
    case OUTPUT_PUSH_PULL:
    case OUTPUT_OPEN_DRAIN_NO_PULL:
    case OUTPUT_OPEN_DRAIN_PULL_UP:
        ret = nrf_drv_gpiote_out_init(gpio->port, &out_config);
        break;
    case IRQ_MODE:
         in_config.pull = NRF_GPIO_PIN_PULLUP;
         ret = nrf_drv_gpiote_in_init(gpio->port, &in_config, gpio->priv);
    default:
        ret = -1;
     break;
   }
    return ret;
}

hal_gpio_output_high、
​hal_gpio_output_low、
​hal_gpio_output_toggle 、
​hal_gpio_input_get
等函数的HAL层对接比较简单,一般在gpio初始化后直接调用相应芯片的驱动即可,
如ST系列: HAL_GPIO_WritePin、HAL_GPIO_ReadPin 进行gpio输入输出操作;
NRF系列:nrf_drv_gpiote_out_set、nrf_drv_gpiote_out_clear、nrf_drv_gpiote_in_is_set进行gpio输入输出操作。

对于gpio的输入中断的对接,ST系列使用了
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)进行gpio输入中断的响应,并在

int32_t hal_gpio_enable_irq(gpio_dev_t *gpio, gpio_irq_trigger_t trigger, gpio_irq_handler_t handler, void *arg)

中定义中断响应的handler 和传入的参数arg,如:

    ret = hal_gpio_enable_irq(&gpio1, IRQ_TRIGGER_RISING_EDGE,  key_handle,  NULL);
    if (ret != 0) {
        printf("hal_gpio_enable_irq key return failed.\n");
    }​

    void key_handle(void *arg) 
    {
          /*key interupt相关操作*/
    }​  ​

与ST不同,NRF系列在使用

ret_code_t nrf_drv_gpiote_in_init(nrf_drv_gpiote_pin_t pin,
                        nrf_drv_gpiote_in_config_t const * p_config,
                          nrf_drv_gpiote_evt_handler_t  evt_handler);

最后一个参数evt_handler来表示中断响应函数,nrf 底层驱动会对这个参数进行判断,如果传入NULL,则表示不使用gpio输入中断功能。

综上所述, hal层porting需要根据不同芯片厂商的驱动的接口来进行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值