
1. 为什么这次USB调试值得单独写一篇接手全志T527的板子时我原以为USB调试是BSP里最“温和”的活。毕竟USB协议成熟、工具链完善Linux内核里对USB的支持也极其丰富再不济还能靠抓包工具硬啃。实际调试下来才发现T527这颗芯片的USB模块牵扯到的东西远超想象——从硬件差分对布线、PHY配置、控制器模式切换到内核驱动枚举流程、设备树节点参数、系统休眠唤醒时的电源时序任何一个环节掉了链子表现出的症状都是“插上没反应”或者“能充电不枚举”但排查路径完全不同。这篇文章主要面向做BSP bring-up的嵌入式工程师以及正在基于T527做平板、商显、车载中控、工业HMI这类产品的开发人员。如果你手里正好有全志T527的开发板或量产板想在Linux环境下把USB Host/Device/OTG调通这篇文章可以把常见的坑提前给你趟一遍。当然如果你只是对USB协议栈感兴趣想看看一个实际SoC平台上的USB软件栈是怎么组织的也会有不少收获。我在这块板子上前后折腾了两周多从烧录固件、改设备树、看内核日志到用逻辑分析仪抓差分线上的包最终把三个USB口两路Host、一路OTG/Device全部调稳。下面把我的调试过程、判断思路、踩坑记录和排查方法完整写出来尽量做到“你照着走一遍也能调通”同时把每个操作背后的原因讲清楚避免知其然不知其所以然。2. USB软件栈结构和T527的平台特点2.1 先搞清楚T527上USB的整体框架全志T527是一款面向高性能物联网和边缘计算场景的ARM SoCCPU通常配四核Cortex-A55整体定位是算力够用、外设丰富、功耗可控。在USB这方面T527集成了多个USB控制器常见配置是两路USB 2.0 Host和一路支持OTG的USB 2.0/3.0组合控制器具体以实际芯片型号和封装为准。从软件角度看Linux内核里对应的是两个核心子系统一个是基于HCDHost Controller Driver的USB Host侧另一个是gadget/function框架的USB Device侧。Host侧T527一般使用EHCI或XHCI控制器驱动具体取决于硬件设计是USB 2.0的EHCI还是USB 3.0的XHCI。Device侧全志的方案一般把MUSB或DWC2、DWC3控制器跑在peripheral模式下配合ConfigFS或者传统的gadget驱动可以模拟出串口、网卡、大容量存储、ADB等设备。OTG模式则让同一个物理口能在Host和Device之间切换切换逻辑靠硬件ID引脚、软件策略或双角色控制器DRD完成。调试时要做的第一件事就是确认自己的板子上每个USB口到底接的是哪个控制器、用的是哪种模式。别一上来就盲改设备树否则后面会花大量时间在排查“改了没生效”这种问题上。我调试时先打开原理图把每个USB口的VBUS、ID、DP/DM或SSTX/SSRX连线走了一遍然后对照芯片手册里的USB控制器基地址定位到设备树里的对应节点。2.2 T527在BSP包里做了哪些封装全志的BSP包一般基于Linux内核同时会附带一堆全志自研的驱动补丁、电源管理框架和平台初始化代码。USB这块全志通常会在arch/arm64/boot/dts/allwinner/下提供现成的设备树模板里面已经定义好了USB控制器的时钟、复位、电源、PHY属性。这些模板是全志内部验证过的最好以它们为起点而不是从零写一个节点。我第一次编译内核时直接用了BSP默认配置没有额外打开任何USB调试选项结果上电后lsusb能看到host控制器但插上U盘就是没有任何反应。后来打开CONFIG_USB_DYNAMIC_MINORS、CONFIG_USB_OTG、CONFIG_USB_CONFIGFS这些选项后才慢慢有了完整的枚举动作。这里建议在bring-up阶段把CONFIG_USB_DEBUG、CONFIG_USB_ANNOUNCE_NEW_DEVICES、CONFIG_USB_OTG全部打开内核日志里会给出很多关键线索。另外全志BSP里还有一个自己的sunxi_usb框架层用于管理USB控制器、PHY、电源和模式切换。它在标准Linux USB栈之上做了一层封装好处是屏蔽了一部分硬件细节坏处是出问题时你得多查一层。如果你在调试中看到sunxi_usb相关的日志别慌那只是全志的封装在刷存在感最终还是要落到内核的usb core层去分析。2.3 和普通PC平台最大的不同电源管理和休眠唤醒T527这类嵌入式SoC和x86 PC在USB调试上最大的不同是电源管理。PC上的USB控制器基本常驻供电插上设备就枚举而嵌入式板卡为了省电USB PHY、控制器、VBUS电源都可能被Linux电源管理框架动态开关。如果休眠时USB控制器掉电、唤醒后没有正确重新初始化就会出现“唤醒后USB失灵”的经典问题。我调试过程中就遇到过一次系统休眠再唤醒后dmesg里能看到usb 1-1: device descriptor read/64, error -110但敲lsusb却没有任何设备。这说明USB控制器已经开始枚举但物理链路异常——大概率是PHY没有完全恢复。后来排查到是设备树里PHY节点的power-domains没有配全导致唤醒时PHY没被重新上电。这个问题的排查思路会在后面的常见问题章节展开。3. 调试前的环境准备和关键配置3.1 硬件准备不只是“一根USB线”USB调试的硬件准备比很多人想的复杂。除了目标板你至少需要以下几种设备USB转串口模块USB转TTL用于查看内核日志。推荐FT232或CP2102方案的模块驱动成熟、稳定性好。注意选择3.3V电平的版本并确认目标板的调试串口电平避免烧坏GPIO。USB Hub最好带外部供电调试Host口时如果只接一个U盘还好但有时候要同时挂多个设备复现问题供电不足会引入假故障。一个已知良好的U盘或USB鼠标键盘用于验证Host口枚举。建议准备USB 2.0和USB 3.0各一个低速、全速、高速设备都测一遍能覆盖更多枚举路径。USB抓包工具或逻辑分析仪如果条件允许准备一个USBCanalyzer如TotalPhase Beagle USB 480或者带USB解码的示波器/逻辑分析仪。没有专用抓包工具时可以用软件层面的usbmon先看看但对于协议级错误如CRC错误、复位信号异常还是硬件抓包更直接。如果只想验证Device/OTG口还需要一根OTG线Type-C转USB母口或MicroUSB转USB母口以及另一台能够作为Host的电脑或开发板。3.2 内核配置项和调试开关在编译内核前建议先打开这些配置项避免反复重编CONFIG_USBy CONFIG_USB_SUPPORTy CONFIG_USB_XHCI_HCDy CONFIG_USB_EHCI_HCDy CONFIG_USB_EHCI_HCD_PLATFORMy CONFIG_USB_OHCI_HCDy CONFIG_USB_OHCI_HCD_PLATFORMy CONFIG_USB_DWC2y # 或 CONFIG_USB_DWC3y取决于T527具体控制器 CONFIG_USB_GADGETy CONFIG_USB_CONFIGFSy CONFIG_USB_CONFIGFS_ACMy CONFIG_USB_CONFIGFS_ECMy CONFIG_USB_CONFIGFS_MASS_STORAGEy CONFIG_USB_CONFIGFS_F_UVCy CONFIG_USB_ANNOUNCE_NEW_DEVICESy CONFIG_USB_DYNAMIC_MINORSy CONFIG_USB_OTGy CONFIG_USB_DEBUGy CONFIG_USB_OTG_FSMy # 如果是OTG模式CONFIG_USB_DEBUG会让内核里的USB核心层输出更多调试信息例如URB传输状态和枚举过程。不过这个选项在5.x内核里可能已经被逐步去掉部分信息需要通过CONFIG_DYNAMIC_DEBUG配合dyndbg参数开启例如echo file drivers/usb/core/hub.c p /sys/kernel/debug/dynamic_debug/control这个命令可以动态打开hub.c里的调试日志非常实用不必重新编译内核就能看到设备枚举的详细过程。3.3 设备树中USB节点的常见配置模板以T527为例设备树中一般会有类似下面的节点具体地址和名称以BSP实际代码为准ehci0 { status okay; }; ohci0 { status okay; }; usb0 { status okay; dr_mode otg; usb_drd_vbus_gpio pio 3 14 GPIO_ACTIVE_HIGH; usb_drd_id_gpio pio 3 15 GPIO_ACTIVE_HIGH; }; usb1 { status okay; dr_mode host; }; usb2 { status okay; dr_mode host; };其中dr_mode是USB控制器的工作模式有三种取值host、peripheral、otg。otg会启动双角色切换逻辑同时受ID引脚和软件策略控制。对于纯Host口的节点直接配成host即可不要配otg否则内核会多跑一套OTG状态机可能引入无谓的异常。另外VBUS电源的控制方式也需要在设备树里体现。有的板子用GPIO控制VBUS使能有的则用固定电源轨还有的通过PMIC的regulator控制。这块配置错了最直接的表现就是“插上USB设备设备没任何反应连供电都没有”。判断VBUS是否正常最简单的方式是用万用表量USB口的5V引脚或用示波器看插入瞬间的电平变化。4. 实操过程全志T527 USB各模式的调试记录4.1 Host模式调试U盘枚举失败到成功板子第一次上电我用串口登录后执行lsusb能看到类似Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub的输出这说明Host控制器已经绑定成功、根Hub已注册。但插入U盘后lsusb里没有任何新设备dmesg也安静得可怕。这是非常典型的“枚举都没开始”的现象。我首先怀疑是VBUS供电没打开于是用万用表量了U盘座子的5V引脚发现电压为0。这就简单了问题出在VBUS电源控制上。查看板子原理图发现VBUS由一颗GPIO控制的负载开关供电GPIO连接到SoC的某个引脚。但设备树里没有配置这个GPIO。解决方法是给对应的USB控制器节点加上VBUS控制属性或者在驱动里注册一个regulator。我用的是后者因为全志BSP已经提供了对应的regulator框架支持。修改好之后重新编译设备树并烧录再次插入U盘这次dmesg里出现了usb 1-1: new high-speed USB device number 2 using ehci0 usb 1-1: New USB device found, idVendor0951, idProduct1666, bcdDevice 1.00 usb 1-1: New USB device strings: Mfr1, Product2, SerialNumber3 usb-storage 1-1:1.0: USB Mass Storage device detected scsi host1: usb-storage看到这一串东西心就定了大半。这里有个小技巧在枚举阶段dmesg里如果出现device descriptor read/64, error -71或error -110代表设备已经响应了复位信号但后续通信失败这时候多半是物理链路问题走线过长、阻抗不匹配、电源纹波大而不是软件配置问题。如果完全没有日志那就要回头检查VBUS、ID引脚、设备树状态。4.2 Device模式调试让板子被电脑识别为ADB设备T527做平板或开发板时经常需要把USB口配置为Device模式让电脑通过ADB访问板子。这里的关键是内核里有完整的gadget/configfs支持并且用户空间要能正确配置UDCUSB Device Controller。先确认UDC设备存在cat /sys/class/udc/udc_name/device/uevent如果有输出说明控制器已经在peripheral模式下。然后通过ConfigFS来创建功能mkdir /sys/kernel/config/usb_gadget/g1 cd /sys/kernel/config/usb_gadget/g1 echo 0x1f3a idVendor echo 0x1000 idProduct mkdir strings/0x409 echo MyBoard strings/0x409/serialnumber echo Allwinner strings/0x409/manufacturer echo T527 strings/0x409/product mkdir functions/ffs.adb mkdir configs/c.1 ln -s functions/ffs.adb configs/c.1 echo udc_name UDC这里以ffs.adb为例即FunctionFS方式实现ADB。实际操作时还需要挂载functionfs并启动adbd守护进程Android系统的adbd会直接使用这个接口。如果只是想先验证Device口物理层是否正常可以先配置成一个简单的串口设备ACMmkdir functions/acm.GS0 ln -s functions/acm.GS0 configs/c.1 echo udc_name UDC然后在电脑上就能看到一个COM口。通过串口工具发数据如果能在板端收到说明Device链路是通的。这一步非常有用可以先把“USB驱动栈”和“ADB应用层”隔离开来定位问题。我在调试时遇到过一个很奇怪的现象用若干U盘测试Host口都正常但是把USB线插到OTG口想进Device模式电脑上就是找不到任何设备。后来发现因为该OTG口硬件设计上通过ID引脚来区分插入的是Host线还是Device线而我用的那根USB线是纯充电线没有接D/D-插进去后SoC检测到的ID状态不对根本没有切换到peripheral模式。换了一根正宗的数据线问题立刻消失。所以当你调试Device/OTG时注意区分数据线和充电线看规格书确认是否支持数据传输。4.3 OTG模式调试Host/Device动态切换的坑OTG模式是嵌入式设备上最常用的也是相对最容易出问题的。全志T527的OTG口一般可以实现插入U盘时当Host读数据、连接电脑时当Device传文件或调试这就是典型的双角色切换。软件上内核的OTG驱动会检测ID引脚电平变化。ID为低电平时表示接入的是A设备Host端此时SoC作为DeviceID为高电平时表示接入的是B设备SoC作为Host。这套逻辑看起来很直观但实际调试中有几个坑ID引脚没有接上拉/下拉电阻。如果外部电路设计时ID线路悬空电平就会飘忽不定导致SoC不断在Host和Device之间切换。用示波器看ID引脚波形能看到毛刺。解决方法是确保ID线有稳定的上下拉配置。VBUS检测时序不对。OTG规范里设备端要先检测到VBUS然后才能开始复位和枚举。如果VBUS检测由PMIC或GPIO控制且这个检测信号没有在复位前稳定枚举就会失败。我见过因为VBUS上并联的电容过大导致检测信号延迟超过协议允许的时间设备不被识别。内核的OTG状态机卡在某个状态。有时候插拔太快状态机还没完成前一个轮次的切换又收到了新的中断就死锁了。这种情况在dmesg里能看到类似的otg: state change from xxx to xxx反复刷屏。解决方案是升级内核补丁或者在使用时插拔不要过快这招治标不治本但对于临时验证很管用。我调OTG时采取了一个比较有效的策略先用一个GPIO模拟ID电平手动切换角色。例如把ID引脚强制拉低看SoC是否进入Device模式再拉高看是否进入Host模式。这样可以排除OTG状态机的问题把焦点集中到硬件连接上。5. USB枚举过程的底层逻辑和常见错误码5.1 枚举到底发生了什么很多新手对USB调试感到无从下手根本原因是没搞懂枚举的过程。这里我用大白话讲一遍方便你排查问题时对症下药。当USB设备插入Hub端口时第一步是Hub检测到设备端D/D-电平变化全速设备在D上拉低速设备在D-上拉高速设备先以全速模式上拉D随后在复位握手期间切换到高速模式。Hub向主机控制器报告端口状态变化主机控制器通过中断或轮询发现新设备然后对端口做复位操作。复位信号发送后设备以默认地址0响应主机发来的GET_DESCRIPTOR请求主机读取设备描述符的前8个字节获取端点0的最大包大小然后主机分配一个地址再发SET_ADDRESS最后主机再次读取完整的设备描述符、配置描述符、字符串描述符等。整个过程如果任何一步通信错误就会体现在dmesg里的错误码上。理解这一点之后排查就变成了看到error -110先怀疑设备端没有正确响应看到device not accepting address怀疑地址设置失败看到unable to enumerate USB device则可能是多次尝试复位后仍无法获取描述符。每个错误码都有对应的物理或软件层面的可能原因需要逐项排查。5.2 常见错误码和应对清单在调试T527过程中我碰到的日志和问题之间对应关系如下表所示内核日志片段含义常见原因排查方向device descriptor read/64, error -71读取设备描述符时收到STALL以外的错误设备端数据线异常、供电不稳、设备固件问题检查D/D-波形、供电电压、换设备测试device descriptor read/64, error -110操作超时设备没有及时响应命令、PHY时钟未恢复检查PHY电源、时钟、复位状态unable to enumerate USB device多次复位后仍失败物理层信号差、控制器驱动初始化失败检查PCB走线、阻抗匹配、差分对等长device not accepting address分配地址失败设备端固件异常、枚举过程出现时序问题换设备、抓包、检查控制器中断配置cannot enable. Maybe the USB cable is bad?端口使能失败过流保护触发、VBUS供电不足、线缆坏更换线缆、检查过流检测引脚timeout: still waiting for xxxx传输超时URB提交后无响应检查驱动、控制器的DMA配置这张表不是万能药但可以帮你快速缩小问题范围。实际调试时我强烈建议准备一个USBCanalyzer或者用Linux的usbmon抓取主机控制器侧的所有URB配合dmesg里的错误码一起看能更快定位到是主机侧问题还是设备侧问题。6. 抓包和动态调试技巧分享6.1 用usbmon在软件层面抓包如果暂时没有硬件抓包工具Linux内核自带的usbmon是性价比最高的选择。它能在主机控制器层面捕获所有USB总线上的URB通信数据包括设置的每个阶段。使用方法mount -t debugfs none /sys/kernel/debug modprobe usbmon cat /sys/kernel/debug/usb/usbmon/0u /tmp/usbmon.txt然后在另一个终端操作USB设备插入U盘、枚举、读写等操作完成后结束抓包分析/tmp/usbmon.txt。里面的标签字段包含URB类型、传输方向、端点和数据长度格式可以参考内核文档流程解析。对于确认“设备有没有响应主机请求”这类问题usbmon已经够用。不过usbmon有个局限它抓的是URB层的逻辑数据看不到物理层的事件如复位信号、低速/全速切换时序、CRC错误。如果怀疑物理层还是得用逻辑分析仪或USB协议分析仪。6.2 开启动态调试后日志刷屏的处理打开CONFIG_USB_DEBUG之后内核日志量会变得非常大插拔一次设备可能打出几十甚至上百行。这时候建议把日志等级调整一下只保留关键信息echo 4 /proc/sys/kernel/printk数字4代表只输出KERN_WARNING及以上级别的日志这样枚举成功时的new device信息不会被打断但不显示底层URB细节。当需要观察URB细节时再调回更高的详细程度。也可以用dmesg -n 8配合dmesg | grep -i usb过滤效果类似。另一个实用技巧是打开CONFIG_USB_STAT和CONFIG_USB_OTG_FSM这样可以看到USB统计信息以及OTG状态机的切换事件。对于OTG模式排查尤其有用能直接知道SoC认为当前是什么角色。7. 常见问题与排查技巧实录7.1 插上U盘没任何反应连灯都不亮这类问题80%出在VBUS供电上。先用万用表量USB口5V电压如果没有去查VBUS的供电链路是PMIC的LDO/DCDC还是GPIO控制的开关还是直连5V电源轨。如果供电正常再看设备树是否把对应控制器节点配成了okay。如果供电和设备树都没问题那就打开内核动态调试去看Hub中断有没有触发如果连中断都没触发很可能是D/D-差分对没有正确连接或对应的GPIO复用功能没配到USB功能上而不是USB PHY本身坏了。7.2 能识别设备但传输数据不稳定经常掉线“能识别但掉线”通常和信号完整性或电源完整性相关。检查D/D-走线是否过长、是否有过孔、阻抗是否控制在90Ω±10%左右。如果硬件无法改动只能从软件上做一些缓解降低USB速率强制全速模式参数usbcore.old_scheme_first1可以让枚举偏向低速握手方式、调整UBPUnit Burst或调度策略、关闭USB自动挂起echo on /sys/bus/usb/devices/1-1/power/control。实测中强制全速对于延长线缆或质量差的线材非常有效但对高速设备性能影响明显只适合临时验证。7.3 系统休眠唤醒后USB不工作这类问题多与电源域和时钟相关。在设备树里检查USB控制器和PHY节点的power-domains、clocks、resets属性。如果PHY的电源域没有在唤醒时重新使能就会出现“控制器工作但PHY没起来”的半死状态。解决方法有两种一种是在系统休眠前手动卸载USB控制器驱动、唤醒后重新加载临时手段另一种是完善设备树电源域引用和驱动中的resume回调让内核正确执行PHY上电序列。我在T527上还遇到过一个和这类似但更隐蔽的问题休眠时USB口输出的VBUS被关断了唤醒后虽然控制器重新初始化但没有重新打开VBUS。后来在设备树里配置了wakeup-source并让驱动在resume时重新使能VBUS电源才解决。如果你的板子也有休眠需求记得把VBUS的电源管理和唤醒逻辑一起验证。7.4 OTG同时接了外设和电脑角色切换异常这是实际使用中最容易遇到的问题。有几种常见场景系统里接入了Type-C的CC逻辑芯片但没有正确配置CC侦测结果和USB控制器之间的联动。此时需要检查PD/CC逻辑的I2C中断以及驱动里是否会把role状态传给USB控制器。用户用了一根没有CC逻辑的普通OTG线导致SoC侧无法识别是否插入了Host。这种只能通过外部电路检测或者切换为手动模式。软件里通过role节点切换时没有处理VBUS时序。正确流程是先切断VBUS等一段时间再切换角色最后重新使能VBUS。如果顺序不对外设可能因为瞬间抖动而陷入错误状态。排查时建议先用GPIO手动模拟角色切换确认控制器自身功能正常再逐步恢复CC逻辑和自动切换配置。这样可以缩小问题范围。8. 调试中值得记录的几条心得体会调试USB的时间一长你会慢慢形成不少直觉。这里写几条个人认为很核心的经验不一定在每个平台都适用但思路是通用的。第一USB调试一定要从物理层往上层逐层验证。永远先确认VBUS有没有电再确认D/D-的波形和差分信号对不对然后看设备能不能响应复位最后才去怀疑内核驱动和协议栈。我在T527上调USB最初就是在“软件配置”上花了很多时间结果最后发现一根USB线的D-脚内部断了导致枚举时只有D有活动、D-没响应整个链路根本建立不起来。这种低级错误其实很容易靠“换一根线”来排除在排查初期就应该做。第二dmesg永远是第一现场但不要只盯着usb关键字。很多USB问题其实是由上游电源、时钟、总线频率引起的所以看到USB报错后要同时看dwc2/dwc3/sunxi_usb、clk、regulator的日志片段。有一次我发现USB枚举失败看完整日志才知道是clk_usb_phy的父时钟频率被其他外设改了导致PHY的参考时钟偏离USB眼图通不过。这种问题从USB自身排查是永远找不到答案的。第三抓包工具和示波器真的是花小钱省大事。一套入门级的USB协议分析仪只要几千元但对于bring-up工程师而言它可能帮你减少一周的“盲调”时间。如果公司暂时没预算USB转串口加逻辑分析仪也能解决大部分问题只是效率低一些。从长远看专业的USB分析工具值得投入。第四内核配置里不要把USB相关的模块编成“未定义”或“自动”在调试阶段尽量改成交织进内核或者至少保证根文件系统里有对应的模块。因为很多SoC平台在启动初期加载模块的顺序容易出问题特别是USB gadget依赖的USB UDC驱动如果模块加载顺序不对板子就不识别Device角色。编进内核是BSP调试阶段最省事的办法。9. 后续可以怎么扩展调试完USB的基本枚举和传输之后针对产品化的方向还可以做很多扩展工作。USB 3.0支持如果T527带USB 3.0控制器还需要额外配置XHCI、收发器、电源管理等。USB 3.0的物理层调试更复杂差分对数量增多信号速率提高对PCB布局和测试设备要求更高。建议单独开一篇来写。USB Gadget的丰富场景目前只验证了ACM和ADB实际产品可能还需要RNDISUSB虚拟网卡、UVC摄像头、UAC音频、MTP等。每一个function的调试侧重点不同特别是UVC和UAC对带宽和实时性要求高需要关注URB调度和延迟。USB安全和防护嵌入式产品经常要过认证USB口的ESD防护、浪涌保护、过流保护都要在硬件设计阶段考虑。如果在调试中发现端口偶尔抽风别忘了检查电路保护器件如TVS、PPTC的参数是否选型正确。QC/PD快充协议如果产品是带电池的平板或手机形态USB口可能还要支持QC或PD快充。这时候USB既要传数据又要走功率协商硬件上多用Type-C接口软件上需要运行PD协议栈。这个领域和普通USB枚举是两套逻辑调试时得把PD协议分析和USB数据链路分开抓。这些扩展方向都是基于我这次调试T527 USB经验自然延伸出来的。先把基础的数据通、枚举稳、休眠唤醒可靠这几件事做好再往上面叠加更花的功能整个系统的稳定性才会有保障。如果你之后在实际调试中也遇到什么奇葩的USB问题欢迎一起交流排查思路。