如何仅通过软件重新初始化STM32微控制器的USB枚举?
STM32F429 USB MSC 软件模拟U盘插拔实现问题
我基于STM32F429开发USB MSC项目,使用HAL库,需要兼容不同型号的U盘。部分U盘必须经过重启或重新枚举后才能正常进行文件读写操作,我希望仅通过软件实现类似物理插拔U盘的USB进程重启效果。尝试了以下重置USB端口的函数,但未能触发USB枚举:
static uint8_t USBMNG_ResetUsbPort(void) { uint32_t curState = ((USBx_HPRT0 ) & 0x01UL); if(curState != 0) { USBx_HPRT0 &= ~(1UL << 12); } else { USBx_HPRT0 &= ~(1UL << 12); USBx_HPRT0 |= (1UL << 12); } return 1; } uint8_t USBMNG_USBDevDisconnect(void) { /* In case phy is stopped, ensure to ungate and restore the phy CLK */ USBx_PCGCCTL &= ~(USB_OTG_PCGCCTL_STOPCLK | USB_OTG_PCGCCTL_GATECLK); USBx_DEVICE->DCTL |= USB_OTG_DCTL_SDIS; return 1; } uint8_t USBMNG_USBDevConnect(void) { /* In case phy is stopped, ensure to ungate and restore the phy CLK */ USBx_PCGCCTL &= ~(USB_OTG_PCGCCTL_STOPCLK | USB_OTG_PCGCCTL_GATECLK); USBx_DEVICE->DCTL &= ~USB_OTG_DCTL_SDIS; return 1; }
问题分析与修复方案
你现有的函数只操作了硬件寄存器的断开/复位位,但缺少HAL库层面USB栈的重置与资源释放流程,导致设备无法触发枚举。以下是完整的软件重置实现步骤:
第一步:停止USB MSC服务与主机栈
先通过HAL库函数停止相关服务,释放占用的资源:// 停止USB MSC服务 if(HAL_MSC_DeInit(&hUSB_Host_MSC) != HAL_OK) { // 按需添加错误处理逻辑 } // 停止USB主机控制器 if(HAL_HCD_Stop(&hhcd_USB_OTG_FS) != HAL_OK) { // 按需添加错误处理逻辑 }第二步:硬件层面模拟插拔并添加延时
优化原有端口重置逻辑,增加必要延时确保U盘识别到断开/连接信号:uint8_t USBMNG_ResetUsbPort(void) { // 断开USB设备 USBx_DEVICE->DCTL |= USB_OTG_DCTL_SDIS; HAL_Delay(500); // 延时保证设备检测到断开状态 // 恢复USB连接 USBx_DEVICE->DCTL &= ~USB_OTG_DCTL_SDIS; HAL_Delay(100); // 等待设备完成初始化 return 1; }注:
USBx需根据硬件配置替换为实际外设实例,比如USB_OTG_FS或USB_OTG_HS第三步:重新初始化USB主机栈与MSC服务
重启完成后重新初始化相关组件,触发U盘枚举:// 重新初始化USB主机控制器 if(HAL_HCD_Init(&hhcd_USB_OTG_FS) != HAL_OK) { // 按需添加错误处理逻辑 } // 重新初始化USB MSC服务 if(HAL_MSC_Init(&hUSB_Host_MSC) != HAL_OK) { // 按需添加错误处理逻辑 }关键注意事项
- 保留原有代码中
USBx_PCGCCTL的时钟配置,确保操作寄存器前USB时钟正常运行 - 延时时间可根据U盘实际情况调整,老旧U盘可能需要延长断开延时至1000ms左右
- 若使用USB高速模式,需确认PHY配置正确,避免因PHY未初始化导致枚举失败
- 保留原有代码中
内容的提问来源于stack exchange,提问作者Nima Aghayan
相关产品推荐
相关产品推荐

