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

资讯详情

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

STM32H573 USB不工作排查指南:从供电到枚举的全流程分析

STM32H573 USB不工作排查指南:从供电到枚举的全流程分析 1. 先搞清楚这颗芯片的USB到底复杂在哪STM32H573VITxQ这颗料属于STM32H5系列里的中高配型号Cortex-M33内核带TrustZone主打的是安全加高性能。但很多人拿到手之后第一件事不是跑安全特性而是把USB先点亮结果就出现了最常见的那个问题——USB not working。先说结论H5系列的USB不像F103那样随便配一下就工作也不像F4那样需要外部晶振提频。H573这颗芯片内部集成了两个USB控制器一个USB_FS全速一个USB_HS高速两个都能工作在OTG模式而且都支持内置PHY。听起来很方便但这恰恰是第一个坑你以为启用USB_FS就够了实际上时钟、电源、引脚复用、甚至TrustZone的隔离配置每个环节都可能让USB直接挂掉。我遇到过不少朋友发来私信说USB枚举不到、设备描述符请求失败、D一直拉不高问我是不是芯片坏了。其实芯片基本不会坏绝大部分情况下是配置链条上断了一环。这篇东西我就按自己的排查思路从电源、时钟、引脚、代码、硬件几个层面拆开讲尽量把我知道的坑都写出来。不管你用的是STM32CubeMX生成的代码还是自己手写寄存器操作的这套排查逻辑都适用。先说一个重要认知USB全速设备枚举的前提是D引脚上有一个1.5k的上拉电阻。F1系列需要外部电阻H5系列内置了一部分但并不是完全不需要关心。而且H573的USB_FS和USB_HS复用的是不同的引脚组选错了组合代码再怎么写都不会工作。2. 供电域检查VDDUSB不接USB永远是死的2.1 VDDUSB引脚的重要性这是我见过的最多、也最容易忽略的原因。STM32H573芯片是独立的USB供电引脚型号上叫VDDUSB一般和VDDA、VDD放在一起。很多人在画板子的时候以为只要VDD接3.3V就万事大吉了结果VDDUSB悬空或者只是接了一个去耦电容没有真正接到3.3V电源轨USB自然完全不工作。为什么H5要单独设计一个VDDUSB引脚原因在于H5系列支持USB_C口供电检测而且为了降低待机功耗USB收发器需要独立供电域控制。如果VDDUSB没有电那么不管你怎么操作寄存器USB物理层的收发器都不会工作D/D-永远是高阻状态电脑上当然什么都检测不到。画板子的时候请仔细核对原理图VDDUSB必须连接到3.3V电源平面并且就近放一个100nF的电容。有的参考设计还会建议串联一个磁珠或者使用LC滤波因为USB全速虽然对电源不苛刻但高速模式HS对电源纹波还是有要求的。如果你用了H573的USB_HS跑高速VDDUSB的供电质量直接影响眼图测试结果。2.2 TrustZone隔离导致的隐性断电H573是带TrustZone的芯片这带来一个非常隐蔽的问题如果启用了TrustZone那么外设的电源管理和时钟管理可能会被安全侧Secure和普通侧Non-Secure隔离。你如果在Non-Secure工程里面操作RCC但对应的RCC寄存器被配置成Secure访问那么写操作会被静默忽略或者产生总线错误。更麻烦的是PWR模块里的VDDUSB控制位如果被安全侧配置成了安全属性你的普通侧代码调用HAL_PWREx_EnableVddUSB()就完全没效果。我见过一个案例对方在CubeMX里勾选了TrustZone然后默认生成的代码在安全侧初始化的时候把USB外设分配给了Non-Secure但PWR模块的某些位还留在Secure侧导致非安全侧代码看起来跑得好好的实际上电源始终没打开。排查思路先把工程里的TrustZone选项全部关闭或者使用单独的Non-Secure工程跑USB确认USB能不能工作。如果能工作再一步步检查外设隔离配置。如果只用到USB完全可以在CubeMX里关闭TrustZone别让安全框架给自己增加不必要的排查难度。3. 时钟树配置USB要的是精确的48MHz3.1 时钟频率对USB的意义USB全速的位时钟是12MHz但控制器内部需要48MHz的参考时钟。H573的USB时钟源可以是PLL1Q、PLL2Q或者PLL3Q中的一路也可以直接使用HSI48。无论选哪一个最终送到USB控制器的时钟频率必须精确等于48MHz误差不能超过0.25%。这个0.25%的容差是USB规范的要求目的是保证帧周期在1ms±0.05%的范围内加上数据线上的位时钟抖动整体预算非常紧。如果时钟偏了最典型的故障现象是插上USB电脑有反应但枚举不稳定有时显示设备描述符请求失败有时识别成未知设备。这种看起来像电气问题的故障你排查半天硬件最后发现是PLL配置算错了。H573的PLL配置比F4要复杂一些。F4的PLL主要是VCO倍频、分频、再给USB一个PLLQ时钟。H5的PLL有三个独立的分频输出P、Q、R而且VCO的输入范围、倍频系数、反馈分频需要一起算。很多人图省事直接用CubeMX自动生成配置这没问题但你必须去Clock Configuration页面看一眼确认USB那一栏显示的是48MHz而不是别的数值。3.2 手写时钟配置的计算方法如果不用CubeMX或者你需要移植代码这里给出手动计算的方法。H573的PLL内部结构是外部HSE比如25MHz经过分频后送入相位频率检测器PFD经过反馈倍频得到VCO频率再分配给各个输出。举个例子如果HSE是25MHz我们希望VCO频率是400MHz那么倍频系数就是400/2516反馈分频N16。VCO之后分别通过分频器输出如果P分频输出给系统时钟取8分频得到50MHzQ分频输出给USB需要48MHz那么Q400/48≈8.33这在整数PLL里根本没法定所以需要调整整个链条。这里就是关键了为了得到一个能整除的48MHzVCO频率必须选成48的整数倍比如384MHz。384MHz在H5的VCO允许范围192~384MHz内N可以是384/2515.36依然不是整数。那怎么办换HSE频率是最直接的但实际硬件已经固定了。所以更常用的方案是选用HSI32或HSI48作为USB时钟源。H573内部有HSI48专门给USB、RNG这类需要48MHz的地方用误差经过校准后能满足USB要求。CubeMX里在时钟树页面把USB时钟源切到HSI48一秒钟搞定。再说一个被很多文章忽略的细节H573的HSI48在芯片内部是有一个校准机制的它在PLL锁定时会尝试自动修正。默认配置下你只要在CubeMX中勾选了USB应用它会自动启用。如果你是自己写库函数务必在初始化后调用校准接口否则HSI48的初始精度可能刚好卡在临界值。3.3 错误的时钟源切换调用顺序即使你配置对了时钟树代码里还有一个经典坑HAL_RCC_GetSysClockFreq()这类函数返回的时钟频率会影响HAL库内部的时序延迟计算。如果你的系统时钟在PLL启动后发生了变化但HAL库的uwTickFreq还没有重新校准那么所有基于时间延迟的初始化步骤比如USB复位里的等待时序都会按照错误的时钟频率来跑最终导致超时失败。具体表现在代码里就是HAL_PCD_Init()返回HAL_OK但HAL_PCD_Start()之后插上USB线设备完全没有反应。这是因为USB控制器内部的软复位序列没有正确执行状态机卡在了某个阶段。这时你需要检查HAL_InitTick()的配置以及在时钟树初始化完成之后有没有调用HAL_RCC_ClockConfig()它会重新计算系统时钟并更新tick基准。4. 引脚复用与硬件连接D和D-必须选对路4.1 H573的USB引脚组H573芯片的USB引脚并不只有一组。USB_FS可以选择PA11/PA12也可以选择PA9/PA10USB_HS则使用PB14/PB15或者PA11/PA12。注意USB_FS和USB_HS如果使用同一组引脚就不能同时使用。很多人拿到芯片看F1的例程用的是PA12作为D、PA11作为D-于是照搬过来结果H573的默认焊盘上PA11/PA12除了USB_FS之外还有其它复用功能CubeMX里如果不手动指定GPIO_AF10之类的复用号生成的代码可能配置成别的功能。我的建议是翻开H573的数据手册或者CubeMX的引脚配置页面把你要用的USB引脚左键选择USB_OTG_FS_DP、USB_OTG_FS_DM确认复用功能号然后检查GPIO模式是否设置成了GPIO_MODE_AF_PP复用推挽输出另外注意是否开启了上拉。对于USB全速设备D和D-一般不做上拉/下拉因为控制器的内部逻辑和外部上拉电阻已经定义了空闲电平。初始化后D引脚会被自动拉高表示这是一个全速设备。4.2 引脚冲突调试口把USB引脚占用了这又是一个超级隐蔽的坑。H573的SWD调试口默认使用PA13/PA14但如果你的板子上SWD和USB引脚共用了一个物理连接器或者你在调试时占用了PA11/PA12附近的引脚USB枚举就会时好时坏。更典型的场景是同时启用了USB和某个UART或者ADC功能它们的引脚复用和USB产生了冲突。CubeMX在引脚冲突时会直接提示红色但如果你直接用寄存器操作就完全不知道。排查的时候先打开CubeMX把工程导入进去看Pinout页面有没有冲突标记。如果引脚被占用CubeMX会提醒你需要手动解除。4.3 外部器件对D/D-的影响H573的USB_FS内置了D上拉控制电路但这个上拉和外部电阻是并联关系。如果你的原理图参考的是F103老设计在D上外接了一个1.5k电阻到3.3V那么和内部上拉并联之后等效电阻会偏小D的电平电压可能不符合USB规范。最直观的现象是电脑能识别设备但握手过程不稳定特别是拔插多次之后偶尔一次识别失败。所以新设计一定要参考H5系列的官方评估板原理图不要在外部再额外加D上拉电阻。如果你已经按老设计做好了板子排查时先断开外部上拉电阻试试。我调试过的板卡里有两三块就是这么莫名其妙的。5. 软件配置CubeMX生成代码后你还需要检查什么5.1 USB设备库的选型STM32CubeMX里针对USB有几种中间件选择USB_Device配合USB Device Library、USB_Power用于USB-C供电等。很多人直接勾选了USB_Device然后选择了HID类或CDC类生成了代码发现不工作。这时候请先确认你选择的类是符合需求的。H573的USB_Device库路径默认是Middlewares/ST/STM32_USB_Device_Library它分为Core和Class两层。Core负责标准设备请求、枚举流程Class实现具体类协议。如果你在CubeMX里选择了CDC类生成后会多出usbd_cdc.c、usbd_cdc_if.c这些文件。如果枚举失败先用HID类调试因为HID类的中断端点逻辑比CDC的批量端点简单出问题的概率更小。等HID能正常识别了再切换成CDC排查。5.2 堆栈大小不足导致枚举失败这是H5上我遇到的一个典型问题。H5的RAM不算小但CubeMX生成的默认链接脚本可能只分配了很保守的堆栈空间。USB设备库在枚举过程中会动态申请内存特别是CDC类收发缓冲区、描述符缓冲区、URB结构体都需要额外的RAM。如果堆Heap大小不够malloc返回NULL整个初始化流程直接崩溃。排查方法在usbd_conf.c里查看USBD_malloc宏定义它通常映射到malloc。给_Min_Heap_Size和_Min_Stack_Size设大一些比如堆设成0x20008KB栈设成0x10004KB编译再烧录。我一般建议在调试阶段直接给堆16KB因为调试器、打印日志这些也会消耗堆空间。别嫌浪费反正H573的RAM有640KB真的不缺这点空间。5.3 中断优先级配置USB外设使用两个中断USB_FS全局中断OTG_FS_IRQn和USB_HS全局中断OTG_HS_IRQn。在HAL_PCD_Start()之后所有USB事件的响应都依赖中断正常触发。如果你在NVIC配置里把USB中断优先级设置成和系统滴答定时器一样高并且没有设置抢占优先级分组会出现中断嵌套混乱。不过更常见的问题是使用FreeRTOS之后USB中断的优先级如果高于configMAX_SYSCALL_INTERRUPT_PRIORITY你在中断回调里调用osMessagePut这类API就会失败然后软件卡死。推荐配置USB中断优先级设为5抢占子优先级0低于RTOS管理临界区的值保证FreeRTOS的API可以安全调用。如果你不用RTOS这个优先级可以随意一些但不要高过SysTick的优先级避免诡异的时序问题。6. 硬件调试三板斧从万用表到逻辑分析仪6.1 用万用表量D/D-的静态电平USB没工作的时候先用万用表量一下D和D-的电压。未连接电脑时这两个引脚应该是0V因为PHY没有供电或者处于高阻。连接电脑之后电脑端的USB主机会把D和D-都拉低设备端的D被设备内部的1.5k上拉拉高到3.3V所以正常情况下D应该是3V以上D-是0V。如果你量到D和D-都是0V并且确认VDDUSB有电那就要检查USB控制器是否被正确初始化。如果D和D-都是3.3V说明两个引脚都被上拉了可能引脚配置错了D和D-接反或者芯片已经进入了某种未知状态。这个测试虽然基础但真的能帮你迅速区分是软件问题还是硬件问题。我每次调试USB第一件事就是上电接电脑量这两根线的电压。不到十秒钟就能排除一大半可能性。6.2 使用逻辑分析仪或示波器抓包再进一步如果你有逻辑分析仪把D和D-接上在电脑上拔插USB线的时候抓取波形。USB全速的波形特征很明显设备插入后D被拉高至少2.5us低功耗模式需要更长时间主机检测到这个状态后会发送复位信号——也就是D和D-同时拉低至少10ms。复位结束后主机开始发送总线枚举信号包括高速握手检测如果是全速设备则跳过、设备地址设置等。这些波形在逻辑分析仪上一目了然。如果拉了D之后主机没有发送复位信号问题可能在主机端换个USB口试试。如果主机发了复位信号但设备没有回应任何数据包那大概率是固件中的端点配置有问题或者中断没有触发。我之前在调试一个H573的自定义HID设备时逻辑分析仪显示设备收到了复位信号但没有发送任何响应包逐行查代码发现是USBD_LL_SetupStage回调里读取的端点号不对在HAL库和USB设备库之间端点0的句柄传递出错了。这种问题不看波形真的很难定位。6.3 USB分析工具的推荐Windows上排查USB枚举问题我推荐两样东西一个是USB Device Tree Viewer可以清晰看到设备的枚举状态、描述符请求的返回情况还能看到设备当前处于什么状态另一个是Bus Hound可以直接抓取USB总线上的数据包并显示每一个URB的请求和响应。如果你在Linux下可以用lsusb -v查看设备树信息用usbmon配合Wireshark抓包。这些工具的主要作用是帮你确认设备端能不能正确响应标准请求。比如最常见的设备描述符请求失败USBDeviceTree Viewer会显示请求了几次、超时了几次。如果每次都是请求超时说明设备根本没有响应总线上的控制传输问题多半在USB控制器的状态机如果请求成功但后续的配置请求失败那可能就是CDC类的配置描述符有问题或者端点描述符的地址超出了芯片的物理端点数量。7. 用Device Tree Viewer和Bus Hound定位具体问题7.1 Device Tree Viewer的观察方法安装USB Device Tree Viewer之后插上设备它会在设备列表里显示你的设备。如果枚举完全失败你会在设备树里看到一个带黄色感叹号的未知设备或者干脆什么都看不到。它的detail面板会列出主机尝试的每一次控制传输包括请求类型、请求码、索引、长度以及返回的状态。看的时候重点关心两个阶段第一有没有GET_DESCRIPTOR请求以及请求的是Device Descriptor还是Configuration Descriptor第二每一次请求的返回状态是OK还是Timeout还是CRC Error。如果GET_DESCRIPTOR请求发出了但返回超时说明设备端中断没有触发或者中断处理里发送数据卡住了回到HAL_PCD_EP_Transmit()的返回值检查上。如果返回的是CRC Error说明数据线上的信号质量有问题比如走线太长、缺少串联电阻、D/D-对地电容过大这些就要靠硬件层面解决了。7.2 Bus Hound的过滤设置Bus Hound默认会抓所有总线数据噪音太多。我一般会配置一个过滤在Settings→Devices中选择目标设备如果设备枚举失败选Unknown Device或者所有设备然后在Capture里只勾选URB和USB Bus两类数据。这样抓出来的数据非常干净每一条控制传输URB都能看到请求内容、数据缓冲区指针、状态码。对于枚举失败的情况你会在Bus Hound中看到主机反复发送GET_DESCRIPTOR(Device)然后超时。这时候可以判断问题出在设备对控制传输的响应链路。重点关注PCD_EP0_OutStart是否被调用USBD_LL_SetupStage回调有没有执行。如果这些回调的断点根本没有触发那就是中断问题如果触发了但是发送状态不对那就是端点配置问题。8. 常见问题速查表现象可能原因排查顺序D无电平变化VDDUSB无供电先万用表测VDDUSB是否3.3VD有电平但无法枚举时钟不是精确48MHz检查CubeMX时钟树确认USB时钟显示48MHz枚举到未知设备D上拉不稳定检查外部1.5k上拉是否多余断开试试设备描述符请求失败中断未触发检查NVIC配置确认USB全局中断已使能枚举超时堆栈不足增大堆栈或先跑HID精简类调试设备识别后掉线供电不稳定或ESD损伤用示波器看VDDUSB纹波换USB线测试HS模式识别为FSHS握手未完成检查USB_HS PHY供电、时钟恢复及时钟源这张表基本覆盖了H573 USB不工作的大部分场景。你可以按照表格顺序从上到下逐步排查大概率能在半小时内定位根因。9. 动手实践最小USB工程配置步骤如果你用的是CubeMX我给出一个可以抄作业的最小配置流程。第一步在Pinout Configuration页面选择Connectivity→USB_FS勾选Activate VBus sensing模式选择Device_Only。如果你用的是USB_HS且内部PHY模式选择Connectivity→USB_HS模式设为Device_Only。第二步中间的时钟树页面把USB时钟源选为HSI48确认时钟树示意的USB频率是48MHz。如果有警告就调整PLL的分频设置直到USB时钟变成绿色48MHz。第三步Middleware选择USB_DEVICEClass选择HID或者Custom_HID。如果是HID在Device Parameters里可以修改报告描述符。调试阶段建议用默认的HID配置不要先自定义。第四步Project Manager生成代码。生成后打开main.c找到MX_USB_DEVICE_Init()确认它在MX_GPIO_Init()之后被调用。然后编译烧录。插上USB线如果一切正常电脑应该识别出HID设备并提示驱动安装成功。我实测过这个流程在H573核心板上一次通过。如果你的板子不行那就回到前面的章节一项项排查电源、时钟、引脚、中断、堆栈。最后分享一个小技巧不管是CubeMX生成还是手写代码在整个USB初始化完成之后加一个GPIO翻转的输出用于调试。每次USB中断触发、进入Setup回调、端点发送完成都翻转一下这个引脚。示波器挂在上面看波形就能非常直观地看到USB状态机的执行流程。比起在调试器里打断点这种方式不会干扰USB时序尤其在处理高速设备和实时系统时真是省心不少。
返回列表