ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

野火鲁班猫4串口实战:从硬件选型到应用层编程与调试避坑指南

野火鲁班猫4串口实战:从硬件选型到应用层编程与调试避坑指南 1. 为什么这块板子的串口值得单独写一篇实战野火鲁班猫4到手之后我第一个跑通的不是HDMI显示也不是NPU推理而是串口。原因很简单串口是嵌入式开发的生命线。板子启动时uboot打印了什么、内核有没有正常挂载文件系统、登录系统后想看实时日志这些场景都绕不开串口。尤其是RK3588S这种多核异构、外设丰富的SoC一旦网络配置出问题或者系统起不来串口往往是你唯一的救命通道。鲁班猫4基于RK3588SCPU是4核A76加4核A55的big.LITTLE架构板子上引出了多路UART。官方文档给的是引脚定义和基础测试方法但实际用起来你会发现几个问题调试串口和普通串口怎么区分RS232和TTL电平混接会不会烧流控要不要开波特率设多少才稳这些细节官方文档不会展开讲但每一个都可能在实操中卡住你半天。这篇内容适合三类人刚拿到鲁班猫4准备点灯的嵌入式新手、从STM32转Linux开发需要重新理解串口子系统的老手、以及做硬件调试需要稳定串口链路的工程师。我会从硬件引脚确认开始一路讲到内核配置、应用层编程、常见故障排查把踩过的坑和验证过的参数都摊开说。2. 鲁班猫4串口硬件层拆解与选型逻辑2.1 先搞清楚板子上到底有几路UART鲁班猫4的RK3588S芯片本身支持多路UART控制器但板子实际引出的路数取决于硬件设计。根据官方原理图和实际测量板子上通常有这么几类串口资源调试串口Debug UART一般是UART2通过板载的Type-C或排针引出默认波特率1500000。这一路在uboot阶段就初始化了内核启动参数里consolettyS2,1500000就是它。注意这个波特率不是常见的115200第一次接上去如果终端乱码先检查波特率。通用串口RS232/TTL通过排针或DB9接口引出通常是UART3、UART4等。这些串口在系统启动后由内核驱动接管设备节点一般是/dev/ttyS3、/dev/ttyS4。RS485串口部分型号会引出一路RS485带收发自动切换电路设备节点同样是/dev/ttySx但应用层需要额外处理方向控制。我实测下来调试串口和通用串口最大的区别在于调试串口在uboot阶段就有输出而通用串口要等内核驱动加载完才能用。如果你只接通用串口板子上电后是看不到uboot打印的这一点新手很容易懵。2.2 TTL、RS232、RS485到底怎么选这是硬件调试里最容易出问题的环节。三种电平标准混接轻则通信失败重则烧毁IO。电平标准逻辑1电平逻辑0电平典型场景鲁班猫4对应TTL3.3V0V板内芯片间通信排针直出RS232-3V~-15V3V~15VPC串口、工控设备需外接转换芯片RS485差分A/B差分A/B长距离、多机通信需外接收发器鲁班猫4的排针引出的UART是3.3V TTL电平不是RS232。如果你直接拿RS232的DB9线接到排针上负电压会灌进SoC的IO大概率烧引脚。正确做法是加一块MAX3232之类的电平转换模块或者用USB转TTL模块CH340、CP2102、FT232都行。注意USB转TTL模块的VCC不要接到板子的VCC上只接GND、TX、RX三根线。板子自己供电模块自己供电两边共地就行。我见过有人把两个VCC接一起结果模块的5V灌进3.3V域板子直接不启动。2.3 引脚确认的实操方法拿到板子先别急着接线用万用表蜂鸣档确认排针和SoC引脚的对应关系。官方原理图会给网络标号比如UART2_TX_M0、UART2_RX_M0但排针丝印可能只写TX、RX。我的习惯是找到原理图里UART对应的页码确认TX和RX的引脚编号。用万用表测排针和测试点的通断确认丝印和原理图一致。接线时TX接RXRX接TX这是交叉连接不是直连。如果板子上有多个UART排针建议用标签纸贴上UART2_DBG、UART3_232避免后面接错。我吃过这个亏调试串口和通用串口接反了终端一直没输出查了两个小时才发现。3. 系统层配置从设备树到设备节点3.1 设备树里UART是怎么配的RK3588S的UART控制器在设备树里通过uart2、uart3等节点描述。以UART2为例典型配置长这样uart2 { status okay; pinctrl-names default; pinctrl-0 uart2m0_xfer; };关键点在于pinctrl-0引用的引脚复用配置。RK3588S的引脚功能是复用的同一个物理引脚可以当GPIO、UART、I2C等。uart2m0_xfer表示使用M0组的TX/RX引脚。如果你在设备树里改错了组引脚就不会输出UART信号。对于通用串口比如UART3配置类似uart3 { status okay; pinctrl-names default; pinctrl-0 uart3m1_xfer; linux,rs485-enabled-at-boot-time; rs485-rts-delay 0 0; };最后两行是RS485特有的如果这路串口接的是RS485收发器需要加上。rs485-rts-delay控制RTS引脚在发送前后的延时单位是毫秒。我实测下来对于9600波特率0 0够用如果波特率高于115200建议设成1 1给收发器留切换时间。3.2 内核启动后怎么确认串口可用系统起来之后第一件事是看设备节点有没有生成ls -l /dev/ttyS*正常应该看到/dev/ttyS0到/dev/ttyS9之类的节点。但注意不是每个ttySx都对应实际引出的串口。有些是内核内部使用的有些是没使能的。更准确的方法是看sysfsls /sys/class/tty/ | grep ttyS cat /proc/tty/driver/serial/proc/tty/driver/serial会列出每个串口的中断号、波特率、收发计数。如果某一行的tx和rx都是0说明这路串口没在收发数据。我一般用这个命令快速判断哪路是活的。还有一个坑调试串口默认被内核console占用。如果你在应用层直接open/dev/ttyS2可能会和内核打印冲突。解决办法是在内核启动参数里把console改成别的或者应用层用/dev/ttyS3这种没被占用的。3.3 权限问题为什么open返回Permission denied普通用户默认没有串口设备的读写权限。/dev/ttyS*的属主通常是root:dialout权限660。你有两个选择把用户加到dialout组sudo usermod -aG dialout $USER然后重新登录。写udev规则给特定串口加权限# /etc/udev/rules.d/99-serial.rules KERNELttyS3, MODE0666改完执行sudo udevadm control --reload-rules sudo udevadm trigger。我推荐用udev规则因为组权限在有些精简系统里不一定生效而且udev规则可以精确到某一路串口不会把调试串口也开放出去。4. 应用层编程从命令行到代码实现4.1 先用stty和echo做快速验证在写代码之前用命令行工具确认硬件链路是通的。这是最省时间的做法# 配置串口参数 stty -F /dev/ttyS3 115200 cs8 -cstopb -parenb -crtscts # 发送数据 echo hello /dev/ttyS3 # 接收数据另开一个终端 cat /dev/ttyS3stty的参数含义115200是波特率cs8是8位数据位-cstopb是1位停止位-parenb是无校验-crtscts是关闭硬件流控。这一套是嵌入式串口最常用的配置除非对方设备明确要求奇偶校验或流控否则就用这个。如果cat能看到echo发出去的内容需要短接TX和RX做回环测试说明串口驱动和硬件都正常。如果看不到先查接线再查设备树最后查波特率。4.2 C语言实现一个可复用的串口类命令行验证通过后用C写一个封装好的串口操作模块。核心就是termios结构体的配置#include termios.h #include fcntl.h #include unistd.h #include stdio.h #include string.h int uart_open(const char *dev, int baud) { int fd open(dev, O_RDWR | O_NOCTTY | O_NDELAY); if (fd 0) { perror(open uart); return -1; } struct termios opt; tcgetattr(fd, opt); // 设置波特率 cfsetispeed(opt, baud); cfsetospeed(opt, baud); // 8N1无流控 opt.c_cflag ~CSIZE; opt.c_cflag | CS8; opt.c_cflag ~PARENB; opt.c_cflag ~CSTOPB; opt.c_cflag ~CRTSCTS; // 原始模式不做任何处理 opt.c_lflag ~(ICANON | ECHO | ECHOE | ISIG); opt.c_iflag ~(IXON | IXOFF | IXANY); opt.c_oflag ~OPOST; // 设置超时 opt.c_cc[VTIME] 10; // 1秒超时 opt.c_cc[VMIN] 0; tcflush(fd, TCIOFLUSH); tcsetattr(fd, TCSANOW, opt); return fd; }几个关键点解释一下。O_NOCTTY表示不要把串口当成控制终端否则程序退出时可能给串口发信号。O_NDELAY配合VMIN0和VTIME10实现非阻塞读读不到数据就等1秒返回。tcflush清掉缓冲区里的残留数据避免上次通信的脏数据干扰。波特率不能用数字直接传要用B115200这种宏。如果对方波特率不是标准值比如921600需要用termios2结构体和ioctl的TCGETS2/TCSETS2这个后面排查部分会讲。4.3 Python方案pyserial快速原型如果只是做数据采集或协议验证Python的pyserial更省事import serial import time ser serial.Serial( port/dev/ttyS3, baudrate115200, bytesizeserial.EIGHTBITS, parityserial.PARITY_NONE, stopbitsserial.STOPBITS_ONE, timeout1 ) # 发送 ser.write(bAT\r\n) time.sleep(0.1) # 接收 data ser.read(ser.in_waiting) print(data) ser.close()pyserial在鲁班猫4上需要先pip3 install pyserial。如果系统没有pip用apt install python3-pip装。注意有些精简系统没有预装pip需要先配好软件源。提示Python的GIL在高速串口场景下可能成为瓶颈。如果波特率超过460800且数据量大建议用C或C。我实测Python在115200下跑持续收发没问题但921600下会丢包。5. 调试实战从乱码到稳定通信的排查路径5.1 终端乱码的四种可能原因接上串口看到乱码按这个顺序排查波特率不匹配最常见。鲁班猫4调试串口默认1500000不是115200。如果你用115200去接看到的就是乱码。确认方法看uboot打印如果uboot阶段就乱码肯定是波特率问题。数据位/停止位/校验位不匹配对方设备可能是7位数据位或2位停止位。用stty -F /dev/ttyS3 -a看当前配置和对方设备手册对比。地线没接TX和RX接了但GND没接信号没有参考电平也会乱码。这是新手最容易忽略的。电平不匹配TTL接RS232或者3.3V接5V。用示波器看TX引脚波形如果幅度不对就是电平问题。我遇到过一次乱码查了半天发现是USB转TTL模块的晶振不准换了一个模块就好了。所以模块质量也很重要CH340便宜但有些批次晶振偏差大FT232贵但稳。5.2 收发数据丢失的排查思路数据能通但偶尔丢包这种问题最磨人。我的排查清单流控没开如果对方设备发得快而你的程序处理慢没有流控就会丢。硬件流控需要RTS/CTS两根线都接软件流控用XON/XOFF字符。鲁班猫4的排针不一定引出RTS/CTS需要查原理图。缓冲区溢出cat /proc/tty/driver/serial看rx计数和overrun计数。如果overrun在涨说明内核缓冲区满了应用层读得太慢。中断冲突cat /proc/interrupts | grep uart看中断号有没有和其他设备共享。共享中断在高负载下可能丢数据。DMA没使能RK3588S的UART支持DMA但设备树里默认可能没开。大数据量场景下开DMA能显著降低CPU占用和丢包率。5.3 非标准波特率的配置方法有些工业设备用非标准波特率比如250000、500000。Linux的termios标准接口只支持标准波特率需要用termios2#include asm/termbits.h #include sys/ioctl.h struct termios2 tio; ioctl(fd, TCGETS2, tio); tio.c_cflag ~CBAUD; tio.c_cflag | BOTHER; tio.c_ispeed 250000; tio.c_ospeed 250000; ioctl(fd, TCSETS2, tio);BOTHER是other baud rate的意思配合c_ispeed和c_ospeed设置任意波特率。这个接口在RK3588S的Linux 5.10内核上是可用的我实测250000和500000都能跑通。5.4 RS485方向控制的坑RS485是半双工发送和接收不能同时进行。如果用的是自动方向控制的收发器比如MAX13487硬件会自动切换应用层不用管。但如果是手动控制的需要GPIO控制DE/RE引脚应用层就要在发送前拉高DE发送完拉低。Linux内核从4.10开始支持RS485自动方向控制通过设备树的linux,rs485-enabled-at-boot-time和rs485-rts-delay配置。但前提是收发器的DE/RE接在SoC的RTS引脚上。如果接的是普通GPIO就需要在应用层用ioctl控制int rts TIOCM_RTS; ioctl(fd, TIOCMBIS, rts); // 拉高RTS进入发送模式 write(fd, data, len); ioctl(fd, TIOCMBIC, rts); // 拉低RTS进入接收模式注意发送完要等数据真正移出移位寄存器再拉低RTS否则最后几个字节会丢。可以在write之后加一个tcdrain(fd)等发送完成。6. 常见问题速查与独家避坑经验6.1 问题速查表现象可能原因排查方法解决终端无输出接线错误检查TX/RX是否交叉交换TX/RX终端乱码波特率不对确认对方波特率改stty或代码Permission denied权限不足ls -l /dev/ttyS*加dialout组或udev规则能发不能收流控或方向控制检查RTS/CTS关流控或加方向控制偶尔丢包缓冲区溢出看overrun计数开DMA或加快读取非标准波特率失败termios限制用termios2BOTHERioctl调试串口冲突console占用看内核启动参数改console或换串口6.2 几个官方文档不会写的经验第一调试串口的波特率是可以改的但没必要。1500000虽然不常见但稳定性没问题。改uboot环境变量baudrate和内核console要同步改漏一个就乱码。我建议保持默认用支持1500000的USB转TTL模块就行CH340B和CP2102都支持。第二排针上的VCC不要用来给USB转TTL模块供电。板子的3.3V输出电流有限带不动模块。而且模块如果通过VCC反向灌电可能导致板子无法复位。只接GND、TX、RX三根线是最稳的。第三长时间通信建议加看门狗。串口程序卡死的情况不少见尤其是用了阻塞读又没设超时。在程序里加一个定时器超过一定时间没收到数据就重新初始化串口。我一般设30秒无数据就tcflush加重新tcsetattr。第四用screen或minicom做交互调试比cat方便。screen /dev/ttyS3 115200可以直接在终端里输入和查看退出用CtrlA然后K。minicom功能更多但配置麻烦screen够用了。第五如果板子上跑的是Buildroot精简系统可能没有stty和cat。这时候用busybox的microcommicrocom -s 115200 /dev/ttyS3。或者自己写一个最简单的C程序做回环测试。6.3 关于RK3588S串口DMA的补充RK3588S的UART控制器支持DMA但在设备树里默认可能没使能。使能方法是在uart节点里加dmas和dma-namesuart3 { dmas dmac0 12, dmac0 13; dma-names tx, rx; };具体DMA通道号要查RK3588S的TRM手册。开DMA之后大数据量收发的CPU占用能从30%降到5%以下。但DMA也有坑小数据量小于FIFO深度反而更慢因为DMA启动有开销。我的经验是单次收发超过64字节再考虑开DMA。7. 从串口延伸到系统调试的完整链路串口调通之后它就成了你调试鲁班猫4其他功能的基础设施。比如网络配置出问题你可以通过串口登录进去改/etc/network/interfaces比如系统起不来你可以通过串口进uboot改启动参数比如想看内核崩溃日志串口是唯一能完整捕获panic信息的地方。我现在的习惯是板子一上电就接好串口screen挂着所有调试操作都在串口终端里做。SSH和ADB虽然方便但依赖网络和USB驱动串口不依赖任何上层服务最可靠。另外串口也是和单片机通信的常用接口。鲁班猫4跑Linux做上位机STM32跑裸机做下位机两者通过UART交换数据这是嵌入式项目里非常经典的架构。鲁班猫4这边用pyserial或C程序收发STM32那边用HAL库的HAL_UART_Transmit和HAL_UART_Receive_IT协议自己定简单场景用\r\n结尾的ASCII字符串就够复杂场景加帧头、长度、CRC校验。如果后续要做多机通信RS485总线挂多个从机鲁班猫4做主站轮询那就需要在应用层实现Modbus RTU协议。Modbus RTU的帧格式是地址功能码数据CRC16波特率一般用9600或19200配合RS485的差分传输可以拉到1200米。这个展开又是另一篇内容了但串口底层配置的逻辑和这篇里讲的是完全一致的。
返回列表