去年的推荐了WCH的一个MCU:

不知道大家还有没有印象
这个MCU不仅常规的IP很全,在老本行通讯连接上面更是顶呱呱,那这次我们就来一次USB测速。那我们要跑就跑最快的3.0.
但USB协议非常乱:

很明显是USB 3.0 Gen 1
还有一点需要注意的就是其实这个USB 3.0是兼容2.0的,就是接入了2.0的线序:

3.0的出现,2.0也兼容,之后我会说一下这个现象

一个完整的USB3.0接口有9根线

引脚定义这里也是精密排列的

也就是3.0
直观看就是有PHY:

而且都集成在这里,里面的USB外设都是完整的

时钟树上面USB3.0是从HSE这个主干路上面来的
这个在初始化的代码里面也可以看到,WCH是使用的自己的IDE,用起来感觉不错,都不需要怎么配置。

因为是双核设计,注意这个V3才是主机
WCH给每个MCU都有一个完善的固件包,里面有每个外设的demo,那这个USBSS也是有的。
在 CH32H417 的这个双核 + USBSS 项目中,时钟初始化分为“系统主时钟” 与 “USB 专用时钟”两部分,分布在两个位置:
这是 MCU 上电后最先执行的配置,负责让 V3F/V5F 核心跑起来;默认使用 HSE (外部晶振 25MHz)倍频。

所以还是设计的很易用
// system_ch32h417.c 中默认开启的宏
#define
SYSCLK_400M_CoreCLK_V5F_400M_V3F_100M_HSE
400000000
//这会将系统时钟配置为 400MHz ,其中 V5F 核跑 400MHz,V3F 核跑 100MHz。
当代码执行到 Hardware() -> USBSS_Device_Init() 时初始化;USBSS_RCC_Init 它会调用 USBSS_PLL_Init(ENABLE) 开启 USBSS 专用的 PLL,并使能 RCC_HBPeriph_USBSS 、 PIPE时钟。
当 USB3 枚举失败回退,或者代码显示调用 USBHS_Device_Init() 时初始化;USBHS_RCC_Init 关键代码如下,它独立配置了一个 480MHz 的 PLL 给 USB2.0 PHY 使用:
RCC_USBHSPLLCLKConfig
(RCC_USBHSPLLSource_HSE); // 源自 HSE
RCC_USBHSPLLReferConfig
(RCC_USBHSPLLRefer_25M); // 参考频率 25M
RCC_USBHS_PLLCmd
(ENABLE); // 启动 PLL
如果要改主频 ,去 V3F/User/system_ch32h417.c 改宏定义;如你要改 USB 时钟源 (比如换了晶振频率),去 Common/ch32h417_usbhs_device.c (USB2) 或 Common/ch32h417_usbss_device.c (USB3) 修改对应的 PLL 配置。
上面的时钟初始化看到了有对2.0的操作,这是为什么?其实是作为 USB 3.0 失败后的回退方案,或在不支持 USB 3.0 的主机上使用;入口在 ch32h417_usbhs_device.c 的 USBHS_Device_Init() 。

也就是高速版的2.0,也有完整的PHY
在2.0这里启用 EP0, EP1, EP3, EP4, EP5,且配置各端点的 DMA 地址 (指向 Data_Buffer 或独立 Buffer);设置最大包长 (512字节 for HS),预设响应状态 (ACK/NAK)。
然后初始化定时器 (TIM12),用于监测 USB 3.0 链路训练是否超时。如果超时未连接,中断服务程序会强制切换到 USB 2.0 模式。
代码逻辑采用的是 "优先尝试 USB 3.0,失败后回退到 USB 2.0" 的策略。系统上电时只会初始化 USB 3.0,如果连接失败(例如插在 2.0 接口上),才会关闭 3.0 并初始化 2.0。
具体流程如下:
在 hardware.c 的 Hardware() 函数中:
USB_Timer_Init( ); // 初始化超时定时器
USBSS_Device_Init( ENABLE );// 仅初始化 USBSS (3.0)
// 注意:此处没有调用 USBHS_Device_Init (2.0)
系统启动时,默认假设用户插入的是 USB 3.0 接口,并开始进行 3.0 链路训练。
在 USBSS_Device_Init 之后,系统会启动一个定时器(TIM12);如果在规定时间内(例如几次中断周期内)USB 3.0 链路没有成功建立(比如用户插的是 USB 2.0 线或接口),定时器中断 TIM12_IRQHandler 会被触发。
在 ch32h417_usbss_device.c 的 TIM12_IRQHandler 中:
if( u3_first_count > 2 ) // 超时判断
{
// 1. 关闭 USB 3.0
USBSS_Device_Init( DISABLE );
// 2. 初始化并开启 USB 2.0
USBHS_Device_Init( ENABLE );
// 3. 停止检测定时器
USB_Timer_Start( DISABLE );
}
此时,芯片才正式切换到 USB 2.0 高速模式工作。
如果当前工作在 USB 2.0 模式下,且检测到了 USB 总线复位 (例如用户拔掉重插,或者主机复位总线),代码会尝试 切回 USB 3.0 再试一次;在 ch32h417_usbhs_device.c 的 USBHS_IRQHandler 中:
if( intflag & USBHS_UDIF_BUS_RST ) // 2.0 总线复位
{
// 再次尝试初始化 3.0,看看是否换到了 3.0 接口
USBSS_Device_Init( ENABLE );
USB_Timer_Start( ENABLE );
}
USB2.0和3.0不是同时初始化 :同一时间只有一个控制器在工作,而且3.0 优先,总是先尝试建立 3.0 连接。
自动切换 :
插 3.0 口 -> 3.0 初始化成功 -> 保持 3.0 工作。
插 2.0 口 -> 3.0 初始化超时 -> 关闭 3.0 -> 初始化 2.0 -> 保持 2.0 工作。

这里枚举成功是这样的
在设备与驱动这里可以看到跑的是 WCH 自家驱动(不是 WinUSB)
Vendor ID : 0x1A86 / Product ID : 0x5537:WCH VID/PID
Driver : CH375W64.SYS (Version: 3.5.2025.8 Date: 2025-08-21)说明枚举出来的是 WCH 自定义类(Class=WCH),由它家的内核驱动接管,而不是 Windows 自带的 WinUSB/libusbK, 自家驱动通常会用更激进的队列深度/URB 管理,吞吐更容易拉满。
如果对这个外设从寄存器出发解读,那就太无聊了,我想可以通俗一点~(主要是着重理解端点这个东西)
USB 3.0 的工作过程本质上是: Host 和 Device 围绕“端点(Endpoint)”不断交换“数据包(DPH)和控制包(TP)”,端点就是“数据通道的编号 + 方向 + 类型 + 状态机”。
USB 不是“随便发数据”,而是:Host 永远是发起者,Device 永远是被动响应者,所有数据都必须走某一个端点;端点是 USB 协议里最核心的抽象。
这是最容易误解的地方,端点是一个“逻辑通信通道”,由 4 个要素唯一确定:
要素 | 含义 |
|---|---|
Endpoint Number | 端点号(0–15,USB3 常用 0–7) |
Direction | IN(Device→Host) or OUT(Host→Device) |
Transfer Type | Control / Bulk / Interrupt / Isochronous |
状态 | Ready / Busy / Halt / NRDY / 等 |
端点可以看作是协议层的“虚拟管道”。
以 Device 视角:
USB 3.0 链路
│
┌──────┴──────┐
│ Endpoint │ ← 这是“端点”
│ (EP n IN) │
└──────┬──────┘
│
DMA / FIFO / SRAM
Host 并不知道你 DMA 在哪,它只知道: “EP n,方向 IN,现在能不能给我数据?”
USB 协议 = 围绕端点进行调度
Host 的核心循环就是:
for each endpoint:
if endpoint ready:
发事务
else:
等 ERDY / 等待
Device 的核心逻辑是:
端点有数据?
是 → 准备好 → ERDY / ACK
否 → NRDY / 等待
我们从 上电 → 插入 → 枚举 → 传输 这个完整流程走一遍。
在 USB 3.0:
Detect → Polling → U0这一步在 RM 里看到的是 LINK 寄存器、U1/U2/U3
需要注意:这一步还没端点,只是“线能不能用”。
所有 USB 设备,永远只有一个 EP0**, EP0 永远是 Control 类型, **EP0 同时支持 IN + OUT
Host → EP0 OUT : SETUP 包(我要认识你)
Device → EP0 IN : 描述符数据
也就是Device 先只需要实现 EP0,其他端点此时 还不存在 / 未使能;所以在 USBSS 里看到:UEP0_TX_CTRL,UEP0_RX_CTRL这是整个 USB 世界的起点。
Host 在枚举过程中会说:
“我需要:一个 Bulk IN EP1,一个 Bulk OUT EP1,最大包长 1024,支持突发”
这一步完成后:EP1 IN / EP1 OUT 才真正“存在”
然后Device 在内部:给 EP1 分 DMA / FIFO,设置端点类型,标记为 ready / idle‘’端点不是一开始就有的,是“被配置出来的”。
这是真正关心的部分。
用 Bulk IN(Device → Host) 举例。
Host:EP1 IN,你有数据吗?
这在 USB 3.0 里不是一个包,而是一组事务:
Device → Host : DPH(数据包头 + 数据)
Host → Device : ACK-TP(我收到了,还能再收 N 个)
这时:DMA 消耗一段 buffer,端点序列号 +1
Device → Host : NRDY-TP
意思是:
“现在别烦我,等我准备好了我再叫你”
当 DMA / FIFO 准备好后:
Device → Host : ERDY-TP
意思是:
“我准备好了,你可以继续问我了”
这就构成了一个完整闭环:
请求 → NRDY → ERDY → 重新请求 → DPH → ACK
这就是在寄存器里看到的:NRDY,ERDY,ACK,NUMP(还能接多少包)
因为 USB 3.0 是“无轮询、事件驱动”的高速总线:不再像 USB 2.0 那样傻轮询,而是允许 Device 主动告诉 Host:“我忙”,“我好了”;这也是为什么:USB 3.0 才能到 5Gbps,其中DMA + 端点 + 突发的设计非常重要。
现在再看 USBSS:
RM 中的概念 | 实际含义 |
|---|---|
UEPn_TX / RX | 第 n 个端点 |
TX / RX | IN / OUT |
CHAIN | 多 buffer 链 |
FIFO | 端点内部缓存 |
DMA_ADDR | 端点数据来源 |
ERDY / NRDY 位 | 端点状态机输出 |
RM 中的概念 | 实际含义 |
|---|---|
UH_TX / RX | Host 发起的事务 |
ACK_NUMP | 对端还能接多少包 |
TX_FAILED | Deferred(端点忙) |
ERDY_IF | Device 叫你继续 |
端点不是硬件资源,而是 USB 协议定义的“数据通道状态机”; USB 3.0 的工作过程,就是 Host 和 Device 围绕端点不断交换: DPH(数据) + TP(控制),并用 ERDY / NRDY / ACK 来做高速流控。

这个是官方给出的结果,看起来不错

用测速工具进行测试


就是上传,下载,以及一发一收做回环测试,我整理了测速的结果:
测试模式 | 上传速度 | 下载速度 |
|---|---|---|
单向下载 | — | 450.64 MB/s |
单向上传 | 447.54 MB/s | — |
双向同时 | 395.16 MB/s | 395.12 MB/s |
USBSS(USB 3.0 SuperSpeed),批量端点(Bulk Endpoint)。
端点大小:1024 Bytes
上传端点:2,3
下传端点:1,3
测试时间:60 秒
数据包大小:4,194,304 Bytes(4MB buffer)
数据量:28366077952 B
时间:60.000 s
平均速度:450.64 MB/s
28366077952 / 60 ≈ 450.64 MB/s(软件显示 450.64 MB/s)
数据一致
数据量:28160557056 B
时间:60.016 s
平均速度:447.54 MB/s
28160557056 / 60.016 ≈ 447.54 MB/s
合理
21932015616 B
60.094 s
395.16 MB/s
21936209920 B
60.000 s
395.12 MB/s
双向几乎对称
物理层速率:5 Gbps
8b/10b 编码
有效数据率:
5 Gbps × 0.8 = 4 Gbps
4 Gbps / 8 = 500 MB/s
模式 | 理论上限 | 实测 |
|---|---|---|
单向下载 | ~500 MB/s | 450.64 MB/s |
单向上传 | ~500 MB/s | 447.54 MB/s |
双向同时(上行) | ~500 MB/s | 395.16 MB/s |
双向同时(下行) | ~500 MB/s | 395.12 MB/s |
单向下载效率:450.64 / 500 = 90.1%
单向上传效率:447.54 / 500 = 89.5%
也就是说:
单向传输链路利用率约 89%–91%
这是一个 非常正常、甚至偏好的数值;实际中考虑到:协议开销,链路层 header,USB transaction overhead,DMA 切换,FIFO flush,PC 主机栈开销,83% 是健康数值。
双向同时传输时,单方向有效吞吐约为 395 MB/s,
对应单方向链路利用率约 79%。
双向下降的原因:主机 xHCI 调度,双向 DMA 争用,片上总线争用,FIFO arbitration,缓存带宽限制;这个值也合理。
首先 USBSS PHY 的 5Gbps SuperSpeed 链路应当是真正建立成功了,因为单向吞吐已经达到 450 MB/s 量级; 其次 Bulk 端点、DMA 与 FIFO 配置整体是健康的,否则很难稳定跑到接近 400 MB/s 以上的双向并发吞吐。
本次 USBSS Bulk 端点测速结果显示:单向传输速度可达 450.64 MB/s(下载)和 447.54 MB/s(上传),双向并发传输时上下行均约 395 MB/s;相对于 USB 3.0 SuperSpeed 500 MB/s 的理论有效上限,单向链路利用率约为 89%–91%,双向同时传输时单方向利用率约为 79%。 整体性能表现已经相当接近 USB 3.0 实际工程可达到的高水平,说明该 USBSS 控制器、Bulk 端点、DMA 与片上总线协同工作是比较健康的。