基于NVIDIA®Jetson AGX Xavier™的Quectel EC200A 4G USB Dongle模块Linux驱动的移植
1. 项目背景
使用Quectel移远EC200A型号的4G模块给NVIDIA® Jetson AGX Xavier™平台添加移动网络。
(1)硬件平台介绍
- NVIDIA® Jetson AGX Xavier™嵌入式平台,如图1左;
- Quectel EC200A 4G USB Dongle通信模块,如图1右。
(2)编译平台和工具
- 系统版本:Ubuntu 20.04.5 LTS
- 编译工具:aarch64-linux-gnu-gcc 9.4.0
本文是在目标设备AGX(arm64/aarch64)上配置并编译Linux驱动,也可以在x64架构的电脑主机上采用交叉编译方式进行配置。如果采用交叉编译的方式则推荐使用的交叉编译工具链为aarch64-linux-gnu-gcc 7.3.1 (Linaro GCC 7.3-2018.05),下载地址:Linaro Releases
2. 准备材料和知识
(1)AGX内核源码
NVIDIA Jetson AGX系列是专为嵌入式人工智能应用而设计的开发板,它具有自己特定的硬件架构和外设。为了适配硬件平台,我们不能使用普通的kernel内核源码。
根据AGX的Linux内核版本,在NVIDIA官网下载对应的Linux内核源码。
1 | mv@ubuntu:~$ uname -a |
这里使用的AGX版本是R35,内核版本是Linux 5.10.104。于是在NVIDIA DEVELOPER下载中心(需要注意的是NVIDIA开发者的.cn网站不提供下载页面,访问后提示找不到页面,这里给出的是NVIDIA开发者.com的网站:Jetson Download Center | NVIDIA Developer)搜索kernel,并选择对应的版本(R35.1),如图2所示。点击下载跳转到对应的下载页面,如图3所示。
现在NVIDIA产品套件的源码是打包在一起的,也就是图3中对应的红框部分${\color{red} \textbf{Driver Package (BSP) Sources}}$。这里我们也可以使用NVIDIA提供的交叉编译工具链aarch64-buildroot-linux-gnu-gcc 9.3(如图3中橙色线框,Bootlin Toolchain gcc 9.3)进行交叉编译。
下载图3中对应的红框部分Driver Package (BSP) Sources后得到public_sources.tbz2。在${\color{orange} \textbf{[DECOMPRESS_OUT] /Linux_for_Tegra/source/public/}}$文件夹内找到kernel_src.tbz2,这就是AGX所使用kernel内核源码文件。将内核源码解压到普通用户目录下的某个文件夹内,便于后续添加USB驱动代码,内核源码解压后的文件如图4所示。
图4中显示的内核源码解压文件,后续我们主要会使用其中的${\color{green} \textbf{[KERNEL_SRC] /kernel/kernel-5.10/}}$ 这个文件夹及其内的源文件。
(2)4G模块EC200A驱动
Quectel EC200A_CN型号的4G模块只需用到USB接口,没有使用RJ45(8P8C)网络接口。于是仅需配置EC200A在Linux系统下的USB驱动即可,无需配置GobiNet驱动和QMI驱动。${\color{skyblue} \textbf{因为GobiNet驱动和QMI驱动是与网卡相关的驱动}}$。因此,这里我们主要移植4G模块在Linux系统下的USB驱动。
3. 移植USB驱动代码
参考Quectel官方提供的《Quectel LTE&5G Linux USB Driver User Guide V2.0.pdf》文件配置USB驱动。
(1)查询4G模块的VID和PID信息
将4G模块的USB口连接到AGX上,在AGX平台使用命令行 lsusb 查询当前设备中所有的USB信息,如下图5所示。从图5中,我们可以看到EC200A模块的 [VID:PID] 为 [2C7C:6005] 。
(2)添加USB驱动代码
A. 修改 [KERNEL_SRC] /kernel/kernel-5.10/drivers/usb/serial/option.c 文件
(i) 添加VID和PID
在option.c文件中的static const struct usb_device_id option_ids[] 中添加设备的VID和PID,如图所示6。
1 | static const struct usb_device_id option_ids[] = { |
(ii) 添加掉电恢复机制
在option.c文件中的static struct usb_serial_driver option_1port_device 中添加掉电恢复机制,如图7所示。
1 | static struct usb_serial_driver option_1port_device = { |
B. 修改 [KERNEL_SRC] /kernel/kernel-5.10/drivers/usb/serial/usb_wwan.c 文件
(·) 添加零包机制
在usb_wwan.c文件中的static struct urb *usb_wwan_setup_urb() 中添加休眠唤醒机制,如图8所示。
1 | static struct urb *usb_wwan_setup_urb(struct usb_serial_port *port, |
C. 配置并编译内核
进入并在 [KERNEL_SRC] /kernel/kernel-5.10/ 目录下进行内核编译。
1 | mkdir ../../kernel_out |
在 [KERNEL_SRC] / 目录下建立了名为 kernel_out 的编译输出文件夹,并导入编译工具链。
接着配置编译选项,如下:
1 | sudo make ARCH=arm64 O=$TEGRA_KERNEL_OUT menuconfig |
在弹出的menuconfig中配置编译输出选项,这里推荐将USB驱动编译成模块(m),便于移植和加载。
1 | [ ] Device Drivers → |
需要注意的是,按照Quectel官方提供的《Quectel LTE&5G Linux USB Driver User Guide V2.0.pdf》中的menuconfig设置后,无法生成独立的.ko文件。它的做法是将驱动模块文件编译进Linux内核中(y),而不是模块化(m)编译生成独立的驱动模块文件(.ko文件)。
最后就可以编译内核了,这里使用的AGX的CPU核心数为8。
1 | sudo make ARCH=arm64 O=$TEGRA_KERNEL_OUT -j8 |
成功编译完成后,有如下输出显示,如图9所示。
D. 移植驱动文件(.ko文件)
在编译输出的kernel_out文件夹中,${\color{orange} \textbf{[kernel_out] /drivers/usb/serial/}}$ 文件夹中找到生成的option.ko,usb_wwan.ko 和 qcserial.ko 文件,并将这些文件复制到AGX的驱动文件夹中。
1 | sudo cp option.ko /usr/lib/modules/5.10.104-tegra/kernel/drivers/usb/serial |
完成后,加载.ko驱动模块并重启。
1 | sudo depmod -a |
4. 驱动测试
(1)驱动查看
重启后,接入4G模块并查看查看驱动加载情况。
1 | sudo modprobe usbmon // 加载usbmon驱动模块 |
如果编译无误,则会出现如图10和11所示的情况。如果没有,则需要考虑重新编译。
(2)串口测试
接着我们使用串口调试工具minicom连接ttyUSB1,尝试对4G模块发送AT指令,测试结果如图12所示。
1 | sudo minicom -c on |
图12中,可以看到AGX检测到4G模块并且成功识别了中国移动SIM卡。
(3)实物测试
将AGX连接显示屏后,发现在连接4G模块后会多出一个移动网络的标识符,如图13左所示。使用ping命令发现也可以连通,驱动移植成功。
参考文献
[1] 移植EC20F 4G模块驱动基于Jetson-xavier-CSDN博客.
[2] 基于Xavier 移植移远EG25G 4G模块-CSDN博客.
[3] 移远EC20 4G模块Linux驱动移植和测试_ec25 4g模块驱动-CSDN博客.
[4] 4G模块 EC20 R2.0 USB Serial/GobiNet/QMI WWAN 驱动移植过程_qmi_wwan-CSDN博客.