版权声明

本文档所有内容文字资料由凌云实验室郭工编著,主要用于凌云嵌入式Linux教学内部使用,版权归属作者个人所有。任何媒体、网站、或个人未经本人协议授权不得转载、链接、转帖或以其他方式复制发布/发表。已经授权的媒体、网站,在下载使用时必须注明来源,违者本人将依法追究责任。

  • Copyright (C) 2021 凌云物网智科实验室·郭工

  • Author: GuoWenxue <guowenxue@gmail.com> QQ: 281143292

wechat_pub

1.1 开发板硬件介绍

IGKBoard (IoT Gateway Kit Board) 开发板凌云物网智科实验室 推出的一款ARM Linux物联网网关开发板。此开发板基于 NXP i.MX6ULL 系列 Cortex-A7 高性能处理器设计,适用于快速开发一系列具有创新性的产品如物联网网关、人机界面工业 4.0 扫描仪、车载终端以及便携式医疗设备。

IGKBoard

1.1.1 硬件资源介绍

hw_table.png

1.1.2 扩展接口说明

对于CPU未使用完的多余的管脚,通过40P引脚扩展接引出。需要注意的是,扩展 IO 第 21 脚 LCD_DATA23 不可外接上拉电阻,否则会影响系统启动。这40P引脚定义如下:

PiHeader

1.1.3 系统启动说明

i.MX6ULL处理器支持eMMC、Nandflash、SD卡等多种启动方式。IGKBoard 上板载了一颗三星公司的 8GB eMMC 存储芯片,此外在开发板背面还带有一个TF卡槽,这样该开发板支持eMMC和SD卡两种启动方式。在开发板上,J3 跳线帽子用来选择启动方式,下图描述了开发板具体启动模式。注意由于核心板上默认关闭了 WDG 功能,所以 WDG 功能无法使用跳线帽开启。

jumper_desc

由上图可知:

  • 如果想设置系统从 EMMC启动(mmc1),则将除看门狗跳线(13、14)短接以外,所有其他跳线帽子全部断开;

  • 如果想设置系统从TF卡启动(mmc0),则将 5/6、7/8、9/10、11/12 、13/14(看门狗跳线) 5个跳线全部短接;

1.2. 系统镜像烧录

1.2.1 软硬件准备

1.2.1.1 软件下载

从凌云实验室的 IGKBoard-IMX6ULL开发板软件目录 下载如下软件,并解压缩/安装相关工具软件:

download_tools

  • flashloader.zip – 板载eMMC存储系统烧录需要(解压缩即可)

  • ch341.zip – 板载CH341 USB转串口驱动(需要安装)

  • win32diskimager-1.0.0.zip – 外置TF卡槽SD卡系统烧录需要(需要安装)

然后从凌云实验室的 IGKBoard-IMX6ULL开发板系统镜像目录 下载系统镜像,这里推荐当前最新的 lf-6.1.36-2.1.0

download_images

  • u-boot-igkboard-imx6ull.imx – U-boot镜像(必须)

  • yocto-mickledore-igkboard-imx6ull.img.bz2 – Yocto 系统镜像(推荐,烧录前需解压缩)

1.2.1.2 开发板硬件连接

如下图所示,连接相关的硬件接口设置:

  • 使用 9V/1A电源(7~28V电压范围)供电,其中 黑色线为GND,红色为9V

  • 使用 TypeC线 连接开发板和PC,该接口专门用来烧录 u-boot系统镜像,Win10系统自带有其驱动;

  • 使用 USB串口调试线 连接开发板和PC,该模块使用CH340 USB转串口芯片;

hw_connect

1.2.2 EMMC系统烧录

1.2.2.1 跳线设置

如下图所示,将 J3 的除WDG以外的跳线帽子全部断开,则进入eMMC启动模式,该模式下开发板上电后将从eMMC读取运行u-boot,进而加载并启动Linux系统。

jumper_emmc

1.2.2.2 软件准备

解压下载的USB转串口驱动文件ch341安装驱动,USB转串口驱动下载并安装好后,将 USB转串口调试器 接入,使用 Win+R 快捷键打开 运行 , 然后输入 devmgmt.msc 命令打开 设备管理器 , 接下来我们应该可以看到相应的串口设备文件。如下图所示:

com_dev

接下来使用 SecureCRT 或其他串口调试软件,打开相应的USB转串口设备,并监听串口(115200,8N1,无流控):

com_scrt

1.2.2.3 烧录文件

IGKBoard开发板 当前支持 Yocto、Buildroot、Debian11 等不同的系统,编译的时候使用的文件系统不一样,生成的系统镜像文件名也不一样。这里以 Yocto 系统编译出来的镜像 yocto-mickledore-igkboard-imx6ull.img 文件为例,讲解 eMMC 系统 的烧录过程,其它的系统镜像同样也可以使用该方式来烧录。

我们将前面下载的 eMMC烧录工具软件(flashloader.zip) 解压缩出来,并把下载解压好的 U-boot 和 Yocto 系统镜像拷贝到该文件夹下:

program_files

  • flashloader.bat – Windows下的烧录批处理脚本,它将读取config.ini配置并调用 uuu.exe 命令来烧录;

  • u-boot-igkboard-6ull.imx – 目标开发板U-boot镜像文件;

  • yocto-mickledore-igkboard-imx6ull.img – 目标开发板Yocto系统镜像文件;

  • uuu.exe – NXP官方的烧录软件;

  • config.ini – 烧录脚本配置文件,主要是指定要烧录的目标开发板;

flashloader.bat 脚本可以用烧录 u-boot系统镜像 到启动介质上去,它同时支持 eMMCTF卡 烧录,只需要修改脚本里的 Media 变量值即可。

1.2.2.4 烧录模式

要想重新烧录开发板,则首先要让开发板进入到烧录模式,然后通过 USB TypeC接口烧录。不同情况下进入烧录模式不一样:

1. 硬件跳线配置

​ 硬件开发板刚生产出来或烧录了错误的 U-boot程序,需要参考 1.2.2.1节 硬件跳线设置为 升级eMMC/SD卡 进入到烧录模式,烧录完成后记得重新跳线配置为 eMMC/SD卡启动 模式这样系统才能正常启动;

2. U-boot里进入

如果已经烧录了u-boot程序,系统上电后出现 “Hit any key to stop autoboot: 3” 时按任意键进入到u-boot的 调试模式.(若没有出现,则按下开发板上的复位按键)

u-boot-dbg

在u-boot调试模式下,可以通过下面两种方式进入到开发板的烧录模式:

  • 如果开发板上烧录的是凌云实验室U-boot (该版本提供了 fastboot命令),则可以直接使用 fastboot 0 命令进入到烧录模式;

  • 如果开发板上烧录的是厂家出厂U-boot (淘宝购买的开发板预装),则需要使用 mmc dev 1 1 && mmc erase 0 40000 命令先擦除 u-boot 后再 重启开发板 进入到烧录模式;

u-boot-fb

1.2.2.5 系统烧录

上述准备工作都准备好之后,直接双击运行文件夹中的 flashloader.bat 批处理脚本将会进入系统烧录,接下来选中自己想要烧录的镜像即可:

emmc_flash

  • 在弹出的对话框中输入选择要烧录的系统镜像,开始烧录。如果一切正常,它将会开始走进度条开始烧录,烧录完成后,批处理脚本将会自动退出。

  • 如果一直等在 “Wait for Known USB Device Appear…” , 说明开发板没有进入到烧录模式,请参考前面相关章节确认开发板进入到烧录模式。如果仍然失败可以换根 USB TypeC 线试试,因为有些 TypeC 线只具有充电功能,而没有USB数据通信能力。

烧录过程中,调试串口上也将会提示相关信息。烧录完成后可以给开发板重新上电,设备将正常启动。

console_prog

1.2.2.6 系统启动

系统重新上电后,串口调试终端上将会输出U-boot的启动信息,3秒内按任意键将会进入到 U-boot 调试模式,否则将会自动启动系统。

u-boot-info

Linux系统启动后,我们可以使用用户名 root ,默认密码 12345 登录系统。如果是Yocto(Honister)系统,登录成功之后系统将会强制要求更改 root 密码。

yocto_bootup

1.2.3 外置TF卡系统烧录

1.2.3.1 跳线设置

如下图所示,将 5/6、7/8、9/10、11/12 、13/14(看门狗跳线) 5个跳线全部短接,则进入外置TF卡启动模式,该模式下开发板上电后将从TF卡读取运行u-boot,进而加载并启动Linux系统。

jumper_tf

1.2.3.2 软件准备

这里我们以 Yocto 系统编译出来的镜像 为例,详细讲解 TF卡的系统烧录过程 ,其它的镜像也都可以使用同样的方式来烧录。

yocto_image

1.2.3.3 镜像烧录

在Windows系统下,我们可以使用 USB接口的TF读卡器 配合 win32diskimager软件 来烧录前面编译制作好的系统镜像。

TFCard

写之前可以使用 SD Card Formatter 工具将 TF 卡格式化一下。

SDCardFormatter

安装并运行 Win32DiskImager 系统镜像烧录程序,选中相应的系统镜像文件和TF卡对应的分区,然后点击 写入 开始烧写系统镜像。

ImageWriter

1.2.3.4 系统启动

TF卡上系统烧录成功之后,将TF卡插入到 IGKBoard 开发板背面的TF卡槽上,设置好开发板的跳线帽子,设置从TF卡启动。开发板上电后,串口调试终端上将会输出U-boot的启动信息,3秒内按任意键将会进入到 U-boot 调试模式,否则将会自动启动Linux系统。Linux系统启动后,我们可以使用用户名 root ,默认密码 12345 登录系统。

yocto_bootup

1.3 系统配置使用

1.3.1 查看硬件信息

首先可以使用 cat /proc/cpuinfo 查看开发板上的 CPU 信息。

root@igkboard:~# cat /proc/cpuinfo
processor       : 0
model name      : ARMv7 Processor rev 5 (v7l)
BogoMIPS        : 24.00
Features        : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae
CPU implementer : 0x41
CPU architecture: 7
CPU variant     : 0x0
CPU part        : 0xc07
CPU revision    : 5

Hardware        : Freescale i.MX6 Ultralite (Device Tree)
Revision        : 0000
Serial          : 5d6acf50183eb9d7

在嵌入式开发过程中,实时了解内存信息非常重要。这里我们经常会使用 freetop 命令查看内存的当前使用情况。

root@igkboard:~# free -h
               total        used        free      shared  buff/cache   available
Mem:           486Mi        63Mi       382Mi       9.4Mi        61Mi       423Mi
Swap:             0B          0B          0B

root@igkboard:~# top
top - 03:07:51 up 11:34,  3 users,  load average: 0.31, 0.25, 0.19
Tasks:  91 total,   1 running,  90 sleeping,   0 stopped,   0 zombie
%Cpu(s): 50.0 us, 50.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
MiB Mem :    486.9 total,    382.2 free,     63.8 used,     61.6 buff/cache
MiB Swap:      0.0 total,      0.0 free,      0.0 used.    423.1 avail Mem

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
 3056 root      20   0    5088   3412   1564 R  15.8   0.7   0:00.08 top
    1 root      20   0   27792   7076   5332 S   0.0   1.4   0:16.86 systemd
    2 root      20   0       0      0      0 S   0.0   0.0   0:00.05 kthreadd

另外也可以通过 /proc/meminfo 文件,查看内存的详细情况。

root@igkboard:~# cat /proc/meminfo
MemTotal:         498556 kB
MemFree:          391356 kB
MemAvailable:     433284 kB
Buffers:           13624 kB
Cached:            41784 kB
SwapCached:            0 kB
Active:            32784 kB
Inactive:          41432 kB
Active(anon):       1232 kB
Inactive(anon):    27256 kB
Active(file):      31552 kB
Inactive(file):    14176 kB
Unevictable:           0 kB
Mlocked:               0 kB
HighTotal:             0 kB
HighFree:              0 kB
LowTotal:         498556 kB
LowFree:          391356 kB
SwapTotal:             0 kB
SwapFree:              0 kB
Dirty:                 0 kB
Writeback:             0 kB
AnonPages:         18808 kB
Mapped:            19244 kB
Shmem:              9680 kB
KReclaimable:       7732 kB
Slab:              20112 kB
SReclaimable:       7732 kB
SUnreclaim:        12380 kB
KernelStack:         736 kB
PageTables:          888 kB
SecPageTables:         0 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:      249276 kB
Committed_AS:      92444 kB
VmallocTotal:    1556480 kB
VmallocUsed:        3704 kB
VmallocChunk:          0 kB
Percpu:              144 kB
CmaTotal:         163840 kB
CmaFree:          162476 kB

很多时候,我们希望知道开发板上运行上的是哪个版本的 Linux内核或处理器架构,这个可以通过 uname 命令来获取。

root@igkboard:~# uname -a
Linux igkboard 6.1.36-dirty #2 SMP PREEMPT Sun Apr 14 18:13:37 CST 2024 armv7l GNU/Linux

root@igkboard:~# uname -r
6.1.36-dirty

root@igkboard:~# uname -m
armv7l

如果想知道我们的 eMMC/TF卡 存储系统的使用情况,则可以使用 df -h 命令来查看。

root@igkboard:~# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/root       7.0G  979M  5.8G  15% /
devtmpfs        163M  4.0K  163M   1% /dev
tmpfs           244M     0  244M   0% /dev/shm
tmpfs            98M  8.9M   89M  10% /run
tmpfs           4.0M     0  4.0M   0% /sys/fs/cgroup
tmpfs           244M  4.0K  244M   1% /tmp
tmpfs           244M  660K  243M   1% /var/volatile
/dev/mmcblk1p1   95M  9.1M   86M  10% /run/media/mmcblk1p1
tmpfs            49M     0   49M   0% /run/user/0

1.3.2 根文件系统扩容

在 IGKBoard-IMX6ULL 开发板板载的是 8GB eMMC,如果是 TF 卡启动那 TF卡的容量就是大家所购买的TF卡大小。但系统上电后,使用 df -h 命令查看,却发现根文件系统只有 2.8GB的存储空间。这是因为我们在制作系统镜像时默认将根分区只做了3GB,这样系统镜像会小很多,烧录也会快一些。

expand_rootfs1

下图是我们制作的系统镜像分区表:

sd_partition

  • Bootloader 从eMMC/TF卡 0 地址开始的一段存储空间必须保留给Bootloader(U-boot)。这是因为如果设置系统从 eMMC 或 TF 卡启动的话,i.MX6ULL CPU在上电后将会从第 2 个扇区以RAW格式读取U-boot程序并启动,所以该分区不能有文件系统,其大小为10MB

  • Boot Partition 该分区用来存储 Linux内核、设备树以及相关的系统启动配置文件。如果像树莓派一样从 TF 卡启动的话,我们可以将其从开发板上取下并使用TF卡读卡器放到 Windows系统下来更新,所以该分区采用 Windows 所能识别的 FAT32 文件系统,其大小为 100MB。其默认挂载到系统的 /run/media/mmcblkp1 路径下;

  • Rootfs Partition 这个分区是Linux系统的根分区(Root File System),它里面用来存放Linux系统所有的程序、命令、动态库、系统配置文件等,其默认挂载到根路径下(/)。该分区的默认大小随着系统镜像的大小动态调整,但 eMMC/TF 卡所有剩余空间全部保留给该分区

在了解到上述背景知识后,我们在 IGKBoard 系统镜像中,参考树莓派写了个 expand_rootfs 的 Shell 脚本,该脚本可以用来将根文件系统分区一键扩容。关于实现的内部机制和原理,大家可以学习该脚本的相关内容。

expand_rootfs2

1.3.3 40Pin接口管理

IGKBoard开发板上提供树莓派兼容的40Pin 扩展引脚,这些引脚默认作为 GPIO 功能使用。如果想作为其它功能(如I2C、SPI、CAN、UART、PWM等)使用,则需要修改 Boot(FAT32) 分区下的 config.txt 配置文件。在开发板上使用 pinctrl -v 命令可以查看各引脚的功能定义。如下图所示:

PiHeader2

接下来我们将介绍如何使能 40Pin 上的各个功能引脚。首先使用 mount 命令确认系统已自动挂载了Boot分区到相应路径下。

root@igkboard:~# mount | grep mmcblk
/dev/mmcblk1p2 on / type ext4 (rw,relatime)
/dev/mmcblk1p1 on /run/media/mmcblk1p1 type vfat (rw,relatime,gid=6,...,errors=remount-ro)

需要注意的是,如果是使用板载的 eMMC 启动,则相应分区对应的设备为 /dev/mmcblk1p1;而如果使用的是外置的 TF 卡启动,其所对应的设备则为 /dev/mmcblk0p1。这是因为TF卡接口接到了 usdhc1 接口上,而 eMMC 卡则接到了 usdhc2 上。

如果系统上电并没有自动挂载起来,则需要手动创建挂载点并将其挂载起来。

root@igkboard:~# mount | grep mmcblk
/dev/mmcblk1p2 on / type ext4 (rw,relatime)

root@igkboard:~# mkdir -p /run/media/mmcblk1p1/

root@igkboard:~# mount /dev/mmcblk1p1 /run/media/mmcblk1p1/

root@igkboard:~# ls /run/media/mmcblk1p1/
config.txt  igkboard-imx6ull.dtb  overlays  zImage

接下来我们就可以修改 /run/media/mmcblk1p1/ 路径下的 config.txt 文件。其配置文件如下:

root@igkboard:~# cat /run/media/mmcblk1p1/config.txt
# Enable LCD overlay
#dtoverlay_lcd=yes

# Enable Camera overlay
#dtoverlay_cam=yes

# Eanble 1-Wire overlay
dtoverlay_w1=yes

# Enable ADC overlay
#dtoverlay_adc=yes

# Enable I2C overlay
dtoverlay_i2c=1

# Enable SPI overlay, SPI1 conflict with UART8(NB-IoT/4G module)
dtoverlay_spi=1

# Enable UART overlays
dtoverlay_uart=2 3 4 7

# Enable CAN overlays
#dtoverlay_can=1 2

# Enable PWM overlays, PWM8 conflict with UART8(NB-IoT/4G module)
#dtoverlay_pwm=7

# Enable extra overlays
#dtoverlay_extra=nbiot-4g

在此配置文件中,# 表示注释,如果想使能相应功能,则需要将行首的 # 去掉。

  • 如果想使能 LCD 触摸屏 支持,去掉 dtoverlay_lcd=yes 行首的注释;

  • 如果想使能 MIPI-CSI 摄像头 支持,去掉 dtoverlay_cam=yes 行首的注释;

  • 如果想使能 DS18B20 传感器 (默认使能),则去掉 dtoverlay_w1=yes 行首的注释,此时物理编号#7引脚将作为一线协议使用;

  • 如果想支持 ADC接口,则去掉 dtoverlay_adc=yes 行首的注释。此时 GPIO1_IO01GPIO1_IO04 两个引脚将作为 ADC功能使用。需要注意的是,这两个引脚也是触摸屏的 ADC 引脚,所以它会与触摸屏冲突;

  • 如果想使能 I2C接口 (默认使能),则去掉 dtoverlay_i2c=1 行首的注释;

  • 如果想使能 SPI接口 (默认使能),则去掉 dtoverlay_spi=1 行首的注释;

  • 如果想使能 UART接口 (默认全部使能),则去掉 dtoverlay_uart=2 3 4 7 行首的注释。如果想只使能部分 UART 接口,则可以修改为 ``dtoverlay_uart=2 3`,这样将只使能 UART2 和 UART3,另外两路 UART 将会作为普通 GPIO口使用;

  • 如果想使能 CAN接口,则去掉 dtoverlay_can=1 2 行首的注释;

  • 如果想使能 PWM接口,则去掉 dtoverlay_pwm=7 行首的注释。需要注意的是,开发板上有两路 PWM(pwm7/pwm8),其中PWM8 会与 NB-IoT/4G 模块所用的 UART8 冲突。

  • 如果想使能 NB-IoT/4G模块,则去掉 dtoverlay_extra=nbiot-4g 行首的注释。需要注意的是,它将会与 40Pin引脚上的 PWM8 冲突。

在修改完上述配置文件后,需要使用 reboot 命令将开发板重启才能生效。这样系统重新启动时,U-boot 会读取 config.txt 配置,然后加载相应的 dtoverlay 文件,使能相应的硬件接口。

1.3.4 有线网络配置

在 IGKBoard上有提供两个百兆以太网卡,系统上电后会默认使用 DHCP 动态获取IP地址。如果我们希望使用 SSH2 远程登录到开发板上来工作时,则需要静态配置IP地址,否则每次重启之后IP地址可能变了。另外,我们也清楚,如果使用 ifconfigrouteip 等命令来配置修改IP地址,它只是临时生效,系统重启后,这些修改就全部没有了。

很显然,要想网络配置永久生效,那我们就必须将相关的网络配置保存到系统的配置文件中去。接下来我们以 Yocto 系统镜像为例讲解开发板上的有线网卡配置,不同系统(Debian、Ubuntu等)的配置方式可能不同。

在 Yocto 系统中,系统的网络由 systemd-networkd 服务管理,其默认配置文件在 /lib/systemd/network//etc/systemd/network/ 路径下。之所以我们的开发板上电后就能自动获取IP地址,这是由 /lib/systemd/network/80-wired.network 配置文件决定。

root@igkboard:~# cat /lib/systemd/network/80-wired.network
[Match]
Type=ether
Name=!veth*
KernelCommandLine=!nfsroot
KernelCommandLine=!ip

[Network]
DHCP=yes

[DHCP]
UseMTU=yes
RouteMetric=10
ClientIdentifier=mac

那如果想要静态配置某个网卡的IP地址,该如何配置呢?这里以 eth1 网卡为例,我们可以在 /etc/systemd/network 路径下创建下一个名为 02-eth1.network 的配置文件,其内容如下:

root@igkboard:~# vi /etc/systemd/network/02-eth1.network
[Match]
Name=eth1

[Network]
Address=192.168.2.169/24
Gateway=192.168.2.1
DNS=114.114.114.114

修改好后,使用 systemctl 命令重启 systemd-networkd 服务即可。

root@igkboard:~# systemctl restart systemd-networkd

接下来,我们使用 ifconfig 命令可以看到 eth1 网卡的IP地址已经被设置为前面配置的静态IP地址了。

root@igkboard:~# ifconfig eth1
eth1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.2.169  netmask 255.255.255.0  broadcast 192.168.2.255
        inet6 fe80::460:58ff:fe50:3ed7  prefixlen 64  scopeid 0x20<link>
        ether 06:60:58:50:3e:d7  txqueuelen 1000  (Ethernet)
        RX packets 8891  bytes 1000027 (976.5 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 3026  bytes 278271 (271.7 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
        
root@igkboard:~# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.2.1     0.0.0.0         UG    0      0        0 eth1
192.168.2.0     0.0.0.0         255.255.255.0   U     0      0        0 eth1        

另外,我们也可以使用 ping 命令测试一下网络的连通性。

root@igkboard:~# ping 4.2.2.2 -c 4
PING 4.2.2.2 (4.2.2.2) 56(84) bytes of data.
64 bytes from 4.2.2.2: icmp_seq=1 ttl=54 time=209 ms
64 bytes from 4.2.2.2: icmp_seq=2 ttl=54 time=231 ms
64 bytes from 4.2.2.2: icmp_seq=3 ttl=54 time=141 ms
64 bytes from 4.2.2.2: icmp_seq=4 ttl=54 time=141 ms

--- 4.2.2.2 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3005ms
rtt min/avg/max/mdev = 141.103/180.625/231.401/40.191 ms

如果想要使用 DHCP 动态获取IP地址,则可以配置文件如下,并重启服务即可。

root@igkboard:~# vi /etc/systemd/network/02-eth1.network
[Match]
Name=eth1

[Network]
DHCP=yes

root@igkboard:~# systemctl restart systemd-networkd

1.3.5 无线网络配置

在 IGKBoard-IMX6ULL 开发板上板载有无线网卡,早期版本板载的芯片为 RTL8188FU WiFi模块,新版本的开发板则板载 RTL8723DU WiFi/蓝牙 无线模块。在我们的Yocto系统镜像中,已经添加了这两个无线网卡的驱动,系统上电后也会自动加载相应的网卡驱动。

root@igkboard:~# lsmod
Module                  Size  Used by
rtw_8723du             16384  0
rtw_8723d              45056  1 rtw_8723du
rtw_usb                20480  1 rtw_8723du
rtw_8723x              20480  1 rtw_8723d
rtw_core              217088  3 rtw_usb,rtw_8723d,rtw_8723x
secvio                 16384  0
error                  20480  1 secvio

开发板刚烧录好上电后,WiFi 网卡默认是禁用的。此时使用 ifconfig 命令并不能看到该网卡,而使用 ifconfig -a 则可以看到当前系统中所有的网卡,包括被禁用的网卡。如下面的 wlan0 就是我们的第一张无线网卡。

root@igkboard:~# ifconfig -a   
eth0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        ether 72:aa:e4:6c:0d:db  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

eth1: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        ether d6:e0:c0:34:d2:53  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 14  bytes 1838 (1.7 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 14  bytes 1838 (1.7 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

sit0: flags=128<NOARP>  mtu 1480
        unspec 00-00-00-00-00-00-08-F7-00-00-00-00-00-00-00-00  txqueuelen 1000  (UNSPEC)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

wlan0: flags=4098<BROADCAST,MULTICAST>  mtu 1500
        ether 00:95:69:8f:96:5a  txqueuelen 1000  (Ethernet)
        RX packets 149  bytes 71701 (70.0 KiB)
        RX errors 0  dropped 39  overruns 0  frame 0
        TX packets 32  bytes 4978 (4.8 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

要想使用无线网卡上网,则首先要使用下面命令使能该网卡。

root@igkboard:~# ifconfig wlan0 up

1.3.5.1 手动联网配置

在 Windows系统下,我们要实现无线上网需要扫描并找到要连接的无线热点,然后再点击连接并输入密码实现无线连接。而在 Linux 或 安卓系统中,通常是由 wpa_supplicant 命令来实现,下面是该命令的使用方法。

root@igkboard:~# wpa_supplicant -h
wpa_supplicant v2.10
Copyright (c) 2003-2022, Jouni Malinen <j@w1.fi> and contributors

This software may be distributed under the terms of the BSD license.
See README for more details.

This product includes software developed by the OpenSSL Project
for use in the OpenSSL Toolkit (http://www.openssl.org/)

usage:
  wpa_supplicant [-BddhKLqqstuvW] [-P<pid file>] [-g<global ctrl>] \
        [-G<group>] \
        -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] [-p<driver_param>] \
        [-b<br_ifname>] [-e<entropy file>] [-f<debug file>] \
        [-o<override driver>] [-O<override ctrl>] \
        [-N -i<ifname> -c<conf> [-C<ctrl>] [-D<driver>] \
        [-m<P2P Device config file>] \
        [-p<driver_param>] [-b<br_ifname>] [-I<config file>] ...]

drivers:
  nl80211 = Linux nl80211/cfg80211
  wext = Linux wireless extensions (generic)
  wired = Wired Ethernet driver
  macsec_linux = MACsec Ethernet driver for Linux
options:
  -b = optional bridge interface name
  -B = run daemon in the background
  -c = Configuration file
  -C = ctrl_interface parameter (only used if -c is not)
  -d = increase debugging verbosity (-dd even more)
  -D = driver name (can be multiple drivers: nl80211,wext)
  -e = entropy file
  -f = log output to debug file instead of stdout
  -g = global ctrl_interface
  -G = global ctrl_interface group
  -h = show this help text
  -i = interface name
  -I = additional configuration file
  -K = include keys (passwords, etc.) in debug output
  -L = show license (BSD)
  -m = Configuration file for the P2P Device interface
  -N = start describing new interface
  -o = override driver parameter for new interfaces
  -O = override ctrl_interface parameter for new interfaces
  -p = driver parameters
  -P = PID file
  -q = decrease debugging verbosity (-qq even less)
  -s = log output to syslog instead of stdout
  -t = include timestamp in debug messages
  -u = enable DBus control interface
  -v = show version
  -W = wait for a control interface monitor before starting
example:
  wpa_supplicant -Dnl80211 -iwlan0 -c/etc/wpa_supplicant.conf

那要连接的 WiFi 和 密码该怎么设定呢?通常我们会将他们保存在一个叫做 wpa_supplicant.conf 的配置文件中,其格式和内容如下:

root@igkboard:~# vi /etc/wpa_supplicant.conf
country=CN
ctrl_interface=/var/run/wpa_supplicant
update_config=1

network={
    ssid="Router_Home"
    scan_ssid=1
    psk="password"
    key_mgmt=WPA-PSK
}
  • ssid 为要连接的无线路由器或热点的 SSID;

  • psk 为无线路由器或热点的连接密码;

接下来运行下面命令就可以实现无线网络的连接了。

root@igkboard:~# wpa_supplicant -B -iwlan0 -c /etc/wpa_supplicant.conf
Successfully initialized wpa_supplicant
rfkill: Cannot open RFKILL control device
  • -B 选项表示放到后台(Backgroud)运行,如不加该选项,此命令将会一直占据命令终端了;

  • -c 选项用来指定无线网络的配置文件;

在Windows下我们可以通过系统右下角图标查看WiFi是否连接上,而在 Linux 系统下则通过 iwconfig 命令查看是否连上。如下面结果显示 ESSID 为前面我配置要连接的路由器 “Router_Home”,由此可见已经连上该路由器了。

root@igkboard:~# iwconfig wlan0
wlan0     IEEE 802.11  ESSID:"Router_Home"
          Mode:Managed  Frequency:2.427 GHz  Access Point: 80:CC:9C:27:F6:F5
          Bit Rate=72.2 Mb/s   Tx-Power=20 dBm
          Retry short limit:7   RTS thr:off   Fragment thr:off
          Encryption key:off
          Power Management:on
          Link Quality=70/70  Signal level=-34 dBm
          Rx invalid nwid:0  Rx invalid crypt:0  Rx invalid frag:0
          Tx excessive retries:0  Invalid misc:0   Missed beacon:0

接下来,我们使用 ifconfig 命令却发现无线网卡并没有获取到 IP 地址,这是因为连接无线路由器(登录认证)与 配置IP地址(网络配置)是两个完全不同的功能。

wlan0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet6 fe80::4a8f:4cff:fece:380c  prefixlen 64  scopeid 0x20<link>
        ether 48:8f:4c:ce:38:0c  txqueuelen 1000  (Ethernet)
        RX packets 916  bytes 124938 (122.0 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 212  bytes 25789 (25.1 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

如果我们想要 DHCP 动态获取 IP地址,那可以使用 udhcpc 命令来实现。

root@igkboard:~# udhcpc -i wlan0
udhcpc: started, v1.36.1
Dropped protocol specifier '.udhcpc' from 'wlan0.udhcpc'. Using 'wlan0' (ifindex=5).
udhcpc: broadcasting discover
udhcpc: broadcasting select for 192.168.2.113, server 192.168.2.1
udhcpc: lease of 192.168.2.113 obtained from 192.168.2.1, lease time 86400
/etc/udhcpc.d/50default: Adding DNS 192.168.2.1
Dropped protocol specifier '.udhcpc' from 'wlan0.udhcpc'. Using 'wlan0' (ifindex=5).

此时再使用 ifconfigroute 命令分别可以查看获取到的 IP 地址、子网掩码和默认网关等信息。

root@igkboard:~# ifconfig wlan0
wlan0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.2.113  netmask 255.255.255.0  broadcast 192.168.2.255
        inet6 fe80::4a8f:4cff:fece:380c  prefixlen 64  scopeid 0x20<link>
        ether 48:8f:4c:ce:38:0c  txqueuelen 1000  (Ethernet)
        RX packets 949  bytes 128040 (125.0 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 235  bytes 29579 (28.8 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

root@igkboard:~# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.2.1     0.0.0.0         UG    0      0        0 eth1
0.0.0.0         192.168.2.1     0.0.0.0         UG    10     0        0 wlan0
192.168.2.0     0.0.0.0         255.255.255.0   U     0      0        0 eth1
192.168.2.0     0.0.0.0         255.255.255.0   U     0      0        0 wlan0

现在我们可以使用 ping 命令测试 Internet 的连接性,其中 -I 选项用来使用指定的网卡做ping命令测试,而 -c 选项表示只发送 4 个ping报文。

root@igkboard:~# ping 4.2.2.2 -I wlan0 -c 4
PING 4.2.2.2 (4.2.2.2) from 192.168.2.113 wlan0: 56(84) bytes of data.
64 bytes from 4.2.2.2: icmp_seq=1 ttl=54 time=234 ms
64 bytes from 4.2.2.2: icmp_seq=2 ttl=54 time=153 ms
64 bytes from 4.2.2.2: icmp_seq=3 ttl=54 time=176 ms
64 bytes from 4.2.2.2: icmp_seq=4 ttl=54 time=198 ms

--- 4.2.2.2 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3005ms
rtt min/avg/max/mdev = 153.430/190.364/233.632/29.623 ms

接下来使用 reboot 重启一下开发板,登录后可以看到前面配置的 WiFi联网都失效了。

root@igkboard:~# reboot

1.3.5.2 自动联网配置

显然,如果想要WiFi上电后就自动连接无线路由器并配置网络上网,则需要将这些联网配置保存到根文件系统上(TF卡或eMMC中)。这时,在我们的Yocto系统镜像中,只需要在 /etc/wpa_supplicant/ 路径下下创建相应无线网卡的配置文件,并使能 wpa-conf 服务,即可实现无线网卡的联网工作。其配置文件如下:

root@igkboard:~# mkdir -p /etc/wpa_supplicant/

root@igkboard:~# vi /etc/wpa_supplicant/wpa_supplicant-wlan0.conf
country=CN
ctrl_interface=/var/run/wpa_supplicant
update_config=1

network={
    ssid="Router_Home"
    scan_ssid=1
    psk="password"
    key_mgmt=WPA-PSK
}
  • ssid 为要连接的无线路由器或热点的 SSID;

  • psk 为无线路由器或热点的连接密码;

创建好后后,使用 systemctl 命令启动 wpa-conf 服务。

root@igkboard:~# systemctl enable --now wpa-conf

过一会后,我们就可以看到无线网卡连上我们的无线路由器了。

root@igkboard:~# iwconfig wlan0
wlan0     IEEE 802.11  ESSID:"Router_Home"
          Mode:Managed  Frequency:2.427 GHz  Access Point: 80:CC:9C:27:F6:F5
          Bit Rate=72.2 Mb/s   Tx-Power=20 dBm
          Retry short limit:7   RTS thr:off   Fragment thr:off
          Encryption key:off
          Power Management:on
          Link Quality=70/70  Signal level=-36 dBm
          Rx invalid nwid:0  Rx invalid crypt:0  Rx invalid frag:0
          Tx excessive retries:0  Invalid misc:0   Missed beacon:0

同样地,我们使用 ifconfig 命令并不能看到其 IP 地址。

root@igkboard:~# ifconfig wlan0
wlan0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet6 fe80::4a8f:4cff:fece:380c  prefixlen 64  scopeid 0x20<link>
        ether 48:8f:4c:ce:38:0c  txqueuelen 1000  (Ethernet)
        RX packets 58  bytes 8390 (8.1 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 29  bytes 4452 (4.3 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

参考前面有线网络的配置,我们在 /etc/systemd/network/ 路径下创建无线网卡的网络配置文件 03-wlan0.network 如下,这里使用 DHCP 协议动态获取 IP 地址。如果想要静态配置其 IP 地址,可以参考前面有线网络的配置来修改。

root@igkboard:~# vi /etc/systemd/network/03-wlan0.network
[Match]
Name=wlan0

[Network]
DHCP=yes

接下来重启 systemd-networkd 服务。

root@igkboard:~# systemctl restart systemd-networkd

接下来再使用 ifconfig 命令就可以看到无线网卡获取到 IP 地址了。

root@igkboard:~# ifconfig wlan0
wlan0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.2.113  netmask 255.255.255.0  broadcast 192.168.2.255
        inet6 fe80::4a8f:4cff:fece:380c  prefixlen 64  scopeid 0x20<link>
        ether 48:8f:4c:ce:38:0c  txqueuelen 1000  (Ethernet)
        RX packets 122  bytes 18202 (17.7 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 47  bytes 7790 (7.6 KiB)

        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

接下来我们使用 reboot 命令重启开发板,上电后发现无线网卡会自动连接无线路由器并获取到IP地址了。

root@igkboard:~# reboot

1.3.6 NTP时间同步

有些时候,嵌入式设备出于成本考虑并没有配备RTC芯片,这样我们只能 NTP协议使用网络同步时间。这里我们可以使用 systemd 服务里自带的 NTP 同步功能来实现网络授时。此时只需要修改其配置文件中的 NTP 服务器地址,并开启NTP服务(/lib/systemd/system/systemd-timesyncd.service),它将会自动同步网络时间。

root@igkboard:~# vi /etc/systemd/timesyncd.conf
... ...

[Time]
NTP=pool.ntp.org
...

root@igkboard:~# systemctl start --now systemd-timesyncd