Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
CherryUSB
GEEHY极海APM32
STM32F407
CherryUSB移植笔记(一):APM32F407VGT6 DWC2移植 Port.A Full-Speed + Por.B High-Speed
发布于 2024-10-16 01:48:32 浏览:1460
订阅该版
[tocm] # CherryUSB移植笔记
APM32F407VGT6 DWC2移植
— — Port.A与Port.B同时使用
关键词:APM32、DWC2、VisualGDB、Visual Studio 2022、CherryUSB、HID >
入门先把手册看了,面向日志调试开发,不懂再找@sakumisu。
> > **CherryUSB耻辱柱(做人不能太唐):** > > ![image-20241215123113-sdf08tu.png](https://oss-club.rt-thread.org/uploads/20241215/a26a4670304908ae0ebe5fe33c1ece9f.png) > > **[CherryUSB手册](https://cherryusb.readthedocs.io/zh_CN/latest/) 在仓库/视频的下面写着,一堆人愣是没看,出问题这不是正常么?** > > ![image-20241015222445-pj9kxxf.png](https://oss-club.rt-thread.org/uploads/20241215/40b6150804c53c8d7225518415001feb.png.webp) >本贴仓库:https://github.com/Ghost-Girls/CherryUSB # 前言 ## 问题 使用STM32的CubeMX是可以配置APM32的,可以同时配置Prot.A和Port.B为USB Full-Speed,直接编译烧录就可以运行,但是是实现不了一个USB Full-Speed和一个USB High-Speed的,因为STM32的High-Speed只是一个命名,内部没有PHY的,需要外挂PHY。 APM32的Demo是只给了单Port的DEMO,双Prot如何使用,与它们之间的差异,并没有比较详细的描述。虽然,整体看下来比STM32的简洁,但是,还是不喜欢一个片子一个协议栈,学习成本太高了。所以,个人更喜欢CherryUSB小而方便移植的协议栈,另外,还是有个活人一直在更新的、交流氛围很活跃的协议栈。 CherrUSB在1.4.0以下是不支持多Port的,在我的催促之下,@sakumisu一个晚上给相关的函数添加了`usbid`,这才比较容易的实现了Prot.A和Port.B的同时使用,APM32的IP是DWC2的非对称IP。 ## 思考 APM32 Port.B大致区别如下: 1. Prot.A和Port.B两个都是DWC2 IP,但是一个扣的多(4EP,无DMA),一个扣的少(6EP,有DMA) 2. Port.B话可以通过开关切换HS PHY,一个是用的内部的PHY,另一个是用的外部PHY,可以理解为切换USB的内/外时钟源; 3. 不需要连接外部PHY的情况下,Prot.A和Port.B的时钟源是共用的; 通过上述的总结,有过USB处理经验的,多半是知道该怎么处理了。 # 资源下载(不懂谷歌百度,可私信) ## 学习视频 1. (STM32与Nordic)CherryUSB移植与(STM32)远程唤醒实现:[https://www.acfun.cn/v/ac46788507](https://www.acfun.cn/v/ac46788507) ## 移植资料下载 1. APM32F407 USB SDK:[https://www.geehy.com/product/fifth/APM32F405_407](https://www.geehy.com/product/fifth/APM32F405_407) 2. CherryUSB:[https://github.com/cherry-embedded/CherryUSB/releases](https://github.com/cherry-embedded/CherryUSB/releases) 3. CherryUSB的 STM32 DEMO:[https://github.com/CherryUSB/cherryusb_stm32](https://github.com/CherryUSB/cherryusb_stm32) ## 开发环境下载 > 礦ision的阅读与编辑体验太差,因此,使用Visual Studio 2022+VisualGDB进行编辑。 1. Visual Studio 2022 Enterprise:[https://visualstudio.microsoft.com/zh-hans/](https://visualstudio.microsoft.com/zh-hans/) 2. VisualGDB(PreCrack):[磁力链接岂不快哉?](magnet:?xt=urn:btih:18c2e625dfc4cff0642a6959b0206fc83251c2d9&dn=VisualGDB%206.0%20r3&tr=http%3A%2F%2Fbt3.t-ru.org%2Fann%3Fmagnet "磁力链接岂不快哉?") 3. Enterprise Crack Code:[https://downloadly.ir](https://downloadly.ir) 打开网页搜索VS2022,就可以看到词条,点击进入下拉可看到神奇代码 # 准备工作 1. 解压SDK,且SDK不要放置于磁盘根目录下,因为工程路径原因会导致找不到文件。 2. 工程给的项目路径是 `..\..\..\..\`,所以`..\..\..\APM32_USB_SDK_v1.1\Examples\APM32F4xx\Device_Examples\OTGD_Custom_HID_Keyboard_HS2\Project\MDK` 3. 相关的导入流程可以看这些文章: RT-Thread问答社区: [Nordic移植笔记:RT_Thread v5.1.0(基于Nordic nRF52840的ble_app_hids_mouse工程)](https://club.rt-thread.org/ask/article/884332873be4c3d6.html) ACFUN(A站)一图流文章:[nRF52840 移植 RT_Thread:基于ble_app_hids_mouse工程]() 4. 打开工程的第一件事:扫一眼,看看启动文件有没有丢失(这个很重要,因为经常丢文件) ![image](https://assets.b3logfile.com/siyuan/1600817247854/assets/image-20241013064632-7f3l4fh.png) 确认过眼神,是你要的工程, 5. 项目导入时没有对应的设备型号,根据内核选择就行了,无非就是Flash和Ram没配置好,自行添加分散加载文件即可。 > 大型工程,如果是有ROM2,就需要添加.sct分散加载文件,添加分散加载文件之后,会默认忽略填写的ROM与RAM地址。 > 添加ROM和RAM地址,不加也能跑,但是,免得编译下载时出现编译报错 ![image](https://assets.b3logfile.com/siyuan/1600817247854/assets/image-20241013064310-504h563.png) 6. 补全工程配置: 1. 选择ARM内核的类型:**`Cortex-M4.fp.sp (--cpu=Cortex-M4.fp.sp)`** 2. 选择标准库类型:**`Microlib`** ![image](https://assets.b3logfile.com/siyuan/1600817247854/assets/image-20241014000227-sx9gyhp.png) 6. 还没完,还需要再选一次,连接的时候还需要再配置为:**`Microlib (--library_type=microlib)`** ![image](https://assets.b3logfile.com/siyuan/1600817247854/assets/image-20241012033455-107cmlf.png) 7. C语言标准:**`C99 (--c99)`** ![image](https://assets.b3logfile.com/siyuan/1600817247854/assets/image-20241013064151-n564fhv.png) 8. 添加CherryUSB的文件: ![image](https://assets.b3logfile.com/siyuan/1600817247854/assets/image-20241013065018-z9xoxgw.png) > usb_glue_apm.c 是由 usb_glue_st.c 修改而来 > 9. 添加CherryUSB的头文件路径: ![image](https://assets.b3logfile.com/siyuan/1600817247854/assets/image-20241013065125-ncgr57q.png) 10. 从 `cherryusb_stm32` 拷贝一个 `usb_config.h` 过来 # CherryUSB移植 ## 移除原厂协议栈 1. 与USB相关的文件夹全部移除 ![image](https://assets.b3logfile.com/siyuan/1600817247854/assets/image-20241015090621-4hbatpt.png) 2. `main.c` 的相关代码全部移除 ![image](https://assets.b3logfile.com/siyuan/1600817247854/assets/image-20241015225541-ov1u2ic.png) ![image](https://assets.b3logfile.com/siyuan/1600817247854/assets/image-20241015225308-cz4u1mj.png) ![image](https://assets.b3logfile.com/siyuan/1600817247854/assets/image-20241015225415-q52xowu.png) ## CherryUSB配置 一段话总结配置流程: > ```c > /**@brief `不想在群里被群主(@sakumisu)屌,就老老实把这段话看完, 除非给钱` > * > * @a 狗群主说CherryUSB的优势在于因为用了DMA,在传输大数据时,能快那么亿点点(USB HOST 必须要支持DMA, 否则无法使用) > * > * @note 1. 必须要配置出一个能打印"Hello World"的串口 > * 2. 在 `V1.3.1` 中,狗群主已为你准备好了 `busid` 传递参数, 很容易就能实现多IP接口同时工作 > * 3. 添加 `extern void xxx_xxx_init(uint8_t busid, uintptr_t reg_base);` 初始化USB协议栈 > * 4. 添加 `usb_dc_low_level_init();` 初始化Port.A和Port.B USB接口的时钟、管脚、中断优先级 > * 5. 添加 `usb_dc_low_level_deinit()`, 用不上就先创建,单纯避免报错 > * 6. 添加 `usbd_get_speed_config()`,根据当前IP的基地址,获取当前USB IO速度,并替换掉 `usb_dc_dwc2.c` 中的USB速度配置 > * 7. 添加 `usb_phy_config()` 宏定义,替换掉 `dwc2_core_init()` 中有关USB PHY的配置 > * 8. 在 `apm32f4xx_int.c` 中添加 `对应的中断函数` 与 `正确的usbid` 才能实现USB的枚举 > */ > ``` ### log 官方默认配置串口1打印输出: ```c USART_Config_T usartConfigStruct; /* USART configuration */ USART_ConfigStructInit(&usartConfigStruct); usartConfigStruct.baudRate = 115200; usartConfigStruct.mode = USART_MODE_TX_RX; usartConfigStruct.parity = USART_PARITY_NONE; usartConfigStruct.stopBits = USART_STOP_BIT_1; usartConfigStruct.wordLength = USART_WORD_LEN_8B; usartConfigStruct.hardwareFlow = USART_HARDWARE_FLOW_NONE; /* COM1 init*/ APM_EVAL_COMInit(COM1, &usartConfigStruct); ``` 串口是用于打印调试,根据打印内容可确认执行的操作内容,相关内容如下图。 ![image](https://assets.b3logfile.com/siyuan/1600817247854/assets/image-20241013071808-jaoq3fh.png) ### CherryUSB协议栈初始化 ```c /* Init USB device */ extern void hid_mouse_init(uint8_t busid, uintptr_t reg_base); hid_mouse_init(0, USB_OTG_HS_BASE); hid_mouse_init(1, USB_OTG_FS_BASE); ``` 编译效果输出如下: ![image](https://assets.b3logfile.com/siyuan/1600817247854/assets/image-20241013072620-fhvlsc4.png) **`error`**:调用了某个没有定义的函数 `usb_dc_low_level_init()` ### 添加USB IO配置函数 `usb_dc_low_level_init()` 函数中主要是进行于USB相关的时钟、引脚、中断优先级的配置,注意USB的时钟源是 **`PLLD`**,相关时钟源分配是在 `apm32f4xx_rcm.c` 中进行。 参考 `cherryusb_stm32` 的demo,先添加一个空函数。 ```c /** * @brief Initializes the low level portion of the device. * @param busid: Bus identifier * * @retval None * @note This function should be called before the driver is used. */ void usb_dc_low_level_init(uint8_t busid) { } /**@brief Deinitializes the low level portion of the device * * @param busid */ void usb_dc_low_level_deinit(uint8_t busid) { } ``` 编译下载,可以得到下面的输出: ![image](https://assets.b3logfile.com/siyuan/1600817247854/assets/image-20241013193722-tpu7tt0.png) **`error`**:获取IP的ep数量 少于 你配置的ep数量(usb没配置时钟,IP没启动,就获取不到信息) > **NOTE** > > ![2MJK2OD_F7VQ0WQVTC6ZI0](https://assets.b3logfile.com/siyuan/1600817247854/assets/2MJK2OD_F7VQ0WQVTC6ZI0-20241013200428-1iwkr82.png) > > 全是 **`00000000`** ,有两个情况: > > 1. 你用的GD32这玩意,就会这样子,将GD32换成APM32解决问题; > 2. 你的USB时钟没有打开,USB都没启动,当然读不出来啊; ### 添加USB IO配置 通过判断地址可以知道配置的是什么IP,DWC2是新思(Synopsys)的USB IP,只要看到USB的引脚在PA11/PA12或是PB14/PB15,想都不用想,基本上就是这个IP了。 原工程在 `usbd_board.c` 的 `USBD_HardwareInit(USBD_INFO_T* usbInfo)` 进行配置,除去不需要的部分修改如下。 ```c void usb_dc_low_level_init(uint8_t busid) { GPIO_Config_T gpioConfig; struct usbd_bus* bus; bus = &g_usbdev_bus[busid]; APM_DelayInit(); // 需要配置延时,直接调用bsp_delay.c if (bus->reg_base == USB_OTG_FS_BASE) { RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_SYSCFG); /* Configure USB OTG */ RCM_EnableAHB2PeriphClock(RCM_AHB2_PERIPH_OTG_FS); /* Configure USB OTG GPIO */ RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_GPIOA); GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_11, GPIO_AF_OTG1_FS); GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_12, GPIO_AF_OTG1_FS); /* USB DM, DP pin configuration */ gpioConfig.mode = GPIO_MODE_AF; gpioConfig.speed = GPIO_SPEED_100MHz; gpioConfig.otype = GPIO_OTYPE_PP; gpioConfig.pupd = GPIO_PUPD_NOPULL; gpioConfig.pin = GPIO_PIN_11 | GPIO_PIN_12; GPIO_Config(GPIOA, &gpioConfig); /* NVIC */ NVIC_ConfigPriorityGroup(NVIC_PRIORITY_GROUP_4); NVIC_EnableIRQRequest(OTG_FS_IRQn, 1, 0); } else if (bus->reg_base == USB_OTG_HS_BASE) { /* Configure USB OTG*/ RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_SYSCFG); RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_OTG_HS); /* Configure USB OTG GPIO */ RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_GPIOB); GPIO_ConfigPinAF(GPIOB, GPIO_PIN_SOURCE_14, GPIO_AF_OTG_HS_FS); GPIO_ConfigPinAF(GPIOB, GPIO_PIN_SOURCE_15, GPIO_AF_OTG_HS_FS); /* USB DM, DP pin configuration */ gpioConfig.mode = GPIO_MODE_AF; gpioConfig.speed = GPIO_SPEED_100MHz; gpioConfig.otype = GPIO_OTYPE_PP; gpioConfig.pupd = GPIO_PUPD_NOPULL; gpioConfig.pin = GPIO_PIN_14 | GPIO_PIN_15; GPIO_Config(GPIOB, &gpioConfig); /* NVIC */ NVIC_ConfigPriorityGroup(NVIC_PRIORITY_GROUP_4); NVIC_EnableIRQRequest(OTG_HS1_IRQn, 1, 0); } } ``` 编译下载,可以得到下面的输出: ![image](https://assets.b3logfile.com/siyuan/1600817247854/assets/image-20241013201412-hm0ycqg.png) 没有报错,但是,打印被中断了,这是跑死了。 ### 修改延时函数 注意,我在代码里面添加了 `APM_DelayInit();` ,另外还要将`HAL_Delay(ms);`修改为: ```c void usbd_dwc2_delay_ms(uint8_t ms) { APM_DelayUs(ms); } ``` 否则,在这个函数里面执行会跑死: ```c static inline void dwc2_set_mode(uint8_t busid, uint8_t mode) { USB_OTG_GLB->GUSBCFG &= ~(USB_OTG_GUSBCFG_FHMOD | USB_OTG_GUSBCFG_FDMOD); if (mode == USB_OTG_MODE_HOST) { USB_OTG_GLB->GUSBCFG |= USB_OTG_GUSBCFG_FHMOD; } else if (mode == USB_OTG_MODE_DEVICE) { USB_OTG_GLB->GUSBCFG |= USB_OTG_GUSBCFG_FDMOD; //# 1<<30 } usbd_dwc2_delay_ms(50); 执行到此会跑死 } ``` 修改后正常执行,打印输出如下: ![image](https://assets.b3logfile.com/siyuan/1600817247854/assets/image-20241013194937-9l00de4.png) **`error`**:总线溢出,两个IP一起用,超出了了配置的 `bus num` 上限 ### 修改USB总线数量 两个IP一起用,需要将此值设置为 `2` ```c /* ================ USB Device Port Configuration ================*/ // #HACK need to set by 2 for apm32 when using Port.A and Port.B #ifndef CONFIG_USBDEV_MAX_BUS #define CONFIG_USBDEV_MAX_BUS 2 // 1 -> 2 : for now, bus num must be 1 except hpm ip #endif ``` 编译下载,可以得到下面的输出: ![image](https://assets.b3logfile.com/siyuan/1600817247854/assets/image-20241013195954-0qvmscz.png) **`error`**:Port.A的EP数量是4,Port.B的EP数量是6,默认配置为6因此就出现报错了。 ### 修改USB端点数量 两个IP一起用,需要将此值设置为 4 ```c #ifndef CONFIG_USBDEV_EP_NUM #define CONFIG_USBDEV_EP_NUM 6 // #TASK 6 -> 4 Port.B support 6 endpoint, but Port.A only support 4 #endif ``` 编译下载,可以得到下面的输出: ![image](https://assets.b3logfile.com/siyuan/1600817247854/assets/image-20241013201907-jpfczis.png) **`error`** :Port.A的FIFO配置错误,计算后不应大于320(但是可以配置为512/4) ### 修改FIFO大小 ```c fifo_num = CONFIG_USB_DWC2_RXALL_FIFO_SIZE; fifo_num += CONFIG_USB_DWC2_TX0_FIFO_SIZE; fifo_num += CONFIG_USB_DWC2_TX1_FIFO_SIZE; fifo_num += CONFIG_USB_DWC2_TX2_FIFO_SIZE; fifo_num += CONFIG_USB_DWC2_TX3_FIFO_SIZE; ``` 计算后,fifo_num不大于320即可: ```c #ifndef CONFIG_USB_DWC2_RXALL_FIFO_SIZE #define CONFIG_USB_DWC2_RXALL_FIFO_SIZE (1024 / 4) // #HACK 1024/4 —> 512/4 #endif ``` 编译下载,可以得到下面的输出: ![image](https://assets.b3logfile.com/siyuan/1600817247854/assets/image-20241013202602-3arr7d0.png) **USB连接电脑没有反应,怎么回事?** 1. 中断没配置; 2. Port.B的开关没配置; ### 添加USB中断函数 ```c /*! * @brief This function handles USB FS Handler * * @param None * * @retval None * */ void OTG_FS_IRQHandler(void) { extern void USBD_IRQHandler(uint8_t busid); USBD_IRQHandler(1); } /*! * @brief This function handles USB HS Handler * * @param None * * @retval None * */ void OTG_HS1_IRQHandler(void) { ///USBD_OTG_IsrHandler(&usbDeviceHandler); extern void USBD_IRQHandler(uint8_t busid); USBD_IRQHandler(0); } ``` 中断配置了,**USB连接电脑没有反应,怎么回事?** ![image](https://assets.b3logfile.com/siyuan/1600817247854/assets/image-20241013202602-3arr7d0.png) PHY ID、EP、FIFO、中断都是配置正确的,那么只剩下HS1_EXT/HSB_EMB的区别了。 ### Port.B USB PHY 寄存器配置 USB PHY 配置在 `dwc2_core_init()` 内进行,只能外部PHY和内部PHY二选一,但是,APM32,Port.A只能内部,Port.B可内可外,问题就出在这。 **before:** ```c static inline int dwc2_core_init(uint8_t busid) { int ret; #if defined(CONFIG_USB_HS) /* Init The ULPI Interface */ USB_OTG_GLB->GUSBCFG &= ~(USB_OTG_GUSBCFG_TSDPS | USB_OTG_GUSBCFG_ULPIFSLS | USB_OTG_GUSBCFG_PHYSEL); /* Select vbus source */ USB_OTG_GLB->GUSBCFG &= ~(USB_OTG_GUSBCFG_ULPIEVBUSD | USB_OTG_GUSBCFG_ULPIEVBUSI); /* Reset after a PHY select */ ret = dwc2_reset(busid); #else /* Select FS Embedded PHY */ USB_OTG_GLB->GUSBCFG |= USB_OTG_GUSBCFG_PHYSEL; /* Reset after a PHY select */ ret = dwc2_reset(busid); #endif return ret; } ``` **After:** ```c static inline int dwc2_core_init(uint8_t busid) { int ret; usb_phy_config(busid); ret = dwc2_reset(busid); return ret; } ``` 在 `main.c` 中定义 `usb_phy_config()` 函数本体: ```c void usb_phy_config(uint8_t busid) { struct usbd_bus* bus; bus = &g_usbdev_bus[busid]; if (bus->reg_base == USB_OTG_HS_BASE) // Port.B { //!? PB HS2->UTMI(internal), HS1->ULPI(external) /// HS2 and HS1 share the same registers, `but when using hs2, need to turn on imdependent registers: usb_switch, poweron_core, otg_suspendm, sw_rref_i2c` //# HS1与HS2共用基地址,且共用寄存器,但是启用HS2需要另外配置四个寄存器 if (HS_USB_CONFIG == OTG_HS2_EMB) { /* Init The UTMI Interface */ USB_OTG_HS2->USB_SWITCH_B.usb_switch = BIT_SET; USB_OTG_HS2->POWERON_CORE_B.poweron_core = BIT_SET; USB_OTG_HS2->OTG_SUSPENDM_B.otg_suspendm = BIT_SET; USB_OTG_HS2->SW_RREF_I2C_B.sw_rref_i2c = 0x05; } /// if using ULPI(HS1), need to configure the ULPI interface else if (HS_USB_CONFIG == OTG_HS1_EXT)// hs1 only config with ULPI { /* Init The ULPI Interface */ ((DWC2_GlobalTypeDef*)(g_usbdev_bus[busid].reg_base))->GUSBCFG &= ~(USB_OTG_GUSBCFG_TSDPS | USB_OTG_GUSBCFG_ULPIFSLS | USB_OTG_GUSBCFG_PHYSEL); /* Select vbus source */ ((DWC2_GlobalTypeDef*)(g_usbdev_bus[busid].reg_base))->GUSBCFG &= ~(USB_OTG_GUSBCFG_ULPIEVBUSD | USB_OTG_GUSBCFG_ULPIEVBUSI); } } else //if(bus->reg_base == USB_OTG_FS_BASE) // Port.A { /* Select FS Embedded PHY */ ((DWC2_GlobalTypeDef*)(g_usbdev_bus[busid].reg_base))->GUSBCFG |= USB_OTG_GUSBCFG_PHYSEL; // 1<<6 0:hs 1:fs } } ``` 编译下载,连接USB打印输出: ![image](https://assets.b3logfile.com/siyuan/1600817247854/assets/image-20241013221255-695gd4y.png) 如果出现如下报错,那么重启一下电脑,或者连接其他电脑端的USB接口排查: ![image](https://assets.b3logfile.com/siyuan/1600817247854/assets/image-20241013203329-i8bqmzh.png) ### 运行demo测试 主循环添加demo,连接USB后会疯狂转圈则表示移植成功。 ```c int main(void) { /* Set the Vector Table base address at 0x08000000 */ NVIC_ConfigVectorTable(NVIC_VECT_TAB_FLASH, 0x0000); USART_Config_T usartConfigStruct; /* USART configuration */ USART_ConfigStructInit(&usartConfigStruct); //usartConfigStruct.baudRate = 230400; usartConfigStruct.baudRate = 230400; usartConfigStruct.mode = USART_MODE_TX_RX; usartConfigStruct.parity = USART_PARITY_NONE; usartConfigStruct.stopBits = USART_STOP_BIT_1; usartConfigStruct.wordLength = USART_WORD_LEN_8B; usartConfigStruct.hardwareFlow = USART_HARDWARE_FLOW_NONE; /* COM1 init*/ APM_EVAL_COMInit(COM1, &usartConfigStruct); APM_EVAL_LEDInit(LED2); APM_EVAL_LEDInit(LED3); APM_EVAL_PBInit(BUTTON_KEY1, BUTTON_MODE_GPIO); APM_EVAL_PBInit(BUTTON_KEY2, BUTTON_MODE_GPIO); printf("This is APM32 CherryUSB demo test\r\n"); /* Init USB device */ extern void hid_mouse_init(uint8_t busid, uintptr_t reg_base); hid_mouse_init(0, USB_OTG_HS_BASE); hid_mouse_init(1, USB_OTG_FS_BASE); printf("USB Device CUSTOM HID Application\r\n"); while (1) { APM_DelayMs(500); extern void hid_mouse_test(uint8_t busid); hid_mouse_test(1); } } ``` # 收尾工作 ## 运行的速度不是USB High-Speed? 需要添加宏定义 **`#define CONFIG_USB_HS`** ,并修改相关配置代码: **before:** ```c USB_OTG_DEV->DCFG &= ~USB_OTG_DCFG_DSPD; #if defined(CONFIG_USB_HS) USB_OTG_DEV->DCFG |= USB_OTG_SPEED_HIGH; #else if (hsphy_type == 0) { USB_OTG_DEV->DCFG |= USB_OTG_SPEED_FULL; } else { USB_OTG_DEV->DCFG |= USB_OTG_SPEED_HIGH_IN_FULL; } #endif ``` **After:** ```c /* Device speed configuration */ USB_OTG_DEV->DCFG &= ~USB_OTG_DCFG_DSPD; USB_OTG_DEV->DCFG |= usbd_get_speed_config(busid, fsphy_type, hsphy_type); ``` IP是固定的,所以速度有三种:**全速、高速、高速降全速** ```c /** * @brief Get USB device speed * @param busid: Bus identifier * @param fsphy_type: Full-speed PHY type * @param hsphy_type: High-speed PHY type * * @retval USB device speed * * @note Type of USB device speed: * Full-Speed PHY Interface Type (FSPhyType) * `2'b00`: Full-speed interface not supported * `2'b01`: Dedicated full-speed interface * `2'b10`: FS pins shared with UTMI+ pins * `2'b11`: FS pins shared with ULPI pins * * High-Speed PHY Interface Type (HSPhyType) * `2'b00`: High-Speed interface not supported * `2'b01`: UTMI+ * `2'b10`: ULPI * `2'b11`: UTMI+ and ULPI * */ uint8_t usbd_get_speed_config(uint8_t busid, uint8_t fsphy_type, uint8_t hsphy_type) { uint8_t ret; struct usbd_bus* bus; bus = &g_usbdev_bus[busid]; if (bus->reg_base == USB_OTG_FS_BASE) { ret = USB_OTG_SPEED_FULL; } else if (bus->reg_base == USB_OTG_HS_BASE) { if (hsphy_type == 0) { ret = USB_OTG_SPEED_FULL; } else { #if defined(CONFIG_USB_HS) ret = USB_OTG_SPEED_HIGH; #else ret = USB_OTG_SPEED_HIGH_IN_FULL; #endif } } return ret; } ``` ## HS的EP只能配置为4个? 稍加修改即可,只需要亿点点时间和亿点点资源占用! 狗群主已经改好了接口: ![image](https://assets.b3logfile.com/siyuan/1600817247854/assets/image-20241013234617-v1nwy4r.png) `CONFIG_USBDEV_EP_NUM` 涉及的内容是不多: ![image](https://assets.b3logfile.com/siyuan/1600817247854/assets/image-20241013235358-yoj5gr0.png) 内容基本上是 `xxxx[busid].out_ep[CONFIG_USBDEV_EP_NUM]` 或者 ` xxx[busid].rx_msg[CONFIG_USBDEV_EP_NUM]`。 实际需要通过 `CONFIG_USBDEV_EP_NUM` 进行判定的,只有下面这些。 ![image](https://assets.b3logfile.com/siyuan/1600817247854/assets/image-20241014004910-e3org2n.png) 可以将 `CONFIG_USBDEV_EP_NUM` 修改为 `CONFIG_DEV_EP_NUM ` ```c uint8_t g_usb_ep_num[CONFIG_USBDEV_MAX_BUS] = { [0] = 4 // #TASK Port.A support 4 endpoint ,[1] = 6 // #TASK Port.B support 6 endpoint }; #deine CONFIG_DEV_EP_NUM g_usb_ep_num[busid] ``` ![image](https://assets.b3logfile.com/siyuan/1600817247854/assets/image-20241015231636-2gkhd4z.png) 然后,将上述的四行进行修改: ```c int usbd_ep_open(uint8_t busid, const struct usb_endpoint_descriptor* ep) { if (ep_idx > (CONFIG_USBDEV_EP_NUM - 1)) { } ``` ```c void USBD_IRQHandler(uint8_t busid) { if (ep_idx > (CONFIG_USBDEV_EP_NUM - 1)) { for (uint8_t i = 0U; i < CONFIG_USBDEV_EP_NUM; i++) { for (ep_idx = 1; ep_idx < CONFIG_USBDEV_EP_NUM; ep_idx++) { for (ep_idx = 1; ep_idx < CONFIG_USBDEV_EP_NUM; ep_idx++) { } ``` 打印部分也要修改,不然会影响判断: ```c USB_LOG_INFO("dwc2 fsphy type:%d, hsphy type:%d, dma support:%d\r\n", fsphy_type, hsphy_type, dma_support); USB_LOG_INFO("dwc2 has %d endpoints and dfifo depth(32-bit words) is %d, default config: %d endpoints\r\n", endpoints, (USB_OTG_GLB->GHWCFG3 >> 16), CONFIG_DEV_EP_NUM); USB_LOG_INFO("=================================\r\n"); if (endpoints < CONFIG_DEV_EP_NUM) { USB_LOG_ERR("dwc2 has less endpoints than config, please check\r\n"); while (1) { } } ``` 端点数量增加了,EP IN 与 EP OUT的状态/消息结构体数量也要增加,虽然端点数量是不对称的,但是依然将 `CONFIG_USBDEV_EP_NUM` 的值为 6。 最终是通过 `CONFIG_DEV_EP_NUM` 进行判断的,因此,`CONFIG_USBDEV_EP_NUM` 的值只要不低于定义EP的数量就行了。 ![image](https://assets.b3logfile.com/siyuan/1600817247854/assets/image-20241026013239-ckroo85.png) 由于 `CONFIG_USBDEV_EP_NUM` 与 `CONFIG_DEV_EP_NUM` 容易混淆,需要注意甄别。 由于是预编译宏,需要修改为如下: ```c if (CONFIG_DEV_EP_NUM > 4) { dwc2_set_txfifo(busid, 4, CONFIG_USB_DWC2_TX4_FIFO_SIZE); fifo_num += CONFIG_USB_DWC2_TX4_FIFO_SIZE; } if (CONFIG_DEV_EP_NUM > 5) { dwc2_set_txfifo(busid, 5, CONFIG_USB_DWC2_TX5_FIFO_SIZE); fifo_num += CONFIG_USB_DWC2_TX5_FIFO_SIZE; } if (CONFIG_DEV_EP_NUM > 6) { dwc2_set_txfifo(busid, 6, CONFIG_USB_DWC2_TX6_FIFO_SIZE); fifo_num += CONFIG_USB_DWC2_TX6_FIFO_SIZE; } if (CONFIG_DEV_EP_NUM > 7) { dwc2_set_txfifo(busid, 7, CONFIG_USB_DWC2_TX7_FIFO_SIZE); fifo_num += CONFIG_USB_DWC2_TX7_FIFO_SIZE; } if (CONFIG_DEV_EP_NUM > 8) { dwc2_set_txfifo(busid, 8, CONFIG_USB_DWC2_TX8_FIFO_SIZE); fifo_num += CONFIG_USB_DWC2_TX8_FIFO_SIZE; } ``` 编译下载,连接USB打印输出: ![image](https://assets.b3logfile.com/siyuan/1600817247854/assets/image-20241014013403-fwdinol.png) 连接USB功能正常,移植结束。 # 工程优化 > `usb_glue_apm.c` 里面的glue是胶水的意思,群友说“胶水逻辑,一般是在不同模块里面耦合用的”,这里的理解的话就是:DWC2移植时与特殊配置的文件。 高内聚低耦合,所以,尽量将APM32的厂商定义的寄存器拿出来进行配置,所有移植相关的配置基本上都在这里。 ![image](https://assets.b3logfile.com/siyuan/1600817247854/assets/image-20241015230843-flvkwpp.png) 没有把所有内容放进去,主要还是因为`busid` 是在 `usbd_core.h` 中定义,只能这样处理了。 ![image](https://assets.b3logfile.com/siyuan/1600817247854/assets/image-20241015231636-2gkhd4z.png) ![image](https://assets.b3logfile.com/siyuan/1600817247854/assets/image-20241015232448-ue9lf9i.png) 单独弄个头文件也不行,另外USB速度与PHY的配置都在 `usb_dc_dwc2.c` 这个模板修改了,看了眼 `CherryUSB-1.4.0/port` 路径下的文件,看到有 `usb_hc_dwc2.c` 的命名。那干脆将 `usb_dc_dwc2.c` 改成 `usb_apm_dwc2.c`,变成APM32独有的配置不就完事了。 ![image](https://assets.b3logfile.com/siyuan/1600817247854/assets/image-20241015233800-iy8fcm3.png) 大功告成,打包`usb_apm_dwc2.c` 与 `usb_glue_apm.c` 丢给狗群主,PR之后,使用极海APM32的诸位就不用重复造轮子了。
12
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
Ghost_Girls
这家伙很懒,什么也没写!
文章
3
回答
4
被采纳
0
关注TA
发私信
相关文章
1
STM32F407 enable ethernet driver
2
F407使用QEMU调试网络功能报错,附Cm_backtrace信息
3
tm32f407-atk-explorer这个BSP中,1M外置的SRAM
4
串口怎样接收int类型数据?
5
F407无法使用RTC,手册上的RTC实验例程跑不通。请各位不吝赐教!
6
CAN不能推出休眠模式
7
ENV配置Lwip后不能将包跟新到本地?
8
程序跳转出问题,怀疑rtt有指定地址的函数
9
rtthread3.1.2中使用env建立的工程需还需要修改什么东西吗
10
在STM32F407跟着教程制作新bsp后 ,程序运行卡死
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
DMA
USB
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
I2C_IIC
ESP8266
UART
WIZnet_W5500
ota在线升级
cubemx
PWM
flash
freemodbus
BSP
packages_软件包
潘多拉开发板_Pandora
定时器
ADC
flashDB
GD32
socket
编译报错
中断
Debug
rt_mq_消息队列_msg_queue
SFUD
msh
keil_MDK
ulog
C++_cpp
MicroPython
本月问答贡献
出出啊
1518
个答案
343
次被采纳
小小李sunny
1444
个答案
290
次被采纳
张世争
813
个答案
177
次被采纳
crystal266
549
个答案
161
次被采纳
whj467467222
1222
个答案
149
次被采纳
本月文章贡献
出出啊
1
篇文章
3
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
3
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部