热度 16
2020-7-1 11:40
3015 次阅读|
0 个评论
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 命名中的 和 这两个参数来操作对应的 GPIO 管脚 ### GPIO 字符数次串命名规则: LSIO.GPIO .IO LSIO.GPIO0.IO09 LSIO.GPIO0.IO12 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 (32 lines) gpiochip1 (32 lines) gpiochip2 (32 lines) gpiochip3 (32 lines) gpiochip4 (32 lines) gpiochip5 (32 lines) gpiochip6 (32 lines) gpiochip7 (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 line 31: unnamed "usb3503 connect" output active-high ----------------------------------- ./ 测试 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: # 松开 SW5 按键 event: FALLING EDGE offset: 12 timestamp: # 通过 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): You are about to install the SDK to " ". Proceed ? 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 ### 定义 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 /environment-setup-aarch64-tdx-linux ### 编译,因为需要 gpiod 库,因此要再 link 选项加入 -lgpiod 选项,否则会出现 ”undefined reference to …” 错误 $ cd $ ${CC} -Wall -lgpiod -lpthread gpio-toggle.c -o gpio-toggle ### 部署 $ scp gpio-toggle root@ :/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 ### 定义 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 /environment-setup-aarch64-tdx-linux ### 在同一个终端中启动 Eclopse IDE $ cd $ ./eclipse ### 在 Eclipse IDE 下参考上面的说明文档创建新的 C/cross compile 工程,并按照说明文档配置好 SDK 。同样因为 linker 需要 gpiod 相关库,因此要在下面位置增加相关库 菜单: Properties 选项卡 : Settings 选项 : Libraries Libraries (-l) 栏目下面增加: gpiod ### Eclipse 点击 build 进行编译,根据选择是 Debug 还是 Release ,编译后的二进制文件会在对应的目录,本文使用 Debug ### 部署 $ cd /gpiotest/Debug $ scp gpiotest root@ :/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 的替代者。