当前位置: 首页 > news >正文

基于 USBD 库 CDC Standalone 例程中的一个 Bug 解析

关键字:STM32U5,USB,ST_USBD_Library

1. 引言

当前越来越多的 STM32 芯片支持 USB-PD,目前新提供的 STM32 的 USB 例程中会把 USB-PD 和 USB 合在一起。如果有客户只需要 USB,那就需要剥离 USB-PD。另外,STM32U5 的 Cube 库中只提供了基于 USBX 的例程,如果客户要使用基于USB_USBD_Library 则需要到 GitHub 上去下载。

2. 问题

2.1. 问题详情

客户在开发其产品过程中,使用了 STM32U575ZIT6Q。因为客户对 USBX 不熟悉,所以希望 ST 能够提供基于 ST_USBD_Library 的 CDC_Standalone 的例程,以实现虚拟串口功能。

建议客户到 GitHub 上去下载:https://github.com/STMicroelectronics/stm32u5-classic-coremw-apps

客户下载后发现里边提供的 CDC_Standalone 的例程是带有 USB-PD 的,客户对 USB-PD 不熟悉,希望能够提供给他们不带 USB-PD 的,所以就需要从这个例程中对 USB-PD 进行剥离。

在对 USB-PD 进行剥离后,并在 usb_device.c 中的 MX_USB_Device_Init() 函数中添加USBD_Start() 函数启动 USB。

按理说,进展到这一步,USB 就应该可以工作的。事实上,发现在 NUCLEO-U575ZI-Q 板子上测试时,当通过 USB 连接到 PC 后,就会发现枚举成功了,PC 可以正常识别到虚拟串口。但是,看起来无法工作,在线调试时发现其进入了 Error_Handler(),也就是说,在什么地方出错了,工作不了。

2.2. 问题分析

查了很多遍,怎么都看不出 USB 的配置哪里有问题,看起来都还好,而且是从原例程剥离时并没有动 USB 的代码,觉得有点不可思议。

后来实在没办法,只好挨个在进入 Error_Handler 的入口处设断点,最后终于捕捉到进入Error_Handler 的地方了,为在 CDC_Itf_Init() 函数中以中断方式启动 TIM3 的地方出问题了,如图 1。

图1. 进入 Error_Handler 的地方。

觉得很奇怪,这只是以中断方式启动 TIM3 而已,为什么会出错?

通过在线调试,查看上面的 TIM_Config()函数时,发现了问题。TIM_Config()函数内容如图 2 所示。

图2. TIM_Config()函数

看一下这个红框里的内容,还有图 1 的红框那边的代码,可以发现这个例程中对 TIM3 以中断方式启动了两次,这是否会有问题呢?

再来看一下 HAL_TIM_Base_Start_IT()函数,如图 3。

图3. HAL_TIM_Base_Start_IT ()函数

从 HAL_TIM_Base_Start_IT()函数的逻辑可以看到,如果连续两次调用,第一次调用时,TIM3 的状态机会变成 HAL_TIM_STATE_BUSY(蓝色框所示),第二次再调用时就会在红色框那边因为状态机不是 HAL_TIM_STATE_READY 而返回 HAL_ERROR,回到 CDC_Itf_Init() 函数就会跳入 Error_Handler()了,从而导致运行可能存在问题。所以,连续调用两次HAL_TIM_Base_Start_IT()函数是不合理的。

2.3. 解决方法

问题找到了后,解决方法也很简单,就是把 TIM_Config()函数中的调用HAL_TIM_Base_Start_IT()的语句去掉,避免重复调用就可以了,如图 4。

图4. 修改后的 TIM_Config()函数

3. 原代码为什么能运行?

细心的朋友们可能就想到了一个问题:你说原代码中就有这个 Bug,那为什么原代码运行得好好的?

这个问题很好,主要是因为在进行 USB-PD 剥离后在编译时编译器提示 Error_Handler() 重复声明了,在 IAR 中只是警告,在 Keil 中就直接是错误了。来看一下原代码中位于 usbd_cdc_if.c 中的 Error_Handler(),如图 5。

图5. usbd_cdc_if.c 中的 Error_Handler()函数

可以看到,在 Error_Handler()中它没有做任何处理,就直接返回了,所以原代码中即使两次调用 HAL_TIM_Base_Start_IT()导致运行到 Error_Handler()也不会被发现,所以感觉良好而已。

但是在 main.c 中还有一个 Error_Handler(),如图 6。

图6. main.c 中的 Error_Handler()函数

正常来说,运行到 Error_Handler()就该用 while(1)停下来看一下出现了什么情况的。所以在编译出现问题的情况下,对 usbd_cdc_if.c 中的 Error_Handler()进行了修改,声明为 weak,从而使得出现问题的时候,直接运行 main.c 中的 Error_Handler()。usbd_cdc_if.c 中的 Error_Handler()的修改如图 7 所示。

图7. 修改后 usbd_cdc_if.c 中的 Error_Handler()函数

所以,剥离 USB-PD 后测试会死掉的原因就在这,连续两次调用 HAL_TIM_Base_Start_IT()进入了 main.c 的 Error_Handler(),然后死在了 while(1)中。

4. 小结

使用 GitHub 上的 https://github.com/STMicroelectronics/stm32u5-classic-coremw-apps软件包进行基于 USB_USBD_Library 的 STM32U5 的 CDC_Standalone 进行开发的时候,需要注意到此 Bug。如果在开发过程中,遇到 Error_Handler(),可以看看是否这里没有修改。
 

http://www.dtcms.com/a/309977.html

相关文章:

  • 在多租户或多服务共享 Redis 时,如何做逻辑隔离或权限控制?
  • Docker Compose入门(2)
  • QD9361开发板教程:基于MIG IP的PL端DDR3测试
  • Manus Wide Research:重新定义AI多智能体并发处理的技术革命
  • windows内核研究(软件调试-调试事件的处理)
  • 无图形界面的CentOS 7网络如何配置
  • 大模型结构比较
  • QT中字符串加tr u8的意思
  • Flink Checkpoint机制:大数据流处理的坚固护盾
  • mongodb中的哈希索引详解
  • Windows11 WSL安装Ubntu22.04,交叉编译C语言应用程序
  • Java集合框架:LinkedList
  • 【Jetson orin-nx】使用Tensorrt并发推理四个Yolo模型 (python版)
  • tensorflow目标分类:分绍(二)
  • 树莓派硬件介绍
  • 提示+掩膜+注意力=Mamba三连击,跨模态任务全面超越
  • 安检机危险品识别准确率↑23.7%:陌讯多模态融合算法实战解析
  • Python爬虫库性能与选型实战指南:从需求到落地的全链路解析
  • 神经网络的基础
  • 工业级蓝光三维扫描仪:汽车零部件高精度检测的利器
  • 研华PCI-1622C 使用RS-422通讯1主多从通讯中断
  • 【QT开发手册】对象模型(对象树) 窗⼝坐标体系
  • EXE加密软件(EXE一机一码加密大师) 最新版1.6.0更新 (附2025最新版本CSDN下载地址)
  • windows mamba-ssm环境配置指南
  • 网络层协议IP
  • 运维端口管理闭环:从暴露面测绘到自动化封禁!
  • 【AI问答记录】grafana接收query请求中未携带step参数,后端基于intervalMs和maxDataPoints等参数计算step的逻辑
  • AcWing 897:最长公共子序列 ← 子序列问题(n≤1e3)
  • “数据管理” 一场高风险的游戏
  • 民航领域数据分类分级怎么做?|《民航领域数据分类分级要求》标准解读