公司动态
深入解析USB设备中断与DMA机制:从原理到TI控制器实战
1. 项目概述与核心价值搞嵌入式USB设备开发的朋友对“中断”和“DMA”这两个词一定不陌生。它们就像是设备控制器的“神经系统”和“高速公路”。中断负责及时响应主机的各种指令和状态变化比如设备被挂起、恢复或者某个端点有数据到达而DMA则是在大数据量传输时绕开CPU让数据在内存和USB控制器之间直接“飞奔”解放CPU算力。今天我们就以TI经典的USB设备控制器参考文档SPRU761A为蓝本把这两个核心机制——尤其是挂起/恢复中断和DMA操作——掰开揉碎了讲清楚。这不仅仅是读数据手册更是理解如何让一个USB设备既省电又高效的关键。无论你是在设计一个低功耗的HID设备还是一个需要高速传输数据的数据采集卡吃透这部分内容都能让你在调试时心里更有底设计时方案更优化。2. USB设备控制器中断体系深度解析USB设备控制器通过一套精细的中断系统让微处理器MPU能够及时知晓并处理总线上发生的各类事件。这套体系大致分为三类通用USB中断、端点特定中断非同步和SOF帧起始中断。理解它们的触发条件和处理流程是编写稳定驱动的基础。2.1 挂起与恢复中断低功耗的守门人挂起Suspend和恢复Resume是USB电源管理的关键。当总线D和D-线保持空闲状态超过3ms时主机认为可以挂起设备以节省功耗设备控制器会在检测到5ms空闲后为识别挂起和准备恢复留出余量触发挂起中断。中断处理的核心逻辑在于判断当前是进入挂起还是退出挂起。这通过读取设备状态寄存器DEVSTAT的SUS位来实现。如果SUS1表示设备已进入挂起模式反之则表示设备正在从挂起中恢复。关键操作与考量低功耗模式进入一旦确认进入挂起MPU应通知应用程序并可能将自身切入低功耗状态如睡眠模式。此时若控制器配置允许SYSCON1.SOFF_DIS048MHz的主时钟会被自动关闭这是功耗下降的大头。远程唤醒设备并非只能被动等待主机唤醒。如果设备支持远程唤醒通过设置DEVSTAT.R_WK_OK 1它可以在需要时主动唤醒总线。操作流程是MPU先恢复时钟如果已停止然后设置系统控制寄存器2的远程唤醒位SYSCON2.RMT_WKP控制器便会驱动总线产生一个“恢复”信号K状态。中断清理处理完状态判断和应用层通知后必须通过向中断源寄存器IRQ_SRC的DS_CHG位写1来清除此次中断否则中断会持续触发。注意一个常见的陷阱是USB复位Reset也会使设备退出挂起状态。但此时硬件会依次产生三个中断恢复中断、复位中断、复位结束中断。因此你的挂起/恢复中断处理程序不需要特别处理复位退出的情况只需专注于SUS状态判断即可复位流程由专门的复位中断服务程序处理。试图在一个中断里处理所有情况反而会让逻辑变得复杂且容易出错。2.2 非同步端点中断数据搬运的指挥官非同步Non-ISO端点主要指控制Control、批量Bulk和中断Interrupt传输端点除了端点0的控制传输部分。它们的数据传输成功与否依赖于精确的握手包ACK, NAK, STALL。对应的中断服务程序ISR是USB数据传输的“前线指挥官”。中断路由与解析这类中断通常映射到MPU的一个特定中断线如IRQ_30。ISR的第一步是“破译”中断源读取IRQ_SRC寄存器检查是接收中断EPn_RX被置位还是发送中断EPn_TX被置位或者两者同时发生。硬件保证同一时间每个方向IN或OUT只有一个端点能产生中断。定位具体端点通过读取端点状态寄存器EPn_STAT获取产生中断的端点号ENDP_NB。配置端点号寄存器这是非常关键且容易出错的一步。在处理该端点的数据之前必须正确设置EP_NUM寄存器告诉控制器接下来要操作哪个端点、哪个方向。例如要处理端点2的OUT接收中断需要设置EP_NUM.EP_NUM 2,EP_NUM.EP_DIR 0(OUT方向),EP_NUM.EP_SEL 1。OUT端点接收中断处理以非控制OUT端点为例中断产生通常意味着一次OUT事务完成。ISR需要检查状态标志寄存器STAT_FLGACK收到表示主机发送的数据包已被设备成功接收。此时ISR需要从RX FIFO中读取数据流程见下文然后通过设置CTRL.SET_FIFO_EN1来“解锁”FIFO准备接收下一个数据包。STALL表示端点处于停滞状态。需要判断停滞是由主机发起还是本地LH发起。如果是本地发起的停滞且条件已解除可以通过设置CTRL.CIR_HALT来清除停滞条件。NAK如果使能了NAK中断则表示设备暂时无法接收数据比如缓冲区满。通常在非DMA模式下NAK中断可能被禁用由硬件自动回复NAK。IN端点发送中断处理当设备有数据要发送给主机时处理流程类似但方向相反。ACK收到表示主机已成功接收上一个数据包。ISR可以将已发送的数据从应用层的发送缓冲区中“退休”移除如果还有后续数据则继续写入TX FIFO并设置CTRL.SET_FIFO_EN1启动发送。STALL处理方式同OUT端点。数据搬运将数据从应用缓冲区写入TX FIFO时需注意端点配置的包大小。如果应用数据长度小于包大小需要发送一个短包Short Packet这通常是通过写入实际数据长度并设置相应标志来实现的。短包是通知主机传输结束的重要信号尤其在批量传输中。2.3 SOF中断与同步传输实时性的保障SOFStart Of Frame中断每1毫秒发生一次为同步Isochronous传输提供了精确的时间基准。同步传输常用于音频、视频等对延迟敏感、允许一定错误率的场景。SOF ISR的核心任务就是为所有已配置的同步端点服务一轮。流程是循环式的遍历所有已配置的同步OUT端点读取其RX FIFO中的数据。遍历所有已配置的同步IN端点向其TX FIFO中写入下一帧要发送的数据。处理同步传输特有的错误状态如DATA_FLUSH数据被刷新通常因错误发生或ISO_ERROR同步错误。清除SOF中断标志IRQ_SRC.SOF。实操心得同步传输的时序要求非常严格。MPU必须在下一个SOF到来之前完成对所有同步端点的读写操作。这意味着你的SOF ISR执行时间必须足够短。在设计时要避免在SOF ISR中进行复杂的计算或内存拷贝。通常的做法是在SOF ISR中只进行必要的数据搬运和状态检查将数据处理如音频编解码放在后台任务中。此外对于IN端点如果上一帧的数据因故未能发送MISS_IN标志需要决定是重发旧数据还是发送新数据这需要根据应用场景制定策略。3. DMA操作解放CPU的数据高速公路当数据量变大时如果每个USB数据包都通过CPU来搬运将会产生海量的中断消耗大量CPU资源。DMA直接内存访问正是为了解决这个问题而生。USB设备控制器通常集成DMA引擎能够自动管理数据在内部FIFO和系统内存之间的传输。3.1 DMA通道架构与配置要点以参考设计为例控制器提供了6个独立的DMA通道3个用于接收OUT3个用于发送IN。这是一个非常重要的资源划分。配置黄金法则通道与端点绑定通过RXDMA_CFG.RXDMAn_EP或TXDMA_CFG.TXDMAn_EP寄存器将一个物理DMA通道分配给一个特定的端点号。写入0则解绑。特别注意控制端点0EP0通常不支持DMA操作因为其传输量小且协议复杂更适合用中断处理。配置时机DMA通道的配置如分配端点、设置传输大小必须在设备地址设置阶段Address State完成也就是在DS_CHG设备状态改变中断期间进行。在其他时间配置可能导致不可预知的行为。MPU访问禁忌一旦启动了某个端点的DMA传输MPU就绝对不能再通过EP_NUM、CTRL、STAT_FLG等寄存器直接访问这个端点直到DMA传输结束。这包括不能设置Halt停滞特性。所有的控制都应通过DMA相关的寄存器来完成。3.2 接收OUTDMA传输详解接收DMA用于将主机发送到设备的数据自动搬运到系统内存。根据端点类型行为有所不同。非同步OUT端点DMA请求触发当数据被硬件放入端点FIFO且达到可触发DMA搬运的条件时控制器会向系统DMA控制器发出请求。两个关键中断传输结束中断RXn_EOT标志着一次DMA传输会话的结束。触发条件有两个1) 收到一个短包包括长度为0的空包2) 传输的事务数达到了预设值RXDMAn.RXn_TC且RXDMAn.RXn_STOP位被置位。处理完EOT中断后必须重新设置CTRL.SET_FIFO_EN来使能该端点才能准备下一次DMA传输。事务计数中断RXn_CNT用作“水印”Watermark通知。当传输的事务数达到RXDMAn.RXn_TC预设值时触发即使传输尚未结束。这常用于监控文件传输进度例如在接收一个未知大小的文件时可以每接收N个数据包就通知一次应用层用于更新进度条或进行初步处理。双缓冲机制很多控制器的DMA支持双缓冲Double Buffering。当DMA正在从“前台缓冲区”Buffer A向内存搬运数据时USB核心可以同时向“后台缓冲区”Buffer B写入新收到的数据。两个缓冲区交替使用极大地提高了吞吐率避免了数据丢失。在配置和使用时需要仔细阅读手册中关于缓冲区切换和指针管理的部分。同步OUT端点DMA 行为相对简单。只要主机在每一个USB帧1ms里发送了同步数据包并且没有错误DMA请求就会在每个帧开始时产生一次。同步DMA没有专用的传输结束或计数中断传输的启停完全由主机的数据流决定。应用层需要通过其他方式如数据量统计来判断传输是否完成。3.3 发送INDMA传输详解发送DMA用于将系统内存中的数据自动搬运到USB控制器的TX FIFO进而发送给主机。非同步IN端点DMA 这是最复杂的一种情况因为它需要处理任意大小的数据块。核心参数是传输大小计数器TXDMAn.TXN_TSC和结束位TXDMAn.TXN_EOT。EOT1TXN_TSC表示要传输的字节总数。EOT0TXN_TSC表示要传输的缓冲区个数每个缓冲区的大小等于端点的物理缓冲区大小如64字节。由于单个DMA传输会话有长度限制例如受限于内部计数器位数传输一个大文件需要拆分成多次DMA会话多次“Pass”。文档中给出了一个精妙的算法和示例大文件传输拆分算法以端点缓冲区大小32字节为例设文件总字节数FTZ 100603。计算EOTB FTZ (32-1) 27。这是最后一段零头字节数。计算temp FTZ 5(除以32) 3143。计算XSWL temp 10(除以1024) 3。这表示有3个完整的“1024缓冲区”块。计算FBT temp 0x3FF 71。这是最后一个“非完整1024块”中的缓冲区数量。传输将分5个DMA会话完成会话1:EOT0, TSC0(0代表1024),XSWL3- 传输 1024 * 32 32768 字节。会话2:EOT0, TSC0,XSWL2- 传输 32768 字节。会话3:EOT0, TSC0,XSWL1- 传输 32768 字节。会话4:EOT0, TSC71,XSWL0- 传输 71 * 32 2272 字节。会话5:EOT1, TSC27,XSWL0- 传输 27 字节。每个DMA会话结束后都会产生一个TXn_DONE中断。在中断处理程序中需要根据XSWL和FBT的值决定并启动下一个会话的传输参数直到整个文件发送完毕。同步IN端点DMA 行为与同步OUT DMA类似但方向相反。在每个SOF到来时如果DMA通道已配置且就绪控制器会发出DMA请求要求MPU的DMA控制器将下一帧的数据写入。TXN_TSC在这里直接表示要写入的字节数且不能超过端点缓冲区大小。同样没有专用的传输完成中断。3.4 DMA通道的禁用与注意事项不当的DMA通道禁用操作会导致数据丢失或硬件挂起。推荐的做法是等待传输完成中断RXn_EOT或TXn_DONE后再将配置寄存器中的端点号写0来禁用通道。如果必须在传输过程中强制禁用需要理解其行为接收时禁用如果禁用时DMA请求正活跃则禁用操作会延迟到当前请求的数据全部被DMA读取完毕后生效。如果使用了双缓冲则需要两个缓冲区的数据都被读走。发送时禁用如果禁用时DMA请求正活跃则禁用操作会延迟到当前请求的数据被填入FIFO并成功发送产生IN事务后生效。即使此时TSC已减到0也不会产生TX_DONE中断。在强制禁用后软件必须轮询TX/RXDMA_CFG.TX/RXDMAn_EP寄存器直到其值变为0确认通道已真正释放才能对该端点进行其他操作。4. 实战配置流程与避坑指南理解了原理我们来看如何将这些知识落地到代码中。以下是一个非同步批量OUT端点启用DMA接收的典型配置流程。4.1 非同步OUT端点DMA接收配置流程端点初始化在设备枚举阶段配置该端点的类型Bulk OUT、地址、最大包大小等。确保端点的双缓冲如果使用等特性已按需配置。等待地址设置中断在设备收到主机分配的地址触发DS_CHG中断后开始DMA配置。配置系统DMA控制器这不是USB控制器的工作但至关重要。你需要配置系统MPU侧的DMA控制器设置源地址为USB控制器的DATA_DMA寄存器地址目标地址为你的应用接收缓冲区传输宽度并启用该DMA通道。绑定USB DMA通道将USB控制器的某个RX DMA通道例如通道0分配给目标端点。RXDMA_CFG.RXDMA0_EP endpoint_number。设置DMA传输参数如果希望传输在收到短包时自动结束只需使能RXn_EOT中断即可。如果希望限制最大传输量例如文件传输则设置RXDMAn.RXn_TC N-1N为期望的事务数并置位RXDMAn.RXn_STOP 1。同时使能RXn_EOT和RXn_CNT中断。使能中断在USB控制器的DMA中断使能寄存器DMA_IRQ_EN中使能对应通道的RXn_EOT_IE和/或RXn_CNT_IE。启动传输这是关键一步先通过EP_NUM寄存器选中目标端点设置EP_NUM.EP_NUM,EP_NUM.EP_DIR0,EP_NUM.EP_SEL1然后设置CTRL.SET_FIFO_EN 1。这个操作会“激活”该端点的FIFO使其准备好接收数据并触发DMA。4.2 常见问题与排查技巧DMA传输不启动检查端点配置确认端点已正确配置为Bulk/Interrupt OUT且已使能。检查SET_FIFO_EN这是最容易被遗忘的一步。必须在绑定DMA通道后手动设置一次CTRL.SET_FIFO_EN1来启动DMA就绪状态。检查系统DMA确认系统DMA控制器的配置正确特别是外设请求信号是否与USB控制器的DMA请求线如DMA_REQ_26正确映射。数据错位或丢失双缓冲切换问题在DMA进行中应用层不能直接访问USB控制器端点的FIFO。数据必须通过DMA搬运到指定内存区域。确保你的应用是从DMA目标缓冲区读取数据而不是试图从USB寄存器读取。数据对齐注意USB控制器和系统内存的数据宽度8位/16位/32位。在配置系统DMA时传输宽度必须匹配。如果USB是16位访问而你的缓冲区是字节数组可能需要处理字节序和访问对齐问题。EOT中断不产生主机未发送短包对于批量传输主机通过发送一个长度小于最大包大小的包短包来表示传输结束。确保主机端协议正确。RXn_STOP机制如果你依赖于RXn_STOP来触发EOT请检查RXDMAn.RXn_TC值是否设置正确以及事务计数是否已达到。可以通过调试器读取相关状态寄存器来验证。性能瓶颈DMA缓冲区大小对于高速批量传输增大端点的MPS最大包大小和合理使用双缓冲能显著提升吞吐量。系统DMA优先级确保USB DMA请求在系统DMA控制器中有足够高的优先级避免因其他DMA传输导致数据溢出。中断处理延迟EOT或DONE中断处理函数应尽可能快仅进行必要的状态清除和通知繁重的数据处理如校验、存储应交给后台任务。长时间的ISR会阻塞下一次传输的启动。