在使用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);
- }