STM32
直播中

周棠亨

7年用户 1041经验值
擅长:可编程逻辑 电源/新能源
私信 关注
[问答]

使用HAL库的USB模块时,当设置要接收的数据长度为大于64字节时,无法从接收结束回调函数的原因?

  在使用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的中断函数处理中看出来。

  • /*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_Receive(hpcd, ep->num, ep->xfer_buff, ep->xfer_len);
  •         }

          说明两个方面: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[ep_addr   0x7FU];

  •   /*setup and start the Xfer */
  •   ep->xfer_buff = pBuf;
  •   ep->xfer_len = len;
  •   ep->xfer_count = 0U;
  •   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 hpcd->OUT_ep[ep_addr   0xF].xfer_count;
  • }

            可以看出,实际上就是直接返回的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[ep_addr   0x7FU];

  •   /*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);
  •         }


回帖(1)

周克涛

2024-4-12 10:13:44
接收的数据个数是maxpacket的整数倍时会出错,收不到zero-length包,所以不会结束
举报

更多回帖

发帖
×
20
完善资料,
赚取积分