1. 环境准备与驱动源码获取
最近在RK3588的ELF 2开发板上折腾CH341 USB转串口模块时,发现系统默认没有这个驱动。Ubuntu 22.04系统虽然对硬件支持已经很完善,但遇到这种小众芯片还是得自己动手。好在整个过程比想象中简单,实测下来从编译到加载成功只用了不到半小时。
首先需要准备好交叉编译环境。因为RK3588是ARM64架构,而我们通常是在x86电脑上开发,所以必须使用交叉编译工具链。ELF 2开发板配套的SDK里已经包含了完整的工具链,路径一般在prebuilts/gcc/linux-x86/aarch64/目录下。我用的版本是gcc-arm-10.3-2021.07,这个要和内核版本匹配。
驱动源码可以从几个渠道获取:
- 官方GitHub仓库(https://github.com/juliagoda/CH341SER)
- 内核源码树中的drivers/usb/serial目录(如果内核版本较新)
- 第三方维护的驱动包
我建议直接用官方仓库的代码,因为更新更稳定。下载后解压到虚拟机里,建议放在和内核源码同级的目录,方便后续编译。解压后的目录结构大致是这样的:
ch341_driver/ ├── ch341.c ├── Makefile ├── readme.txt └── ...2. 内核配置与交叉编译
2.1 内核头文件准备
编译驱动最关键的是内核配置要正确。很多人在这一步踩坑,就是因为内核配置不匹配。ELF 2开发板的内核源码通常随SDK一起提供,路径类似/home/user/elf/work/ELF2-linux-source/kernel。
首先确认内核已经编译过,并且.config文件存在。如果之前清理过编译中间文件,可能需要重新编译内核:
cd /path/to/kernel/source make ARCH=arm64 CROSS_COMPILE=aarch64-none-linux-gnu- elf2_defconfig make ARCH=arm64 CROSS_COMPILE=aarch64-none-linux-gnu- -j82.2 修改驱动Makefile
驱动目录里的Makefile需要针对开发板环境进行修改。这是我调整后的版本:
CONFIG_MODULE_SIG=n KERNELDIR := /home/yyn/elf/work/ELF2-linux-source/kernel PWD := $(shell pwd) obj-m := ch341.o build: kernel_modules kernel_modules: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules \ ARCH=arm64 \ CROSS_COMPILE=/home/yyn/elf/work/ELF2-linux-source/prebuilts/gcc/linux-x86/aarch64/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu- clean: $(MAKE) -C $(KERNELDIR) M=$(PWD) clean关键参数说明:
KERNELDIR:指向开发板内核源码路径CROSS_COMPILE:指定交叉编译工具链前缀ARCH=arm64:指定目标架构CONFIG_MODULE_SIG=n:禁用模块签名验证(开发阶段建议关闭)
2.3 执行交叉编译
进入驱动目录执行编译:
make clean make如果一切顺利,会在当前目录生成ch341.ko文件。常见的编译错误及解决方法:
- 找不到内核头文件:检查KERNELDIR路径是否正确
- 函数未定义:可能是内核配置选项没开,需要重新配置内核
- 类型不匹配:驱动代码和内核版本不兼容,需要调整代码
3. 驱动部署与测试
3.1 手动加载驱动
将编译好的.ko文件拷贝到开发板,可以通过scp或者U盘:
scp ch341.ko user@192.168.x.x:/home/user/在开发板上加载驱动:
sudo insmod ch341.ko dmesg | grep ch341 # 查看内核日志 ls /dev/tty* # 检查设备节点如果看到/dev/ttyUSB0之类的设备,说明驱动加载成功。可以用minicom或者screen测试串口通信:
sudo apt install minicom sudo minicom -D /dev/ttyUSB03.2 常见问题排查
遇到驱动加载失败时,可以按以下步骤排查:
- 检查内核日志
dmesg,看是否有错误信息 - 确认USB设备被识别:
lsusb应该能看到"1a86:7523"(CH341的VID:PID) - 检查内核配置是否包含USB串口支持:
zcat /proc/config.gz | grep USB_SERIAL - 尝试不同版本的驱动代码
4. 开机自动加载配置
4.1 系统级安装
为了让驱动每次开机自动加载,需要将驱动安装到系统目录:
sudo cp ch341.ko /lib/modules/$(uname -r)/kernel/drivers/usb/serial/ sudo depmod -a4.2 配置自动加载
创建systemd模块加载配置文件:
echo "ch341" | sudo tee /etc/modules-load.d/ch341.conf验证配置是否生效:
sudo systemctl restart systemd-modules-load lsmod | grep ch3414.3 udev规则配置(可选)
如果需要固定设备节点名称,可以创建udev规则:
echo 'SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", SYMLINK+="ttyCH341"' | sudo tee /etc/udev/rules.d/99-ch341.rules sudo udevadm control --reload-rules这样无论插哪个USB口,设备都会固定为/dev/ttyCH341,方便脚本调用。
5. 进阶配置与优化
5.1 驱动参数调整
CH341驱动支持一些可调参数,查看当前参数:
modinfo ch341常用的可调参数包括:
write_timeout:写操作超时时间read_timeout:读操作超时时间baudrate_base:基准波特率
可以在加载时指定参数:
sudo insmod ch341.ko baudrate_base=9216005.2 性能优化建议
- 提高缓冲区大小:修改驱动源码中的
CH341_TX_QUEUE_SIZE和CH341_RX_QUEUE_SIZE - 调整内核调度策略:对实时性要求高的应用可以设置FIFO调度
- 关闭终端回显:减少不必要的数据传输
5.3 多设备管理
当连接多个CH341设备时,可以通过以下方式区分:
ls /sys/bus/usb-serial/devices/ # 查看所有USB串口设备 udevadm info -a -p /sys/class/tty/ttyUSB0 # 查看设备详细信息可以在udev规则中使用序列号等属性进行区分。
整个流程走下来,最大的感受是嵌入式Linux开发虽然有时候需要折腾驱动,但一旦掌握了方法,其实很有规律可循。关键是要理解内核模块的编译加载机制,以及systemd和udev的工作原理。记得第一次成功加载驱动时,看到串口设备出现的那种成就感,这就是嵌入式开发的乐趣所在吧。