1. 高速USB主机子系统:串行接口模式与TLL配置详解
在嵌入式系统开发中,USB主机功能的集成一直是个既关键又复杂的环节。尤其是在那些对成本、功耗和PCB面积都极其敏感的便携式或工业设备里,传统的并行UTMI+接口动辄几十根信号线,常常让硬件工程师感到头疼。为了解决这个问题,德州仪器(TI)在其高速USB主机子系统中引入了一套灵活的串行接口模式,配合TLL逻辑接口,为嵌入式USB主机设计提供了一条精简高效的路径。这套方案的核心思想,就是用更少的引脚,实现同样可靠的USB通信,但代价是牺牲了高速(High-Speed)模式,仅支持全速(Full-Speed)和低速(Low-Speed)。对于很多不需要480Mbps高速传输的应用场景,比如连接鼠标、键盘、U盘或者一些工业传感器,这完全够用,而且能显著降低系统复杂度和BOM成本。今天,我就结合TI的官方文档和实际项目经验,把这套串行接口和TLL配置的里里外外给大家掰扯清楚,希望能帮你绕过我当年踩过的那些坑。
1. 串行接口模式的核心思想与设计考量
1.1 为什么需要串行接口?
在深入细节之前,我们得先明白一个根本问题:为什么放着成熟的并行UTMI+接口不用,非要搞一套串行接口?答案很简单,就是为了“瘦身”。标准的UTMI+(USB 2.0 Transceiver Macrocell Interface Plus)是一个并行、同步的接口,它包含了数据线、控制线和状态线,通常需要16位或更多位宽的数据总线,以及配套的时钟和控制信号。这对于一颗集成了USB Host功能的复杂SoC来说,意味着要拿出相当数量的GPIO或者专用引脚来对接一个外部的USB PHY芯片。
而在许多嵌入式应用中,USB可能只是众多功能中的一个,PCB空间和引脚资源都非常宝贵。串行接口模式应运而生,它通过一个叫做USBTLL的模块,将内部并行的UTMI+协议转换成了串行、异步的比特流。你可以把这个USBTLL模块想象成一个“协议翻译官”,它坐在SoC内部的主机控制器和外部世界之间。主机控制器还是按照UTMI+的规矩说话(并行、同步),USBTLL则负责把这些话翻译成更简洁的“电报”(串行、异步),然后通过寥寥几根线发送给外部的收发器(Transceiver)或者另一个设备的TLL接口。
这种转换带来的最直接好处就是引脚数量的锐减。从文档中可以看到,串行接口模式最少只需要2根线(DAT和SE0或DP和DM)就能实现双向通信,最多也只需要6根线。这相比于并行接口是一个巨大的优势。但天下没有免费的午餐,这个优势是用性能换来的。由于串行化过程以及接口本身是组合逻辑(没有随路时钟),其工作频率必须与USB线路上的实际比特率同步。对于全速(12 Mbps)和低速(1.5 Mbps)来说,这个频率尚在可接受范围内,但对于高速(480 Mbps)所需的复杂时钟和数据恢复机制,串行接口就力不从心了。因此,串行接口模式一个最重要的限制就是:它仅支持全速和低速(FS/LS)USB数据传输。如果你的应用必须支持高速设备,那么这条路就走不通了,必须回归并行ULPI或UTMI+接口。
1.2 系统架构与USBTLL模块的角色
理解了“为什么”之后,我们来看“是什么”。整个高速USB主机子系统的核心架构,可以参照文档中的图24-29。简单来说,它主要由三大部分构成:
- 主机控制器:包含EHCI(用于高速)和OHCI(用于FS/LS)控制器,负责处理高层的USB协议、调度事务、管理数据缓冲区等。它通过L3/L4互联总线与系统其他部分通信。
- USBTLL模块:这是串行接口模式的核心。它一端通过标准的UTMI+接口与主机控制器对话,另一端则提供我们讨论的各种串行接口(6-pin, 4-pin, 3-pin)和TLL接口。它负责完成并行到串行的编码/解码,以及侧带信号(Sideband Signals)的处理。
- 物理接口:即连接到SoC引脚的那一组信号线(
mmx_txdat,mmx_txse0,mmx_txen_n,mmx_rxrcv,mmx_rxdp,mmx_rxdm,其中x=1,2,3代表端口号)。这些引脚的功能是复用的,具体扮演什么角色(是输出DAT还是输入DP?),完全取决于你配置成了哪种接口模式。
这里需要特别强调一个关键概念:Transceiver配置和TLL配置是互斥的。文档里明确写着“ULPI (PHY) Interfaces and ULPI TLL Interfaces can not be used together”。这意味着,对于一个给定的USB端口,你只能二选一:要么把它配置成连接一个外部USB收发器芯片(Transceiver Configuration),要么把它配置成直接连接另一个集成了USB设备控制器的芯片的TLL接口(TLL Configuration)。前者是经典的“主机SoC + 外部PHY”模式;后者则是“主机SoC直连设备SoC”的模式,省去了中间的PHY芯片,常用于芯片间互连(Chip-to-Chip)。
注意:在硬件设计初期就必须确定每个USB端口的用途。如果你需要连接标准的USB插座和电缆,就必须使用Transceiver配置,并外接一颗USB PHY芯片(如TI的TUSB1210)。如果你是想在板子上直接将两颗SoC的USB主机和设备控制器对接,那么就可以使用TLL配置,实现无PHY的直连。
2. 串行接口模式详解:从6针到2针
串行接口模式根据数据方向和控制信号的复杂度,分成了多种子模式,核心区别在于引脚数量和信号编码方式。理解这些模式是正确配置硬件和软件的基础。
2.1 外部收发器接口模式
当你需要连接一个外部USB PHY芯片时,就使用这类模式。PHY芯片负责完成USB线路上的模拟信号(D+/D-差分信号)与SoC可以理解的数字信号之间的转换。
2.1.1 6针单向模式(6-Pin Unidirectional)
这是最“完整”的串行模式,使用了全部6个信号引脚,并且发送(TX)和接收(RX)路径是独立的(单向)。它又根据发送数据的编码方式分为两种:
- DAT/SE0编码:如表24-23和图24-19所示。SoC通过
TXEN(传输使能)、DAT(数据)、SE0(单端0)三个输出信号来控制PHY芯片驱动D+和D-线。同时,通过RCV(差分接收)、DP(D+单端)、DM(D-单端)三个输入信号来读取PHY芯片从USB线路上接收到的状态。这种编码更接近USB协议层的逻辑状态。 - DP/DM编码:如表24-24和图24-20所示。SoC直接输出
DP和DM的逻辑电平给PHY芯片,由PHY芯片原样驱动到USB差分线上。接收路径与DAT/SE0编码相同。
选择哪种编码?这取决于你选用的外部PHY芯片支持哪种接口。大部分常见的全速/低速PHY都同时支持这两种模式,需要通过芯片的配置引脚(如MODE)来选择。在设计原理图时,务必查阅PHY芯片的数据手册,确保SoC端的信号连接与PHY芯片的期望模式匹配。
2.1.2 双向模式(3-Pin & 4-Pin Bidirectional)
为了进一步节省引脚,可以利用USB通信半双工的特性(同一时刻只能发送或接收)。双向模式将发送和接收路径复用到同一组引脚上。
- 3针双向DAT/SE0模式:如表24-25和图24-21所示。仅使用
TXEN、DAT、SE0三根线。当TXEN有效时,DAT和SE0为输出,控制PHY发送;当TXEN无效时,DAT和SE0变为输入,用于接收PHY传来的总线状态。需要注意的是,文档明确指出该器件不支持3针双向的DP/DM编码。 - 4针双向DP/DM模式:如表24-26和图24-22所示。使用
TXEN、DP、DM、RCV四根线。DP和DM是双向的,在发送时作为输出,在接收时作为���入。RCV始终是输入,用于接收差分信号。同样,文档指出不支持4针双向的DAT/SE0编码。
实操心得:双向模式的时序挑战双向模式虽然省了引脚,但引入了方向切换的时序问题。从TX切换到RX时,SoC的I/O引脚需要从输出模式切换到输入模式,这个过程中如果处理不当,会产生短暂的冲突(Contention)或总线浮空(Floating),可能导致数据错误。因此,在驱动程序中,必须确保在
TXEN信号变化前后,有足够的时间裕量(通常由PHY或SoC的硬件逻辑保证,但软件需了解其机制)。在调试时,如果发现通信不稳定,可以尝试用示波器抓取TXEN和DAT/DP/DM信号的时序,检查切换瞬间是否有毛刺。
2.2 TLL逻辑接口模式
TLL模式用于SoC与SoC之间的直接数字连接,无需中间的PHY芯片。你可以把它理解为一种“数字化的USB”。在这种模式下,我们的SoC扮演主机角色,而连接的另一个芯片(内部集成USB设备控制器)扮演设备角色。TLL接口传输的已经是经过编码的数字信号,而非模拟差分信号。
2.2.1 TLL模式与收发器模式的关系
文档中强调,TLL配置是收发器配置的“镜像”。这句话非常关键。意思是,信号线的物理连接是一样的,但数据流的方向是相反的。
- 在收发器模式下,SoC(主机)输出控制信号(
TXEN,DAT/SE0或DP/DM)给外部PHY,并接收PHY返回的状态信号(RCV,DP,DM)。 - 在TLL模式下,SoC(主机)的同一个引脚,可能变为接收来自对方设备控制器的控制信号,或者输出状态信号给对方。
例如,在6针单向TLL模式下(图24-23,24-24),原本在收发器模式中作为输出的mmx_txdat和mmx_txse0,在TLL模式中变成了输入(DAT-TLL input),用于接收对方设备发来的数据;而原本作为输入的mmx_rxdp和mmx_rxdm,则变成了输出(DP-TLL output),用于向对方设备发送单端接收状态。
2.2.2 独特的2针双向TLL模式
这是最精简的模式,仅使用2根线(DAT和SE0,或DP和DM)实现双向通信。它之所以能工作,是因为在空闲状态(没有数据传输时),总线需要靠上拉/下拉电阻来维持一个确定的状态,以标识设备是全速还是低速,或者未连接。
如表24-27和24-28所示,2针TLL模式需要根据连接设备的类型(全速或低速)来配置不同的上拉/下拉电阻:
- DP/DM编码:
- 连接全速设备:DP线上拉,DM线下拉。
- 连接低速设备:DP线下拉,DM线上拉。
- 未连接设备:DP和DM都下拉。
- DAT/SE0编码:
- 连接全速设备:DAT线上拉,SE0线下拉。
- 连接低速设备:DAT线下拉,SE0线上拉。
- 未连接设备:DAT线下拉,SE0线上拉。
这些电阻通常需要外接在PCB上。这是硬件设计中的一个关键点,如果电阻配置错误,对方设备将无法被正确识别,导致枚举失败。图24-27和24-28清晰地展示了这两种情况下的连接方式。
注意事项:TLL模式的电平与驱动能力TLL接口是数字信号,电平通常是SoC的I/O电压(如1.8V, 3.3V)。而标准USB差分信号是模拟信号,电平在0V至3.3V之间变化。因此,TLL模式绝对不能直接连接到标准的USB插座或电缆上,否则会损坏接口。它仅用于板级芯片间的数字互连。另外,需要确认双方SoC的I/O电平是否兼容,必要时需使用电平转换器。
3. 侧带信号与软件控制
串行接口只负责传输USB数据本身。但一个完整的USB连接还需要许多控制和管理功能,例如:
- 速度选择:告知PHY是工作在Full-Speed还是Low-Speed。
- 挂起/恢复:控制PHY进入低功耗状态。
- 上拉/下拉使能:控制D+或D-线上的1.5kΩ上拉电阻,这是设备被主机识别的关键。
- VBUS控制与检测:控制主机端口是否提供5V VBUS电源,并检测VBUS是否有效。
这些信息被称为“侧带信号”。在并行UTMI+接口中,它们有专用的信号线。而在串行接口模式下,这些信号需要通过其他方式传递。
3.1 侧带信号的实现方式
文档24.2.2.4.2节明确指出,侧带信号的实现是“case-by-case, ad hoc”(视具体情况而定,特设的)。主要有两种方式:
- 专用引脚:为每一个侧带控制或状态信号分配一个独立的GPIO。这种方式简单直接,但会占用更多引脚资源。
- 串行总线:通过I2C、SPI或UART等串行总线,配合一个中断引脚,来读写PHY芯片内部的寄存器,从而控制侧带功能。这是更常见、更节省引脚的方式。许多USB PHY芯片(如SMSC的USB3320)都内置了I2C或SMBus接口用于配置。
在TLL配置下(图24-18),情况更特殊一些。因为另一端连接的也是一个数字控制器,侧带信号可能直接通过另外的数字信号线传递,或者被整合到TLL数据协议中(取决于具体实现)。
3.2 关键寄存器:TXEN极性控制
在串行接口中,TXEN(传输使能)信号至关重要,它指示当前是主机在发送数据(驱动总线)还是处于接收状态(监听总线)。文档中特别用CAUTION提示了TXEN信号的极性是可编程的。
通过配置CONTROL.CONTROL_WKUP_CTRL寄存器中的MM_FSUSBx_TXEN_N_OUT_POLARITY_CTRL位(x=1,2,3对应三个端口),可以控制TXEN信号是低电平有效还是高电平有效。这个配置必须与外部PHY芯片或对端TLL设备的期望极性严格一致。例如,如果你的PHY芯片数据手册规定TXEN低电平时驱动总线,那么你就需要将该控制位设置为与之匹配的极性。配置错误会导致总线冲突或根本无法通信。
4. 配置与调试实战指南
理论讲完了,我们来看看怎么把它用起来。这里以一个常见的场景为例:在TI的AM335x系列处理器上,配置USB0端口为全速主机,使用外部PHY芯片(如TUSB1210),采用4针双向DP/DM模式。
4.1 硬件设计与连接
首先,根据选定的模式(4-pin bidirectional DP/DM)和PHY芯片手册,完成原理图设计。以AM335x的USB0端口为例,我们需要连接以下信号:
| AM335x引脚 | 信号名称 (模式:4-pin bidir DP/DM) | PHY芯片 (TUSB1210) 引脚 | 功能描述 |
|---|---|---|---|
| USB0_DRVVBUS | (侧带信号) | VBUS_CTRL | 控制VBUS电源输出 |
| USB0_DM | I/O: DM | DP | 双向数据负线 |
| USB0_DP | I/O: DP | DM | 双向数据正线 |
| USB0_RCV | I: RCV | RCV | 差分接收器输出 |
| USB0_TXEN | O: TXEN | TXEN | 发送使能 |
| (GPIO) | (侧带) | MODE, XTAL1等 | PHY配置、时钟 |
关键点:
- 上拉电阻:在USB0_DP线上,需要连接一个1.5kΩ的上拉电阻到3.3V(通过一个MOSFET开关控制,开关由
USB0_DRVVBUS或另一个GPIO控制)。这是全速设备被识别所必需的。 - PHY配置:TUSB1210的
MODE引脚需要正确配置,以选择4-pin bidirectional DP/DM模式。这通常通过连接固定电平或由SoC的GPIO在上电时控制完成。 - 时钟:确保为PHY芯片提供正确的时钟(如24MHz晶振)。
4.2 软件驱动配置
在Linux内核中,配置通常通过设备树(Device Tree)完成。以下是一个简化的设备树节点示例,展��了如何配置USB0控制器和PHY:
/* 定义USB0控制器 */ &usb0 { status = "okay"; dr_mode = "host"; /* 配置为主机模式 */ pinctrl-names = "default"; pinctrl-0 = <&usb0_pins>; /* 引脚复用配置 */ /* 指定PHY,这里假设PHY通过I2C配置 */ phys = <&usb0_phy>; phy-names = "usb2-phy"; }; /* 配置USB0的引脚复用 */ &am33xx_pinmux { usb0_pins: pinmux_usb0_pins { pinctrl-single,pins = < AM33XX_IOPAD(0x9a0, PIN_OUTPUT | MUX_MODE0) /* USB0_DRVVBUS */ AM33XX_IOPAD(0x9a4, PIN_INPUT_PULLDOWN | MUX_MODE0) /* USB0_DM */ AM33XX_IOPAD(0x9a8, PIN_INPUT_PULLDOWN | MUX_MODE_MODE0) /* USB0_DP */ AM33XX_IOPAD(0x9ac, PIN_INPUT | MUX_MODE0) /* USB0_RCV */ AM33XX_IOPAD(0x9b0, PIN_OUTPUT | MUX_MODE0) /* USB0_TXEN */ >; }; }; /* 定义外部PHY节点,假设其I2C地址为0x18 */ &i2c0 { usb0_phy: phy@18 { compatible = "ti,tusb1210"; reg = <0x18>; /* 其他PHY特定属性,如复位GPIO、时钟等 */ reset-gpios = <&gpio1 15 GPIO_ACTIVE_LOW>; vcc-supply = <&vcc_3v3>; }; };在驱动层面,内核的musb或dwc2等USB主机控制器驱动会与PHY驱动(tusb1210)协作。PHY驱动负责通过I2C配置PHY芯片的工作模式(如设置为4-pin bidirectional DP/DM),并管理侧带信号(如VBUS控制)。
4.3 调试技巧与常见问题排查
在实际调试中,串行接口USB主机可能会遇到各种问题。下面是一个常见问题速查表:
| 现象 | 可能原因 | 排查步骤 |
|---|---|---|
设备插入无反应,lsusb不显示 | 1. VBUS未供电。 2. D+线上拉电阻未使能。 3. PHY未正确初始化。 4. SoC与PHY间模式不匹配。 | 1. 测量USB插座VBUS引脚是否有5V。 2. 测量D+线电压,插入全速设备后应为3.3V左右(被上拉)。 3. 检查PHY芯片的复位、时钟、电源是否正常,I2C通信是否成功。 4. 核对SoC的 TXEN极性、数据编码模式与PHY配置是否一致。 |
设备能识别但枚举失败(如usb 1-1: device descriptor read/64, error -110) | 1. 数据传输时序问题。 2. 信号完整性差(反射、串扰)。 3. 电源噪声大,导致数据错误。 | 1. 使用示波器或逻辑分析仪抓取DP/DM或DAT/SE0信号,看数据包波形是否规整,TXEN切换时序是否满足PHY要求。2. 检查USB差分线是否等长、阻抗是否控制在90Ω±10%,远离噪声源。 3. 测量VBUS和3.3V电源的纹波,确保在规格范围内。 |
| 通信间歇性失败 | 1. 双向模式方向切换时序临界。 2. 软件驱动有bug。 3. 外部干扰。 | 1. 尝试在驱动中增加TXEN切换后的微小延迟(需谨慎,可能违反USB时序规范)。2. 检查内核日志 dmesg,看是否有相关错误或警告。3. 在差分线上并联共模扼流圈,增强抗干扰能力。 |
| TLL模式对端设备无法识别 | 1. 上拉/下拉电阻配置错误。 2. 双方电平不兼容。 3. 对方设备控制器未配置为TLL模式。 | 1. 对照表24-27/24-28,用万用表测量DP/DM或DAT/SE0线上的静态电平是否正确。2. 测量双方I/O引脚电压,确认是否在同一电平域(如都是3.3V LVCMOS)。 3. 确认对端SoC的USB设备控制器也配置在了对应的TLL模式。 |
一个关键的调试工具是逻辑分析仪。配合USB协议分析软件(如Saleae Logic自带的USB分析插件),可以非侵入式地捕获DP/DM线上的数字波形,并解码出USB数据包。这对于判断问题是出在物理层、链路层还是协议层非常有帮助。例如,如果你能看到主机发送了Reset信号,设备也有回应,但后续的GET_DESCRIPTOR请求出错,那么问题可能出在数据内容或CRC校验上;如果根本看不到任何主机发起的通信,那么问题很可能在主机控制器的初始化或PHY的配置上。
5. 复位、时钟与电源管理要点
高速USB主机子系统涉及两个主要的电源域:USBHOST(包含主机控制器)和CORE(包含USBTLL模块)。它们有独立的复位和时钟。
- 复位:如表24-30所示,存在硬件复位(
USBHOST_RESET,USBTLL_RESET)和软件复位(通过UHH_SYSCONFIG.SOFTRESET和USBTLL_SYSCONFIG.SOFTRESET寄存器位)。硬件复位通常由上电复位或电源管理单元触发。软件复位是调试和恢复的利器。当USB子系统出现卡死或异常时,在驱动中触发一次软件复位,往往能使其恢复,而无需重启整个系统。 - 时钟:USB主机控制器需要工作时钟(如
USBHOST_48M_FCLK),USBTLL模块也需要自己的时钟(如USBTLL_ICLK)。这些时钟必须由PRCM(电源与时钟管理模块)正确配置和使能,且频率要符合数据手册要求。时钟未开启或频率错误是导致USB功能完全失效的常见原因。 - 电源管理:当系统进入低功耗状态时,需要按照顺序先关闭USB主机控制器、USBTLL模块,最后再处理PHY芯片。唤醒时则顺序相反。这部分逻辑通常由芯片的PRCM和USB驱动共同协作完成,但作为开发者,需要了解其流程,避免在电源状态切换时造成数据丢失或硬件异常。
理解并熟练运用串行接口与TLL配置,是嵌入式工程师在资源受限环境下实现稳定USB主机功能的一项宝贵技能。它要求你对硬件连接、信号时序、软件配置都有清晰的把握。希望这篇结合了文档解读与实践经验的梳理,能成为你手边一份有用的参考。在实际项目中,最稳妥的做法永远是:仔细阅读你所使用的具体SoC和PHY芯片的最新数据手册,用示波器和逻辑分析仪验证你的假设,然后写一小段测试代码进行验证,步步为营。