在STM32G4上移植CherryUSB协议栈(usb_device)
本文实现了STM32G4模拟 usb hid 设备作为鼠标
CherryUSB版本为v1.4.3
ST的固件库为STM32Cube_FW_G4_V1.6.1
CherryUSB介绍(摘自CherryUSB的readme)
CherryUSB 是一个小而美的、可移植性高的、用于嵌入式系统的 USB 主从协议栈。同时 CherryUSB 具有以下优点:
易于学习 USB
为了方便用户学习 USB 基本知识、枚举、驱动加载、IP 驱动,因此,编写的代码具备以下优点:
- 代码精简,逻辑简单,无复杂 C 语言语法
- 树状化编程,代码层层递进
- Class 驱动和 porting 驱动模板化、精简化
- API 分类清晰(从机:初始化、注册类、命令回调类、数据收发类;主机:初始化、查找类、数据收发类)
易于使用 USB
为了方便用户使用 USB 接口,考虑到用户学习过 uart 和 dma,因此,设计的数据收发类接口具备以下优点:
- 等价于使用 uart tx dma/uart rx dma
- 收发长度没有限制,用户不需要关心 USB 分包过程(porting 驱动做分包过程)
易于发挥 USB 性能
考虑到 USB 性能问题,尽量达到 USB 硬件理论带宽,因此,设计的数据收发类接口具备以下优点:
- Porting 驱动直接对接寄存器,无抽象层封装
- Memory zero copy
- IP 如果带 DMA 则使用 DMA 模式(DMA 带硬件分包功能)
- 长度无限制,方便对接硬件 DMA 并且发挥 DMA 的优势
- 分包功能在中断中处理
从机协议栈整体执行流程
主机协议栈整体执行流程
项目地址
开始移植
- 使用 STM32CubeMX 创建工程,配置基本的 RCC、UART (作为 log 使用,但是我们移植的 G4 系列的 usb ip 核为 fsdev,基本没有配置项,故无 log)
- 我们这里使用的是 fsdev ip,勾选 USB。开启 USB 中断,其他配置对我们没用,cherry 的代码中不会使用任何 ST 的 USB 库
检查时钟树,保证 USB 时钟为 48MHz
发现一个现象,如果用的是PLL出来的48M,后面注释MX自动生成的 usb init 似乎可有可无,但是用HSI的48M,则必须注释掉MX生成的 usb init,否则无法枚举
- Generate CODE
在项目目录里拷进CherryUSB源码
- 添加 CherryUSB 必须要的源码,以及想要使用的 class 驱动,可以将对应 class 的 demo template 添加方便测试,我这里就添加 hid 的 class 和 demo template 来测试。
- 将 ./CherryUSB/cherryusb_config_template.h 复制到 ./Core/Inc 并重命名为 usb_config.h
- 如果使用 fsdev ip,在 usb_config.h 中实现以下宏
1 | // 以下细节不同芯片可能有出入,要改!! |
- 拷贝 usb_xxx.c 里面的 HAL_PCD_MspInit 函数中的内容到 usb_dc_low_level_init 函数中,并屏蔽 ST 生成的 USB 初始化
1 | void usb_dc_low_level_init(uint8_t busid) { |
- 在中断函数中调用 USBD_IRQHandler,并传入 busid
- 调用 template 的内容初始化,并填入 busid 和 USB IP 的 reg base,busid 从 0 开始,不能超过CONFIG_USBDEV_MAX_BUS,这里 reg base 在 stm32xxx.h 里找。
顺利的话,应该接上 USB 鼠标就开始转圈了,但是这里出现了没法枚举的情况。
由于 fsdev ip 本来就只有一个配置项,故怀疑是
1 |
这里的 define 不太合适,改为“1”后解决问题,鼠标开始转圈圈了。
注意注意:配置USB时钟的时候如果用HSI的48MHz频率,则必须不要忘了注释MX生成的 usb init。
参考资料
- CherryUSB 使用指南——遇事不决先看官方文档,这是能找到的最好的资料,99%的问题文档里都提到过,感谢@sakumisu
- APM32F407VGT6 DWC2移植 Port.A Full-Speed + Por.B High-Speed——另一位大佬的帖子,看完受益匪浅
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Comment