基本都是摘抄正点原子的文章:《领航者 ZYNQ 之嵌入式Linux 开发指南 V3.2.pdf》,因初次学习,仅作学习摘录之用,有不懂之处后续会继续更新~
工程的创建参考:《ZYNQ学习之Petalinux 设计流程实战》
一、GPIO 之 LED 的使用
GPIO 驱动程序通过 sysfs 文件系统提供了用户空间对 GPIO 的访问,因而通过终端控制 LED 极其方便。
启动领航者开发板,进入《ZYNQ学习之Petalinux 设计流程实战》定制的 Linux 系统后在串口终端中输入如下命令进入到 sysfs 文件系统的 leds 接口处:
cd /sys/class/leds
ls
这 6 个 LED 对应开发板上的 6 个 LED 灯,名字的命名跟板子上对应 LED 丝印上的名字是一样的。先来看下 leds 下的内容,以 ps_led1 为例,输入“ls ps_led1”,执行结果如下图所示:
可以看到有 brightness 和 trigger。Brightness 可以控制 led 灯的亮灭,trigger 可以选择触发方式。向 ps_led1 的 brightness 写入 0,即输入“echo 0 > ps_led1/brightness”命令,如下图所示:
可以看到PS_LED1常灭。
现在输入“echo 1 > ps_led1/brightness”命令,如下图所示:
可以看到PS_LED1常亮。
这就是通过 brightness 来控制 led 灯的亮灭,其他led灯也可以以此种方式控制。
现在来看下如何通过 trigger 来控制 led。首先输入“cat ps_led1/trigger”命令看下有多少种触发方式,如下图所示:
root@ALIENTEK-ZYNQ:/sys/class/leds# cat ps_led1/trigger
[none] kbd-scrolllock kbd-numlock kbd-capslock kbd-kanalock kbd-shiftlock kbd-altgrlock kbd-ctrllock kbd-altlock kbd-shiftllock kbd-shiftrlock kbd-ctrlllock kbd-ctrlrlock mmc0 mmc1 timer oneshot heartbeat backlight gpio cpu cpu0 cpu1 default-on transient flash torch
可以看到触发方式非常多,其中“[]”中的内容表示当前触发方式。可知当前触发方式 为 none,也就是表示无任何触发反应。
现在试一下 timer 触发,输入命令“echo timer > ps_led1/trigger”,如下图所示
可以看到开发板上 ps_led1 灯以定时器的方式每秒闪烁一次,这就是 timer 触发方式的效果,与我们在设备树中配置的效果一样。现在来看下 heartbeat 方式的效果,输入命令“echo heartbeat > ps_led1/trigger”,如下图所示:
此时可以看到开发板上的 PS_LED1 灯像心跳一样的闪烁这就是 heartbeat 触发方式的效果。其它触发方式可以单独试用,需要提醒的是并不是所有的触发方式都能有反应,必须满足相应触发条件才行。
二、GPIO 之按键的使用
GPIO 按键的使用非常简单,通过读取文件/dev/input/event0 可以获取由 GPIO 按键生成的按键事件。在串口终端中输入“cat /dev/input/event0 | hexdump”命令,然后按下一个按键,输入事件将打印到控制台;
cat /dev/input/event0 | hexdump
如下图所示:
在按键盘上的Ctrl + C 退出。
三、EEPROM 的使用
在配置设备树的时候,设备树文件中配置了两个 I2C 外设,一个是 EEPROM,另一个是 RTC。首先来看下如何读写 EEPROM。
在/sys/class/i2c-adapter 目录下有两个 I2C 总线控制器,如下图所示:
i2c-1 和 i2c-2 分别对应 ZYNQ PS 端的两个 I2C 总线控制器,开发板上的 EEPROM 挂载在i2c-1 总线下。进入到/sys/class/i2c-adapter/i2c-1/目录下,查看该目录下的内容,如下图所示:
root@ALIENTEK-ZYNQ:/sys/class/i2c-adapter# cd i2c-1
root@ALIENTEK-ZYNQ:/sys/class/i2c-adapter/i2c-1# ls
1-0050 1-0051 delete_device device i2c-dev name new_device of_node power subsystem uevent
其中 1-0050 中的 1 代表 i2c-1,50 代表器件地址 50,也就是 eeprom 的器件地址。 进入到 1-0050/目录下,可以看到该目录有一个 eeprom 文件,如下图所示:
root@ALIENTEK-ZYNQ:/sys/class/i2c-adapter/i2c-1# cd 1-0050
root@ALIENTEK-ZYNQ:/sys/class/i2c-adapter/i2c-1/1-0050# ls
1-00500 driver eeprom modalias name of_node power subsystem uevent
可以通过 eeprom 文件对 EEPROM 设备进行读写操作,譬如向 eeprom 设备中写入“hello world”,然后读取出来,输入命令如下:
echo "hello world" > eeprom #向 eeprom 设备中写入“hello world”
head -1 eeprom #读取 eeprom
执行结果如下图所示:
至此eeprom 设备的读写就完成了。
四、RTC 的使用
在上一小节中,/sys/class/i2c-adapter/i2c-1/目录下除了 1-0050 文件夹,还有一个 1-0051 文件夹,对应 RTC 设备。
进入 1-0051/目录,查看其目录内容,如下图所示:
root@ALIENTEK-ZYNQ:/sys/class/i2c-adapter/i2c-1# cd 1-0051
root@ALIENTEK-ZYNQ:/sys/class/i2c-adapter/i2c-1/1-0051# ls
driver modalias name of_node power rtc subsystem uevent
可以看到有一个 rtc 文件夹,那么操作 rtc 是不是像 eeprom 那样呢? 当然不是,对于 rtc,linux 有一个专用的命令:hwclock。 在 Linux 中有硬件时钟与系统时钟两种时钟。硬件时钟是指电路板上的时钟设备,也就 是通常可在电脑 BIOS 画面设定的时钟。系统时钟则是指 kernel 中的时钟。当 Linux 启动时,系统时钟会去读取硬件时钟的设定,之后系统时钟独立运作。所有 Linux 相关指令与函数都是读取系统时钟的设定。
使用 date 和 hwclock 命令可分别查看和设定系统时钟和硬件时钟。
在串口终端中输入下面的指令查看系统时间:
date
串口终端如下图所示:
上图中箭头所指示的位置就是当前的系统时间。 在串口终端中输入下面的指令查看硬件(RTC)时钟:
hwclock
串口终端如下图所示:
上图中显示的便是当前 RTC 时钟芯片中的时间。
在串口终端中输入下面的指令将系统时间设置为当前日期和时间(2024/4/06, 11:12:55),然后使用 date 指令查看所设置的系统时间:
date -s "2024-04-06 11:12:55"
date
在串口终端中输入下面的命令将系统时间写入 RTC 时钟芯片中,然后使用 hwclock 命令查看硬件时钟。
hwclock -w # 将系统时钟同步至硬件时钟
hwclock # 查看硬件时钟
五、QSPI 的使用
首先执行“cat /proc/mtd”命令查看 qspi flash 分区信息,如下图所示:
cat /proc/mtd
linux 系统将 qspi flash 分成了 6 个分区:mtd0、mtd1、mtd2、mtd3、mtd4 以及 mtd5 分区,分区 名分别是:boot、bootenv、bitstream、device-tree、kernel 以及 space,不同分区用于存放不同镜像文件。 本小节使用第 6 个mtd5,即 space 分区。
5.1 读写测试
执行下面这条命令读取 flash 的第六个分区,为了节省时间,只读取 64 个字节:
hexdump -C -n 64 /dev/mtdblock5 #读 flash 第六个分区长度为 64 个字节
左边红箭头处显示的是十六进制表示的相对地址,一行地址共有 16 字节数据;中间红框中显示的是十六进制表示的数据,而右边箭头处则是对应的 ASCII 字符,由于有些数据没有 对应的 ASCII 字符,所以用“................”来表示。 执行下面这条命令将字符串写入 QSPI 的第六个分区中:
echo "ALIENTEK ZYNQ 7010" > /dev/mtdblock5 #将字符串写入
flash hexdump -C -n 64 /dev/mtdblock5 #读取 flash 中内容
双引号(" ")中间的字符串就是我们要写入的,从上面可以知道,当写入之后再次读取 flash,发现写入与读取的数据是相同的,所以 qspi flash 读写测试成功!
5.2 复制文件
首先在用户“root”根目录下创建“test.txt”文件,并向文件中写入“flash test”内容,命令如下所示:
touch test.txt #创建 test.txt 文本
echo "flash test" > test.txt #向文本中写入内容
cat test.txt #查看test.txt中的文本
结果如下图所示:
使用“flashcp”命令复制文本文件到 flash 第六个分区,命令如下所示:
flashcp test.txt /dev/mtd5 #复制文本文件到 flash 中
hexdump -C -n 64 /dev/mtdblock5 #查看分区中的内容是否和文本中一致
执行结果如下图所示:
从上图中可以看到,文本中的“flash test”内容已经成功复制到 flash 分区中了。
六、USB 的使用
领航者底板上有四个 USB HOST 接口和一个 USB SLAVE 接口,本小节通过访问 USB 设备——U 盘,来学习 USB HOST 接口的使用。
开发板上 USB HOST 和 SLAVE 接口共用相同 ZYNQ 引脚,使用前要通过跳线帽手动选择。使用跳线帽将 P4 端子的 DN 与 HN 相连、DP 与 HP 相连, 注意先连接 DN 与 HN,此时USB_HOST 接口被激活。
将 fat32 格式的 U 盘插入底板上 4 个 USB HOST 接口中的一个。注意,U 盘文件系统格式不支持 ntfs,ntfs格式的用户请将 U盘重新格式化成 fat32,格式化之前请备份 U盘中的数据。 此时串口终端会有打印信息,如下所示:
信息打印出来之后,插入的 U 盘就已经被挂载到根文件系统中了,此时可通过 df 命令查看挂载点,如下所示:
红色框标识出来的就是笔者插入的 USB 设备——U 盘,显示 U 盘文件系统格式是 vfat,也就 fat32,实际容量为 15G,挂载点是/run/media/sda1,进入到该目录可以看到 U 盘中存放的文件以及文件夹,如下所示:
通过下面这条命令创建一个文件 hello.txt,内容为“hello Zynq”,如下所示:
touch test.txt
echo "hello Zynq" > test.txt
echo "hello Zynq" > hello.txt
写入的内容与读取出来的内容一致,说明 U 盘读写测试没有问题。测试完成之后不要直接把 U 盘拔了,需要先把 U 盘卸载,在串口终端中输入如下命令:
cd #退出 U 盘所在目录
umount /run/media/sda1/ #卸载 U 盘
卸载成功之后就可以把U盘拔掉了。
七、以太网的使用
领航者开发板有两路千兆以太网接口,GE_PS 和 GE_PL;由于 GE_PS 网口使用了 PS 端 IO 资源,而 GE_PL 网口使用了 PL 端 IO 资源,所以这里也把 GE_PS 网口称为 PS 网口、而把GE_PL 网口称为 PL 网口,如下所示:
注:连接网口的网线要使用千兆网线,譬如 CAT-5E 类网线或 CAT-6 类网线,正点原子在实际测试当中,发现 CAT-5E 类网线并不稳定,所以这里推荐使用 CAT-6 类网线进行测试。
7.1 查看网络设备
在串口终端执行下面这条命令可以查看系统中的所有网络设备,如下所示:
ifconfig -a
上图显示了当前系统中所有的网络设备,其中 eth0表示开发板上的PS网口、而eth1则表示开发板上的 PL网口。
还可以直接使用 ifconfig命令不加任何选项查看当前系统已经激活(打开)的网络设备,如下图所示:
ifconfig
上图中的 eth0 就是开发板上的 PS 网口,可以通过 ifconfig 命令来关闭或激活对应的网口。
ifconfig 命令打开或关闭 PS 网口的命令如下所示:
ifconfig eth0 down #关闭 eth0(PS 网口)
ifconfig eth0 up #打开 eth0(PS 网口)
ifconfig 命令打开或关闭 PL 网口的命令如下所示:
ifconfig eth1 down #关闭 eth1(PL 网口)
ifconfig eth1 up #打开 eth1(PL 网口)
如果是用 ip 命令,则对应命令如下:
ip link set eth0 down #关闭 eth0(PS 网口)
ip link set eth0 up #打开 eth0(PS 网口)
下面在使用 PS 网口的时候,需要先把 PL 网口给关闭,只打开 PS 网口;同理使用PL 网口的时候,需要把 PS 网口给关闭,只打开 PL 网口;在后面的使用当中,以 PS 网口为例进行介绍,PL 网口使用方式相同。
7.2 外网连接测试(有路由器)
在测试之前,先使用网线将开发板 PS 网口连接到能够上网的路由器设备上,如果没有能够上网的路由器设备的请跳过该小节,进入下一小节,因为访问外网需要联网的路由器。
执行下面的命令打开开发板的 PS 网口,并且关闭 PL 网口:
ip link set eth1 down #关闭 PL 网口
ip link set eth0 up #打开 PS 网口
ip link show up
结果如下图所示:
接下来我们需要给 PS 网口分配一个 IP 地址,使用 udhcpc 命令从 DHCP 服务器中动态获取一个 IP 地址,如下所示:
udhcpc -i eth0 #eth0 动态获取 IP 地址
从上图中可以看到,这里 PS 网口动态获取得到的 IP 地址为 192.168.2.3。获取到 IP 地址之后,接下来需要测试下开发板是不是能够上网,也就是测试开发板 PS 网口是否工作正常、是否能够连接外网。
当然首先确定开发板 PS 网口连接到的路由器是能够连接外网的,可以使用 ping 命令来测试开发板与另一台主机的网络连接是否通畅。
ping 命令是基于 ICMP(Internet Control Message Protocol)协议来工作的,执行 ping 命令本地主机会向目标主机发送一份 ICMP回显请求报文,并等待目标主机返回 ICMP 应答;因为ICMP 协议会要求目标主机收到消息之后,必须返回 ICMP 应答消息给本地主机,如果本地主机收到了目标主机的应答,则表示两台主机之间的网络运行、网络连接是正常的。
例如在串口终端执行 ping 命令来测试开发板(本地主机)与百度 www.baidu.com 服务器(目标主机)之间的网络连接是否通畅,如下所示:
从上图可以知道,通过开发板对百度服务器主机(IP 地址:183.2.172.42)发送了10 次应答请求,并且每次都收到了它的应答消息(64 字节数据),并且没有数据丢失,说明开发板与百度服务器主机之间的网络运行、网络连接是 OK 的,也就意味着的开发板与外网是连通的。
PL 网口的外网连接测试同理。
7.3 电脑直连测试(无路由器)
在开发过程中,电脑和开发板互相访问是经常需要的,这可以通过路由器来实现,连接到同一路由器的设备是可以互相访问的,如果没有路由器,也可以使用网线将开发板 PS 网口或者 PL 网口直接连接到电脑的以太网接口上,也就是电脑直连,不过这种方式不能访问外网。
这里以 PS 网口为例,用网线将开发板的 PS 网口和电脑的以太网接口相连接。 连接好网线之后,需要设置电脑以太网的 IP地址(设置方法可以参考该视频链接:Linux 开发板网络直连电脑的设置方法)。本节设置电脑的 IP 地址如下图所示:
配置完成后,在串口终端中执行下面这些命令打开开发板的 PS 网口,并且关闭 PL 网口:
ifconfig eth1 down #关闭 PL 网口
ifconfig eth0 up #打开 PS 网口
执行下面的命令设置开发板 eth0 网口的静态 IP 地址为 192.168.1.10:
ifconfig eth0 192.168.1.10 netmask 255.255.255.0
设置完成后,开发板的 IP 地址和电脑的 IP 就在同一网段。接下来进行 Ping 测试,看开发板和电脑能不能相互 Ping 通。
首先开发板 ping 电脑,命令如下:
ping -c4 192.168.1.89
结果如下图所示:
如果 Ping 不通电脑,请关闭电脑的防火墙后再尝试。 电脑 ping 开发板。首先打开电脑的 cmd 命令提示符,然后输入如下命令:
ping -c4 192.168.1.10
结果如下:
开发板和电脑相互 Ping 通,说明双方的通信基本上没啥问题了。
八、eMMC 的使用
开发板板载 8GB eMMC,可以把 eMMC 当作固定在板子上的 SD 卡,其使用方式跟SD卡一样。接下来通过简单的读写来学习 eMMC 的使用。
由于本小节需要对 eMMC进行格式化操作,而《ZYNQ学习之Petalinux 设计流程实战》中生成的根文件系统不支持格式化命令,需要重新配置。
运行“petalinux-config -c rootfs”命令打开根文件系统配置界面,如下图:
进入“Filesystem Packages → base → e2fsprogs”选项下,勾选“e2fsprogs-mke2fs”选项,如下图所示:
配置完成后保存并退出:
重新编译工程:
petalinux-build
确认生成了image.ub文件,如下:
cd images/linux/
ls -l
将编译后生成的 image.ub 复制到 sd 卡替换原来的 image.ub 文件。
cp image.ub /media/gbxluo/boot/
ls -l /media/gbxluo/boot/
系统重新启动后,进入系统,输入“df -Th”命令,查看挂载的文件系统,如下图所示:
其中“/dev/mmcblk1p1”就是 eMMC 设备,代表 eMMC 的第一个分区,挂载在 “/media/sd-mmcblk1p1”挂载点。接下来参考《ZYNQ学习之Petalinux 设计流程实战》制作 SD 启动卡的步骤,重新将eMMC 格式化成一个分区。 分别执行下面两个命令,先从挂载点卸载 eMMC,再对 eMMC 分区,结果如下图所示:
umount /media/sd-mmcblk1p1
fdisk /dev/mmcblk1
执行后输入“p”,结果如下图所示:
可以看到 eMMC 已经有一个 p1(mmcblk1p1)分区,为了演示如何新建分区,这里我们先删除该分区。输入“d”删除第一个分区,再次输入“d”提示没有分区可以删除,如下图所示:
接下来输入“n”创建新分区,输入“p”选择创建主分区,按回车键,然后输入“1”设置分区号,接下来设置分区起始扇区,都按回车键,选择默认即可,如下图所示:
输入“p”检查分区表,可以看到新建的分区,如果没有问题,输入“w”保存并退出, 如下图所示:
分区创建完成后,就可以格式化分区了。在终端输入如下命令:
mkfs.ext4 -L rootfs /dev/mmcblk1p1
该命令将分区格式化成 ext4 分区并命名为“rootfs”,如下图所示:
如果提示该分区已经存在一个 ext4文件系统,询问是否继续,直接输入“y”并回车。
格式化完成后还需要重新挂载 eMMC 到系统,如下图所示:
mount /dev/mmcblk1p1 /media/sd-mmcblk1p1/
此时就可以对 eMMC 进行读写操作了。
echo “hello gbxluo” > /media/sd-mmcblk1p1/test.txt
cat /media/sd-mmcblk1p1/test.txt
echo “www.openedv.com” > /media/sd-mmcblk1p1/test.txt 用于在 eMMC 中创建名为 test.txt 的文本文件,并向文件中写入内容为“hello gbxluo”的文本内容,
cat /media/sd-mmcblk1p1/test.txt用于将文件中的内容打印出来,可以看到写入和读出的内容相同,如下图所示:
eMMC 的使用方式跟 SD 卡没啥区别。