1. 项目概述与核心价值
搞嵌入式USB开发,特别是用TI的C2000系列这类实时微控制器,最头疼的往往不是写业务逻辑,而是跟那一大堆控制器寄存器打交道。手册里每个位域都认识,连起来就不知道该怎么配了。尤其是USB这种协议栈相对复杂的接口,端点寄存器的配置直接关系到数据传输的稳定性和效率。今天,我就结合TMS320F2807x的USB控制器,把USBTXCSRH、USBRXMAXP、USBRXCSRL这些关键端点寄存器掰开揉碎了讲清楚,重点聊聊怎么利用它们实现高效的DMA传输和可靠的数据包管理。无论你是在做USB主机(比如连接U盘、HID设备)还是USB设备(比如实现一个自定义的CDC或HID设备),这篇文章都能帮你绕过我当年踩过的那些坑,直接配出稳定高效的USB通信链路。理解这些寄存器,本质上就是理解USB控制器如何替你管理数据流,让你从繁琐的字节搬运中解放出来,专注于更上层的应用逻辑。
2. USB端点寄存器架构与核心设计思路
2.1 端点:USB数据通信的逻辑管道
在深入寄存器之前,必须建立对“端点”(Endpoint)的清晰概念。你可以把USB控制器想象成一个邮局,而每个端点就是邮局里一个个独立的信箱(编号为EP1, EP2, EP3...)。每个信箱有固定的用途:有的专门收信(IN端点,设备到主机),有的专门发信(OUT端点,主机到设备)。TMS320F2807x的USB控制器为每个这样的“信箱”配备了一套独立的管理工具,也就是我们今天要讲的端点寄存器组。
这套寄存器组的设计遵循一个核心思路:状态与控制分离,通用与专用结合。例如,USBTXCSRL和USBTXCSRH(发送控制与状态寄存器低/高字节)共同管理一个发送端点(OUT方向)的所有事务。低字节寄存器通常包含最常用、需要快速响应的状态位,如数据就绪(TXRDY)、错误标志等;而高字节寄存器则包含更高级或模式化的控制位,如DMA使能、自动处理模式等。这种分离既保证了关键状态访问的效率,又使得功能配置清晰有序。
2.2 主机模式与设备模式下的寄存器差异
一个容易被忽视但至关重要的细节是,同一组端点寄存器在主机模式(Host Mode)和设备模式(Device Mode)下,其位域定义和功能可能完全不同。这是由USB协议中主机与设备角色的根本性不对称所决定的。
以USBTXCSRH[n]寄存器为例:
- 在主机模式下:它包含
DTWE(数据翻转写使能)和DT(数据翻转)位,因为作为通信的发起者,主机需要主动管理数据包同步机制(Data Toggle)。 - 在设备模式下:这两个位被保留或功能不同。设备通常响应主机的请求,数据翻转序列由硬件根据接收到的ACK自动维护,软件干预的场景较少。
因此,在配置寄存器前,第一件事就是确认你的USB控制器当前工作在哪种模式,并查阅对应模式下的寄存器描述表。盲目照搬代码是USB开发中最常见的错误来源之一。
2.3 寄存器访问的基本准则
访问这些寄存器时,有几点硬件层面的经验需要牢记:
- 对齐访问:尽管很多寄存器是8位或16位,但TI的C2000系列通常要求32位对齐访问。使用C语言中的
volatile关键字修饰寄存器指针,并确保访问地址是4的倍数,可以避免潜在的硬件总线错误。 - 时序敏感操作:有些位的操作有严格的顺序要求。例如,手册中明确警告:
DMAMOD位不能在DMAEN位被清除的同一周期或之前被清除。这意味着在关闭DMA功能时,正确的步骤是先确保DMA传输已完全停止(可能需查询状态),再清除DMAMOD,最后清除DMAEN。违反这个顺序可能导致DMA控制器状态机挂起。 - 写1清除(W1C)标志位:像
STALLED、ERROR这类状态标志位,通常是通过向该位写1来清除的,写0无效。这是一个常见的硬件设计模式,用于确保软件能明确地确认并清除中断源。
3. 核心寄存器深度解析与配置要点
3.1 发送控制与状态高位寄存器(USBTXCSRH)
这个寄存器是发送端点的“大脑”,控制着数据推送的高级行为。我们逐位分析其妙用。
AUTOSET (Bit 7): 自动置位魔术师这个位是提升CPU效率的关键。当AUTOSET=1时,只要写入发送FIFO的数据量达到了USBTXMAXP[n]寄存器中定义的最大包长度,硬件就会自动将TXRDY位置1,通知USB核心“数据已备好,可以发送了”。
实操心得:在批量传输(Bulk Transfer)中,强烈建议启用
AUTOSET。这能让你用memcpy或DMA连续填充FIFO,而无需每写一个包就手动操作一次TXRDY位,极大简化了代码。但要注意,如果你发送的是一个短包(Short Packet,数据量小于最大包长),AUTOSET不会生效,你必须手动置位TXRDY来触发这次发送。短包常用于标识一个传输阶段的结束。
DMAEN & DMAMOD (Bit 4 & Bit 2): DMA传输的双保险
DMAEN=1:开启该端点的DMA请求。但这只是第一步。手册提示,最多只有3个TX端点可以连接到DMA模块。你需要同时在USBDMASEL寄存器中,将DMAATX、DMABTX或DMACTX字段配置为当前端点的编号,完成“物理连接”。DMAMOD:此位决定了DMA传输完成后的中断报告策略。DMAMOD=0:每成功传输一个数据包(Packet)就产生一次中断。适用于需要实时处理每个包的应用,例如流媒体音频,每个音频帧都需要及时处理。DMAMOD=1:仅在整段DMA传输(可能由多个包组成)全部完成后,才产生一次中断。这非常适合大块数据的搬运,比如读写U盘的一个扇区(512字节),可能被拆成多个USB包传输。使用此模式能显著降低中断频率,提升系统实时性。
注意事项:
DMAMOD位仅在端点配置为批量或中断传输模式时有效。等时传输(Isochronous)不适用,因为等时传输不重试,也没有包级别的成功确认概念。
FDT (Bit 3): 强制数据翻转的急救按钮FDT位是一个强力但危险的工具。置1后,它会强制切换DT位并清空FIFO中的数据包,即使没有收到对方的ACK确认。
踩坑记录:这个功能主要用于从错误中恢复。例如,主机和设备之间的数据包序列(DATA0, DATA1)因某个丢包而失步,导致后续所有包因序列错误被拒绝。此时,在精确控制的时机(确保对方也复位了序列)使用
FDT,可以强行同步序列。手册特别警告:此位仅在TXRDY置位时设置才安全。在其他时间设置,可能损坏正在传输或准备中的有效数据,造成不可预知的通信混乱。务必慎用。
MODE (Bit 5): 端点方向切换器此位仅在使用双向FIFO(即同一个FIFO既用于发送也用于接收)时才有效。通过软件切换MODE位,可以动态改变该端点的数据流方向。这在实现某些特殊协议或节省硬件资源时有用,但会增加软件复杂度,一般建议为发送和接收分配独立的端点。
3.2 最大接收数据端点寄存器(USBRXMAXP)
这个16位寄存器定义了单次事务(Transaction)中,该接收端点所能接受的最大数据载荷(Payload)。其低11位(Bit 10-0)MAXLOAD以字节为单位。
配置计算与约束
- 协议限制:对于全速(Full-Speed)USB的批量或中断传输,单个数据包的最大载荷理论上是64字节。高速模式下可达512字节。你设置的值不能超过USB规范对你当前速度下该传输类型的限制。
- FIFO容量约束:这是最关键的硬件限制。
USBRXMAXP[n]设定的值绝对不能超过分配给该端点的接收FIFO的总大小。例如,如果EP2的RX FIFO深度被配置为128字节,那么MAXLOAD就不能设为256。 - 双缓冲要求:如果你使能了该端点的双缓冲(Double-Buffering),那么
MAXLOAD的值不能超过FIFO总大小的一半。因为双缓冲意味着需要两个独立的缓冲区(Buffer A和Buffer B)来乒乓操作:当一个缓冲区正在被USB核心填充时,另一个缓冲区可以供CPU或DMA读取。如果包太大,一个包就占满了整个FIFO,双缓冲就失去了意义。 - DMA基础模式下的对齐要求:手册脚注提到,为了使DMA基础模式下的中断正常产生,
USBRXMAXP[n]必须设置为偶数。这是因为DMA传输通常以字(4字节)为单位,偶数设置可以避免边界对齐问题。
配置示例:假设为EP2配置一个全速批量接收端点,分配了64字节的FIFO,并启用双缓冲。
- 首先,全速批量包最大64字节,符合。
- 其次,FIFO总大小64字节,双缓冲要求每个缓冲区<=32字节。因此,
MAXLOAD应设为32。- 最后,检查是否为偶数(32是偶数),满足DMA要求。 所以,应配置
USBRXMAXP[2] = 32。
3.3 接收控制与状态低位寄存器(USBRXCSRL)
这是接收端点的“前线指挥所”,负责处理数据到达后的即时状态和操作。
REQPKT (Bit 5, 主机模式): 请求数据包在主机模式下,当你想从设备读取数据(发起IN事务)时,需要将此位置1。硬件会在发起事务后自动清除此位。结合高字节寄存器的AUTORQ位,可以实现自动连续请求,非常适合大数据块传输。
FLUSH (Bit 4): FIFO清道夫当接收FIFO中的数据出错或你想丢弃当前数据包时,将此位置1。它会复位FIFO指针并清除RXRDY位。
重要警告:手册明确指出,此位仅当
RXRDY位为1时设置才是安全的。如果在RXRDY=0(FIFO空或数据已被取走)时刷新,可能会破坏内部FIFO状态机,导致后续数据错乱。对于双缓冲FIFO,你可能需要连续执行两次FLUSH操作才能完全清空两个缓冲区。
DATAERR / NAKTO (Bit 3, 主机模式): 错误与超时监视器
- 对于批量端点:此位作为
NAKTO(NAK超时)。如果设备持续返回NAK握手包(表示“忙,请重试”),时间超过了USBRXINTERVAL[n]寄存器中NAKLMT字段设定的时限,此位会被置1,端点暂停。软件必须清除此位才能恢复传输。这防止了主机因设备永久繁忙而陷入死循环。 - 对于其他端点:此位可能指示数据错误(如CRC校验失败)。
RXRDY (Bit 0): 数据到达的门铃这是最重要的状态位之一。当RXRDY=1时,表示至少有一个完整的数据包已经到达接收FIFO,等待读取。如何清除它取决于AUTOCL(自动清除)位的设置:
AUTOCL=1:当从FIFO中读取的数据量恰好等于USBRXMAXP[n]定义的最大包长时,硬件自动清除RXRDY。这常用于固定长度的数据流。AUTOCL=0或 读取的数据量小于最大包长(短包):软件必须手动清除RXRDY位(通常通过向一个特定的清除寄存器位写1),以告知硬件“数据已取走,可以接收下一个包了”。
3.4 接收控制与状态高位寄存器(USBRXCSRH)
AUTOCL & AUTORQ (Bit 7 & Bit 6, 主机模式): 自动化流水线
AUTOCL:如前所述,控制RXRDY的自动清除。AUTORQ:这是一个强大的自动化工具。当AUTORQ=1且RXRDY位被清除(意味着上一个包已被取走)时,硬件会自动将REQPKT位置1,发起下一个IN事务请求。这实现了“取走一个,立即请求下一个”的流水线操作,无需软件干预,极大提升了连续读取数据的效率。
联动配置技巧:在主机模式下进行大数据量读取时,典型的优化配置是:
AUTOCL=1,AUTORQ=1,并配合DMA。这样,DMA负责将数据从FIFO搬移到内存,每搬完一个最大包,RXRDY自动清零,紧接着AUTORQ触发新的数据请求,形成一个全自动的高效数据流。注意:当收到短包时,AUTORQ位会被硬件自动清零,因为短包通常意味着传输结束,需要软件介入判断。
DISNYET/PIDERR (Bit 4, 设备模式): 流量控制开关在设备模式下,对于高速(High-Speed)USB的批量或中断传输,设备可以通过发送NYET握手包来告知主机“暂时没准备好,请稍后再试”,这是一种流量控制机制。当DISNYET=1时,设备将禁用发送NYET,对所有成功接收的数据包都回复ACK。这在FIFO处理速度足够快,或者你想简化协议交互时可以使用。但如果FIFO已满,又禁用了NYET,设备将无法有效通知主机暂停发送,可能导致数据丢失。因此,除非你非常确定数据流不会超过处理能力,否则建议保持此位为默认值0。
4. DMA传输与数据包管理的实战配置流程
理解了单个寄存器后,我们将其串联起来,看一个完整的实战场景:在TMS320F2807x上,为主机模式的EP2端点配置一个批量OUT传输(主机发送数据到设备),并使用DMA将数据从内存自动搬运到USB发送FIFO。
4.1 步骤一:端点基础配置
首先,我们需要告诉USB控制器,EP2端点是一个做什么用的“信箱”。
- 配置端点类型与目标:写入
USBTXTYPE[2]寄存器。SPEED字段:根据连接的设备速度,设置为2h(全速)或3h(低速)。PROTO字段:对于批量传输,设置为2h(Bulk)。TEP字段:设置为目标设备的端点号。例如,如果通信的设备其OUT端点号为1,则此处填1。这个值来自设备枚举时返回的端点描述符。
- 配置数据包大小:写入
USBTXMAXP[2]寄存器。根据目标设备端点描述符中报告的wMaxPacketSize(例如64字节)进行设置。同时确保此值不超过分配给EP2的发送FIFO大小。
4.2 步骤二:启用DMA传输流水线
接下来,配置高级控制,启用自动化。
- 配置发送控制高位寄存器:写入
USBTXCSRH[2]寄存器。- 设置
DMAEN = 1,使能EP2的DMA请求。 - 设置
DMAMOD = 1,我们希望在整个DMA传输块(比如传输512字节数据,分为8个64字节的USB包)完成后才产生一次中断,减少CPU打扰。 - 设置
AUTOSET = 1,启用自动置位TXRDY。这样,每当DMA或CPU向FIFO写满一个最大包(64字节),硬件就自动标记数据就绪。
- 设置
- 连接DMA通道:配置
USBDMASEL寄存器。假设我们使用DMA通道A来处理发送,找到DMAATX字段,将其值设置为2(代表EP2)。这就完成了端点与DMA控制器之间的“接线”。
4.3 步骤三:DMA控制器配置
现在去配置DMA控制器本身(这部分属于DMA外设,但至关重要)。
- 设置源地址与目标地址:
- 源地址(
SRC_ADDR):你的应用程序数据在内存中的起始地址(例如,一个数组tx_data_buffer的地址)。 - 目标地址(
DST_ADDR):USB控制器中EP2发送FIFO的访问地址。这是一个固定的外设地址,需查阅芯片内存映射表。
- 源地址(
- 设置传输量:在DMA控制寄存器中,设置总传输字节数(
TRANSFER_SIZE)为512。 - 设置传输单元与地址模式:
- 传输单元大小���
BURST_SIZE):设置为16或32(字)。USB FIFO通常以字(4字节)为单位访问。 - 源地址模式:设置为“递增”(Increment),因为我们是顺序读取内存中的数据。
- 目标地址模式:设置为“固定”(Fixed),因为我们始终是往同一��FIFO地址写入。
- 传输单元大小���
- 配置触发源:将DMA传输的触发源设置为“USB EP2 TX DMA请求”。这样,每当USB控制器需要数据填充FIFO时,就会向DMA发出请求。
4.4 步骤四:启动传输与流程闭环
- 启动DMA:使能配置好的DMA通道。
- 写入第一包数据(可选但推荐):在DMA自动工作前,软件可以手动向EP2的FIFO写入第一个数据包(最多64字节)。这能更快地启动第一次USB事务。
- 自动运行:此后,流程进入自动化:
- DMA根据请求,将数据从内存搬运到USB发送FIFO。
- 当FIFO中数据达到
USBTXMAXP[2]设定的大小时,硬件自动置位TXRDY。 - USB核心检测到
TXRDY,发起一次USB OUT事务,将数据包发送给设备。 - 设备回复ACK后,FIFO空间释放,
TXRDY清零,DMA收到新请求,继续填充下一个包。 - 循环直至DMA完成全部512字节的传输。
- 完成中断:当DMA传输完所有数据(
DMAMOD=1模式下),USB控制器会产生一个中断。在中断服务程序(ISR)中,你需要检查USBTXCSRL[2]寄存器中的状态位(如是否有错误),并进行必要的清理工作。
核心逻辑闭环:这个配置的精髓在于形成了一个“DMA搬运 -> FIFO满 -> 自动TXRDY -> USB发送 -> 腾空FIFO -> 触发下一次DMA请求”的闭环。CPU仅在初始化和最终完成中断时介入,实现了极高的数据传输效率。
5. 双缓冲机制与高级数据包管理
5.1 双缓冲(Double-Packet Buffering)原理与配置
双缓冲是USB控制器提升吞吐量、避免数据覆盖的关键技术。以接收端点为例,它有两个独立的物理缓冲区:Buffer A和Buffer B。
- 阶段1:USB核心正在将接收到的数据包写入Buffer A。
- 阶段2:Buffer A写满后,硬件自动将
RXRDY置位,同时立即切换至Buffer B,准备接收下一个数据包。此时,CPU或DMA可以安全地从Buffer A读取数据。 - 阶段3:当Buffer B也写满时,如果Buffer A的数据已被读取完毕(
RXRDY已清除),则硬件再次切换回Buffer A进行写入,同时置位RXRDY通知Buffer B数据就绪。
这就实现了接收和读取的并行操作,消除了等待时间。发送端点的双缓冲原理类似,实现了数据填充和USB发送的并行。
配置与禁用双缓冲功能通常是默认使能的。寄存器USBRXDPKTBUFDIS和USBTXDPKTBUFDIS用于禁用特定端点的双缓冲。为什么需要禁用?
- 节省FIFO内存:对于数据量很小或实时性要求不高的端点(例如某些中断端点),禁用双缓冲可以将两个缓冲区的内存合并为一个更大的缓冲区,用于其他更需要大缓冲的端点。
- 简化软件逻辑:在某些极简应用中,单缓冲的管理更直接。
配置注意:如果你决定禁用某个端点的双缓冲,那么之前提到的
MAXLOAD不能超过FIFO总大小的限制就变成了不能超过整个FIFO大小,而不是一半。同时,在刷新FIFO(FLUSH)时,也只需要操作一次。
5.2 数据翻转(Data Toggle)机制与软件干预
数据翻转是USB保证数据包序列同步的底层机制。每个数据包(DATA0, DATA1)都带有一个交替的PID(Packet ID)。发送方和接收方各自维护一个DT位(在USBTXCSRH和USBRXCSRH中),用于跟踪期望接收的下一个PID。
硬件自动管理:在正常通信中,每当一个数据包被成功确认(ACK),硬件会自动翻转DT位。这个过程完全透明,无需软件干预。
软件何时需要干预?在错误恢复场景下。例如:
- 通信因干扰中断,导致一方
DT序列与另一方不同步。 - 软件需要主动复位一个端点的传输状态。
安全操作流程:
- 停止当前活动:确保端点没有正在进行的事务(
TXRDY或RXRDY为0)。 - 获取写权限:将
DTWE位(Data Toggle Write Enable)置1。注意,此位在写入后会自动清零,是一个“一次性”使能位。 - 写入目标值:在
DTWE=1的同一个操作周期内,向DT位写入期望的值(通常是0,即复位到DATA0状态)。 - 恢复传输:重新配置端点并开始新的传输。
绝对禁忌:不要在数据传输过程中(
TXRDY=1或RXRDY=1)随意修改DT位,这必然导致数据包序列错误,通信失败。手册中“Care should be taken”的警告绝非空话。
5.3 块传输(Block Transfer)与包计数管理
在主机模式下进行大数据量IN传输(从设备读取)时,可以使用块传输配合USBRQPKTCOUNT[n]寄存器进行精细控制。
场景:主机需要从设备读取1024字节数据,设备端点最大包长为64字节,因此需要16个IN事务。
传统方式:软件循环16次,每次先置位REQPKT,等待RXRDY,读取数据,清除RXRDY。
块传输优化方式:
- 设置
USBRXMAXP[n] = 64。 - 设置
USBRQPKTCOUNT[n] = 16(要请求的包数量)。 - 配置
USBRXCSRH[n]:AUTORQ=1(自动请求),AUTOCL=1(自动清除),并启用DMA。 - 软件只需一次性置位
REQPKT,或者依靠AUTORQ在第一次RXRDY清除后自动发起请求。 - 硬件会自动管理剩下的15次请求。DMA会连续地将16个包的数据从FIFO搬移到内存。
- 当
USBRQPKTCOUNT[n]递减到0,且所有数据接收完毕,产生中断通知软件。
这种方式将多次事务请求的调度工作交给了硬件,软件只需处理开始和结束,效率更高,尤其适合与DMA配合进行大块数据搬运。
6. 常见问题排查与调试技巧实录
6.1 问题一:数据传输卡死,无任何中断产生
现象:配置好端点并启动传输后,程序似乎“冻住”了,没有进入预期的TX或RX中断服务程序。
排查思路:
- 检查端点使能与方向:首先确认
USBINDEX寄存器是否已正确指向你要操作的端点号(n)。一个常见的低级错误是操作了USBTXCSRL[1],但USBINDEX还指向0,结果配置全写给了EP0。 - 检查FIFO分配:如果端点根本没有被分配到有效的FIFO空间,它无法工作。查阅芯片手册的USB章节,确认
USBFIFOx寄存器是否已为你的端点(EPn)分配了非零大小的FIFO。我曾遇到过忙活半天,最后发现FIFO大小为0的尴尬情况。 - 检查DMA连接:如果使用了DMA,确认
USBDMASEL寄存器中对应的DMAxTX或DMAxRX字段是否已正确设置为端点号n。DMAEN位打开了,但“线路”没接上,DMA请求无法送达。 - 检查协议与速度匹配:主机模式下,
USBTXTYPE[n]/USBRXTYPE[n]中的PROTO和SPEED字段必须与目标设备端点描述符完全匹配。一个全速设备配成了低速,通信根本无法建立。
6.2 问题二:能收到数据,但数据错乱或丢失
现象:通信似乎建立了,也能触发中断,但读取到的数据内容不对,或者每几个包就丢一个。
排查思路:
- 首要怀疑:数据翻转(Data Toggle)不同步。这是导致数据包被静默丢弃(设备回复ACK但主机/设备因PID错误而忽略数据)的最常见原因。在调试器中,同时监控通信两端端点的
DT位。在传输开始前,它们应该都为0(DATA0)。成功传输一个包后,应同时翻转为1(DATA1)。如果发现不同步,就需要按前述安全流程复位DT序列。 - 检查FIFO指针与
FLUSH操作:是否在不恰当的时机(RXRDY=0时)执行了FLUSH操作?这会导致内部FIFO状态机错乱。确保只在RXRDY=1时刷新FIFO。 - 核对
USBRXMAXP与AUTOCL设置:如果AUTOCL=1,但实际收到的数据包长度不等于USBRXMAXP设定的值(例如收到了一个短包),那么RXRDY位不会被自动清除。如果你没有手动清除它,端点将无法接收下一个包,表现为“丢包”。在中断服务程序中,读取USBRXCOUNT[n]获取实际字节数,并与USBRXMAXP比较,以决定是否需要手动清除RXRDY。 - DMA传输边界问题:当使用DMA从接收FIFO读取数据时,手册警告数据总是以4字节为单位读取。如果你设置的
USBRXMAXP不是4的倍数,DMA可能会多读几个字节(对齐到下一个字边界),这可能破坏后续内存中的数据。解决方案是确保MAXLOAD是4的倍数,或者在DMA传输完成后,根据USBRXCOUNT的实际值来修正数据长度。
6.3 问题三:DMA传输不完整或中断异常
现象:DMA似乎启动了,但传输到一半停止,或者中断产生的时间点不符合预期。
排查思路:
DMAMOD位理解错误:如果设DMAMOD=0(每包中断),却期待只在全部数据传完才进一次中断,那肯定会困惑。确认你的中断服务程序(ISR)设计能与DMAMOD模式匹配。在DMAMOD=0模式下,ISR会被频繁调用,需要高效地处理每个包。- DMA传输大小与
USBRQPKTCOUNT不匹配:在主机IN块传输中,USBRQPKTCOUNT设定了请求的包数。如果DMA配置的传输总字节数不等于USBRQPKTCOUNT * USBRXMAXP,会导致DMA提前搬完数据但硬件还在等待剩余包,或者硬件传输结束但DMA还在空转。 - 中断标志未清除:USB或DMA中断产生后,必须在ISR中读取相应的中断状态寄存器(如
USBRXIS、USBTXIS)并清除对应的中断标志位。如果忘记清除,会导致中断持续触发或不再触发。
6.4 调试技巧:利用状态寄存器进行“快照”诊断
当通信异常时,不要盲目修改代码。应该编写一个调试函数,在关键点(如进入中断时、超时发生时)将相关端点的所有控制状态寄存器(USBTXCSRL/H,USBRXCSRL/H,USBTXCOUNT,USBRXCOUNT等)的值读取并打印或保存下来。
对比这些“快照”与预期值:
TXRDY/RXRDY状态是否符合预期?FULL位是否被置位(表示FIFO满/空)?ERROR或STALLED位是否被置位?DT位的值是多少?
通过分析这些状态位的组合,可以非常精准地定位问题所在阶段,是FIFO管理问题、DMA握手问题,还是协议层的握手问题。这种基于寄存器状态的诊断方法,比盲目抓取USB总线数据更直接有效。