[实战]zynq7000设备树自动导出GPIO
目录
- zynq7000设备树自动导出GPIO
- 添加设备树节点
- 验证实验
- 结论
zynq7000设备树自动导出GPIO
今天无聊,掏出我82年产的microzed玩一玩。玩啥好呢,要不点个灯吧。于是,三下五除二,通过linux sys接口以及echo,很快就点亮了。无聊按了一下复位按键,发现系统重新先加载后,灯又不亮了。这不能忍,于是继续深入,发现导出的gpio都没了。
linux sys 接口,对GPIO实行的export操作,是临时性质的,因此每次重启系统,都需要重新进行export。通常可以通过制作脚本,在系统加载后或者用户登录后自动export,但今天,我想借这个事情,聊一条怎么用linux设备树解决这个问题。
添加设备树节点
相关的基础知识,可以参考我的博客
[Linux实战] Linux设备树原理与应用详解
[实战]Zynq设备树详细教程
[实战] 深入解析Petalinux下Zynq7000设备树开发:从理论到实战
zynq的用户自定义设备树,在{petalinux工程}/project-spec/meta-user/recipes-bsp/device-tree/files/ 下,那个叫 system-user.dtsi 就是, 用文本编辑工具打开它,会发现它是这样的:
/include/ "system-conf.dtsi"
/ {
};
这是一个空文件,里面没有任何节点,用户自定义的节点,只需要添加在这里面就行。
对于gpio自动导出,只需要新建一个gpio-export节点,并设置好必要属性,具体内容如下
/include/ "system-conf.dtsi"
/ {gpio-export {compatible = "gpio-export";#gpio-cells = <2>;gpio47 {gpio-export,name = "custom_gpio47";gpio-export,output = <0>;gpios = <&gpio0 47 0>;};};
};
- gpio-export { … }
作用:创建一个名为gpio-export的子节点,用于管理GPIO导出功能。
- compatible = “gpio-export”;
作用:绑定Linux内核的gpio-export驱动,该驱动负责将GPIO导出到用户空间。
验证:可通过内核源码查找COMPATIBLE_STR匹配(如drivers/gpio/gpio-export.c)。
- #gpio-cells = <2>;
作用:声明每个GPIO描述需要2个参数(控制器、引脚号、激活电平)。
背景:与GPIO控制器的#gpio-cells定义一致,确保语法匹配。
- gpio47 { … }
作用:定义GPIO 47的导出配置,子节点名称通常与GPIO编号对应。
- gpio-export,name = “custom_gpio47”;
作用:指定用户空间看到的GPIO名称(在/sys/class/gpio/下生成同名目录)。
用户空间路径:
/sys/class/gpio/custom_gpio47/
- gpio-export,output = <0>;
作用:初始化方向为输入(0=输入,1=输出)。
扩展:若需初始化为输出,需添加gpio-export,init = <0/1>;设置默认电平。
- gpios = <&gpio0 47 0>;
作用:关联硬件GPIO控制器和引脚,格式为:
<&控制器 引脚号 激活电平>
参数详解:
- &gpio0:Zynq的MIO控制器(GPIO 0-53)。
- 47:GPIO编号(需确认硬件未复用为其他功能)。
- 0:低电平有效(若设为1,则active-high)。
改完之后保存,petalinux-build
在petalinux工程目录下运行
petalinux-build
[INFO] Sourcing buildtools
[INFO] Building project
[INFO] Sourcing build environment
[INFO] Generating workspace directory
INFO: bitbake petalinux-image-minimal
NOTE: Started PRServer with DBfile: /D/study/zynq7010_project/build/cache/prserv.sqlite3, Address: 127.0.0.1:43583, PID: 73789
Loading cache: 100% |#############################################################| Time: 0:00:01
Loaded 6495 entries from dependency cache.
Parsing recipes: 100% |#############################################################| Time: 0:00:02
Parsing of 4461 .bb files complete (4459 cached, 2 parsed). 6497 targets, 627 skipped, 1 masked, 0 errors.
NOTE: Resolving any missing task queue dependencies
Initialising tasks: 100% |#############################################################| Time: 0:00:08
Checking sstate mirror object availability: 100% |#############################################################| Time: 0:00:11
Sstate summary: Wanted 478 Local 9 Network 304 Missed 165 Current 1106 (65% match, 89% complete)
Removing 19 stale sstate objects for arch zynq_generic: 100% |#############################################################| Time: 0:00:00
NOTE: Executing Tasks
NOTE: Tasks Summary: Attempted 4232 tasks of which 4178 didn't need to be rerun and all succeeded.
INFO: Successfully copied built images to tftp dir:
/tftpboot/microZed
[INFO] Successfully built project
然后打包,在工程目录下运行
petalinux-package --boot --fsbl --fpga --u-boot --force
然后将boot.bin、image.ub、boot.csr三个文件拷贝到sd卡fat分区,把rootfs.tar.gz文件解压缩要sd卡ext分区。插入microzed,重启。
验证实验
首先启动之前的版本
zynq7010:~$ cd /sys/class/gpio/
zynq7010:/sys/class/gpio$ ls
export gpiochip906 unexport
可见目录下没有任何导出的gpio,手动导出:
为了方便操作,先切换root:
zynq7010:/sys/class/gpio$ sudo -i
Password:
root@zynq7010:~#
再进行导出
root@zynq7010:~# cd /sys/class/gpio/
root@zynq7010:/sys/class/gpio# ls
export gpiochip906 unexport
root@zynq7010:/sys/class/gpio# echo 953 > export
root@zynq7010:/sys/class/gpio# ls
export gpio953 gpiochip906 unexport
导出成功,进行属性配置和值操作,严重gpio操作成功
root@zynq7010:/sys/class/gpio# echo out > gpio953/direction
root@zynq7010:/sys/class/gpio#
root@zynq7010:/sys/class/gpio#
root@zynq7010:/sys/class/gpio# echo 1 > gpio953/value
root@zynq7010:/sys/class/gpio# cat gpio953/value
1
root@zynq7010:/sys/class/gpio# echo 0 > gpio953/value
root@zynq7010:/sys/class/gpio# cat gpio953/value
修改属性为GPO,同时修改输出值,操作都成功了。
复位办卡,重新启动,再次查看GPIO情况
zynq7010:~$ cd /sys/class/gpio/
zynq7010:/sys/class/gpio$ ls
export gpiochip906 unexport
上次导出的已经没有了,export是一个临时操作,每次重启后都会丢失,需要重新export。
好了,上修改了设备树后的版本,看看什么情况。
zynq7010:~$ cd /sys/class/gpio/
zynq7010:/sys/class/gpio$ ls
export gpiochip906 unexport
哦和,还是一样的,没有被导出。是什么原因呢????
经过仔细研究linux设备操作,搞清楚了问题的根本原因,他在于设备树只是申明有这么一个设备,但是是不是会使用,取决于驱动,所以现在要想实现自动export还得自己写一段驱动才行。这个事情先留后面了。在这里借用linux本身就已经有驱动的Led设备。我们通过设备树,把这个设备定义成LED设备,这样linux加载时,就会自动export了。
设备树改动如下:
/include/ "system-conf.dtsi"
/ {my_gpios {compatible = "gpio-leds"; // 使用标准 gpio-leds 驱动(自动导出)status = "okay";my_gpio0 {label = "my-gpio0";gpios = <&gpio0 47 0>; // EMIO GPIO 0 (MIO 0-53, EMIO 54-117)default-state = "on"; // 初始状态};};
};
保存,编译,打包,拷贝到SD卡,启动开发版。进去一查看
zynq7010:~$ cd /sys/class/gpio/
zynq7010:/sys/class/gpio$ ls
export gpiochip906 unexport
傻了,怎么还没有不应该阿。。。。
突然,灵光一线,设备树把它指定为led设备了,就算导出了,也不再这里了,因该会有一个led目录,于是仔细查看果然:
zynq7010:~$ ls /sys/class/leds/
mmc0:: my-gpio0
这个my-gpio0不就是我在设备树中定义的标签吗?原来他躲在这里。正好我这个gpio就是用来控制板子上Led,我低头一看板子,果然多亮了一个灯,开心。
继续进到目录,看到
root@zynq7010:/sys/class/leds/my-gpio0# ls
brightness device max_brightness power subsystem trigger uevent
root@zynq7010:/sys/class/leds/my-gpio0#
brightness 应该就是控制指令了,于是:
root@zynq7010:/sys/class/leds/my-gpio0# cat brightness
1
root@zynq7010:/sys/class/leds/my-gpio0#
现在灯亮它是1,改成0应该灭了,试一下:
root@zynq7010:/sys/class/leds/my-gpio0# echo 0 > brightness
root@zynq7010:/sys/class/leds/my-gpio0# echo 1 > brightness
root@zynq7010:/sys/class/leds/my-gpio0# echo 0 > brightness
果然,灭-亮-灭,就是它了。
结论
通过本文,应该对设备树、驱动、linux硬件驱动框架,应该能有个感性的认知了。
本文的实验至少说明:
- linux可以通过设备树实现设备的自动export
- 但是能否export,除了设备树之外,还需要驱动配合,设备树只是定义设备,驱动才是用户,export是驱动做的。