GPIO中断

切换root用户

只有root用户可以控制GPIO,在测试之前需要先切换到root用户。

1
2
3
$ khadas@Khadas:~$ su
Password:
root@Khadas:/home/khadas#

设置GPIO引脚

  • 确认你需要使用的引脚,以VIM3为例:
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
root@Khadas:/home/khadas# gpio readall
+------+-----+----------+------+---+----+---- Model Khadas VIM3 --+----+---+------+----------+-----+------+
| GPIO | wPi | Name | Mode | V | DS | PU/PD | Physical | PU/PD | DS | V | Mode | Name | wPi | GPIO |
+------+-----+----------+------+---+----+-------+----++----+-------+----+---+------+----------+-----+------+
| | | 5V | | | | | 1 || 21 | | | | | GND | | |
| | | 5V | | | | | 2 || 22 | P/U | | 1 | ALT1 | PIN.A15 | 6 | 475 |
| | | USB_DM | | | | | 3 || 23 | P/U | | 1 | ALT1 | PIN.A14 | 7 | 474 |
| | | USB_DP | | | | | 4 || 24 | | | | | GND | | |
| | | GND | | | | | 5 || 25 | P/U | | 1 | ALT0 | PIN.AO2 | 8 | 498 |
| | | MCU3V3 | | | | | 6 || 26 | P/U | | 1 | ALT0 | PIN.AO3 | 9 | 499 |
| | | MCUNRST | | | | | 7 || 27 | | | | | 3V3 | | |
| | | MCUSWIM | | | | | 8 || 28 | | | | | GND | | |
| | | GND | | | | | 9 || 29 | P/D | | 0 | ALT0 | PIN.A1 | 10 | 461 |
| | | ADC0 | | | | | 10 || 30 | P/D | | 0 | ALT0 | PIN.A0 | 11 | 460 |
| | | 1V8 | | | | | 11 || 31 | P/D | | 0 | ALT0 | PIN.A3 | 12 | 463 |
| | | ADC1 | | | | | 12 || 32 | P/D | | 0 | ALT0 | PIN.A2 | 13 | 462 |
| 506 | 1 | PIN.H5 | ALT3 | 0 | | P/U | 13 || 33 | P/D | | 0 | ALT1 | PIN.A4 | 14 | 464 |
| | | GND3 | | | | | 14 || 34 | | | | | GND | | |
| 433 | 2 | PIN.H6 | IN | 0 | | P/D | 15 || 35 | P/D | | 0 | ALT3 | PWM-F | 15 | 432 |
| 434 | 3 | PIN.H7 | IN | 0 | | P/D | 16 || 36 | | | | | RTC | | |
| | | GND | | | | | 17 || 37 | P/D | | 0 | IN | PIN.H4 | 16 | 431 |
| 497 | 4 | PIN.AO1 | ALT0 | 1 | | P/U | 18 || 38 | | | | | MCU-FA1 | | |
| 496 | 5 | PIN.AO0 | ALT0 | 1 | | P/U | 19 || 39 | P/D | | 0 | IN | PIN.Z15 | 17 | 426 |
| | | 3V3 | | | | | 20 || 40 | | | | | GND | | |
+------+-----+----------+------+---+----+-------+----++----+-------+----+---+------+----------+-----+------+

选择你需要使用的GPIO,确认对应的物理引脚和GPIO值。这里以GPIOH6为例,则对应的GPIO值为433,物理引脚为第15脚。

  • Export GPIO
1
root@Khadas:/home/khadas# echo 433 > /sys/class/gpio/export
注意

请确保gpio readall查看到的GPIOH_6状态为普通GPIO,如果不是,你需要先把这个管脚配置为普通GPIO,方法为编辑文件/boot/env.txt,移除overlays节点里面的uart3,然后保存重启系统。

详细信息请查看 Device Tree Overlays

  • 测试程序源码gpio-irq.c
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <poll.h>

#define SYSFS_GPIO_DIR "/sys/class/gpio"
#define MAX_BUF 255

int gpio_export(unsigned int gpio)
{
int fd, len;
char buf[MAX_BUF];

fd = open(SYSFS_GPIO_DIR "/export", O_WRONLY);

if (fd < 0) {
fprintf(stderr, "Can't export GPIO %d pin: %s\n", gpio, strerror(errno));
return fd;
}

len = snprintf(buf, sizeof(buf), "%d", gpio);
write(fd, buf, len);
close(fd);

return 0;
}

int gpio_unexport(unsigned int gpio)
{
int fd, len;
char buf[MAX_BUF];

fd = open(SYSFS_GPIO_DIR "/unexport", O_WRONLY);

if (fd < 0) {
fprintf(stderr, "Can't unexport GPIO %d pin: %s\n", gpio, strerror(errno));
return fd;
}

len = snprintf(buf, sizeof(buf), "%d", gpio);
write(fd, buf, len);
close(fd);

return 0;
}

int gpio_set_edge(unsigned int gpio, char *edge)
{
int fd, len;
char buf[MAX_BUF];

len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/edge", gpio);

fd = open(buf, O_WRONLY);

if (fd < 0) {
fprintf(stderr, "Can't set GPIO %d pin edge: %s\n", gpio, strerror(errno));
return fd;
}

write(fd, edge, strlen(edge)+1);
close(fd);

return 0;
}

int gpio_set_pull(unsigned int gpio, char *pull)
{
int fd, len;
char buf[MAX_BUF];

len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/pull", gpio);

fd = open(buf, O_WRONLY);

if (fd < 0) {
fprintf(stderr, "Can't set GPIO %d pin pull: %s\n", gpio, strerror(errno));
return fd;
}

write(fd, pull, strlen(pull)+1);
close(fd);

return 0;
}

int main(int argc, char *argv[])
{
struct pollfd fdset[2];
int fd, ret, gpio;
char buf[MAX_BUF];

if (argc < 3 || argc > 4) {
fprintf(stdout, "usage : sudo sysfs_irq_test <gpio> <edge> [pull]\n");
fflush(stdout);
return -1;
}

gpio = atoi(argv[1]);
if (gpio_export(gpio)) {
fprintf(stdout, "error : export %d\n", gpio);
fflush(stdout);
return -1;
}

if (gpio_set_edge(gpio, argv[2])) {
fprintf(stdout, "error : edge %s\n", argv[2]);
fflush(stdout);
return -1;
}

if (argv[3] && gpio_set_pull(gpio, argv[3])) {
fprintf(stdout, "error : pull %s\n", argv[3]);
fflush(stdout);
return -1;
}

snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);
fd = open(buf, O_RDWR);
if (fd < 0)
goto out;

while (1) {
memset(fdset, 0, sizeof(fdset));
fdset[0].fd = STDIN_FILENO;
fdset[0].events = POLLIN;
fdset[1].fd = fd;
fdset[1].events = POLLPRI;
ret = poll(fdset, 2, 3*1000);

if (ret < 0) {
perror("poll");
break;
}

fprintf(stderr, ".");

if (fdset[1].revents & POLLPRI) {
char c;
(void)read (fd, &c, 1) ;
lseek (fd, 0, SEEK_SET) ;
fprintf(stderr, "\nGPIO %d interrupt occurred!\n", gpio);
}

if (fdset[0].revents & POLLIN)
break;

fflush(stdout);
}

close(fd);
out:
if (gpio_unexport(gpio)) {
fprintf(stdout, "error : unexport %d\n", gpio);
fflush(stdout);
}

return 0;
}

  • 编译源码
1
root@Khadas:/home/khadas# gcc -o gpio-irq gpio-irq.c
  • 运行程序
1
2
3
4
./gpio-irq 433 rising down
.
GPIO 433 interrupt occurred!
..........

通过杜邦线连接物理引脚的PIN20PIN15,触发中断。现象如下:

1
2
3
4
5
6
7
8
9
root@Khadas:/home/khadas# ./gpio-irq 433 rising down
.
GPIO 433 interrupt occurred!
..
GPIO 433 interrupt occurred!
.
GPIO 433 interrupt occurred!
.
GPIO 433 interrupt occurred!
  • 测试程序说明

运行格式如下:

1
root@Khadas:/home/khadas# ./gpio-irq <edge> [pull]

<edge>可设置为rising或者failing, [pull]为可选参数,设置为up或者down