Linux下国产CH343驱动实战:从编译到自启动的完整指南
1. 初识CH343:为什么选择这款国产USB转串口芯片
第一次接触CH343是在去年做工业网关项目的时候。当时我们需要在嵌入式板卡上扩展4个高速串口,市面上常见的CP210x、FT232这些进口芯片要么价格翻倍,要么交期长达半年。偶然看到沁恒微电子的CH343芯片,实测下来发现这真是个宝藏国产芯片——波特率支持到6Mbps,外围电路只需要两个电容,最重要的是价格只有进口芯片的三分之一。
CH343本质上是一个USB转高速串口的桥接芯片,和常见的CH340系列算是同门师兄弟。但它的性能提升非常明显:最高波特率从CH340的2Mbps提升到6Mbps,内置的128字节FIFO缓冲区也让大数据量传输更稳定。我在做Modbus RTU转TCP网关时,用CH343连接电力仪表,115200波特率下连续工作72小时没有出现任何数据丢失。
2. 驱动获取与编译:手把手教你适配内核
2.1 驱动源码获取的正确姿势
官方驱动仓库在GitHub上维护得挺勤快,建议直接克隆最新版本:
git clone https://github.com/WCHSoftGroup/ch343ser_linux.git这里有个坑要注意:不同内核版本可能需要特定分支的驱动。比如我们项目用的4.19内核,直接编译main分支会报错。后来发现要切换到legacy-kernel4.x分支才适配。建议先git branch -a查看所有分支,选择最接近你内核版本的。
2.2 编译前的内核准备
编译驱动最头疼的就是内核头文件匹配问题。我建议直接用当前运行中的内核源码来编译:
KERNELDIR=/lib/modules/$(uname -r)/build如果遇到"Module.symvers not found"错误,说明你的系统可能没装内核开发包。在Ubuntu上可以这样解决:
sudo apt install linux-headers-$(uname -r)2.3 Makefile的定制化修改
官方Makefile默认配置可能不适合你的环境,这几个参数建议检查:
# 修改为你实际的内核路径 KERNELDIR ?= /home/yourname/linux-5.10 # 交叉编译时需要指定架构和工具链 ARCH ?= arm CROSS_COMPILE ?= arm-linux-gnueabihf-特别提醒:在嵌入式环境编译时,一定要确认KERNELDIR指向的是配套的内核源码树,而不是主机上的内核。我有次不小心用x86的内核编译arm驱动,浪费了半天时间排查。
3. 驱动加载的两种实战方案
3.1 动态加载:快速验证的利器
编译成功后你会得到ch343.ko文件,测试加载最安全的方式是:
sudo insmod ch343.ko dmesg | tail -20 # 查看内核日志确认加载情况如果看到"ch343: USB Serial support registered"就说明成功了。不过这里有个隐藏知识点:现代Linux内核默认会优先加载CDC-ACM驱动,导致CH343可能无法独占设备。解决方法是在加载前先卸载冲突驱动:
sudo modprobe -r cdc_acm3.2 静态编译:生产环境的稳妥选择
对于量产设备,我更推荐把驱动编译进内核。具体步骤:
- 将驱动源码复制到内核的
drivers/usb/serial/目录 - 修改同目录下的Kconfig,添加:
config USB_SERIAL_CH343 tristate "CH343 USB to serial converter" depends on USB_SERIAL help Say Y here if you want to use the CH343 USB serial adapter.- 在Menuconfig中启用该选项:
make menuconfig # 找到 Device Drivers -> USB support -> USB Serial Converter support -> CH343 USB to serial converter4. 开机自启动的完整解决方案
4.1 传统方法:/etc/modules的局限
很多教程会告诉你在/etc/modules里添加模块名,像这样:
echo "ch343" | sudo tee -a /etc/modules但实际在嵌入式系统中,这个方法有两个问题:
- 模块加载顺序不可控,CDC驱动可能还是优先加载
- 某些精简版系统可能没有这个文件
4.2 更可靠的systemd方案
我推荐用systemd服务来确保加载顺序:
# /etc/systemd/system/ch343-driver.service [Unit] Description=Load CH343 Driver Before=serial-getty@ttyUSB0.service After=syslog.target [Service] Type=oneshot ExecStart=/sbin/modprobe ch343 ExecStartPost=/bin/sleep 1 # 给设备枚举留出时间 [Install] WantedBy=multi-user.target然后启用服务:
sudo systemctl enable ch343-driver.service这个方案的优点是能精确控制加载时机,还能配合udev规则自动创建设备节点。
5. 实际应用中的排坑指南
5.1 设备节点权限问题
新插入的CH343设备通常会是/dev/ttyUSBx,但普通用户可能没权限访问。永久解决方案是创建udev规则:
# /etc/udev/rules.d/99-ch343.rules SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="55d4", MODE="0666"更新规则后记得重新加载:
sudo udevadm control --reload-rules sudo udevadm trigger5.2 高速传输的缓冲区优化
当波特率超过1Mbps时,建议调整内核缓冲区参数:
sudo stty -F /dev/ttyUSB0 6000000 sudo sysctl -w net.core.rmem_max=4194304 sudo sysctl -w net.core.wmem_max=4194304在代码中也需要相应设置:
struct serial_struct serinfo; ioctl(fd, TIOCGSERIAL, &serinfo); serinfo.flags |= ASYNC_LOW_LATENCY; ioctl(fd, TIOCSSERIAL, &serinfo);5.3 多设备同时工作的技巧
当连接多个CH343设备时,可以通过绑定物理端口来固定设备名。首先查看设备路径:
udevadm info -a -p $(udevadm info -q path -n /dev/ttyUSB0)然后创建基于端口号的规则:
# /etc/udev/rules.d/98-ch343-by-port.rules SUBSYSTEM=="tty", KERNELS=="1-1.2:1.0", SYMLINK+="ttyCH343_0" SUBSYSTEM=="tty", KERNELS=="1-1.3:1.0", SYMLINK+="ttyCH343_1"6. 进阶应用:GPIO和硬件流控
虽然CH343主打串口功能,但它其实还支持GPIO控制。通过ioctl可以操作这些引脚:
#define CH343_GPIO_NUM 4 // CH343有4个GPIO // 获取GPIO状态 ioctl(fd, CH343_IOCTL_GET_GPIO, &gpio_state); // 设置GPIO方向为输出 gpio_config.direction = CH343_GPIO_OUT; ioctl(fd, CH343_IOCTL_SET_GPIO_DIR, &gpio_config); // 输出高电平 gpio_value.index = 0; // GPIO0 gpio_value.value = 1; ioctl(fd, CH343_IOCTL_SET_GPIO_VALUE, &gpio_value);硬件流控的配置也很重要,特别是在工业环境中:
struct termios options; tcgetattr(fd, &options); options.c_cflag |= CRTSCTS; // 启用RTS/CTS流控 tcsetattr(fd, TCSANOW, &options);最近在做一个光伏逆变器监控项目,就是靠CH343的硬件流控功能稳定实现了115200波特率下7x24小时不间断通信。相比之前用过的某进口芯片,国产CH343在长线传输时的抗干扰表现反而更出色。
