不知是否是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);
}
这个你调试了么,能保证收到字节数是累加的么? 接收的数据个数是maxpacket的整数倍时会出错,收不到zero-length包,所以不会结束,囧:'(
页:
[1]