USB控制器是现代计算机系统中负责管理USB总线通信的核心组件,它实现了USB协议栈的物理层和数据链路层功能。作为主机与外围设备之间的桥梁,USB控制器通过精心设计的硬件架构和寄存器配置,实现了高效、可靠的数据传输。
USB控制器主要支持两种工作模式:
主机模式(Host Mode):控制器作为USB总线的主设备,负责枚举和管理连接的USB设备。在这种模式下,控制器需要处理总线供电、设备枚举、数据传输调度等复杂任务。主机模式下支持四种基本传输类型:控制传输、批量传输、中断传输和同步传输。
外设模式(Peripheral Mode):控制器作为USB总线的从设备,响应主机的请求并执行相应操作。这种模式通常用于嵌入式设备中,使设备能够通过USB接口与主机通信。
实际应用中,部分高级USB控制器支持OTG(On-The-Go)功能,可以在主机和外设模式间动态切换,但本文主要聚焦于主机模式下的操作细节。
一个典型的USB控制器包含以下关键功能模块:
串行接口引擎(SIE):负责处理USB协议的低层细节,包括位填充/解填充、CRC生成/校验、PID验证等。SIE是USB控制器的"翻译官",将原始的串行数据转换为并行数据供上层处理。
端点FIFO缓冲区:通常采用双缓冲设计(DPB位控制),每个端点都有独立的发送和接收FIFO。例如EP0的FIFO大小通常为64字节,而其他端点的FIFO大小可通过寄存器配置。双缓冲机制允许控制器在处理一个数据包的同时接收/发送另一个数据包,显著提高吞吐量。
DMA控制器:高级USB控制器集成DMA引擎,支持4个TX和4个RX通道(对应EP1-EP4)。DMA通过描述符链实现自动数据传输,减轻CPU负担。在配置DMA时,需要注意描述符中的SOP(Start Of Packet)和EOP(End Of Packet)标志位定义数据包的边界。
寄存器组:包括控制/状态寄存器(如HOST_CSR0)、类型寄存器(如HOST_RXTYPE)、最大包长寄存器(如RXMAXP)等。这些寄存器构成了软件与USB控制器硬件交互的编程接口。
控制传输是USB通信中最基础也是最重要的传输类型,主要用于设备枚举、配置和命令传输。一个完整的控制传输包含三个阶段:SETUP阶段、DATA阶段(可选)和STATUS阶段。
SETUP阶段由主机发起,用于传输控制请求。以下是典型的SETUP包发送流程:
配置端点0:作为默认控制端点,EP0需要在主机模式初始化时正确配置:
c复制// 示例:配置EP0为控制端点
HOST_RXTYPE = (USB_SPEED_FULL << 6) | (USB_EP0_CONTROL << 4) | 0x00;
RXMAXP = 64; // 设置最大包大小为64字节
加载SETUP数据:将8字节的SETUP包写入EP0 FIFO。SETUP包包含bmRequestType、bRequest、wValue、wIndex和wLength字段。
启动传输:设置HOST_CSR0寄存器的TXPKTRDY位(bit 1),控制器将自动发送SETUP令牌包和DATA0包。
处理响应:等待EP0中断,检查HOST_CSR0寄存器:
DATA阶段是可选的,根据SETUP请求的wLength字段决定是否存在。DATA阶段可以是IN或OUT方向:
请求数据:设置HOST_CSR0的REQPKT位(bit 5),控制器发送IN令牌。
接收数据:设备响应DATA0/DATA1包,控制器自动处理数据切换(Data Toggle)。
中断处理:检查HOST_CSR0状态:
c复制if (HOST_CSR0 & RXSTALL) {
// 设备返回STALL,请求不支持
} else if (HOST_CSR0 & ERROR) {
// 三次尝试失败
} else if (HOST_CSR0 & RXPKTRDY) {
// 数据就绪,读取FIFO
uint8_t data[64];
usb_read_fifo(EP0, data, 64);
}
加载数据:将要发送的数据写入EP0 FIFO,注意不超过wMaxPacketSize。
启动传输:设置TXPKTRDY位(bit 1),控制器发送OUT令牌和DATAx包。
处理响应:检查ACK/NAK/STALL响应,必要时重试(由HOST_NAKLIMIT0寄存器控制重试次数)。
STATUS阶段确认整个控制传输的完成状态,方向与DATA阶段相反:
设置状态包:同时设置STATUSPKT(bit 6)和REQPKT(bit 5)位。
接收零长度包:设备应返回DATA1包(长度为0)。
确认完成:检查ACK响应,清除RXPKTRDY位。
设置状态包:同时设置STATUSPKT(bit 6)和TXPKTRDY(bit 1)位。
发送零长度包:控制器发送DATA1包(长度为0)。
确认完成:检查ACK响应,完成传输。
控制传输中数据切换(Data Toggle)是关键机制:SETUP阶段总是使用DATA0,后续DATA阶段在DATA0和DATA1间交替。控制器通常自动处理数据切换,但可通过CLRDATATOG位(bit 7)强制重置。
批量传输用于传输大量非实时数据,如文件传输、打印数据等。与控制传输不同,批量传输可以使用除EP0外的其他端点,支持更高的吞吐量。
批量IN传输指数据从设备到主机的传输,典型配置步骤如下:
设置端点类型:
c复制HOST_RXTYPE = (USB_SPEED_HIGH << 6) | (USB_BULK << 4) | endpoint_num;
RXMAXP = 512; // 高速模式下最大512字节
配置NAK超时:
c复制HOST_RXINTERVAL = 0x10; // NAK重试间隔(16微帧)
启用双缓冲(可选):
c复制RXFIFOSZ |= (1 << 4); // 设置DPB位
启用DMA(可选):
c复制HOST_RXCSR |= (1 << 13); // 设置DMAEN位
DMACHTYPE = 0x01; // 配置DMA通道类型
请求数据:设置HOST_RXCSR的REQPKT位(bit 5),触发IN事务。
处理响应:
自动请求模式:当启用DMA时,可设置AUTOREQ寄存器实现自动IN请求:
c复制AUTOREQ = (0x01 << (endpoint_num * 2)); // 模式1自动请求
批量OUT传输指数据从主机到设备的传输,配置与批量IN类似但使用不同的寄存器:
设置端点类型:
c复制HOST_TXTYPE = (USB_SPEED_HIGH << 6) | (USB_BULK << 4) | endpoint_num;
TXMAXP = 512;
配置DMA描述符:
c复制typedef struct {
uint32_t next_desc; // 下一个描述符指针
uint32_t buf_ptr; // 数据缓冲区指针
uint16_t buf_len; // 有效数据长度
uint16_t buf_off; // 缓冲区偏移
uint32_t flags; // SOP/EOP等标志位
} dma_desc_t;
dma_desc_t desc __attribute__((aligned(32)));
desc.buf_ptr = (uint32_t)buffer;
desc.buf_len = data_length;
desc.flags = (1 << 31); // 设置SOP位
加载数据:写入FIFO或设置DMA描述符。
启动传输:设置HOST_TXCSR的TXPKTRDY位(bit 0)。
处理响应:
批量传输性能优化要点:
- 合理设置NAK超时值(HOST_RXINTERVAL/HOST_TXINTERVAL),平衡响应速度和总线利用率
- 对于大数据量传输,务必启用DMA和双缓冲
- 高速模式下使用最大包长(512字节)减少协议开销
- 合理安排传输时机,避免总线带宽竞争
中断传输适用于定期轮询小数据量的场景,如HID设备。与批量传输的主要区别在于:
轮询间隔:通过HOST_RXINTERVAL/HOST_TXINTERVAL寄存器设置,单位取决于速度模式:
端点类型配置:
c复制// 配置中断IN端点
HOST_RXTYPE = (USB_SPEED_FULL << 6) | (USB_INTERRUPT << 4) | endpoint_num;
HOST_RXINTERVAL = 10; // 每10ms轮询一次
数据处理:通常采用中断驱动方式,在端点中断服务例程中处理数据。
同步传输用于等时数据流,如音频、视频,特点包括:
无错误重传:不保证数据完整性,但保证带宽和延迟。
配置示例:
c复制// 配置同步IN端点
HOST_RXTYPE = (USB_SPEED_HIGH << 6) | (USB_ISOCHRONOUS << 4) | endpoint_num;
HOST_RXINTERVAL = 1; // 每微帧一次传输
时序考虑:建议利用SOF_PULSE信号同步数据处理,避免缓冲区欠载/溢出。
| 传输类型 | 数据可靠性 | 时序保证 | 典型应用 | 最大包长(高速) |
|---|---|---|---|---|
| 控制传输 | 高 | 无 | 设备配置 | 64字节 |
| 批量传输 | 高 | 无 | 大文件传输 | 512字节 |
| 中断传输 | 高 | 有限 | HID设备 | 1024字节 |
| 同步传输 | 低 | 严格 | 音视频流 | 1024字节 |
STALL响应:表示端点处于停止状态,通常需要清除 halt:
c复制// 清除IN端点STALL
HOST_RXCSR &= ~(1 << 6); // 清除RXSTALL位
HOST_RXCSR |= (1 << 7); // 设置CLRDATATOG
NAK超时:设备暂时无法响应,处理策略:
CRC/位填充错误:通常由信号完整性引起,建议:
逻辑分析仪:使用USB协议分析仪捕获总线信号,推荐配置:
软件调试技巧:
典型问题排查流程:
code复制1. 检查电源和复位信号
2. 验证时钟配置
3. 确认PHY正确初始化
4. 检查端点配置寄存器
5. 分析总线状态机
DMA描述符链优化:
中断合并:对于高频率传输,可以:
内存布局优化:
在实际项目中,我曾遇到一个因DMA缓冲区不对齐导致的性能问题:当传输大量小包时,系统性能下降了近40%。通过将缓冲区对齐到64字节边界并使用预分配策略,不仅解决了性能问题,还减少了约25%的CPU占用。这提醒我们,USB控制器的性能优化需要关注底层细节。