05、基于整数的GPIO接口
基于整数的接口最为人所熟知。GPIO用整数标识,GPIO上需要执行的每个操作都使用该整数。以下是包含传统GPIO访问函数的头文件:
C
#include <linux/gpio.h>
1
使用步骤:
- 注册:gpio_request (cat /sys/kernel/debug/gpio )
- 输出方向:gpio_direction_output
- 电平配置:gpio_get_value
- 中断:goio_to_irq
一、GPIO的申请和配置
1.1 申请GPIO
使用gpio_request()
函数来申请并获取GPIO的使用权:
C
int gpio_request(unsigned gpio, const char *label);
1
参数说明:
gpio
:要使用的GPIO编号label
:给这个GPIO起个名字(比如在系统文件/sys/kernel/debug/gpio
里显示的名字)
注意:必须检查返回值。返回0表示成功,负数代表出错。
1.2 释放GPIO
使用完GPIO后,用gpio_free()
释放资源:
C
void gpio_free(unsigned int gpio);
1
1.3 检查GPIO有效性
使用gpio_is_valid()
提前确认GPIO编号是否合法:
C
bool gpio_is_valid(int number);
1
1.4 设置GPIO方向
- 输入模式:用
gpio_direction_input()
设置: - 输出模式:用
C
int gpio_direction_output(unsigned gpio, int value);
1
- 0 → 初始低电平
- 1 → 初始高电平
二、GPIO值的读写
2.1 原子上下文(如中断处理)
这类GPIO直接通过内存访问(比如芯片内置GPIO),不会导致等待:
c
static int gpio_get_value(unsigned gpio)
void gpio_set_value(unsigned int gpio, int value);
1
2
2
2.2 非原子上下文(如I2C/SPI总线)
这类GPIO需要等待操作完成(可能会暂停程序):
c
static int gpio_get_value_cansleep(unsigned gpio);
void gpio_set_value_cansleep(unsigned gpio,int value);
1
2
2
关键区别:后者函数名带有cansleep
,表示可能需要等待,不能在中断处理中使用。
三、GPIO转中断
3.1 获取中断号
用gpio_to_irq()
将GPIO编号转为中断号:
C
int gpio_to_irq(unsigned gpio);
1
3.2 注册中断处理
获取中断号后,用request_irq()
或request_threaded_irq()
注册处理函数:
C
// 示例代码
int gpio_int = ...; // 通过设备树等获取的GPIO编号
int irq_num = gpio_to_irq(gpio_int); // 转换为中断号
// 注册中断处理函数(这里用线程式中断为例)
error = devm_request_threaded_irq(&client->dev, irq_num,
NULL, my_interrupt_handler, // 无上半部,下半部是自定义函数
IRQF_TRIGGER_RISING | IRQF_ONESHOT, // 触发条件:上升沿,单次触发
input_dev->name, my_data_struct); // 中断名称和数据指针
if (error) {
// 处理注册失败
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
关键参数说明:
IRQF_TRIGGER_RISING
:设置为上升沿触发IRQF_ONESHOT
:确保中断处理完成后立即释放中断线
四、关键注意事项
- 释放资源:使用完GPIO务必调用
gpio_free()
,否则可能导致资源泄露 - 检查有效性:使用前最好用
gpio_is_valid()
确认GPIO编号存在 - 睡眠判断:通过
gpio_cansleep()
判断GPIO是否可能阻塞程序 - 上下文匹配:带
cansleep
的函数不能在中断处理中使用 - 方向设置:必须先设置GPIO方向(输入/输出)才能读写值
五、实验
C
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/gpio.h> /* 遗留的基于整数的GPIO */
#include <linux/interrupt.h> /* IRQ */
static unsigned int GPIO_LED_RED = 8; //放到设备树里面
static unsigned int GPIO_BTN1 = 115;
static unsigned int GPIO_BTN2 = 116;
static unsigned int GPIO_LED_GREEN = 120;
static unsigned int irq;
static irq_handler_t btn1_pushed_irq_handler(unsigned int irq,
void *dev_id, struct pt_regs *regs)
{
int state;
/*读取BTN2值并更改LED状态*/
state = gpio_get_value(GPIO_BTN2);
gpio_set_value(GPIO_LED_RED, state);
gpio_set_value(GPIO_LED_GREEN, state);
pr_info("GPIO_BTN1 interrupt: Interrupt! GPIO_BTN2 state is %d)\n", state);
return IRQ_HANDLED;
}
static int __init helloworld_init(void)
{
int retval;
/*
* 可以检查GPIO在控制器上是否有效
* 使用gpio_is_valid()函数
* 例:
* if (!gpio_is_valid(GPIO_LED_RED)) {
* pr_infor("Invalid Red LED\n");
* return -ENODEV;
* }
*/
gpio_request(GPIO_LED_GREEN, "green-led");
gpio_request(GPIO_LED_RED, "red-led");
gpio_request(GPIO_BTN1, "button-1");
gpio_request(GPIO_BTN2, "button-2");
/*
* 配置按钮GPIO作为输入
*
* 在此之后,只有当控制器具有该特性时才可以调用gpio_set_debounce()
*
* 例如,取消延迟200ms的按钮
* gpio_set_debounce(GPIO_BTN1, 200);
*/
gpio_direction_input(GPIO_BTN1);
gpio_direction_input(GPIO_BTN2);
/*
* 将LED GPIO设置为输出,初始值设置为0
*/
gpio_direction_output(GPIO_LED_RED, 0);
gpio_direction_output(GPIO_LED_GREEN, 0);
irq = gpio_to_irq(GPIO_BTN1);
retval = request_threaded_irq(irq, NULL,\
btn1_pushed_irq_handler, \
IRQF_TRIGGER_LOW | IRQF_ONESHOT, \
"device-name", NULL);
pr_info("Hello world!\n");
return 0;
}
static void __exit hellowolrd_exit(void)
{
free_irq(irq, NULL);
gpio_free(GPIO_LED_RED);
gpio_free(GPIO_LED_GREEN);
gpio_free(GPIO_BTN1);
gpio_free(GPIO_BTN2);
pr_info("End of the world\n");
}
module_init(hellowolrd_init);
module_exit(hellowolrd_exit);
MODULE_LICENSE("GPL");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85