运行 Ux_Host_HUB_HID_MSC 通过 Hub 连接 U 盘读写不稳定问题分析 LAT1511
关键字:USB_OTG_HS,USB,HUB,FILEx,U 盘
1. 前言
客户使用 STM32U5 来开发一款外销型充电产品时,需要使用到 USB_OTG_HS 实现 HUB功能,并对 HUB 上的 U 盘进行高速写入操作。然而,客户在 NUCLEO-U5A5ZJ 板上运行 ST 官方例程 Ux_Host_HUB_HID_MSC 进行 U 盘性能读写测试时发现,在向 U 盘中写入小量数据是好的。但是,如果一次性连续写入大量数据如 1G 时会随机出现写入失败,返回值为 0x5C。
客户进一步反馈,如果直接将 U 盘连接到 NUCLEO 板,不通过 HUB 转接是 OK 的。且对U 盘有选择性,有些 U 盘出错概率小一些,有些概率 100%出现。希望知道 STM32U5 的 U 盘最快读写速度是多少。
2. 问题调研与复现
对客户板子及原理图进行检查后并未发现明显问题,笔者使用 STM32U5A9J-DK 板子对问题进行了验证。由于 FILEx 默认只支持 FAT32 格式的 U 盘,笔者使用的 U 盘容量是64G,需使能对 ExFAT 格式大容量 U 盘支持。
例程默认的 U 盘写入测试程序如下图所示:
显然例程默认数据单次写入长度是很小的,而且只写入了一次,频次远远不够。
修改测试程序大幅提高单次数据写入长度和数据吞吐量,测试代码如下所示。
笔者一共测试了 3 个不同品牌型号的 U 盘,测试结果如下:
所有 U 盘直连到板子都能成功写入,但是当通过 HUB 连接后,U 盘均会出现写入失败,只是各品牌的 U 盘出失败的概率不一样,还与 Hub 的口相关,有些 PORT 口概率低一些。
如下图所示:
将 UCHAR Write_buffer[64]单次写入数据长度改为 64/128/256/512 进行测试发现,可以成功(但是偶尔也会出错),但是速率无法接受。
3. 问题解决办法
通过上面对问题的复现,U 盘写入失败确实与 Hub 有关,通过对 FILEx 写入函数 fx_file_write 进行 debug,发现返回值 0x5C 并不属于 FILEx 模块里面定义的返回值,而是在 USBx/core 的头文件中定义的,0x5C 为 USB 传输请求超时。
进一步跟踪代码发现,出现传输超时由_ux_hcd_stm32_request_control_transfer 函数内部等待信号量时发生超时:
经过多次反复尝试,修改单次写入长度 Length 的大小(Write_buffer[Length])可以显著改善。因此,笔者大胆推测接 HUB 后,引发的 Timeout 原因极有可能与 MCU 处理性能密切相关,笔者查阅了 HUB 的相关资料,市面上大部分 HUB 主控芯片均采用高性能 ASIC 专用芯片,往往HUB 具有较高的数据吞吐量, 极低的响应延时时间。
既然,推测可能是与 MCU 处理性能相关,那么我们有没有什么办法提高 MCU 处理性能呢?经过检查代码发现在初始化 USB_OTG_HS 时内部 DMA 是没有使能的。于是使能USB_OTG_HS 内部专用 DMA。
重新编译后,再次下载运行,插上 HUB 重新测试写入超时现象消失,笔者分别将单次写入长度最大设置到 64K,即 Write_buffer[64*1024],并且交叉更换不同的 HUB 和 U 盘写入仍然正常。
如下图所示:
使能 USB_OTG_HS 的 DMA 本质是减小了 CPU 的负载,从而提升总线响应时间和效率。既然使能 DMA 可以解决此问题。这又令笔者想到了 STM32H5 的 ICache 支持 2 种配置模式,分别为 :
1-way(direct mapped mode) :每个缓存块只能存储在缓存中的一个固定位置。每个块只能存放在特定位置,容易导致冲突(即不同的数据可能映射到相同的位置,导致频繁替换。
2-way(set associative cache) : 缓存被分为多个组,每组可以容纳两个块。因为每个组可以存放两个块,减少了冲突的概率。
对于更详细和专业的 Cache 介绍读者可以查阅相关更专业的资料。
例程使用的 ICache 默认模式为 1-way(direct mapped mode) ,那么我们将其改为 2-way(set associative cache) 能否提升 USB 写入的性能呢,从而达到与使能 DMA 同样的效果呢。
修改代码使能 ICACHE_2WAYS 模式,将 hhcd_USB_OTG_HS.Init.dma_enable=DISABLE.
下载代码测试发现,问题不再出现,交叉更换不同的 HUB 和 U 盘写入仍然正常。
除了前面提到的使能 DMA,ICACHE_2WAYS 使能以外,我们还可以做如下配置,来进一步提升写入性能。
以下是笔者向 U 盘连续地写入 1GByte 文件时所获得的实测性能,供参考如下:
4. 总结
可见,使能 USB_OTG_HS 的 DMA 和配置 ICache 工作模式为 2-way(set associative cache) ,均可以解决此问题,但只能定性此问题确实与 CPU 的性能相关。而多级 HUB 传输它需要额外的数据进行数据的包装,从而导致时间的增加。