|
本帖最后由 archon 于 2021-12-7 15:19 编辑
各位好,因为需要进行较高速传输,所以我用STM32H7+USB3300做了一个基于USB HS的CDC虚拟串口,用的cubeMX生成的工程,启用了USB HS、外部PHY、CDC中间件,堆和栈空间都改大了。编译是通过的,枚举也正常,打开串口很OK,但问题是如果我在CUBEMX里不启用USB OTG HS外设的IP Internal DMA,那么串口是可以工作的,但启用以后,串口会在发送一定量数据后卡死,CDC_Transmit_HS()函数始终返回USBD_BUSY。这个一定量数据和每次调用发送函数时选择的数据量有关,如果是每次传输1字节,那么347次传输后固定卡死,如果每次传输的是8或32字节则1440字节后卡死,如果传输的是384、512、576字节,则会在第四次发送时卡死。
我试过在枚举完成后在调试状态下手动填充对应的寄存器启动发送,同样也是一样的现象,576字节的发送只能成功三次。单步跟踪发现在HAL库中执行这一句:
USBx_INEP(epnum)->DIEPCTL |= (USB_OTG_DIEPCTL_CNAK | USB_OTG_DIEPCTL_EPENA);
后,EP1会通过DMA自动启动传输过程并在传输是自动更新对应的DMA地址和传输量与包数计数器,传输完成后EP1会自动停止,传输量寄存器自动清零,但第四次调用后,EP1会停留在ENABLE状态,传输量寄存器计数清零但包数不清零,同时USB协议栈也不在调用CDC_DataIn回调。在PC上分析USB端口活动发现出现持续不断的大量的USBD_STATUS_XACT_ERROR。
卡死时没有发现明确的寄存器状态变化,手工停止EP1并重新配置对应寄存器也无法继续发送,但插拔USB重新枚举后可以再次发送3次。
请问有任何人遇到过同样的情况吗?USB HS CDC这个内部DMA到底可以用吗?谢谢!
问题已经找到。STM32CUBEMX生成默认工程时,usbd_conf.c文件中的如下函数:
- USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev)
- {
- /* Init USB Ip. */
- if (pdev->id == DEVICE_HS) {
- /* Link the driver to the stack. */
- hpcd_USB_OTG_HS.pData = pdev;
- pdev->pData = &hpcd_USB_OTG_HS;
- hpcd_USB_OTG_HS.Instance = USB_OTG_HS;
- hpcd_USB_OTG_HS.Init.dev_endpoints = 9;
- hpcd_USB_OTG_HS.Init.speed = PCD_SPEED_HIGH;
- hpcd_USB_OTG_HS.Init.dma_enable = ENABLE;
- hpcd_USB_OTG_HS.Init.phy_itface = USB_OTG_ULPI_PHY;
- hpcd_USB_OTG_HS.Init.Sof_enable = DISABLE;
- hpcd_USB_OTG_HS.Init.low_power_enable = DISABLE;
- hpcd_USB_OTG_HS.Init.lpm_enable = DISABLE;
- hpcd_USB_OTG_HS.Init.vbus_sensing_enable = DISABLE;
- hpcd_USB_OTG_HS.Init.use_dedicated_ep1 = DISABLE;
- hpcd_USB_OTG_HS.Init.use_external_vbus = DISABLE;
- if (HAL_PCD_Init(&hpcd_USB_OTG_HS) != HAL_OK)
- {
- Error_Handler( );
- }
- #if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
- /* Register USB PCD CallBacks */
- HAL_PCD_RegisterCallback(&hpcd_USB_OTG_HS, HAL_PCD_SOF_CB_ID, PCD_SOFCallback);
- HAL_PCD_RegisterCallback(&hpcd_USB_OTG_HS, HAL_PCD_SETUPSTAGE_CB_ID, PCD_SetupStageCallback);
- HAL_PCD_RegisterCallback(&hpcd_USB_OTG_HS, HAL_PCD_RESET_CB_ID, PCD_ResetCallback);
- HAL_PCD_RegisterCallback(&hpcd_USB_OTG_HS, HAL_PCD_SUSPEND_CB_ID, PCD_SuspendCallback);
- HAL_PCD_RegisterCallback(&hpcd_USB_OTG_HS, HAL_PCD_RESUME_CB_ID, PCD_ResumeCallback);
- HAL_PCD_RegisterCallback(&hpcd_USB_OTG_HS, HAL_PCD_CONNECT_CB_ID, PCD_ConnectCallback);
- HAL_PCD_RegisterCallback(&hpcd_USB_OTG_HS, HAL_PCD_DISCONNECT_CB_ID, PCD_DisconnectCallback);
- HAL_PCD_RegisterDataOutStageCallback(&hpcd_USB_OTG_HS, PCD_DataOutStageCallback);
- HAL_PCD_RegisterDataInStageCallback(&hpcd_USB_OTG_HS, PCD_DataInStageCallback);
- HAL_PCD_RegisterIsoOutIncpltCallback(&hpcd_USB_OTG_HS, PCD_ISOOUTIncompleteCallback);
- HAL_PCD_RegisterIsoInIncpltCallback(&hpcd_USB_OTG_HS, PCD_ISOINIncompleteCallback);
- #endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
- /* USER CODE BEGIN TxRx_Configuration */
- HAL_PCDEx_SetRxFiFo(&hpcd_USB_OTG_HS, 0x200);
- HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_HS, 0, 0x80);
- HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_HS, 1, 0x174);
- /* USER CODE END TxRx_Configuration */
- }
- return USBD_OK;
- }
复制代码 其中:
HAL_PCDEx_SetRxFiFo(&hpcd_USB_OTG_HS, 0x200);
标红部分参数过大,修改为0x80后DMA传输正常。是否会影响数据接收,因为我的项目不需要接收大量数据所以暂无测试,如有需要可以尝试调整。
感觉这个函数可能问题挺多的,再次更新。USB CDC实际用到了3个EP,但函数中:
hpcd_USB_OTG_HS.Init.dev_endpoints = 9;
初始化为9个EP,实测修改为3个似乎并不影响使用。
此外在stm32h7xx_hal_pcd_ex.c中,关于HAL_PCDEx_SetTxFiFo函数有如下说明:
When DMA is used 3n * FIFO locations should be reserved for internal DMA registers
其中n为FIFO号。其实我不太看得懂这段注释,但感觉启用DMA后FIFO尽量不要设置的太大,尤其内部代码会将传入值翻倍以后写入寄存器。实测RxFIFO设置为0x20时无法工作,0x40时可以正常工作,TxFIFO设置为0x80到0x200均可正常工作。
|
评分
-
查看全部评分
|