diff --git a/cores/arduino/stm32/usb/cdc/usbd_cdc.c b/cores/arduino/stm32/usb/cdc/usbd_cdc.c index 5a23bff2e5..4aac278a2a 100644 --- a/cores/arduino/stm32/usb/cdc/usbd_cdc.c +++ b/cores/arduino/stm32/usb/cdc/usbd_cdc.c @@ -651,9 +651,9 @@ static uint8_t USBD_CDC_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum) USBD_CDC_ItfTypeDef *ctrl = (USBD_CDC_ItfTypeDef *)pdev->pUserData; if (pdev->pClassData != NULL) { - if ((pdev->ep_in[epnum].total_length > 0U) && ((pdev->ep_in[epnum].total_length % hpcd->IN_ep[epnum].maxpacket) == 0U)) { + if ((hcdc->TxLastLength > 0U) && ((hcdc->TxLastLength % hpcd->IN_ep[epnum].maxpacket) == 0U)) { /* Update the packet total length */ - pdev->ep_in[epnum].total_length = 0U; + hcdc->TxLastLength = 0U; /* Send ZLP */ USBD_LL_Transmit(pdev, epnum, NULL, 0U); @@ -835,7 +835,7 @@ uint8_t USBD_CDC_TransmitPacket(USBD_HandleTypeDef *pdev) hcdc->TxState = 1U; /* Update the packet total length */ - pdev->ep_in[CDC_IN_EP & 0xFU].total_length = hcdc->TxLength; + hcdc->TxLastLength = hcdc->TxLength; /* Transmit next packet */ USBD_LL_Transmit(pdev, CDC_IN_EP, hcdc->TxBuffer, diff --git a/cores/arduino/stm32/usb/cdc/usbd_cdc.h b/cores/arduino/stm32/usb/cdc/usbd_cdc.h index 4ed668414d..9fd1fb08c1 100644 --- a/cores/arduino/stm32/usb/cdc/usbd_cdc.h +++ b/cores/arduino/stm32/usb/cdc/usbd_cdc.h @@ -41,9 +41,9 @@ extern "C" { /** @defgroup usbd_cdc_Exported_Defines * @{ */ -#define CDC_IN_EP 0x81U /* EP1 for data IN */ +#define CDC_IN_EP 0x82U /* EP1 for data IN */ #define CDC_OUT_EP 0x01U /* EP1 for data OUT */ -#define CDC_CMD_EP 0x82U /* EP2 for CDC commands */ +#define CDC_CMD_EP 0x83U /* EP2 for CDC commands */ #ifndef CDC_HS_BINTERVAL #define CDC_HS_BINTERVAL 0x10U @@ -115,6 +115,7 @@ typedef struct { uint8_t *TxBuffer; uint32_t RxLength; uint32_t TxLength; + uint32_t TxLastLength; __IO uint32_t TxState; __IO uint32_t RxState; diff --git a/cores/arduino/stm32/usb/usbd_conf.c b/cores/arduino/stm32/usb/usbd_conf.c index 399a5fe088..97f0bd37ac 100644 --- a/cores/arduino/stm32/usb/usbd_conf.c +++ b/cores/arduino/stm32/usb/usbd_conf.c @@ -28,10 +28,12 @@ /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ /* Size in words, byte size divided by 2 */ -#define PMA_EP0_OUT_ADDR (8 * 3) +#define PMA_EP0_OUT_ADDR (8 * 4) #define PMA_EP0_IN_ADDR (PMA_EP0_OUT_ADDR + USB_MAX_EP0_SIZE) -#define PMA_CDC_OUT_ADDR (PMA_EP0_IN_ADDR + USB_MAX_EP0_SIZE) -#define PMA_CDC_IN_ADDR (PMA_CDC_OUT_ADDR + USB_FS_MAX_PACKET_SIZE) +#define PMA_CDC_OUT_BASE (PMA_EP0_IN_ADDR + USB_MAX_EP0_SIZE) +#define PMA_CDC_OUT_ADDR ((PMA_CDC_OUT_BASE + USB_FS_MAX_PACKET_SIZE) | \ + (PMA_CDC_OUT_BASE << 16U)) +#define PMA_CDC_IN_ADDR (PMA_CDC_OUT_BASE + USB_FS_MAX_PACKET_SIZE * 2) #define PMA_CDC_CMD_ADDR (PMA_CDC_IN_ADDR + USB_FS_MAX_PACKET_SIZE) /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ @@ -520,9 +522,9 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev) #else HAL_PCDEx_PMAConfig(&g_hpcd, 0x00, PCD_SNG_BUF, PMA_EP0_OUT_ADDR); HAL_PCDEx_PMAConfig(&g_hpcd, 0x80, PCD_SNG_BUF, PMA_EP0_IN_ADDR); - HAL_PCDEx_PMAConfig(&g_hpcd, 0x01, PCD_SNG_BUF, PMA_CDC_OUT_ADDR); - HAL_PCDEx_PMAConfig(&g_hpcd, 0x81, PCD_SNG_BUF, PMA_CDC_IN_ADDR); - HAL_PCDEx_PMAConfig(&g_hpcd, 0x82, PCD_SNG_BUF, PMA_CDC_CMD_ADDR); + HAL_PCDEx_PMAConfig(&g_hpcd, 0x01, PCD_DBL_BUF, PMA_CDC_OUT_ADDR); + HAL_PCDEx_PMAConfig(&g_hpcd, 0x82, PCD_SNG_BUF, PMA_CDC_IN_ADDR); + HAL_PCDEx_PMAConfig(&g_hpcd, 0x83, PCD_SNG_BUF, PMA_CDC_CMD_ADDR); #endif #endif /* USE_USB_HS */ return USBD_OK; diff --git a/system/Drivers/STM32F1xx_HAL_Driver/Inc/stm32f1xx_ll_usb.h b/system/Drivers/STM32F1xx_HAL_Driver/Inc/stm32f1xx_ll_usb.h index f5516639c8..a5f8dd26b8 100644 --- a/system/Drivers/STM32F1xx_HAL_Driver/Inc/stm32f1xx_ll_usb.h +++ b/system/Drivers/STM32F1xx_HAL_Driver/Inc/stm32f1xx_ll_usb.h @@ -160,6 +160,9 @@ typedef struct uint32_t xfer_len; /*!< Current transfer length */ uint32_t xfer_count; /*!< Partial transfer length in case of multi packet transfer */ + + uint16_t pending0; /*!, Fact, that double buffering transfer have pended data */ + uint16_t pending1; /*!, Fact, that double buffering transfer have pended data */ }USB_OTG_EPTypeDef; typedef struct @@ -269,8 +272,8 @@ typedef struct uint8_t doublebuffer; /*!< Double buffer enable This parameter can be 0 or 1 */ - - uint16_t tx_fifo_num; /*!< This parameter is not required by USB Device FS peripheral, it is used + + uint16_t tx_fifo_num; /*!< This parameter is not required by USB Device FS peripheral, it is used only by USB OTG FS peripheral This parameter is added to ensure compatibility across USB peripherals */ @@ -278,11 +281,15 @@ typedef struct This parameter must be a number between Min_Data = 0 and Max_Data = 64KB */ uint8_t *xfer_buff; /*!< Pointer to transfer buffer */ - + + uint32_t xfer_len; /*!< Current transfer length */ uint32_t xfer_count; /*!< Partial transfer length in case of multi packet transfer */ + uint16_t pending0; /*!, Fact, that double buffering transfer have pended data */ + uint16_t pending1; /*!, Fact, that double buffering transfer have pended data */ + } USB_EPTypeDef; #endif /* USB */ /** diff --git a/system/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_pcd.c b/system/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_pcd.c index ca32983705..d314252b62 100644 --- a/system/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_pcd.c +++ b/system/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_pcd.c @@ -100,8 +100,12 @@ /** @defgroup PCD_Private_Macros PCD Private Macros * @{ */ -#define PCD_MIN(a, b) (((a) < (b)) ? (a) : (b)) -#define PCD_MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define PCD_PENDED_ZLP 0xffff +#define PCD_PENDED_PROCESSED 0xfffe +#define PCD_OUT_DTOG(value) (((value) & USB_EP_DTOG_RX) != 0) +#define PCD_OUT_SW(value) (((value) & USB_EP_DTOG_TX) != 0) +#define PCD_IN_DTOG(value) (((value) & USB_EP_DTOG_TX) != 0) +#define PCD_IN_SW(value) (((value) & USB_EP_DTOG_RX) != 0) /** * @} */ @@ -117,6 +121,9 @@ static HAL_StatusTypeDef PCD_WriteEmptyTxFifo(PCD_HandleTypeDef *hpcd, uint32_t #if defined (USB) static HAL_StatusTypeDef PCD_EP_ISR_Handler(PCD_HandleTypeDef *hpcd); #endif /* USB */ + +static HAL_StatusTypeDef HAL_PCD_EP_ReceiveData(PCD_HandleTypeDef *hpcd, PCD_EPTypeDef* ep); + /** * @} */ @@ -190,18 +197,22 @@ HAL_StatusTypeDef HAL_PCD_Init(PCD_HandleTypeDef *hpcd) hpcd->IN_ep[index].maxpacket = 0U; hpcd->IN_ep[index].xfer_buff = 0U; hpcd->IN_ep[index].xfer_len = 0U; + hpcd->IN_ep[index].pending0 = 0U; + hpcd->IN_ep[index].pending1 = 0U; } for (index = 0U; index < 15U ; index++) { hpcd->OUT_ep[index].is_in = 0U; hpcd->OUT_ep[index].num = index; - hpcd->IN_ep[index].tx_fifo_num = index; + hpcd->OUT_ep[index].tx_fifo_num = index; /* Control until ep is activated */ hpcd->OUT_ep[index].type = EP_TYPE_CTRL; hpcd->OUT_ep[index].maxpacket = 0U; hpcd->OUT_ep[index].xfer_buff = 0U; hpcd->OUT_ep[index].xfer_len = 0U; + hpcd->OUT_ep[index].pending0 = 0U; + hpcd->OUT_ep[index].pending1 = 0U; } /* Init Device */ @@ -873,9 +884,6 @@ HAL_StatusTypeDef HAL_PCD_EP_Open(PCD_HandleTypeDef *hpcd, uint8_t ep_addr, uint { ep = &hpcd->OUT_ep[ep_addr & 0x7FU]; } - ep->num = ep_addr & 0x7FU; - - ep->is_in = (0x80U & ep_addr) != 0U; ep->maxpacket = ep_mps; ep->type = ep_type; @@ -903,17 +911,13 @@ HAL_StatusTypeDef HAL_PCD_EP_Close(PCD_HandleTypeDef *hpcd, uint8_t ep_addr) { ep = &hpcd->OUT_ep[ep_addr & 0x7FU]; } - ep->num = ep_addr & 0x7FU; - - ep->is_in = (0x80U & ep_addr) != 0U; - + __HAL_LOCK(hpcd); USB_DeactivateEndpoint(hpcd->Instance , ep); __HAL_UNLOCK(hpcd); return HAL_OK; } - /** * @brief Receive an amount of data * @param hpcd: PCD handle @@ -925,15 +929,13 @@ HAL_StatusTypeDef HAL_PCD_EP_Close(PCD_HandleTypeDef *hpcd, uint8_t ep_addr) 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_buff = pBuf; ep->xfer_len = len; ep->xfer_count = 0U; - ep->is_in = 0U; - ep->num = ep_addr & 0x7FU; if ((ep_addr & 0x7FU) == 0U) { @@ -941,7 +943,7 @@ HAL_StatusTypeDef HAL_PCD_EP_Receive(PCD_HandleTypeDef *hpcd, uint8_t ep_addr, u } else { - USB_EPStartXfer(hpcd->Instance , ep); + HAL_PCD_EP_ReceiveData(hpcd, ep); } return HAL_OK; @@ -975,8 +977,6 @@ HAL_StatusTypeDef HAL_PCD_EP_Transmit(PCD_HandleTypeDef *hpcd, uint8_t ep_addr, ep->xfer_buff = pBuf; ep->xfer_len = len; ep->xfer_count = 0U; - ep->is_in = 1U; - ep->num = ep_addr & 0x7FU; if ((ep_addr & 0x7FU) == 0U) { @@ -1010,9 +1010,7 @@ HAL_StatusTypeDef HAL_PCD_EP_SetStall(PCD_HandleTypeDef *hpcd, uint8_t ep_addr) } ep->is_stall = 1U; - ep->num = ep_addr & 0x7FU; - ep->is_in = ((ep_addr & 0x80U) == 0x80U); - + __HAL_LOCK(hpcd); USB_EPSetStall(hpcd->Instance , ep); if((ep_addr & 0x7FU) == 0U) @@ -1044,9 +1042,7 @@ HAL_StatusTypeDef HAL_PCD_EP_ClrStall(PCD_HandleTypeDef *hpcd, uint8_t ep_addr) } ep->is_stall = 0U; - ep->num = ep_addr & 0x7FU; - ep->is_in = ((ep_addr & 0x80U) == 0x80U); - + __HAL_LOCK(hpcd); USB_EPClearStall(hpcd->Instance , ep); __HAL_UNLOCK(hpcd); @@ -1192,6 +1188,12 @@ static HAL_StatusTypeDef PCD_WriteEmptyTxFifo(PCD_HandleTypeDef *hpcd, uint32_t return HAL_OK; } + +HAL_StatusTypeDef HAL_PCD_EP_ReceiveData(PCD_HandleTypeDef *hpcd, PCD_EPTypeDef* ep) +{ + USB_EPStartXfer(hpcd->Instance, ep); +} + #endif /* USB_OTG_FS */ #if defined (USB) @@ -1204,80 +1206,80 @@ static HAL_StatusTypeDef PCD_EP_ISR_Handler(PCD_HandleTypeDef *hpcd) { PCD_EPTypeDef *ep = NULL; uint16_t count = 0; + uint16_t pmaBuffer = 0; uint8_t epindex = 0; - __IO uint16_t wIstr = 0; + __IO uint16_t wIstr = 0; __IO uint16_t wEPVal = 0; - + /* stay in loop while pending interrupts */ while (((wIstr = hpcd->Instance->ISTR) & USB_ISTR_CTR) != 0) { /* extract highest priority endpoint number */ epindex = (uint8_t)(wIstr & USB_ISTR_EP_ID); - + if (epindex == 0) { /* Decode and service control endpoint interrupt */ - - /* DIR bit = origin of the interrupt */ + + /* DIR bit = origin of the interrupt */ if ((wIstr & USB_ISTR_DIR) == 0) { /* DIR = 0 */ - + /* DIR = 0 => IN int */ /* DIR = 0 implies that (EP_CTR_TX = 1) always */ PCD_CLEAR_TX_EP_CTR(hpcd->Instance, PCD_ENDP0); ep = &hpcd->IN_ep[0]; - + ep->xfer_count = PCD_GET_EP_TX_CNT(hpcd->Instance, ep->num); ep->xfer_buff += ep->xfer_count; - + /* TX COMPLETE */ HAL_PCD_DataInStageCallback(hpcd, 0U); - - + + if((hpcd->USB_Address > 0U)&& ( ep->xfer_len == 0U)) { hpcd->Instance->DADDR = (hpcd->USB_Address | USB_DADDR_EF); hpcd->USB_Address = 0U; } - } else { /* DIR = 1 */ - + /* DIR = 1 & CTR_RX => SETUP or OUT int */ /* DIR = 1 & (CTR_TX | CTR_RX) => 2 int pending */ ep = &hpcd->OUT_ep[0U]; wEPVal = PCD_GET_ENDPOINT(hpcd->Instance, PCD_ENDP0); - + if ((wEPVal & USB_EP_SETUP) != 0U) { /* Get SETUP Packet*/ ep->xfer_count = PCD_GET_EP_RX_CNT(hpcd->Instance, ep->num); - USB_ReadPMA(hpcd->Instance, (uint8_t*)hpcd->Setup ,ep->pmaadress , ep->xfer_count); - /* SETUP bit kept frozen while CTR_RX = 1*/ - PCD_CLEAR_RX_EP_CTR(hpcd->Instance, PCD_ENDP0); - + USB_ReadPMA(hpcd->Instance, (uint8_t*)hpcd->Setup ,ep->pmaadress , ep->xfer_count); + /* SETUP bit kept frozen while CTR_RX = 1*/ + PCD_CLEAR_RX_EP_CTR(hpcd->Instance, PCD_ENDP0); + /* Process SETUP Packet*/ HAL_PCD_SetupStageCallback(hpcd); } - + else if ((wEPVal & USB_EP_CTR_RX) != 0U) { PCD_CLEAR_RX_EP_CTR(hpcd->Instance, PCD_ENDP0); /* Get Control Data OUT Packet*/ ep->xfer_count = PCD_GET_EP_RX_CNT(hpcd->Instance, ep->num); - + if (ep->xfer_count != 0U) { USB_ReadPMA(hpcd->Instance, ep->xfer_buff, ep->pmaadress, ep->xfer_count); ep->xfer_buff+=ep->xfer_count; } - + /* Process Control Data OUT Packet*/ - HAL_PCD_DataOutStageCallback(hpcd, 0U); - + HAL_PCD_DataOutStageCallback(hpcd, 0U); + PCD_SET_EP_RX_CNT(hpcd->Instance, PCD_ENDP0, ep->maxpacket); PCD_SET_EP_RX_STATUS(hpcd->Instance, PCD_ENDP0, USB_EP_RX_VALID); } @@ -1286,77 +1288,140 @@ static HAL_StatusTypeDef PCD_EP_ISR_Handler(PCD_HandleTypeDef *hpcd) else { /* Decode and service non control endpoints interrupt */ - + + /* + * SW - DTOG_TX in USB_EPnR register (it act as SW_BUF for dbl buf OUT ep) + * P0 - if ep->pending0 have non-zero value + * P1 - if ep->pending1 have non-zero value + * + * We can get one of following variants here: + * SW P1 P0 + * 0 0 0 - read buffer 0. ^SW when have buffer, +P0 otherwise + * 0 1 0 - same, but interrupt happens in danger zone. As before, -P1 + * 1 1 0 - unprocessed buffer in queue - do nothing and +P0 + * 1 1 1 - same, but interrupt happens in danger zone. As before + * + * 1 0 0 - read buffer 1. ^SW when have buffer, +P1 otherwise + * 1 0 1 - same, but interrupt happens in danger zone. As before, -P0 + * 0 0 1 - unprocessed buffer in queue - do nothing and +P1 + * 0 1 1 - same, but interrupt happens in danger zone. As before + * + * Variant tables: + * + * buffer selection Buffer 1 abort Buffer 0 abort Clear pending + * TX /P1/P0 \ TX /P1/P0 \ TX /P1/P0 \ TX /P1/P0 \ + * | / \ | / \ | / \ | / \ + * | 00 01 11 10 | 00 01 11 10 | 00 01 11 10 | 00 01 11 10 + * 0: 0 1 1 0 0: x A A x 0: - x x - 0: . x x N + * 1: 1 1 0 0 1: - - x x 1: x x A A 1: . Z x x + * + * legend: + * 0: must read buffer 0 + * 1: must read buffer 1 + * x: impossible to get here + * A: abort read, wait for main thread, and set other buffer to pended + * -: does not abort, this is regular read + * N: must clear pending oNe (in case of IRQ asserting in danger zone) + * Z: must clear pending Zero (in case of IRQ asserting in danger zone) + * .: pending clearing can be performed, because it's already clear + * + * resulting logic expressions + * 1: SW ? !P1 : P0 A1: !SW N: !SW + * 0: SW ? P1 : !P0 A0: SW Z: SW + * + * SW ? !P1 : P0 - test to determine, then buffer 1 used. + * if this case, SW determine regular read, or !SW, that we must abort IRQ + * in other case, !SW determine regular read, SW - abort IRQ + * if IRQ asserted in danger zone, two cases require extra pending clear + * with 1 0 1, clearing P0, with 0 1 0 - clear P1 + * but, many other cases aborted before, and clear something, that already + * empty - is do nothing - so clear P1, then !SW, and P0 then SW + * + * Danger zone - is time after PCD_FreeUserBuffer and before + * ep->pendingX = 0 in HAL_PCD_EP_ReceiveData + */ + /* process related endpoint register */ wEPVal = PCD_GET_ENDPOINT(hpcd->Instance, epindex); if ((wEPVal & USB_EP_CTR_RX) != 0U) - { + { /* clear int flag */ PCD_CLEAR_RX_EP_CTR(hpcd->Instance, epindex); ep = &hpcd->OUT_ep[epindex]; - + /* OUT double Buffering*/ if (ep->doublebuffer == 0U) { - count = PCD_GET_EP_RX_CNT(hpcd->Instance, ep->num); - if (count != 0U) + count = (uint16_t) PCD_GET_EP_RX_CNT(hpcd->Instance, ep->num); + pmaBuffer = ep->pmaadress; + } + else if (PCD_OUT_SW(wEPVal) ? ep->pending1 == 0 : ep->pending0 != 0) + { + count = (uint16_t) PCD_GET_EP_DBUF1_CNT(hpcd->Instance, ep->num); + pmaBuffer = ep->pmaaddr1; + if (ep->xfer_len == 0 || ep->xfer_buff == 0 || !PCD_OUT_SW(wEPVal)) { - USB_ReadPMA(hpcd->Instance, ep->xfer_buff, ep->pmaadress, count); + ep->pending1 = (uint16_t) (count == 0 ? PCD_PENDED_ZLP : count); + return HAL_OK; } + ep->pending0 = 0; } else { - if (PCD_GET_ENDPOINT(hpcd->Instance, ep->num) & USB_EP_DTOG_RX) + count = (uint16_t) PCD_GET_EP_DBUF0_CNT(hpcd->Instance, ep->num); + pmaBuffer = ep->pmaaddr0; + if (ep->xfer_len == 0 || ep->xfer_buff == 0 || PCD_OUT_SW(wEPVal)) { - /*read from endpoint BUF0Addr buffer*/ - count = PCD_GET_EP_DBUF0_CNT(hpcd->Instance, ep->num); - if (count != 0U) - { - USB_ReadPMA(hpcd->Instance, ep->xfer_buff, ep->pmaaddr0, count); - } + ep->pending0 = (uint16_t) (count == 0 ? PCD_PENDED_ZLP : count); + return HAL_OK; } - else + ep->pending1 = 0; + } + + if (count != 0U) + { + /* buffer doesn't contains enough space, stall and error */ + if (count > ep->xfer_len) { - /*read from endpoint BUF1Addr buffer*/ - count = PCD_GET_EP_DBUF1_CNT(hpcd->Instance, ep->num); - if (count != 0U) - { - USB_ReadPMA(hpcd->Instance, ep->xfer_buff, ep->pmaaddr1, count); - } + USB_EPSetStall(hpcd->Instance, ep); + return HAL_ERROR; } - PCD_FreeUserBuffer(hpcd->Instance, ep->num, PCD_EP_DBUF_OUT); + USB_ReadPMA(hpcd->Instance, ep->xfer_buff, pmaBuffer, count); } + + if (ep->doublebuffer != 0U) + { + PCD_FreeUserBuffer(hpcd->Instance, ep->num, PCD_EP_DBUF_OUT); + } + /*multi-packet on the NON control OUT endpoint*/ ep->xfer_count+=count; ep->xfer_buff+=count; - + ep->xfer_len-=count; + if ((ep->xfer_len == 0U) || (count < ep->maxpacket)) { /* RX COMPLETE */ HAL_PCD_DataOutStageCallback(hpcd, ep->num); } - else + else if (ep->doublebuffer == 0U) { - HAL_PCD_EP_Receive(hpcd, ep->num, ep->xfer_buff, ep->xfer_len); + PCD_SET_EP_RX_STATUS(hpcd->Instance, ep->num, USB_EP_RX_VALID); } - + } /* if((wEPVal & EP_CTR_RX) */ - + if ((wEPVal & USB_EP_CTR_TX) != 0U) { ep = &hpcd->IN_ep[epindex]; - + /* clear int flag */ PCD_CLEAR_TX_EP_CTR(hpcd->Instance, epindex); - + /* IN double Buffering*/ if (ep->doublebuffer == 0U) { ep->xfer_count = PCD_GET_EP_TX_CNT(hpcd->Instance, ep->num); - if (ep->xfer_count != 0U) - { - USB_WritePMA(hpcd->Instance, ep->xfer_buff, ep->pmaadress, ep->xfer_count); - } } else { @@ -1364,26 +1429,18 @@ static HAL_StatusTypeDef PCD_EP_ISR_Handler(PCD_HandleTypeDef *hpcd) { /*read from endpoint BUF0Addr buffer*/ ep->xfer_count = PCD_GET_EP_DBUF0_CNT(hpcd->Instance, ep->num); - if (ep->xfer_count != 0U) - { - USB_WritePMA(hpcd->Instance, ep->xfer_buff, ep->pmaaddr0, ep->xfer_count); - } } else { /*read from endpoint BUF1Addr buffer*/ ep->xfer_count = PCD_GET_EP_DBUF1_CNT(hpcd->Instance, ep->num); - if (ep->xfer_count != 0U) - { - USB_WritePMA(hpcd->Instance, ep->xfer_buff, ep->pmaaddr1, ep->xfer_count); - } } - PCD_FreeUserBuffer(hpcd->Instance, ep->num, PCD_EP_DBUF_IN); + PCD_FreeUserBuffer(hpcd->Instance, ep->num, PCD_EP_DBUF_IN); } /*multi-packet on the NON control IN endpoint*/ ep->xfer_count = PCD_GET_EP_TX_CNT(hpcd->Instance, ep->num); ep->xfer_buff+=ep->xfer_count; - + /* Zero Length Packet? */ if (ep->xfer_len == 0U) { @@ -1394,11 +1451,104 @@ static HAL_StatusTypeDef PCD_EP_ISR_Handler(PCD_HandleTypeDef *hpcd) { HAL_PCD_EP_Transmit(hpcd, ep->num, ep->xfer_buff, ep->xfer_len); } - } + } } } return HAL_OK; } + +HAL_StatusTypeDef HAL_PCD_EP_ReceiveData(PCD_HandleTypeDef *hpcd, PCD_EPTypeDef* ep) +{ + uint16_t count; + uint16_t pmaBuffer; + volatile uint16_t wEPVal; + volatile uint16_t tmpVal; + volatile uint16_t *pCount; + + wEPVal = PCD_GET_ENDPOINT(hpcd->Instance, ep->num); + count = (wEPVal & USB_EP_DTOG_TX) ? ep->pending1 : ep->pending0; + while (count != 0 && count != PCD_PENDED_PROCESSED) + { + if (ep->xfer_buff == 0 || ep->xfer_len == 0) + { + return HAL_OK; + } + + if (PCD_OUT_SW(wEPVal)) + { + ep->pending1 = PCD_PENDED_PROCESSED; + pmaBuffer = ep->pmaaddr1; + } + else + { + ep->pending0 = PCD_PENDED_PROCESSED; + pmaBuffer = ep->pmaaddr0; + } + + if (count == PCD_PENDED_ZLP) + { + count = 0; + } + else if (count > ep->xfer_len) + { + /* buffer doesn't contains enough space, stall and error */ + USB_EPSetStall(hpcd->Instance, ep); + return HAL_ERROR; + } + + USB_ReadPMA(hpcd->Instance, ep->xfer_buff, pmaBuffer, count); + + /*multi-packet on the NON control OUT endpoint*/ + ep->xfer_count += count; + ep->xfer_buff += count; + ep->xfer_len -= count; + + if (ep->xfer_len == 0U || count < ep->maxpacket) + { + /* RX COMPLETE */ + HAL_PCD_DataOutStageCallback(hpcd, ep->num); + } + + /* + * ENTER DANGER ZONE + * Yes, disable interrupts can be used (or CTRM in USB_CNTR can be cleared) + * but it's not good. We can rule concurrency (or just simple determine, if + * interrupt asserted in danger zone or not) + */ + PCD_FreeUserBuffer(hpcd->Instance, ep->num, ep->is_in); + + if (PCD_OUT_SW(wEPVal)) + { + pCount = &ep->pending1; + } + else + { + pCount = &ep->pending0; + } + + do + { + /* + * ep->pendingX can be changed in some cases in the IRQ handler. + * under these cases, new value must be used, clearing must be skipped. + */ + tmpVal = __LDREXH(pCount); + } + while (tmpVal == PCD_PENDED_PROCESSED && __STREXH(0, pCount)); + /* + * EXIT DANGER ZONE + */ + + wEPVal = PCD_GET_ENDPOINT(hpcd->Instance, ep->num); + count = (wEPVal & USB_EP_DTOG_TX) ? ep->pending1 : ep->pending0; + } + if (ep->doublebuffer == 0 && ep->xfer_buff != 0 && ep->xfer_len != 0) + { + PCD_SET_EP_RX_STATUS(hpcd->Instance, ep->num, USB_EP_RX_VALID); + } + return HAL_OK; +} + #endif /* USB */ /** diff --git a/system/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_ll_usb.c b/system/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_ll_usb.c index 1ee33c137d..d5019caf33 100644 --- a/system/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_ll_usb.c +++ b/system/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_ll_usb.c @@ -1725,54 +1725,51 @@ HAL_StatusTypeDef USB_ActivateEndpoint(USB_TypeDef *USBx, USB_EPTypeDef *ep) if (ep->doublebuffer == 0) { - if (ep->is_in) + if (ep->is_in == 1) { - /*Set the endpoint Transmit buffer address */ + /* Set the endpoint Transmit buffer address */ PCD_SET_EP_TX_ADDRESS(USBx, ep->num, ep->pmaadress); PCD_CLEAR_TX_DTOG(USBx, ep->num); - /* Configure NAK status for the Endpoint*/ - PCD_SET_EP_TX_STATUS(USBx, ep->num, USB_EP_TX_NAK); + /* Configure NAK status for the Endpoint */ + PCD_SET_EP_TX_STATUS(USBx, ep->num, USB_EP_TX_NAK); } else { - /*Set the endpoint Receive buffer address */ + /* Set the endpoint Receive buffer address */ PCD_SET_EP_RX_ADDRESS(USBx, ep->num, ep->pmaadress); - /*Set the endpoint Receive buffer counter*/ + /* Set the endpoint Receive buffer counter */ PCD_SET_EP_RX_CNT(USBx, ep->num, ep->maxpacket); PCD_CLEAR_RX_DTOG(USBx, ep->num); - /* Configure VALID status for the Endpoint*/ - PCD_SET_EP_RX_STATUS(USBx, ep->num, USB_EP_RX_VALID); + /* All ep must NAK to every host request before PrepareReceive */ + PCD_SET_EP_RX_STATUS(USBx, ep->num, USB_EP_RX_NAK); } } - /*Double Buffer*/ + /* Double Buffer */ else { - /*Set the endpoint as double buffered*/ + /* Set the endpoint as double buffered */ PCD_SET_EP_DBUF(USBx, ep->num); - /*Set buffer address for double buffered mode*/ + /* Set buffer address for double buffered mode */ PCD_SET_EP_DBUF_ADDR(USBx, ep->num,ep->pmaaddr0, ep->pmaaddr1); - if (ep->is_in==0) + if (ep->is_in == 1) { - /* Clear the data toggle bits for the endpoint IN/OUT*/ + /* Clear the data toggle bits for the endpoint IN/OUT */ PCD_CLEAR_RX_DTOG(USBx, ep->num); PCD_CLEAR_TX_DTOG(USBx, ep->num); - - /* Reset value of the data toggle bits for the endpoint out*/ - PCD_TX_DTOG(USBx, ep->num); - - PCD_SET_EP_RX_STATUS(USBx, ep->num, USB_EP_RX_VALID); - PCD_SET_EP_TX_STATUS(USBx, ep->num, USB_EP_TX_DIS); + PCD_SET_EP_TX_STATUS(USBx, ep->num, USB_EP_TX_VALID); + PCD_SET_EP_RX_STATUS(USBx, ep->num, USB_EP_RX_DIS); } else { - /* Clear the data toggle bits for the endpoint IN/OUT*/ + PCD_SET_EP_DBUF_CNT(USBx, ep->num, ep->is_in, ep->maxpacket); + /* Clear the data toggle bits for the endpoint IN/OUT */ PCD_CLEAR_RX_DTOG(USBx, ep->num); PCD_CLEAR_TX_DTOG(USBx, ep->num); - PCD_RX_DTOG(USBx, ep->num); - /* Configure DISABLE status for the Endpoint*/ + /* All ep must NAK to every host request before PrepareReceive */ + /* Reset value of the data toggle bits for the endpoint out */ + PCD_SET_EP_RX_STATUS(USBx, ep->num, USB_EP_RX_VALID); PCD_SET_EP_TX_STATUS(USBx, ep->num, USB_EP_TX_DIS); - PCD_SET_EP_RX_STATUS(USBx, ep->num, USB_EP_RX_DIS); } } @@ -1789,11 +1786,11 @@ HAL_StatusTypeDef USB_DeactivateEndpoint(USB_TypeDef *USBx, USB_EPTypeDef *ep) { if (ep->doublebuffer == 0) { - if (ep->is_in) + if (ep->is_in == 1) { PCD_CLEAR_TX_DTOG(USBx, ep->num); /* Configure DISABLE status for the Endpoint*/ - PCD_SET_EP_TX_STATUS(USBx, ep->num, USB_EP_TX_DIS); + PCD_SET_EP_TX_STATUS(USBx, ep->num, USB_EP_TX_DIS); } else { @@ -1805,27 +1802,25 @@ HAL_StatusTypeDef USB_DeactivateEndpoint(USB_TypeDef *USBx, USB_EPTypeDef *ep) /*Double Buffer*/ else { - if (ep->is_in==0) + if (ep->is_in == 1) { /* Clear the data toggle bits for the endpoint IN/OUT*/ PCD_CLEAR_RX_DTOG(USBx, ep->num); PCD_CLEAR_TX_DTOG(USBx, ep->num); - - /* Reset value of the data toggle bits for the endpoint out*/ - PCD_TX_DTOG(USBx, ep->num); - - PCD_SET_EP_RX_STATUS(USBx, ep->num, USB_EP_RX_DIS); + PCD_RX_DTOG(USBx, ep->num); + /* Configure DISABLE status for the Endpoint*/ PCD_SET_EP_TX_STATUS(USBx, ep->num, USB_EP_TX_DIS); + PCD_SET_EP_RX_STATUS(USBx, ep->num, USB_EP_RX_DIS); } else { /* Clear the data toggle bits for the endpoint IN/OUT*/ PCD_CLEAR_RX_DTOG(USBx, ep->num); PCD_CLEAR_TX_DTOG(USBx, ep->num); - PCD_RX_DTOG(USBx, ep->num); - /* Configure DISABLE status for the Endpoint*/ - PCD_SET_EP_TX_STATUS(USBx, ep->num, USB_EP_TX_DIS); + /* Reset value of the data toggle bits for the endpoint out*/ + PCD_TX_DTOG(USBx, ep->num); PCD_SET_EP_RX_STATUS(USBx, ep->num, USB_EP_RX_DIS); + PCD_SET_EP_TX_STATUS(USBx, ep->num, USB_EP_TX_DIS); } } @@ -1840,13 +1835,13 @@ HAL_StatusTypeDef USB_DeactivateEndpoint(USB_TypeDef *USBx, USB_EPTypeDef *ep) */ HAL_StatusTypeDef USB_EPStartXfer(USB_TypeDef *USBx , USB_EPTypeDef *ep) { - uint16_t pmabuffer = 0; - uint32_t len = ep->xfer_len; + uint16_t pmabuffer; + uint32_t len; /* IN endpoint */ if (ep->is_in == 1) { - /*Multi packet transfer*/ + /* Multi packet transfer */ if (ep->xfer_len > ep->maxpacket) { len=ep->maxpacket; @@ -1861,8 +1856,8 @@ HAL_StatusTypeDef USB_EPStartXfer(USB_TypeDef *USBx , USB_EPTypeDef *ep) /* configure and validate Tx endpoint */ if (ep->doublebuffer == 0) { - USB_WritePMA(USBx, ep->xfer_buff, ep->pmaadress, len); PCD_SET_EP_TX_CNT(USBx, ep->num, len); + pmabuffer = ep->pmaadress; } else { @@ -1879,41 +1874,24 @@ HAL_StatusTypeDef USB_EPStartXfer(USB_TypeDef *USBx , USB_EPTypeDef *ep) PCD_SET_EP_DBUF0_CNT(USBx, ep->num, ep->is_in, len); pmabuffer = ep->pmaaddr0; } - USB_WritePMA(USBx, ep->xfer_buff, pmabuffer, len); - PCD_FreeUserBuffer(USBx, ep->num, ep->is_in); } - - PCD_SET_EP_TX_STATUS(USBx, ep->num, USB_EP_TX_VALID); - } - else /* OUT endpoint */ - { - /* Multi packet transfer*/ - if (ep->xfer_len > ep->maxpacket) - { - len=ep->maxpacket; - ep->xfer_len-=len; - } - else - { - len=ep->xfer_len; - ep->xfer_len =0; - } - - /* configure and validate Rx endpoint */ - if (ep->doublebuffer == 0) + + USB_WritePMA(USBx, ep->xfer_buff, pmabuffer, (uint16_t) len); + + if (ep->doublebuffer == 0) { - /*Set RX buffer count*/ - PCD_SET_EP_RX_CNT(USBx, ep->num, len); + PCD_SET_EP_TX_STATUS(USBx, ep->num, USB_EP_TX_VALID); } else { - /*Set the Double buffer counter*/ - PCD_SET_EP_DBUF_CNT(USBx, ep->num, ep->is_in, len); + PCD_FreeUserBuffer(USBx, ep->num, ep->is_in); } - + } + else + { PCD_SET_EP_RX_STATUS(USBx, ep->num, USB_EP_RX_VALID); } - + return HAL_OK; } diff --git a/system/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc/usbd_cdc.h b/system/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc/usbd_cdc.h index 059451722c..90b0edf39b 100644 --- a/system/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc/usbd_cdc.h +++ b/system/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc/usbd_cdc.h @@ -154,6 +154,7 @@ uint8_t USBD_CDC_SetRxBuffer(USBD_HandleTypeDef *pdev, uint8_t *pbuff); uint8_t USBD_CDC_ReceivePacket(USBD_HandleTypeDef *pdev); +uint8_t USBD_CDC_ClearBuffer(USBD_HandleTypeDef *pdev); uint8_t USBD_CDC_TransmitPacket(USBD_HandleTypeDef *pdev); /** diff --git a/system/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c b/system/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c index 882fc30873..402cc95472 100644 --- a/system/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c +++ b/system/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c @@ -877,6 +877,25 @@ uint8_t USBD_CDC_ReceivePacket(USBD_HandleTypeDef *pdev) return USBD_FAIL; } } + +uint8_t USBD_CDC_ClearBuffer(USBD_HandleTypeDef *pdev) +{ + USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef *) pdev->pClassData; + + /* Suspend or Resume USB Out process */ + if (pdev->pClassData != NULL) { + if (pdev->dev_speed == USBD_SPEED_HIGH) { + /* Prepare Out endpoint to receive next packet */ + USBD_LL_PrepareReceive(pdev, CDC_OUT_EP, 0, 0); + } else { + /* Prepare Out endpoint to receive next packet */ + USBD_LL_PrepareReceive(pdev, CDC_OUT_EP, 0, 0); + } + return USBD_OK; + } else { + return USBD_FAIL; + } +} /** * @} */ diff --git a/system/Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_def.h b/system/Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_def.h index 34913a51d9..371cda5767 100644 --- a/system/Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_def.h +++ b/system/Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_def.h @@ -223,9 +223,6 @@ typedef struct { typedef struct { uint32_t status; uint32_t is_used; - uint32_t total_length; - uint32_t rem_length; - uint32_t maxpacket; } USBD_EndpointTypeDef; /* USB Device handle structure */ @@ -239,10 +236,11 @@ typedef struct _USBD_HandleTypeDef { USBD_EndpointTypeDef ep_out[15]; uint32_t ep0_state; uint32_t ep0_data_len; + uint32_t ep0_rem_len; + uint32_t ep0_total_len; uint8_t dev_state; uint8_t dev_old_state; uint8_t dev_address; - uint8_t dev_connection_status; uint8_t dev_test_mode; uint32_t dev_remote_wakeup; diff --git a/system/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_core.c b/system/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_core.c index 95a64d21e8..8cf3feff84 100644 --- a/system/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_core.c +++ b/system/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_core.c @@ -289,18 +289,14 @@ USBD_StatusTypeDef USBD_LL_SetupStage(USBD_HandleTypeDef *pdev, uint8_t *psetup) USBD_StatusTypeDef USBD_LL_DataOutStage(USBD_HandleTypeDef *pdev, uint8_t epnum, uint8_t *pdata) { - USBD_EndpointTypeDef *pep; - if (epnum == 0U) { - pep = &pdev->ep_out[0]; - if (pdev->ep0_state == USBD_EP0_DATA_OUT) { - if (pep->rem_length > pep->maxpacket) { - pep->rem_length -= pep->maxpacket; + if (pdev->ep0_rem_len > USB_MAX_EP0_SIZE) { + pdev->ep0_rem_len -= USB_MAX_EP0_SIZE; USBD_CtlContinueRx(pdev, pdata, - (uint16_t)MIN(pep->rem_length, pep->maxpacket)); + (uint16_t)MIN(pdev->ep0_rem_len, USB_MAX_EP0_SIZE)); } else { if ((pdev->pClass->EP0_RxReady != NULL) && (pdev->dev_state == USBD_STATE_CONFIGURED)) { @@ -338,24 +334,20 @@ USBD_StatusTypeDef USBD_LL_DataOutStage(USBD_HandleTypeDef *pdev, USBD_StatusTypeDef USBD_LL_DataInStage(USBD_HandleTypeDef *pdev, uint8_t epnum, uint8_t *pdata) { - USBD_EndpointTypeDef *pep; - if (epnum == 0U) { - pep = &pdev->ep_in[0]; - if (pdev->ep0_state == USBD_EP0_DATA_IN) { - if (pep->rem_length > pep->maxpacket) { - pep->rem_length -= pep->maxpacket; + if (pdev->ep0_rem_len > USB_MAX_EP0_SIZE) { + pdev->ep0_rem_len -= USB_MAX_EP0_SIZE; - USBD_CtlContinueSendData(pdev, pdata, (uint16_t)pep->rem_length); + USBD_CtlContinueSendData(pdev, pdata, (uint16_t)pdev->ep0_rem_len); /* Prepare endpoint for premature end of transfer */ USBD_LL_PrepareReceive(pdev, 0U, NULL, 0U); } else { /* last packet is MPS multiple, so send ZLP packet */ - if ((pep->total_length % pep->maxpacket == 0U) && - (pep->total_length >= pep->maxpacket) && - (pep->total_length < pdev->ep0_data_len)) { + if ((pdev->ep0_total_len % USB_MAX_EP0_SIZE == 0U) && + (pdev->ep0_total_len >= USB_MAX_EP0_SIZE) && + (pdev->ep0_total_len < pdev->ep0_data_len)) { USBD_CtlContinueSendData(pdev, NULL, 0U); pdev->ep0_data_len = 0U; @@ -410,13 +402,10 @@ USBD_StatusTypeDef USBD_LL_Reset(USBD_HandleTypeDef *pdev) USBD_LL_OpenEP(pdev, 0x00U, USBD_EP_TYPE_CTRL, USB_MAX_EP0_SIZE); pdev->ep_out[0x00U & 0xFU].is_used = 1U; - pdev->ep_out[0].maxpacket = USB_MAX_EP0_SIZE; - /* Open EP0 IN */ USBD_LL_OpenEP(pdev, 0x80U, USBD_EP_TYPE_CTRL, USB_MAX_EP0_SIZE); pdev->ep_in[0x80U & 0xFU].is_used = 1U; - pdev->ep_in[0].maxpacket = USB_MAX_EP0_SIZE; /* Upon Reset call user call back */ pdev->dev_state = USBD_STATE_DEFAULT; pdev->ep0_state = USBD_EP0_IDLE; diff --git a/system/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ioreq.c b/system/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ioreq.c index 1c58dc3f04..5c7f5f62a2 100644 --- a/system/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ioreq.c +++ b/system/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ioreq.c @@ -89,8 +89,8 @@ USBD_StatusTypeDef USBD_CtlSendData(USBD_HandleTypeDef *pdev, uint8_t *pbuf, { /* Set EP0 State */ pdev->ep0_state = USBD_EP0_DATA_IN; - pdev->ep_in[0].total_length = len; - pdev->ep_in[0].rem_length = len; + pdev->ep0_total_len = len; + pdev->ep0_rem_len = len; /* Start the transfer */ USBD_LL_Transmit(pdev, 0x00U, pbuf, len); @@ -128,8 +128,8 @@ USBD_StatusTypeDef USBD_CtlPrepareRx(USBD_HandleTypeDef *pdev, uint8_t *pbuf, { /* Set EP0 State */ pdev->ep0_state = USBD_EP0_DATA_OUT; - pdev->ep_out[0].total_length = len; - pdev->ep_out[0].rem_length = len; + pdev->ep0_total_len = len; + pdev->ep0_rem_len = len; /* Start the transfer */ USBD_LL_PrepareReceive(pdev, 0U, pbuf, len);