"); //-->
By Toradex秦海
1). 简介
NXP iMX8是NXP去年底发布的基于Cortex-A72/A53和Coretex-M4异构多核架构的ARM处理器,本文就基于嵌入式Linux演示GPIO相关应用示例。
本文所演示的ARM平台来自于Toradex 基于NXP iMX8QM ARM处理器的Apalis iMX8QM ARM嵌入式平台。
2). 准备
a). Apalis iMX8QM ARM核心版配合Apalis Evaluation Board载板,连接调试串口UART1(载板X29)到开发主机方便调试。
b). Apalis iMX8 Cortex-A核心安装Toradex Ycoto Linux Console image V3.04版本,详细信息请参考这里。
d). Apalis Evaluation Board GPIO相关硬件连接
X2 MXM_3 <-> X34 LED1
X2 MXM_5 <-> X34 SW5
X2 MXM_11 <-> X34 SW1
3). GPIO 命令行测试
a). 嵌入式Linux系统下之前呗广泛应用的GPIO工具为sysfs GPIO接口(/sys/class/gpio),但是目前这个项目已经处于deprecated状态,经Linux Kernel Community确定其替代者就是GPIO字符设备API Libgpiod。因此,尽管本文测试使用的Toradex Ycoto Linux Console image V3.04版本依然支持sysfs GPIO接口,但是已经不建议使用,如果需要相关说明,可以参考这里。本文接下来的测试都是基于Libgpiod来进行。
b). GPIO 数字编码
./ ARM SOC定义GPIO管脚通常为一串字母数字的组合,之前sysfs API操作时候需要将不同SOC GPIO的字母数字命名转换为纯数字编码,对于不同的SOC转换规则的详细说明请见这里,而本文使用的libgpiod API则直接可以按照GPIO命名进行操作,更为直观和便利。
./ 首先根据 Apalis iMX8 datasheet 4.4章节的表格,找出所需要GPIO管脚的字母数字组合命名,比如本文涉及的三个GPIO管脚;在接下来的Libgpiod API中都需要使用对应的GPIO命名中的<controller>和<gpio>这两个参数来操作对应的GPIO管脚
### GPIO字符数次串命名规则:LSIO.GPIO<controller>.IO<gpio>
X2 MXM_3 -> LSIO.GPIO0.IO09
X2 MXM_5 -> LSIO.GPIO0.IO12
X2 MXM_11 -> LSIO.GPIO4.IO01
c). 在具体调试GPIO之前,还需要确认在Linux kernel device tree中,这个管脚被定义为GPIO且并没有被其他驱动功能占用,否则在具体操作GPIO的时候会出现冲突导致异常,关于device tree的说明本文不赘述,可以参考这里。本文所涉及的三个GPIO管脚默认即配置为GPIO,因此无需修改。
d). 调用Libgpiod API在命令行下进行GPIO测试
./ Apalis iMX8 上电开机进入嵌入式Linux系统,下面操作在调试串口下进行
./ 罗列GPIO banks,也就是对应的上面提到的controller。可以看到有8个banks,每个banks包含32 lines,也就是32 gpio。当然,实际上结合具体的SOC和模块定义,不一定每个banks和lines都有对应的GPIO管脚,有效的肯呢个只是一部分。
-----------------------------------
root@apalis-imx8:~# gpiodetect
gpiochip0 [5d080000.gpio] (32 lines)
gpiochip1 [5d090000.gpio] (32 lines)
gpiochip2 [5d0a0000.gpio] (32 lines)
gpiochip3 [5d0b0000.gpio] (32 lines)
gpiochip4 [5d0c0000.gpio] (32 lines)
gpiochip5 [5d0d0000.gpio] (32 lines)
gpiochip6 [5d0e0000.gpio] (32 lines)
gpiochip7 [5d0f0000.gpio] (32 lines)
-----------------------------------
./ 查看某个bank具体GPIO lines的情况,可以查看系统中当前哪些GPIO被占用了。
-----------------------------------
root@apalis-imx8:~# gpioinfo 0
gpiochip0 - 32 lines:
line 0: unnamed unused input active-high
line 1: unnamed unused input active-high
line 2: unnamed unused input active-high
line 3: unnamed unused input active-high
line 4: unnamed unused input active-high
line 5: unnamed unused input active-high
line 6: unnamed unused input active-high
line 7: unnamed unused input active-high
line 8: unnamed unused output active-high
line 9: unnamed unused output active-high
line 10: unnamed unused input active-high
line 11: unnamed unused input active-high
line 12: unnamed unused input active-high
line 13: unnamed unused input active-high
line 14: unnamed unused input active-high
line 15: unnamed unused input active-high
line 16: unnamed unused input active-high
line 17: unnamed unused input active-high
line 18: unnamed unused input active-high
line 19: unnamed unused input active-high
line 20: unnamed unused input active-high
line 21: unnamed unused input active-high
line 22: unnamed unused input active-high
line 23: unnamed unused input active-high
line 24: unnamed unused input active-high
line 25: unnamed unused input active-high
line 26: unnamed unused input active-high
line 27: unnamed unused input active-high
line 28: unnamed unused input active-high
line 29: unnamed unused input active-high
line 30: unnamed "reset" output active-low [used]
line 31: unnamed "usb3503 connect" output active-high [used]
-----------------------------------
./ 测试X2 MXM_3 管脚GPIO output操作,gpioset命令的作用就是设置对应GPIO管脚为输出状态,并输出为设置的高或者低电平。
-----------------------------------
# 设置GPIO输出为高电平驱动LED点亮
root@apalis-imx8:~# gpioset 0 9=1
# 设置GPIO输出为低电平驱动LED熄灭
root@apalis-imx8:~# gpioset 0 9=0
# 通过 gpioinfo查看bank0 可以发现line 9是output状态
root@apalis-imx8:~# gpioinfo 0
gpiochip0 - 32 lines:
……
line 9: unnamed unused output active-high
……
-----------------------------------
./ 测试X2 MXM_11 管脚GPIO input操作,gpioget命令的作用就是设置对应GPIO管脚为输入状态,并读取当前的GPIO电平。
-----------------------------------
# SW1 拨至低电平位置(靠近载板边缘),读取连接的X2 MXM_11GPIO电平
root@apalis-imx8:~# gpioget 4 1
0
# SW1 拨至高电平位置(远离载板边缘),读取连接的X2 MXM_11GPIO电平
root@apalis-imx8:~# gpioget 4 1
1
# 通过 gpioinfo查看bank4 可以发现line 1是input状态
root@apalis-imx8:~# gpioinfo 4
gpiochip4 - 32 lines:
……
line 1: unnamed unused input active-high
……
-----------------------------------
./ 测试X2 MXM_5 管脚GPIO 中断操作,gpiomon命令的作用就是设置对应的GPIO为输入状态,并监测对应GPIO管脚的事件(。
-----------------------------------
# 设置X2 MXM_5 管脚中断监测
root@apalis-imx8:~# gpiomon 0 12
# 按下SW5按键
event: RISING EDGE offset: 12 timestamp: [1609840088.602076625]
# 松开SW5按键
event: FALLING EDGE offset: 12 timestamp: [1609840089.268163875]
# 通过 gpioinfo查看bank0 可以发现line 12是input状态
root@apalis-imx8:~# gpioinfo 0
gpiochip0 - 32 lines:
……
line 12: unnamed unused input active-high
……
-----------------------------------
4). GPIO C代码示例程序测试
a). 首先先在开发Linux 主机安装SDK,SDK为按照这里说明通过Ycoto project/OpenEmbedded 环境编译得到,安装过程中根据提示可以自行更改SDK安装目录
-----------------------------------
$ chmod +x tdx-xwayland-glibc-x86_64-Qt5-Wayland-Image-aarch64-toolchain-2.6.4.sh
$ ./tdx-xwayland-glibc-x86_64-Qt5-Wayland-Image-aarch64-toolchain-2.6.4.sh
TDX Wayland with XWayland SDK installer version 2.6.4
=====================================================
Enter target directory for SDK (default: /opt/tdx-xwayland/2.6.4): <SDK_install_dir>
You are about to install the SDK to "<SDK_install_dir>". Proceed[Y/n]? Y
…
-----------------------------------
b). c代码示例1 - 测试X2 MXM_3 管脚输出循环驱动LED亮和灭,时间间隔为1s
./ 源代码参考如下
https://github.com/simonqin09/Apalis_iMX8_Libgpiod/blob/master/gpio-toggle/gpio-toggle.c
./ 主要说明如下
-----------------------------------
### include libgpiod 头文件
#include <gpiod.h>
### 定义GPIO chip和line 结构体
struct gpiod_chip *output_chip;
struct gpiod_line *output_line;
### 配置GPIO为输出
output_chip = gpiod_chip_open_by_name(chip);
output_line = gpiod_chip_get_line(output_chip, offset);
gpiod_line_request_output(output_line, "gpio-toggle", GPIOD_LINE_ACTIVE_STATE_HIGH);
### 切换GPIO输出状态
int line_value = 0; OR ine_value = 1;
gpiod_line_set_value(output_line, line_value);
-----------------------------------
./ 编译,本示例使用通过命令行编译方式,详细说明请参考这里
-----------------------------------
### export SDK 环境变量
$ source <SDK_install_dir>/environment-setup-aarch64-tdx-linux
### 编译,因为需要gpiod库,因此要再link选项加入 -lgpiod 选项,否则会出现 ”undefined reference to …” 错误
$ cd <work_dir>
$ ${CC} -Wall -lgpiod -lpthread gpio-toggle.c -o gpio-toggle
### 部署
$ scp gpio-toggle root@<apalis_imx8_ipaddress>:/home/root
-----------------------------------
./ 测试,在Apalis iMX8上面运行刚编译部署好的 gpio-toggle 二进制程序,载板上面的LED1 LED灯会1s间隔亮和灭
-----------------------------------
root@apalis-imx8:~# cd /home/root/
root@apalis-imx8:~# ./gpio-toggle
Usage by bank/pin number:
gpio-toggle OUTPUT-BANK-NUMBER OUTPUT-GPIO-NUMBER
root@apalis-imx8:~# ./gpio-toggle 0 9
LED turns ON
LED turns OFF
LED turns ON
LED turns OFF
……
-----------------------------------
c). c代码示例2 - 测试X2 MXM_5 管脚通过按键输入,捕获上升沿事件后切换X2 MXM_3输出状态驱动LED亮和灭
./ 源代码参考如下
https://github.com/simonqin09/Apalis_iMX8_Libgpiod/blob/master/gpiotest/gpiotest.c
./ 主要说明如下
-----------------------------------
### include libgpiod 头文件
#include <gpiod.h>
### 定义GPIO chip和line 以及event结构体
struct gpiod_chip *input_chip;
struct gpiod_line *input_line;
struct gpiod_line_event event;
### 配置GPIO为输入,中断事件为上升沿
input_chip = gpiod_chip_open_by_name(chip);
input_line = gpiod_chip_get_line(input_chip, offset);
gpiod_line_request_rising_edge_events(input_line, "gpiotest");
### GPIO输入事件响应
while (1) {
gpiod_line_event_wait(input_line, NULL);
if (gpiod_line_event_read(input_line, &event) != 0)
continue;
/* this should always be a rising event in our example */
if (event.event_type != GPIOD_LINE_EVENT_RISING_EDGE)
continue;
……
}
-----------------------------------
./ 编译,本示例使用通过Eclipse IDE工具进行编译,详细Eclipse IDE 下载安装以及SDK配置说明请参考这里
-----------------------------------
### export SDK 环境变量
$ source <SDK_install_dir>/environment-setup-aarch64-tdx-linux
### 在同一个终端中启动Eclopse IDE
$ cd <Eclipse_install_dir>
$ ./eclipse
### 在Eclipse IDE下参考上面的说明文档创建新的C/cross compile工程,并按照说明文档配置好SDK。同样因为linker需要gpiod相关库,因此要在下面位置增加相关库
菜单:
Project --> Properties
选项卡:
C/C++ Build --> Settings
选项:
Cross GCC Linker --> Libraries
Libraries (-l) 栏目下面增加:
gpiod
### Eclipse 点击build进行编译,根据选择是Debug还是Release,编译后的二进制文件会在对应的目录,本文使用Debug
### 部署
$ cd <Eclipse_workspace>/gpiotest/Debug
$ scp gpiotest root@<apalis_imx8_ipaddress>:/home/root
-----------------------------------
./ 测试,在Apalis iMX8上面运行刚编译部署好的 gpiotest 二进制程序,载板上面的LED1 LED灯初始状态为灭,随着按下SW5按键交替亮和灭
-----------------------------------
root@apalis-imx8:~# cd /home/root/
root@apalis-imx8:~# ./gpiotest
Usage by bank/pin number:
gpio-test INPUT-BANK-NUMBER INPUT-GPIO-NUMBER OUTPUT-BANK-NUMBER OUTPUT-GPIO-NUMBER
root@apalis-imx8:~# ./gpiotest 0 12 0 9
LED initial status is OFF
button pressed 1 times
LED turns ON
button pressed 2 times
LED turns OFF
button pressed 3 times
LED turns ON
……
-----------------------------------
5). 总结
本文基于NXP iMX8示例了嵌入式Linux使用Libgpiod API来驱动GPIO,通过示例可见其直观性和便利性均大大优于传统的 sysfs API,因此会被 Linux Kernel Community确定为 sysfs API的替代者。
*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。