Edit online

设计说明

5 Nov 2024
Read time: 8 minute(s)

源码说明

GPIO HAL 层相关 .c.h 文件分别位于 luban-lite\bsp\artinchip\hal\gpioluban-lite\bsp\artinchip\include\hal 目录。 Driver 层相关 .c.h 文件分别位于 luban-lite\bsp\artinchip\drv\gpioluban-lite\bsp\artinchip\include\drv 目录。 主要源文件说明如下:
1.
文件 说明
aic_hal_gpio.h GPIO HAL 层 API 的头文件
aic_hal_gpio.c GPIO HAL 层 API 的实现
aic_drv_gpio.h GPIO DRV 层 API 的头文件
aic_drv_gpio.c GPIO driver 注册以及 GPIO DRV 层 API 的实现
aic_hal_gpio_def_v10.c GPIO V1.0 的配置
aic_hal_gpio_def_v11.c GPIO V1.1 的配置
aic_hal_gpio_def_v12.c GPIO V1.2 的配置

模块架构

GPIO 驱动 Driver 层采用 RT-Thread 的 PIN 设备驱动框架,如果只使用 HAL 层也可以支持 Baremetal 方式的应用场景。


../../../../_images/sw_system21.png

  1. GPIO HAL 层。提供了 PinMux 和通用 GPIO 功能寄存器级的功能封装。

  2. GPIO Driver 层。

    • RT-Thread。通用 GPIO 功能注册成 RTT Pin driver,PinMux 直接以 API 的形式提供。

    • BareMental。用户自定义 Driver 直接调用 GPIO HAL 层 API。

RTT Pin 驱动

RT-Thread 调用 rt_device_pin_register() 把通用 GPIO 功能注册成 Pin Driver,Pin Driver 提供了以下功能:

  • 模式配置。配置输入、输出模式,输入上下拉配置。

  • 读取端口状态。读取输入端口的电平状态。

  • 设置端口状态。配置输出端口的电平状态。

  • GPIO 中断配置。注册中断,使能中断。

因为一个系统只允许注册一个 Pin Device,所以在调用的时候除了先使用 rt_device_find() 查找 Device 的形式来调用功能,也可以直接使用一组 rt_pin_xxx() 的函数直接来调用功能。

关键流程设计

初始化流程

RT-Thread 系统初始化时会自动调用 GPIO 驱动初始化函数:

Reset_Handler
    → entry()
        → rtthread_startup()
            → rt_hw_board_init()
                → rt_components_board_init()
                    → drv_pin_init()
drv_pin_init() 注册了 RTT Pin 驱动:
const static struct rt_pin_ops _drv_pin_ops =
{
    drv_pin_mode,
    drv_pin_write,
    drv_pin_read,
#ifdef AIC_GPIO_IRQ_DRV_EN
    drv_pin_attach_irq,
    drv_pin_detach_irq,
    drv_pin_irq_enable,
#else
    RT_NULL,
    RT_NULL,
    RT_NULL,
#endif
    drv_pin_get,
};

int drv_pin_init(void)
{
    int ret = RT_EOK;

    ret = rt_device_pin_register("pin", &_drv_pin_ops, RT_NULL);

    return ret;
}
INIT_BOARD_EXPORT(drv_pin_init);
GPIO IRQ 流程

../../../../_images/gpio_irq.png

Luban-Lite 对 GPIO IRQ 做了一个二级中断的封装:
  1. 一级中断。每个 GPIO Group 共享一个物理中断号,每个 GPIO Group 最多包含 32 个 GPIO Pin 脚。
  2. 二级中断。每个 GPIO Pin 脚中断也虚拟成标准的 Luban-Lite 中断,但是实际上是 GPIO Group ISR 做了一次中转。

接口设计

Driver 层接口设计
以下接口是 Pin 设备驱动框架的标准接口。
struct rt_pin_ops
{
    void (*pin_mode)(struct rt_device *device, rt_base_t pin, rt_base_t mode);
    void (*pin_write)(struct rt_device *device, rt_base_t pin, rt_base_t value);
    int (*pin_read)(struct rt_device *device, rt_base_t pin);
    rt_err_t (*pin_attach_irq)(struct rt_device *device, rt_int32_t pin,
                    rt_uint32_t mode, void (*hdr)(void *args), void *args);
    rt_err_t (*pin_detach_irq)(struct rt_device *device, rt_int32_t pin);
    rt_err_t (*pin_irq_enable)(struct rt_device *device, rt_base_t pin, rt_uint32_t enabled);
    rt_base_t (*pin_get)(const char *name);
};
2. drv_pin_mode
函数原型 void drv_pin_mode(struct rt_device *device, rt_base_t pin, rt_base_t mode)
功能说明 设置 Pin 模式,包括输入/输出模式、上下拉模式
参数定义
pin:Pin id
mode: 输入/输出模式、上下拉模式 (PIN_MODE_xxx 格式的宏)
注意事项 -
3. drv_pin_write
函数原型 void drv_pin_write(struct rt_device *device, rt_base_t pin, rt_base_t value)
功能说明 设置输出 Pin 的电平状态
参数定义
pin:Pin id
value: 电平状态 0/1
注意事项 -
4. drv_pin_read
函数原型 int drv_pin_read(struct rt_device *device, rt_base_t pin)
功能说明 设置输出 Pin 的电平状态
参数定义 pin:Pin id
返回值 电平状态 0/1
注意事项 -
5. drv_pin_attach_irq
函数原型 rt_err_t drv_pin_attach_irq(struct rt_device *device, rt_int32_t pin, rt_uint32_t mode, void (*hdr)(void *args), void *args)
功能说明 Pin 注册中断
参数定义
pin:Pin id
mode: 中断触发模式,边沿还是电平触发 (PIN_IRQ_MODE_xxx 格式的宏)
hdr:pin 中断处理函数
args:中断处理时的自定义参数
返回值 操作是否成功 (0=OK, other=Error)
注意事项 -
6. drv_pin_detach_irq
函数原型 rt_err_t drv_pin_detach_irq(struct rt_device *device, rt_int32_t pin)
功能说明 Pin 注销中断
参数定义 pin:Pin id
返回值 操作是否成功 (0=OK, other=Error)
注意事项 -
7. drv_pin_irq_enable
函数原型 rt_err_t drv_pin_irq_enable(struct rt_device *device, rt_base_t pin, rt_uint32_t enabled)
功能说明 使能 Pin 中断
参数定义
pin:Pin id
enabled: 1 = en, 0 = dis
返回值 操作是否成功 (0=OK, other=Error)
注意事项 -
8. drv_pin_get
函数原型 rt_base_t drv_pin_get(const char *name)
功能说明 根据 Pin Name 获取 Pin Id
参数定义 name:Pin Name 字符串 (“PA.1” 类似格式)
返回值 Pin Id
注意事项 -
HAL 层接口设计
9. hal_gpio_set_func
函数原型 int hal_gpio_set_func(unsigned int group, unsigned int pin, unsigned int func)
功能说明 设置 Pin 的 Function 模式
参数定义
group:group id
pin:offset in group
func: 0 = 关闭, 1 = 通用 GPIO, 2~8 = 专用功能
返回值 操作是否成功 (0=OK, other=Error)
注意事项 -
10. hal_gpio_get_func
函数原型 int hal_gpio_get_func(unsigned int group, unsigned int pin, unsigned int *pfunc)
功能说明 获取 Pin 的 Function 模式
参数定义
group:group id
pin:offset in group
func: 0 = 关闭, 1 = 通用 GPIO, 2~8 = 专用功能
返回值 操作是否成功 (0=OK, other=Error)
注意事项 -
11. hal_gpio_direction_input
函数原型 int hal_gpio_direction_input(unsigned int group, unsigned int pin)
功能说明 设置 Pin 为输入模式
参数定义
group:group id
pin:offset in group
返回值 操作是否成功 (0=OK, other=Error)
注意事项 -
12. hal_gpio_direction_output
函数原型 int hal_gpio_direction_output(unsigned int group, unsigned int pin)
功能说明 设置 Pin 为输出模式
参数定义
group:group id
pin:offset in group
返回值 操作是否成功 (0=OK, other=Error)
注意事项 -
13. hal_gpio_set_bias_pull
函数原型 int hal_gpio_set_bias_pull(unsigned int group, unsigned int pin, unsigned int pull)
功能说明 设置 Pin 的上下拉模式
参数定义
group:group id
pin:offset in group
pull: 0 = 关闭, 2 = 下拉, 3 = 上拉
返回值 操作是否成功 (0=OK, other=Error)
注意事项 -
14. hal_gpio_set_drive_strength
函数原型 int hal_gpio_set_drive_strength(unsigned int group, unsigned int pin, unsigned int strength)
功能说明 设置 Pin 的驱动能力
参数定义
group:group id
pin:offset in group
strength: 0 ~ 7
返回值 操作是否成功 (0=OK, other=Error)
注意事项 -
15. hal_gpio_set_debounce
函数原型 int hal_gpio_set_debounce(unsigned int group, unsigned int pin, unsigned int debounce)
功能说明 设置 Pin 的防抖能力
参数定义
group:group id
pin:offset in group
debounce: 0 ~ 0xFFF
返回值 操作是否成功 (0=OK, other=Error)
注意事项 -
16. hal_gpio_set_irq_mode
函数原型 int hal_gpio_set_irq_mode(unsigned int group, unsigned int pin, unsigned int irq_mode)
功能说明 设置 Pin 的中断模式
参数定义
group:group id
pin:offset in group
irq_mode: 0 = 下降沿,1 = 上升沿,2 = 低电平,3 = 高电平,4 = 双沿
返回值 操作是否成功 (0=OK, other=Error)
注意事项 -

Demo

此 Demo 是 test_gpio 命令的部分代码,含二级中断使用方法(详见 test_gpio.c),可以作为 GPIO 的使用参考:
static u32 test_gpio_input_pin_cfg(char *arg_pin)
{
    // 1.test_gpio_pin_check 函数获取引脚号
    static u32 pin = 0;
    pin = test_gpio_pin_check(arg_pin, GPIO_SET_MODE_FLAG);

    // 2.引脚模式设置为 Input-PullUp 模式,即上拉输入模式
    rt_pin_mode(pin, PIN_MODE_INPUT_PULLUP);

    // 3.rt_pin_attach_irq 函数将中断处理程序 test_gpio_input_irq_handler 附加到引脚上,并设置中断触发模式为上升沿和下降沿
    rt_pin_attach_irq(pin, PIN_IRQ_MODE_RISING_FALLING,
                    test_gpio_input_irq_handler, &pin);

    // 4.rt_pin_irq_enable 函数启用引脚的中断功能
    rt_pin_irq_enable(pin, PIN_IRQ_ENABLE);

    return pin;
}