尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

STM32H723 USB Host读U盘全流程实战:从MSC协议到FATFS挂载

STM32H723 USB Host读U盘全流程实战:从MSC协议到FATFS挂载 做嵌入式这些年USB disk 是我碰过最看似简单、坑位最多的需求之一。STM32H723 这颗芯片我用了挺久单论 USB 场景它比 F407/F429 舒服太多主频 550MHz、1MB Flash、560KB SRAM两个独立 USB OTG 控制器其中一个还支持外接 ULPI 高速 PHY。当年在 F407 上跑 USB Host FATFS 读 U 盘调试枚举失败、BOT 超时、热插拔死机这些问题动不动就耗掉一两个星期。换到 H723 上软件栈成熟了、内存充裕了整个开发周期能压缩一半以上。STM32H723 USB disk 这个需求通常分两种一是让 H723 当 Host去读写外部 U 盘典型场景是固件升级、配置导入、日志导出二是让 H723 当 Device把自己或外挂存储模拟成一个 U 盘插到电脑上直接访问典型场景是数据采集器、量产工具、Bootloader 升级盘。这两条技术路线差别很大坑也不一样。这篇文章我会以 Host 读 U 盘为主线把协议、硬件、软件、调试全链路讲透最后附上 Device 模式虚拟 U 盘的要点。不管你用的是标准库、HAL 库还是裸机 RTOS这篇文章都按能被你直接抄走的标准来写。我在实际项目里遇到的那些坑也会全部列出来。1. 先想清楚H723 的 USB disk 到底做什么1.1 两个方向别搞混很多人在需求阶段就没分清 Host 和 Device导致方案推倒重来。我见过一个团队用 F407 做设备端虚拟 U 盘做到一半发现客户需要的是设备主动去读 U 盘里的升级包整个 USB 方向反了白白浪费两个月。USB Host 模式是 MCU 主动发起通信去枚举和管理外部设备。做USB disk场景时H723 就是一个小型主机外接 U 盘、读卡器甚至移动硬盘。MCU 需要提供 VBUS 电源处理枚举、地址分配、配置描述符解析、BOT 协议、FAT32 文件系统解析这一整条链路都要自己跑。USB Device 模式则完全反过来。H723 作为从设备通过 Mass Storage ClassMSC对外暴露一个块设备电脑端看到的就是一个可移动磁盘。MCU 作为翻译官把 SCSI READ/WRITE 命令翻译成对内嵌 Flash、外部 SPI Flash 或 SD 卡的读写操作。从市场需求看Host 模式的应用量远大于 Device 模式。设备固件升级、参数配置、数据记录、边缘计算节点等场景都离不开读 U 盘这个动作。我的建议是先判断清楚你的产品是主动去读还是被电脑读再决定用哪个方向。两种模式在 H723 上都能实现但软件复杂度和调试成本差别很大。1.2 为什么是 STM32H723 这颗料H723 在 ST 的产品线里定位很有意思它比 H743 便宜不少但性能一点都不弱。550MHz 的 Cortex-M7 主频跑 USB Host 协议栈时MSC 数据处理、FATFS 文件解析、校验运算这些活儿都能轻松扛住不会出现 F103 那种主频不够协议栈跑不动的窘境。USB 资源上H723 带两个 OTG 控制器OTG1 支持 HS/FS可以外接 ULPI PHY 跑 USB 2.0 高速480MbpsOTG2 只支持 FS12Mbps。这个配置和 F407 类似但关键在于 H723 的 RAM 大、总线带宽高内部 DMA 更充裕跑大块传输时不容易出现 FIFO 溢出。实际测试中用内部 FS PHY 读 U 盘稳定读写速度能做到 700KB/s 左右比 F407 上同配置高了不少。另一个优势是 CubeH7 软件栈的成熟度。STM32 官方提供的 USB Host 库、FATFS 中间件在 H7 上已经迭代得非常稳定。再加上 H7 的 Flash 容量大可以把 Debug 日志、协议追踪代码全部编进去调试体验远超小 Flash 芯片。顺便说一句H723 的两个 USB 控制器是可以同时用的。我的一个项目里就是 OTG1 做 Host 读 U 盘同时 OTG2 做虚拟串口供产测使用互不干扰这在大规模量产调试时非常实用。1.3 整体架构一条完整的数据通路先明确整个 Host 模式的数据流向U 盘通过 USB 线缆连接到 H723 的 OTG 控制器H723 作为主机完成枚举链路稳定后FATFS 文件系统把 U 盘抽象成一个可访问的存储介质应用层的固件升级、配置读写功能再基于文件系统来操作。这条链路分四层物理层VBUS 供电、D/D- 差分信号、OTG 控制器内部 PHY 的信号解析协议层枚举控制传输、MSC 类驱动BOT 传输、SCSI 命令集文件系统层FATFS 对 U 盘分区、目录、文件的解析应用层具体业务比如打开升级包、读取配置文件每一层都有各自的坑。物理层的供电和信号完整性问题会让枚举不稳定协议层的 BOT 状态机错误会导致传输卡死文件系统层对 exFAT 和 4K 扇区的支持不足会导致挂载失败应用层则容易踩 DMA 缓冲对齐、跨簇读写等细节问题。这篇文章后面的章节就是按这个分层逐个击破。2. USB Host 侧核心协议MSC/BOT/SCSI 怎么跑通的2.1 枚举过程中到底发生了什么很多人把 USB 枚举当成一个黑盒调不通就查堆栈其实枚举的每一步都是你能看到的。U 盘插入后主机侧会依次做这些事检测设备插入VBUS 电平变化 / 数据线上拉检测对设备进行复位SE0 信号持续至少 10ms读取设备描述符的前 8 字节拿到 bMaxPacketSize0确定端点 0 的最大包长再次复位发送 SET_ADDRESS 分配地址用新地址读取完整设备描述符读取配置描述符包括接口描述符、端点描述符根据接口描述符的 bInterfaceClass 判断设备类型0x08 就是 Mass Storage选择配置SET_CONFIGURATIONUSB 枚举完成这一步最关键的调试手段是抓包。如果你有 USB 分析仪枚举失败时一眼就能看出是哪一步超时了。没有分析仪的话ST 的 USB Host 库在 DEBUG 模式下会输出USBH_DEBUG日志能精确显示卡在哪个状态。我的经验是80% 的枚举失败都出在电源上不是 VBUS 供电不足就是 D/D- 走线太长只有 20% 是代码逻辑问题。关于枚举建议去翻一下《圈圈教你玩 USB》里讲枚举的那一章虽然例子用的老芯片但枚举流程这么多年基本没变过理解透了以后排查问题会有质的提升。2.2 BOT 状态机与关键 SCSI 命令U 盘用的传输协议叫 Bulk-Only TransportBOT所有数据都走 Bulk 端点。BOT 协议的核心是三段式主机发 CBWCommand Block Wrapper31 字节、然后数据传输可选的 Data 阶段、最后设备返回 CSWCommand Status Wrapper13 字节。CBW 的 dCBWCB 字段里装的就是 SCSI 命令。U 盘最核心 SCSI 命令就这几个INQUIRY查询设备基本信息00h 操作码READ CAPACITY(10)读取总扇区数和扇区大小25hTEST UNIT READY查询设备是否就绪00hREAD(10)读取数据28hWRITE(10)写入数据2AhMODE SENSE(6)查询设备模式参数1AhPREVENT ALLOW MEDIUM REMOVAL锁定介质防止弹出1EhBOT 状态机最需要注意的是 CSW 校验。每次传输结束后主机都要检查 CSW 里的 dCSWSTATUS只有返回 0命令成功才算完成。返回 1 表示命令失败返回 2 表示相位错误。相位错误是 LUN 死锁和设备无响应的高发原因处理方式通常是复位端点或复位设备。实际开发中ST 官方 USB Host 库已经把这套状态机封装好了你不需要自己实现 CBW/CSW 的收发解析但建议把USBH_MSC_Worker这个函数里的状态转移看懂。很多时候设备卡死问题就出在 BOT 状态机卡在某个状态没跳出来你得知道它卡在哪一环才能下手。2.3 ST 官方 USB Host 库在协议层帮你做了啥、没做啥ST 的 USB Host 库分层很清晰底层 HCDHost Controller Driver管硬件寄存器中间层 USBH 管枚举和标准请求上层是对各种类的驱动。Mass Storage 类驱动usbh_msc.c实现了 BOT 协议和 SCSI 命令封装。库帮你做好了这些事枚举流程和标准设备请求的处理BOT 状态的自动推进和维护SCSI 命令的构造和解析端点的 STALL 处理部分场景设备断开时的清理但库没帮你做的事更需要关注FATFS 的挂载和文件操作需要你自己在应用层调用热插拔的可靠检测需要你自己处理对异常 U 盘的容错比如返回错误状态后自动复位需要你扩展读写性能优化批量扇区传输、DMA 缓冲需要你针对应用调整特别是最后一点很多人在 F407 上读 U 盘只有 200KB/s就以为是 USB 的极限其实问题出在每次只发一条 READ(10) 读一个扇区。改成一次读 32 个扇区速度立刻能翻好几倍。3. 硬件设计要点这块坑最多3.1 最小硬件连接与关键器件选型如果你在 TM32 上做过 USB Device知道 D/D- 直接接到芯片引脚就行。USB Host 就不一样了供电、检测、保护、Type-C CC 逻辑一个都不能少。最简 Host 连接方案Type-A 口USB_OTG_HS_DM 接连接器 D-USB_OTG_HS_DP 接连接器 DUSB_OTG_HS_VBUS 接连接器 VBUS 输出USB_OTG_HS_ID 悬空Host 模式下拉到地或直接由库处理VBUS 电源开关输出接连接器 VBUS电源开关建议选带电流限制和热关断的型号比如 TPS2041B、RT9742、AP2822 这些都很常见。选型时注意两点一是持续电流要大于 500mAUSB 2.0 规范要求 Host 至少提供 500mA二是开关的导通电阻要小否则满载时 VBUS 电压掉到 4.5V 以下U 盘供电不足会直接枚举失败。3.2 VBUS 供电与检测的坑最容易被忽略VBUS 供电是 Host 模式最容易翻车的点。很多人直接把板子的 5V 电源连到 USB 连接器上没有任何开关控制这会带来两个问题第一U 盘插入瞬间的浪涌电流可能把电源拉垮第二设备不能控制 VBUS 的通断遇到 USB 死锁时无法通过断电复位恢复。正确的做法5V 电源先进电源开关开关的 EN 引脚接 MCU 的 GPIO比如 PG6软件控制 VBUS 上电时机。设备接入后先延时 50ms 再拉高 EN等 VBUS 稳定后再开始枚举。这样还能实现长按按键强制复位 U 盘的功能量产调试时特别好用。VBUS 检测同样重要。H723 的 USB_OTG_HS_VBUS 引脚内部有比较器可以直接接 5V具体耐压参看数据手册H7 系列的 VBUS 引脚是 5V 耐受设计。某些参考设计会用电阻分压后再送入引脚这时要注意分压后的电平必须高于 VBUS 检测阈值否则芯片永远认为 U 盘没接入。我个人习惯是直接把 VBUS 接引脚再通过软件里的HAL_HCD_ConnectCallback触发插拔事件。3.3 时钟、上下拉与布线的坑USB 对时钟精度要求很高。全速模式12Mbps要求 48MHz 时钟误差在 ±0.25% 以内。H723 的 48MHz 时钟来自 PLL 的某个输出配置时一定要精确计算。如果你用内部 HSI48MHz 的精度一般够用但如果板子温漂大还是建议用外部晶振HSE驱动。H723 的内部 FS PHY 不需要外部上下拉电阻芯片内部已经处理好了 D/D- 的上下拉逻辑。但如果你是外接高速 PHY比如 USB3300 走 ULPI 接口就得仔细看 PHY 芯片手册可能需要在数据线上加串阻。布线方面的硬性要求是 D/D- 走差分线保持 90Ω 差分阻抗长度尽量短小于 5cm 为佳远离时钟线和电源开关的电感。我踩过一次坑D/D- 从连接器绕了大半个板子到芯片结果 12Mbps 的 FS 都枚举不稳定改成短走线后一次通过。另一个细节是 VBUS 和 GND 之间要加 4.7μF 和 0.1μF 去耦电容紧贴连接器放置。4. 软件实现从 CubeMX 到 FATFS 挂载4.1 CubeMX 配置Host MSC FATFS一次到位用 CubeMX 配置 H723 的 USB Host FATFS其实只需要几步但每一步都有容易忽略的细节。先选芯片然后按下面顺序配置USB_OTG_HS 外设打开Mode 选 Host_Only如果只做 Host 就选这个选 OTG 反而麻烦Middleware 里打开 USB_HOSTClass for Host 选 Mass Storage ClassMiddleware 里打开 FATFS在 Advanced 设置里把 USB disk 勾上这步忘了的话FATFS 不会关联到底层的 USB MSC 驱动配置系统时钟确保 USB 相关时钟是 48MHz生成代码生成的代码里main.c中MX_USB_HOST_Init()会完成 USB Host 库初始化MX_FATFS_Init()完成文件系统初始化。这里要注意的是USBH_Init里面注册的用户回调函数默认是空实现但热插拔事件都靠它一定要补全。4.2 枚举与挂载的状态机怎么搭ST 官方库的事件回调机制是这样的USBH_User_Process会在设备接入、枚举完成、设备断开时被调用你在里面处理自己的业务逻辑。典型的 Host 状态机APPLICATION_IDLE空闲状态等待 U 盘插入APPLICATION_READYU 盘枚举成功等待文件系统挂载APPLICATION_RUNNING执行文件读写业务APPLICATION_DISCONNECTU 盘拔出清理资源关键代码在USBH_User_Process里void USBH_User_Process(USBH_HandleTypeDef *phost, uint8_t id) { switch (id) { case HOST_USER_CONNECTION: break; case HOST_USER_DISCONNECTION: f_mount(NULL, , 0); // 卸载文件系统 app_state APPLICATION_IDLE; break; case HOST_USER_CLASS_ACTIVE: app_state APPLICATION_READY; break; default: break; } }在 main 主循环里需要不断调用MX_USB_HOST_Process()来驱动 USB Host 状态机同时检查app_state一旦变成APPLICATION_READY就执行挂载和文件操作。这一步有个常见错误直接在回调里做文件挂载但回调里还在 USB Host 中断上下文会导致 FATFS 的f_mount卡死。正确做法是在主循环里做。4.3 FATFS 挂载与文件读写给一个能直接抄的示例当app_state变为APPLICATION_READY后就可以挂载文件系统了。这里建议用FM_FAT | FM_READONLY | FM_NOFS等参数控制读取权限如果只是做固件升级强制只读挂载可以避免意外损坏文件系统。下面是挂载和读文件的完整示例FRESULT res; FATFS fs; FIL fil; uint8_t buf[4096] __attribute__((aligned(4))); res f_mount(fs, , 1); if (res ! FR_OK) { printf(mount fail: %d\r\n, res); return; } res f_open(fil, update.bin, FA_READ); if (res ! FR_OK) { printf(open fail: %d\r\n, res); return; } UINT bytes_read; while (f_read(fil, buf, sizeof(buf), bytes_read) FR_OK bytes_read 0) { // 处理读取到的数据比如写入内部 Flash } f_close(fil); f_mount(NULL, , 0); // 卸载有几个细节在这里特别强调第一缓冲区的对齐。H723 的 USB DMA 要求缓冲区 4 字节对齐用__attribute__((aligned(4)))可以保证。因为 ST 的 USB Host 库内部用 DMA 搬运数据不对齐的缓冲区会导致总线错误或者数据错乱。第二大文件读取要分块。FATFS 的f_read内部按簇读取但每次读取的大小影响性能。实测下来单次读 4KB 到 16KB 是最平衡的太小的块浪费 SCSI 命令开销太大的块可能触发 U 盘内部缓冲问题。第三FATFS 对 exFAT 的支持默认是关闭的。如果你需要读 exFAT 格式的 U 盘超过 32GB 的分区大概率是 exFAT需要在ffconf.h里打开FF_FS_EXFAT同时注意 H723 的 Flash 空间还够不够塞下额外的代码。4.4 写入性能和可靠性量产设备的隐藏要求读文件相对简单写文件才是量产设备的重灾区。如果你的产品需要把日志写到 U 盘或往 U 盘导出数据要注意 FATFS 的写缓冲和同步问题。f_write并不是实时写到 U 盘的数据先进 FATFS 的缓冲区直到缓冲区满或调f_sync才真正落盘。如果用户直接拔 U 盘最后一段数据很可能丢FAT 表也可能损坏。所以在每次写日志后都要调用f_sync(fil)实测性能损耗可以接受。批量写入优化方面与读取同理建议一次写入多个扇区。往 FATFS 的写接口传一个大缓冲比如 32KB让底层 MSC 驱动自动拆分成多条 WRITE(10) 命令会比每次写 512 字节快得多。还有一点需要注意写操作时 USB Host 库内部的状态机是阻塞式的。如果 U 盘响应慢f_write会卡在那里导致主循环无法响应其他事件。这时要评估你的系统是否需要多线程或超时机制。ST 官方库本身对超时的处理比较粗我的做法是加看门狗定时器在极端情况下降级处理。5. 想反过来做让 H723 变成 U 盘Device 模式5.1 官方 MSC 中间件结构如果你要做的是设备虚拟 U 盘整体思路就变了。CubeMX 里把 USB_OTG_HS或 FS配置为 Device_Only然后在 Middleware 里选择 USB_DEVICEClass 选 Mass Storage Class。ST 官方 MSC 中间件的核心是一个接口文件usbd_storage_if.c里面定义了五个函数对应 SCSI 命令的底层操作STORAGE_GetCapacity返回介质总扇区数和扇区大小STORAGE_IsReady返回介质是否就绪STORAGE_Read读取指定扇区范围的数据STORAGE_Write写入指定扇区范围的数据STORAGE_GetMaxLun返回支持的 LUN 数量上层 USB 协议栈收到电脑发来的 SCSI READ(10) 命令后会调用STORAGE_Read收到 WRITE(10) 后调用STORAGE_Write。所以你的工作核心就是把这几个函数对接到底层真实的存储介质上。默认示例代码是把内部 Flash 模拟成 U 盘容量只有几 KB基本不能用于实际产品。你需要替换成自己的介质。5.2 不同存储介质的实现差异把内部 Flash 、外部 SPI Flash、SD 卡分别对接给 MSC 中间件复杂度完全不同。内部 Flash 最简单但要注意扇区擦除粒度。STM32H7 的内部 Flash 扇区大小不一最小的 8KB最大的 128KB而 U 盘逻辑扇区通常是 512 字节所以STORAGE_Write收到 512 字节写入时需要先读回整个物理扇区、修改对应区域、再擦除并写回。这个过程稍有不慎就会破坏数据只适合放小配置文件。外部 SPI Flash如 W25Q64是虚拟 U 盘的性价比之选。W25Q 的扇区是 4KB同样要做读-改-写操作。需要一个 RAM 缓冲区至少 4KB来暂存H723 的 RAM 完全够用。另外 SPI 读写的速度直接决定 U 盘的速度建议用 QSPI 接口的 Flash性能好很多。SD 卡方案最复杂也最实用。如果 SD 卡挂 SDMMC 接口你需要自己把STORAGE_Read/STORAGE_Write转发给HAL_SD_ReadBlocks/HAL_SD_WriteBlocks同时注意 SD 卡的初始化时机和 DMA 缓冲对齐。ST 官方其实有 SD 卡 FATFS USB MSC 的示例但 CubeMX 不会帮你自动拼装得手动整合。Device 模式的性能瓶颈通常出在STORAGE_Read/STORAGE_Write每次只处理一个 512 字节扇区。Windows 对 U 盘的读写优化算法会发多扇区命令但 ST 的 MSC 中间件默认是最小实现。如果速度上不去建议重写这两个函数支持一次处理多个扇区。5.3 虚拟 U 盘的安全弹出处理电脑端点击安全删除硬件时主机会发送 SCSI 命令PREVENT ALLOW MEDIUM REMOVAL和START STOP UNITST 的 MSC 中间件默认会返回 OK但并没有真正对底层介质做 flush。如果你的设备在写入数据时被拔出数据丢失风险照样存在。要在固件里做好收到弹出命令后把缓存写回介质、关闭写操作的逻辑。如果底层介质是 SD 卡至少要把 FATFS 的系统时钟断开并调用f_mount(NULL)如果是 SPI Flash建议把剩余数据写完后把写保护打开。6. 实战排查手册我这几年攒下来的问题清单6.1 枚举阶段的常见问题枚举失败是所有 USB 问题里最折磨人的现象往往是电脑能识别板子不识别或偶尔识别偶尔不识别。我整理了一张排查表按出现频率排序现象可能原因排查方法插入 U 盘无任何反应VBUS 未供电或电压低于 4.4V万用表量连接器 VBUS确认电源开关已打开USB 寄存器没检测到设备D/D- 接反或短路示波器看 D 是否有上拉电平变化枚举超时时钟不准或走线过长频率计测 48MHz检查走线阻抗和长度枚举到一半设备掉线电源波动抓 VBUS 波形看插入瞬间是否有跌落到 3.3V 以下换一个 U 盘又正常黑片 U 盘不兼容降低 USB 速率或增加超时时间最实用的工具是 USB 分析仪但如果没有可以在 USB Host 库的 DEBUG 宏打开后从串口打印枚举状态。ST 库的USBH_Status会告诉你卡在哪一步比瞎猜高效得多。6.2 文件系统与读写阶段的问题枚举成功了但 FATFS 挂载失败这也是高频问题。最常见的FR_NO_FILESYSTEM有三个原因U 盘分区格式是 exFAT而ffconf.h没开FF_FS_EXFATU 盘是超级软盘格式无分区表直接放 FAT 卷FATFS 的挂载参数没选对扇区大小不是 512 字节需要检查disk_ioctl的GET_SECTOR_SIZE返回值读写过程卡死或数据错误则要重点检查 BOT 状态机。比如某个 U 盘在收到 WRITE(10) 后返回 STALL说明它不支持你的写入长度或扇区范围。ST 库的USBH_MSC_HandleBOTError函数里加了错误计数你需要把计数读出来看是否在累加如果累加频繁说明是 U 盘的协议兼容性问题。有一个经典案例某品牌 U 盘在写入时如果主机没有先发 TEST UNIT READY写入命令直接返回错误。处理方式是在挂载后先主动发几个 TEST UNIT READY 命令让 U 盘从休眠状态唤醒。ST 库里有一个SCSI_TestUnitReady函数可以在挂载前调用几次。6.3 兼容性问题的应对策略USB 存储设备可能是嵌入式里最鱼龙混杂的外设了。同一个 U 盘在电脑上怎么插都能用到单片机上就各种怪问题。我总结了一套兼容性应对策略从成本低到高排序第一缓存对齐和命令超时。很多 U 盘的问题出在主机读太快、命令太频繁适当增加 SCSI 命令之间的延时或把超时时间从默认的 100ms 加到 500ms能解决大部分问题。第二端点的批量传输大小。全速 U 盘的最大 Bulk 包大小是 64 字节高速是 512 字节。如果你配置成 512 而实际 U 盘是全速的传输就会错乱。建议在枚举完成后根据端点的wMaxPacketSize动态调整缓冲区大小不要写死。第三热插拔去抖。USB 连接器的机械抖动会导致 VBUS 电平跳变软件上要做去抖处理。我的习惯是检测到连接事件后延时 200ms再读取 USB 外设的HPRT寄存器确认状态连续读 3 次一致才认为设备接入。这个方法帮我解决了无数一会儿识别一会儿不识别的问题。第四如果上面都不行老老实实上协议分析仪。不建议为了省钱去买山寨分析仪抓到的包错乱反而浪费时间。一个稳定的 USB 分析仪哪怕只用一次也值回票价。7. 最后分享一些实战心得USB 这个领域光看手册是不够的一定要跑到真机上去试。我做过一个极端案例某品牌的老款 U 盘在所有标准接口上都正常但在我们板子上反复出现 READ CAPACITY 超时折腾了三天。最后的解决方案居然是在初始化时先发一条 INQUIRY 再发 TEST UNIT READY而不是直接发 READ CAPACITY。这种问题用逻辑分析仪是查不出原因的只能靠协议状态机微调和经验积累。我的习惯是把 ST 官方 USB Host 库的源码在工程里用#define USBH_MSC_DEBUG_ENABLE打开调试输出挂载失败时能从串口定位到具体函数。刚接触 STM32 USB 的朋友建议先跑一遍 ST 官方的USB_Host/MSC_Standalone例程不加任何业务逻辑确认原始功能没问题后再往上叠需求。很多人一上来就改代码加功能出问题了一团乱麻反而无从下手。还有一点USB 相关的代码建议放在独立模块里通过回调把事件抛给应用层不要在 USB 回调函数里做耗时操作。比如在USBH_User_Process里直接调f_mount一旦 U 盘响应慢整个 USB 协议栈就卡死在中断里软硬件都查不出问题。正确做法是把状态置为APPLICATION_READY让主循环去处理。这个项目做完后H723 的 USB Host 功能我基本是当一个稳定外设在用了。回看整个过程USB disk 这个需求本身不复杂复杂的是它对全链路的要求硬件供电、协议栈、文件系统、应用层任何一层出问题都会表现为不通。把这套东西吃透后面再遇到 USB 转串口、USB 虚拟网卡、USB 摄像头接入这些衍生需求都会顺畅很多。
返回列表