buyadong 发表于 2017-11-5 05:22:49

不知是否是HAL库USB模块的bug,记录一下

    在使用HAL库的USB模块时,使用了自定义的USB设备,发现了一个问题,    库版本为1.1.1,
    芯片为STM32F103T8
    USB类型:自定义USB FS Device
    问题现象:
         当设置要接收的数据长度为大于64字节时,无法从接收结束回调函数(USBD_xxx_DataOut)中获取已接收数据的字节数。
    原因分析:
            当使用语句:
                USBD_LL_PrepareReceive(pdev,
                           MY_EPOUT_ADDR,
                           hmyusb->RxBuffer,
                           300);
             配置要接收的字节数为300,此时ep.xfer_len = 300-64=236 ,HAL库本身对设置高于max_packet的包可以进行组包,这个可以从USB的中断函数处理中看出来。
<font color="#ff0000">/*multi-packet on the NON control OUT endpoint*/</font>
      ep->xfer_count+=count;
      ep->xfer_buff+=count;
      
<font color="#ff0000">      if ((ep->xfer_len == 0U) || (count < ep->maxpacket))</font>
      {
      /* RX COMPLETE */
   HAL_PCD_DataOutStageCallback(hpcd, ep->num);
      }
      else
      {
   <font color="#ff0000">HAL_PCD_EP_Receive(hpcd, ep->num, ep->xfer_buff, ep->xfer_len);</font>
      }         说明两个方面:1、HAL包调用接收结束的回调函数的条件为:接收完预设的数据长度 或者 接收到小于max_packet长度的包。
         当接收到第一个64字节后,因为还不满要求接收的长度,因此HAL库调用了HAL_PCD_EP_Receive进行再接收数据包。问题出在HAL_PCD_EP_Receive函数中,对ep->xfer_count 清0了。
HAL_StatusTypeDef HAL_PCD_EP_Receive(PCD_HandleTypeDef *hpcd, uint8_t ep_addr, uint8_t *pBuf, uint32_t len)
{
PCD_EPTypeDef *ep = NULL;

ep = &hpcd->OUT_ep;

/*setup and start the Xfer */
ep->xfer_buff = pBuf;
ep->xfer_len = len;
<font color="#ff0000">ep->xfer_count = 0U;</font>
ep->is_in = 0U;
ep->num = ep_addr & 0x7FU;

if ((ep_addr & 0x7FU) == 0U)
{
   USB_EP0StartXfer(hpcd->Instance , ep);
}
else
{
      USB_EPStartXfer(hpcd->Instance , ep);
}

return HAL_OK;
}               而在cube的USB例程中,在接收结束回调函数中,均是调用 USBD_LL_GetRxDataSize (pdev, epnum)函数来获取接收到的数据长度,
uint32_t USBD_LL_GetRxDataSize(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
{
      return HAL_PCD_EP_GetRxCount((PCD_HandleTypeDef*)pdev->pData, ep_addr);
}

uint16_t HAL_PCD_EP_GetRxCount(PCD_HandleTypeDef *hpcd, uint8_t ep_addr)
{
   return <font color="#ff0000">hpcd->OUT_ep.xfer_count;</font>
}             可以看出,实际上就是直接返回的xfer_count。 也就是说,我设置了接收300个,但实际上主机只发了100个过来,那么会导致调用USBD_LL_GetRxDataSize函数判断接收到的长度只有 36个(主要是因为HAL库在设置连续接收时,对xfer_count进行了清0)。
      暂时解决方案:
             拷贝了一个HAL_PCD_EP_Receive函数改名成HAL_PCD_EP_ReceiveContinue,在里面把xfer_count = 0删除。并把USB中断中当需要继续接收时的设置函数改成HAL_PCD_EP_ReceiveContinue。

HAL_StatusTypeDef HAL_PCD_EP_ReceiveContinue(PCD_HandleTypeDef *hpcd, uint8_t ep_addr, uint8_t *pBuf, uint32_t len)
{
PCD_EPTypeDef *ep = NULL;

ep = &hpcd->OUT_ep;

/*setup and start the Xfer */
ep->xfer_buff = pBuf;
ep->xfer_len = len;
ep->is_in = 0U;
ep->num = ep_addr & 0x7FU;

if ((ep_addr & 0x7FU) == 0U)
{
   USB_EP0StartXfer(hpcd->Instance , ep);
}
else
{
      USB_EPStartXfer(hpcd->Instance , ep);
}

return HAL_OK;
}                /*multi-packet on the NON control OUT endpoint*/
      ep->xfer_count+=count;
      ep->xfer_buff+=count;
      
      if ((ep->xfer_len == 0U) || (count < ep->maxpacket))
      {
    /* RX COMPLETE */
    HAL_PCD_DataOutStageCallback(hpcd, ep->num);
      }
      else
      {
      HAL_PCD_EP_ReceiveContinue(hpcd, ep->num, ep->xfer_buff, ep->xfer_len);
      }





shuihehe 发表于 2019-6-13 09:48:06

这个你调试了么,能保证收到字节数是累加的么?

makeWorks 发表于 2020-7-31 16:14:13

接收的数据个数是maxpacket的整数倍时会出错,收不到zero-length包,所以不会结束,囧:'(
页: [1]
查看完整版本: 不知是否是HAL库USB模块的bug,记录一下