设计说明
4 Dec 2024
Read time: 8 minute(s)
源码说明
GPIO HAL 层相关 .c 和 .h 文件分别位于
luban-lite\bsp\artinchip\hal\gpio 和
luban-lite\bsp\artinchip\include\hal 目录。 Driver 层相关
.c 和 .h 文件分别位于
luban-lite\bsp\artinchip\drv\gpio 和
luban-lite\bsp\artinchip\include\drv 目录。 主要源文件说明如下:
文件 | 说明 |
---|---|
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 方式的应用场景。
-
GPIO HAL 层。提供了 PinMux 和通用 GPIO 功能寄存器级的功能封装。
-
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 流程
Luban-Lite 对 GPIO IRQ 做了一个二级中断的封装:
- 一级中断。每个 GPIO Group 共享一个物理中断号,每个 GPIO Group 最多包含 32 个 GPIO Pin 脚。
-
二级中断。每个 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);
};
函数原型 | void drv_pin_mode(struct rt_device *device, rt_base_t pin, rt_base_t mode) |
---|---|
功能说明 | 设置 Pin 模式,包括输入/输出模式、上下拉模式 |
参数定义 |
pin:Pin id
mode: 输入/输出模式、上下拉模式 (PIN_MODE_xxx 格式的宏)
|
注意事项 | - |
函数原型 | void drv_pin_write(struct rt_device *device, rt_base_t pin, rt_base_t value) |
---|---|
功能说明 | 设置输出 Pin 的电平状态 |
参数定义 |
pin:Pin id
value: 电平状态 0/1
|
注意事项 | - |
函数原型 | int drv_pin_read(struct rt_device *device, rt_base_t pin) |
---|---|
功能说明 | 设置输出 Pin 的电平状态 |
参数定义 | pin:Pin id |
返回值 | 电平状态 0/1 |
注意事项 | - |
函数原型 | 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) |
注意事项 | - |
函数原型 | rt_err_t drv_pin_detach_irq(struct rt_device *device, rt_int32_t pin) |
---|---|
功能说明 | Pin 注销中断 |
参数定义 | pin:Pin id |
返回值 | 操作是否成功 (0=OK, other=Error) |
注意事项 | - |
函数原型 | 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) |
注意事项 | - |
函数原型 | rt_base_t drv_pin_get(const char *name) |
---|---|
功能说明 | 根据 Pin Name 获取 Pin Id |
参数定义 | name:Pin Name 字符串 (“PA.1” 类似格式) |
返回值 | Pin Id |
注意事项 | - |
HAL 层接口设计
函数原型 | 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) |
注意事项 | - |
函数原型 | 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) |
注意事项 | - |
函数原型 | int hal_gpio_direction_input(unsigned int group, unsigned int pin) |
---|---|
功能说明 | 设置 Pin 为输入模式 |
参数定义 |
group:group id
pin:offset in group
|
返回值 | 操作是否成功 (0=OK, other=Error) |
注意事项 | - |
函数原型 | int hal_gpio_direction_output(unsigned int group, unsigned int pin) |
---|---|
功能说明 | 设置 Pin 为输出模式 |
参数定义 |
group:group id
pin:offset in group
|
返回值 | 操作是否成功 (0=OK, other=Error) |
注意事项 | - |
函数原型 | 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) |
注意事项 | - |
函数原型 | 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) |
注意事项 | - |
函数原型 | 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) |
注意事项 | - |
函数原型 | 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;
}