RK3399Pro作为一款高性能嵌入式处理器,原生串口资源常常不够用。我在实际项目中就遇到过需要扩展4个串口的场景,这时候XR21V1414IM48这类USB转串口芯片就成了救命稻草。这款芯片最大的优势在于单USB接口就能扩展出4个独立串口,而且支持最高3Mbps的波特率,完全能满足工业级应用需求。
先说说硬件连接要点。RK3399Pro开发板通常会有Type-C或标准USB接口,而XR21V1414IM48芯片采用48引脚QFN封装,焊接时要注意以下几点:
我推荐使用现成的评估板开始实验,比如EXAR官方的XREVKIT-1414。第一次使用时,接上开发板后可以通过lsusb命令检查设备是否被识别:
bash复制lsusb -v -d 04e2:1414
正常情况应该能看到类似这样的输出:
code复制idVendor 0x04e2 Exar Corp.
idProduct 0x1414
bcdDevice 1.00
XR21V1414IM48的驱动在Linux内核中其实已经支持,但需要确认内核配置。我建议从kernel 4.4以上版本开始,这个系列的驱动最稳定。关键文件位于:
code复制drivers/usb/serial/xr_usb_serial_common.c
drivers/usb/serial/xr_usb_serial_hal.c
在menuconfig中需要确保以下选项开启:
code复制Device Drivers →
USB support →
USB Serial Converter support →
<*> Exar USB serial converters
<*> Exar multi-port serial support
RK3399Pro需要正确配置USB控制器的设备树节点。在arch/arm64/boot/dts/rockchip/rk3399.dtsi中添加:
dts复制&usb_host0_ehci {
status = "okay";
#address-cells = <2>;
#size-cells = <2>;
xr21v1414: serial@1 {
compatible = "exar,xr21v1414";
reg = <1>;
};
};
这里有个坑我踩过:RK3399Pro的USB3.0控制器需要特别处理PHY配置,否则会出现枚举失败。解决方法是在设备树中明确指定phy-names:
dts复制usbdrd_dwc3_0: usb@fe800000 {
phys = <&u2phy0_otg>;
phy-names = "usb2-phy";
};
驱动初始化的关键函数是xr_usb_serial_init(),它完成了三个重要工作:
特别要注意的是波特率初始设置:
c复制xr_usb_serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
这里设置了默认9600波特率、8数据位、启用接收、挂断时关闭设备等标志。我在工业现场遇到过因为没设置CLOCAL导致通信中断的问题,这个标志位表示忽略调制解调器控制线。
驱动通过xr_usb_serial_ids数组来识别设备:
c复制static const struct usb_device_id xr_usb_serial_ids[] = {
{ USB_DEVICE(0x04e2, 0x1414) }, // XR21V1414IM48
{ }
};
当USB核心检测到VID=0x04e2且PID=0x1414的设备时,就会绑定这个驱动。有个实用技巧:可以通过sysfs动态加载驱动:
bash复制echo 04e2 1414 > /sys/bus/usb/drivers/xr_usb_serial/new_id
原始文章的测试代码可以改进几点:
改进后的主函数框架:
c复制int main(int argc, char **argv)
{
struct sigaction saio;
fd = open_port(argv[1]);
saio.sa_handler = signal_handler;
saio.sa_flags = 0;
sigaction(SIGIO, &saio, NULL);
fcntl(fd, F_SETFL, FNDELAY);
fcntl(fd, F_SETOWN, getpid());
fcntl(fd, F_SETFL, O_ASYNC );
while(1) {
usleep(100000);
/* 数据处理逻辑 */
}
}
RK3399Pro需要aarch64架构的工具链。我推荐使用Linaro的gcc-linaro-7.5.0版本,Makefile要特别注意静态链接:
makefile复制CC = aarch64-linux-gnu-gcc
CFLAGS = -O2 -Wall -static
uart_test: uart_test.c
$(CC) $(CFLAGS) -o $@ $^
静态编译可以避免目标板缺少动态库的问题,实测可执行文件大小约800KB左右。
遇到设备不识别时,可以按这个流程排查:
dmesg | grep xr输出我遇到过最棘手的问题是通信随机中断,最终发现是PCB布局问题导致USB信号完整性差。解决方法是在D+和D-线上串接22Ω电阻。
对于高波特率应用(>1Mbps),需要调整内核参数:
bash复制echo 2048 > /sys/module/usbcore/parameters/usbfs_memory_mb
同时建议关闭打印调试信息以降低CPU负载:
c复制#undef dev_dbg
#define dev_dbg(dev, fmt, ...) do {} while (0)
在RK3399Pro上实测,4个串口同时工作在3Mbps波特率时,CPU占用率约15%。如果发现数据丢失,可以尝试提高线程优先级:
c复制struct sched_param param = { .sched_priority = 50 };
pthread_setschedparam(pthread_self(), SCHED_FIFO, ¶m);