diff --git a/targets/TARGET_STM/TARGET_STM32F4/device/stm32f4xx_hal_pcd.c b/targets/TARGET_STM/TARGET_STM32F4/device/stm32f4xx_hal_pcd.c index a6ed3193fe..7e14649c3c 100644 --- a/targets/TARGET_STM/TARGET_STM32F4/device/stm32f4xx_hal_pcd.c +++ b/targets/TARGET_STM/TARGET_STM32F4/device/stm32f4xx_hal_pcd.c @@ -106,6 +106,7 @@ * @{ */ static HAL_StatusTypeDef PCD_WriteEmptyTxFifo(PCD_HandleTypeDef *hpcd, uint32_t epnum); +static HAL_StatusTypeDef PCD_ReadRxFifo(PCD_HandleTypeDef *hpcd); // MBED PATCH /** * @} */ @@ -394,6 +395,13 @@ void HAL_PCD_IRQHandler(PCD_HandleTypeDef *hpcd) } } + // MBED PATCH + if (( epint & USB_OTG_DOEPINT_EPDISD) == USB_OTG_DOEPINT_EPDISD) + { + CLEAR_OUT_EP_INTR(epnum, USB_OTG_DOEPINT_EPDISD); + } + // MBED PATCH + if(( epint & USB_OTG_DOEPINT_STUP) == USB_OTG_DOEPINT_STUP) { /* Inform the upper layer that a setup packet is available */ @@ -667,27 +675,7 @@ void HAL_PCD_IRQHandler(PCD_HandleTypeDef *hpcd) /* Handle RxQLevel Interrupt */ if(__HAL_PCD_GET_FLAG(hpcd, USB_OTG_GINTSTS_RXFLVL)) { - USB_MASK_INTERRUPT(hpcd->Instance, USB_OTG_GINTSTS_RXFLVL); - - temp = USBx->GRXSTSP; - - ep = &hpcd->OUT_ep[temp & USB_OTG_GRXSTSP_EPNUM]; - - if(((temp & USB_OTG_GRXSTSP_PKTSTS) >> 17U) == STS_DATA_UPDT) - { - if((temp & USB_OTG_GRXSTSP_BCNT) != 0U) - { - USB_ReadPacket(USBx, ep->xfer_buff, (temp & USB_OTG_GRXSTSP_BCNT) >> 4U); - ep->xfer_buff += (temp & USB_OTG_GRXSTSP_BCNT) >> 4U; - ep->xfer_count += (temp & USB_OTG_GRXSTSP_BCNT) >> 4U; - } - } - else if (((temp & USB_OTG_GRXSTSP_PKTSTS) >> 17U) == STS_SETUP_UPDT) - { - USB_ReadPacket(USBx, (uint8_t *)hpcd->Setup, 8U); - ep->xfer_count += (temp & USB_OTG_GRXSTSP_BCNT) >> 4U; - } - USB_UNMASK_INTERRUPT(hpcd->Instance, USB_OTG_GINTSTS_RXFLVL); + PCD_ReadRxFifo(hpcd); // MBED PATCH } /* Handle SOF Interrupt */ @@ -1131,6 +1119,86 @@ HAL_StatusTypeDef HAL_PCD_EP_Transmit(PCD_HandleTypeDef *hpcd, uint8_t ep_addr, return HAL_OK; } +// MBED PATCH +/** + * @brief Abort a transaction. + * @param hpcd: PCD handle + * @param ep_addr: endpoint address + * @retval HAL status + */ +HAL_StatusTypeDef HAL_PCD_EP_Abort(PCD_HandleTypeDef *hpcd, uint8_t ep_addr) +{ + USB_OTG_GlobalTypeDef *USBx = hpcd->Instance; + HAL_StatusTypeDef ret = HAL_OK; + USB_OTG_EPTypeDef *ep; + + if ((0x80 & ep_addr) == 0x80) + { + ep = &hpcd->IN_ep[ep_addr & 0x7F]; + } + else + { + ep = &hpcd->OUT_ep[ep_addr]; + } + + __HAL_LOCK(&hpcd->EPLock[ep_addr & 0x7F]); + + ep->num = ep_addr & 0x7F; + ep->is_in = ((ep_addr & 0x80) == 0x80); + + USB_EPSetNak(hpcd->Instance, ep); + + if ((0x80 & ep_addr) == 0x80) + { + ret = USB_EPStopXfer(hpcd->Instance , ep); + if (ret == HAL_OK) + { + ret = USB_FlushTxFifo(hpcd->Instance, ep_addr & 0x7F); + } + } + else + { + /* Set global NAK */ + USBx_DEVICE->DCTL |= USB_OTG_DCTL_SGONAK; + + /* Read all entries from the fifo so global NAK takes effect */ + while (__HAL_PCD_GET_FLAG(hpcd, USB_OTG_GINTSTS_RXFLVL)) + { + PCD_ReadRxFifo(hpcd); + } + + /* Stop the transfer */ + ret = USB_EPStopXfer(hpcd->Instance , ep); + if (ret == HAL_BUSY) + { + /* If USB_EPStopXfer returns HAL_BUSY then a setup packet + * arrived after the rx fifo was processed but before USB_EPStopXfer + * was called. Process the rx fifo one more time to read the + * setup packet. + * + * Note - after the setup packet has been received no further + * packets will be received over USB. This is because the next + * phase (data or status) of the control transfer started by + * the setup packet will be naked until global nak is cleared. + */ + while (__HAL_PCD_GET_FLAG(hpcd, USB_OTG_GINTSTS_RXFLVL)) + { + PCD_ReadRxFifo(hpcd); + } + + ret = USB_EPStopXfer(hpcd->Instance , ep); + } + + /* Clear global nak */ + USBx_DEVICE->DCTL |= USB_OTG_DCTL_CGONAK; + } + + __HAL_UNLOCK(&hpcd->EPLock[ep_addr & 0x7F]); + + return ret; +} +// MBED PATCH + /** * @brief Set a STALL condition over an endpoint. * @param hpcd PCD handle @@ -1356,6 +1424,44 @@ static HAL_StatusTypeDef PCD_WriteEmptyTxFifo(PCD_HandleTypeDef *hpcd, uint32_t return HAL_OK; } +// MBED PATCH +/** + * @brief Process the next RX fifo entry + * @param hpcd: PCD handle + * @retval HAL status + */ +static HAL_StatusTypeDef PCD_ReadRxFifo(PCD_HandleTypeDef *hpcd) +{ + USB_OTG_GlobalTypeDef *USBx = hpcd->Instance; + USB_OTG_EPTypeDef *ep; + uint32_t temp = 0; + + USB_MASK_INTERRUPT(hpcd->Instance, USB_OTG_GINTSTS_RXFLVL); + + temp = USBx->GRXSTSP; + + ep = &hpcd->OUT_ep[temp & USB_OTG_GRXSTSP_EPNUM]; + + if(((temp & USB_OTG_GRXSTSP_PKTSTS) >> 17U) == STS_DATA_UPDT) + { + if((temp & USB_OTG_GRXSTSP_BCNT) != 0U) + { + USB_ReadPacket(USBx, ep->xfer_buff, (temp & USB_OTG_GRXSTSP_BCNT) >> 4U); + ep->xfer_buff += (temp & USB_OTG_GRXSTSP_BCNT) >> 4U; + ep->xfer_count += (temp & USB_OTG_GRXSTSP_BCNT) >> 4U; + } + } + else if (((temp & USB_OTG_GRXSTSP_PKTSTS) >> 17U) == STS_SETUP_UPDT) + { + USB_ReadPacket(USBx, (uint8_t *)hpcd->Setup, 8U); + ep->xfer_count += (temp & USB_OTG_GRXSTSP_BCNT) >> 4U; + } + USB_UNMASK_INTERRUPT(hpcd->Instance, USB_OTG_GINTSTS_RXFLVL); + + return HAL_OK; +} +// MBED PATCH + /** * @} */ diff --git a/targets/TARGET_STM/TARGET_STM32F4/device/stm32f4xx_hal_pcd.h b/targets/TARGET_STM/TARGET_STM32F4/device/stm32f4xx_hal_pcd.h index d5b8e1605b..eeeaccf93d 100644 --- a/targets/TARGET_STM/TARGET_STM32F4/device/stm32f4xx_hal_pcd.h +++ b/targets/TARGET_STM/TARGET_STM32F4/device/stm32f4xx_hal_pcd.h @@ -300,6 +300,7 @@ HAL_StatusTypeDef HAL_PCD_EP_Open(PCD_HandleTypeDef *hpcd, uint8_t ep_addr, uint 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); HAL_StatusTypeDef HAL_PCD_EP_Transmit(PCD_HandleTypeDef *hpcd, uint8_t ep_addr, uint8_t *pBuf, uint32_t len); +HAL_StatusTypeDef HAL_PCD_EP_Abort(PCD_HandleTypeDef *hpcd, uint8_t ep_addr); // MBED PATCH uint16_t HAL_PCD_EP_GetRxCount(PCD_HandleTypeDef *hpcd, uint8_t ep_addr); HAL_StatusTypeDef HAL_PCD_EP_SetStall(PCD_HandleTypeDef *hpcd, uint8_t ep_addr); HAL_StatusTypeDef HAL_PCD_EP_ClrStall(PCD_HandleTypeDef *hpcd, uint8_t ep_addr); diff --git a/targets/TARGET_STM/TARGET_STM32F4/device/stm32f4xx_ll_usb.c b/targets/TARGET_STM/TARGET_STM32F4/device/stm32f4xx_ll_usb.c index c114307b94..b610d02553 100644 --- a/targets/TARGET_STM/TARGET_STM32F4/device/stm32f4xx_ll_usb.c +++ b/targets/TARGET_STM/TARGET_STM32F4/device/stm32f4xx_ll_usb.c @@ -450,7 +450,8 @@ HAL_StatusTypeDef USB_ActivateEndpoint(USB_OTG_GlobalTypeDef *USBx, USB_OTG_EPTy if (((USBx_INEP(ep->num)->DIEPCTL) & USB_OTG_DIEPCTL_USBAEP) == 0U) { - USBx_INEP(ep->num)->DIEPCTL |= ((ep->maxpacket & USB_OTG_DIEPCTL_MPSIZ ) | (ep->type << 18U) |\ + // MBED PATCH + USBx_INEP(ep->num)->DIEPCTL = ((ep->maxpacket & USB_OTG_DIEPCTL_MPSIZ ) | (ep->type << 18U) |\ ((ep->num) << 22U) | (USB_OTG_DIEPCTL_SD0PID_SEVNFRM) | (USB_OTG_DIEPCTL_USBAEP)); } } @@ -460,7 +461,8 @@ HAL_StatusTypeDef USB_ActivateEndpoint(USB_OTG_GlobalTypeDef *USBx, USB_OTG_EPTy if (((USBx_OUTEP(ep->num)->DOEPCTL) & USB_OTG_DOEPCTL_USBAEP) == 0U) { - USBx_OUTEP(ep->num)->DOEPCTL |= ((ep->maxpacket & USB_OTG_DOEPCTL_MPSIZ ) | (ep->type << 18U) |\ + // MBED PATCH + USBx_OUTEP(ep->num)->DOEPCTL = ((ep->maxpacket & USB_OTG_DOEPCTL_MPSIZ ) | (ep->type << 18U) |\ (USB_OTG_DIEPCTL_SD0PID_SEVNFRM)| (USB_OTG_DOEPCTL_USBAEP)); } } @@ -481,7 +483,8 @@ HAL_StatusTypeDef USB_ActivateDedicatedEndpoint(USB_OTG_GlobalTypeDef *USBx, USB { if (((USBx_INEP(ep->num)->DIEPCTL) & USB_OTG_DIEPCTL_USBAEP) == 0U) { - USBx_INEP(ep->num)->DIEPCTL |= ((ep->maxpacket & USB_OTG_DIEPCTL_MPSIZ ) | (ep->type << 18U) |\ + // MBED PATCH + USBx_INEP(ep->num)->DIEPCTL = ((ep->maxpacket & USB_OTG_DIEPCTL_MPSIZ ) | (ep->type << 18U) |\ ((ep->num) << 22U) | (USB_OTG_DIEPCTL_SD0PID_SEVNFRM) | (USB_OTG_DIEPCTL_USBAEP)); } @@ -495,7 +498,8 @@ HAL_StatusTypeDef USB_ActivateDedicatedEndpoint(USB_OTG_GlobalTypeDef *USBx, USB { if (((USBx_OUTEP(ep->num)->DOEPCTL) & USB_OTG_DOEPCTL_USBAEP) == 0U) { - USBx_OUTEP(ep->num)->DOEPCTL |= ((ep->maxpacket & USB_OTG_DOEPCTL_MPSIZ ) | (ep->type << 18U) |\ + // MBED PATCH + USBx_OUTEP(ep->num)->DOEPCTL = ((ep->maxpacket & USB_OTG_DOEPCTL_MPSIZ ) | (ep->type << 18U) |\ ((ep->num) << 22U) | (USB_OTG_DOEPCTL_USBAEP)); debug = (uint32_t)(((uint32_t )USBx) + USB_OTG_OUT_ENDPOINT_BASE + (0U)*USB_OTG_EP_REG_SIZE); @@ -865,6 +869,174 @@ HAL_StatusTypeDef USB_EP0StartXfer(USB_OTG_GlobalTypeDef *USBx , USB_OTG_EPTypeD return HAL_OK; } +// MBED PATCH +/** + * @brief USB_EPStoptXfer : stop transfer on this endpoint + * @param USBx : Selected device + * @param ep: pointer to endpoint structure + * @retval HAL status + * @note IN endpoints must have NAK enabled before calling this function + * @note OUT endpoints must have global out NAK enabled before calling this + * function. Furthermore, the RX fifo must be empty or the status + * HAL_BUSY will be returned. + */ +HAL_StatusTypeDef USB_EPStopXfer(USB_OTG_GlobalTypeDef *USBx , USB_OTG_EPTypeDef *ep) +{ + HAL_StatusTypeDef ret = HAL_OK; + uint32_t count = 0U; + uint32_t epint, fifoemptymsk; + + /* IN endpoint */ + if (ep->is_in == 1U) + { + + /* EP enable, IN data in FIFO */ + if (((USBx_INEP(ep->num)->DIEPCTL) & USB_OTG_DIEPCTL_EPENA) == USB_OTG_DIEPCTL_EPENA) + { + /* Disable this endpoint */ + USBx_INEP(ep->num)->DIEPCTL |= USB_OTG_DIEPCTL_EPDIS; + count = 0; + do + { + if (++count > 200000U) + { + return HAL_TIMEOUT; + } + } + while ((USBx_INEP(ep->num)->DIEPCTL & USB_OTG_DIEPCTL_EPENA) == USB_OTG_DIEPCTL_EPENA); + } + + /* Clear transfer complete interrupt */ + epint = USB_ReadDevInEPInterrupt(USBx, ep->num); + if((epint & USB_OTG_DIEPINT_XFRC) == USB_OTG_DIEPINT_XFRC) + { + CLEAR_IN_EP_INTR(ep->num, USB_OTG_DIEPINT_XFRC); + } + + /* Mask fifo empty interrupt */ + fifoemptymsk = 0x1U << ep->num; + atomic_clr_u32(&USBx_DEVICE->DIEPEMPMSK, fifoemptymsk); + } + else /* OUT endpoint */ + { + if (((USBx_OUTEP(ep->num)->DOEPCTL) & USB_OTG_DOEPCTL_EPENA) == USB_OTG_DOEPCTL_EPENA) + { + /* Disable this endpoint */ + USBx_OUTEP(ep->num)->DOEPCTL |= USB_OTG_DOEPCTL_EPDIS; + count = 0; + do + { + if (++count > 200000U) + { + return HAL_TIMEOUT; + } + if ((USBx->GINTSTS & USB_OTG_GINTSTS_RXFLVL) == USB_OTG_GINTSTS_RXFLVL) + { + /* Although not mentioned in the Reference Manual, it appears that the + * rx fifo must be empty for an OUT endpoint to be disabled. Typically + * this will happen when setting the global OUT nak (required by Reference + * Manual) as this requires processing the rx fifo. This is not guaranteed + * though, as a setup packet can arrive even while global OUT nak is set. + * + * During testing this event was observed and prevented endpoint disabling + * from completing until the rx fifo was empty. To address this problem + * return HAL_BUSY if the rx fifo is not empty to give higher level code + * a chance to clear the fifo and retry the operation. + * + */ + return HAL_BUSY; + } + } + while ((USBx_OUTEP(ep->num)->DOEPCTL & USB_OTG_DOEPCTL_EPENA) == USB_OTG_DOEPCTL_EPENA); + } + + /* Clear interrupt */ + epint = USB_ReadDevOutEPInterrupt(USBx, ep->num); + if(( epint & USB_OTG_DOEPINT_XFRC) == USB_OTG_DOEPINT_XFRC) + { + CLEAR_OUT_EP_INTR(ep->num, USB_OTG_DOEPINT_XFRC); + } + } + return ret; +} + +/** + * @brief USB_EPSetNak : stop transfer and nak all tokens on this endpoint + * @param USBx : Selected device + * @param ep: pointer to endpoint structure + * @retval HAL status + */ +HAL_StatusTypeDef USB_EPSetNak(USB_OTG_GlobalTypeDef *USBx , USB_OTG_EPTypeDef *ep) +{ + uint32_t count = 0; + if (ep->is_in == 1U) + { + USBx_INEP(ep->num)->DIEPCTL |= USB_OTG_DIEPCTL_SNAK; + count = 0; + do + { + if (++count > 200000U) + { + return HAL_TIMEOUT; + } + } + while ((USBx_INEP(ep->num)->DIEPCTL & USB_OTG_DIEPCTL_NAKSTS) != USB_OTG_DIEPCTL_NAKSTS); + } + else + { + USBx_OUTEP(ep->num)->DOEPCTL |= USB_OTG_DOEPCTL_SNAK; + count = 0; + do + { + if (++count > 200000U) + { + return HAL_TIMEOUT; + } + } + while ((USBx_OUTEP(ep->num)->DOEPCTL & USB_OTG_DOEPCTL_NAKSTS) != USB_OTG_DOEPCTL_NAKSTS); + } + return HAL_OK; +} + +/** + * @brief USB_EPSetNak : resume transfer and stop naking on this endpoint + * @param USBx : Selected device + * @param ep: pointer to endpoint structure + * @retval HAL status + */ +HAL_StatusTypeDef USB_EPClearNak(USB_OTG_GlobalTypeDef *USBx , USB_OTG_EPTypeDef *ep) +{ + uint32_t count = 0; + if (ep->is_in == 1U) + { + USBx_INEP(ep->num)->DIEPCTL |= USB_OTG_DIEPCTL_CNAK; + count = 0; + do + { + if (++count > 200000U) + { + return HAL_TIMEOUT; + } + } + while ((USBx_INEP(ep->num)->DIEPCTL & USB_OTG_DIEPCTL_NAKSTS) == USB_OTG_DIEPCTL_NAKSTS); + } + else + { + USBx_OUTEP(ep->num)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK; + count = 0; + do + { + if (++count > 200000U) + { + return HAL_TIMEOUT; + } + } + while ((USBx_OUTEP(ep->num)->DOEPCTL & USB_OTG_DOEPCTL_NAKSTS) == USB_OTG_DOEPCTL_NAKSTS); + } + return HAL_OK; +} +// MBED PATCH + /** * @brief USB_WritePacket : Writes a packet into the Tx FIFO associated * with the EP/channel diff --git a/targets/TARGET_STM/TARGET_STM32F4/device/stm32f4xx_ll_usb.h b/targets/TARGET_STM/TARGET_STM32F4/device/stm32f4xx_ll_usb.h index 1048bee537..34de08cc1a 100644 --- a/targets/TARGET_STM/TARGET_STM32F4/device/stm32f4xx_ll_usb.h +++ b/targets/TARGET_STM/TARGET_STM32F4/device/stm32f4xx_ll_usb.h @@ -416,6 +416,9 @@ HAL_StatusTypeDef USB_DeactivateEndpoint(USB_OTG_GlobalTypeDef *USBx, USB_OTG_EP HAL_StatusTypeDef USB_ActivateDedicatedEndpoint(USB_OTG_GlobalTypeDef *USBx, USB_OTG_EPTypeDef *ep); HAL_StatusTypeDef USB_DeactivateDedicatedEndpoint(USB_OTG_GlobalTypeDef *USBx, USB_OTG_EPTypeDef *ep); HAL_StatusTypeDef USB_EPStartXfer(USB_OTG_GlobalTypeDef *USBx , USB_OTG_EPTypeDef *ep, uint8_t dma); +HAL_StatusTypeDef USB_EPStopXfer(USB_OTG_GlobalTypeDef *USBx , USB_OTG_EPTypeDef *ep); // MBED PATCH +HAL_StatusTypeDef USB_EPSetNak(USB_OTG_GlobalTypeDef *USBx , USB_OTG_EPTypeDef *ep); // MBED PATCH +HAL_StatusTypeDef USB_EPClearNak(USB_OTG_GlobalTypeDef *USBx , USB_OTG_EPTypeDef *ep); // MBED PATCH HAL_StatusTypeDef USB_EP0StartXfer(USB_OTG_GlobalTypeDef *USBx , USB_OTG_EPTypeDef *ep, uint8_t dma); HAL_StatusTypeDef USB_WritePacket(USB_OTG_GlobalTypeDef *USBx, uint8_t *src, uint8_t ch_ep_num, uint16_t len, uint8_t dma); void * USB_ReadPacket(USB_OTG_GlobalTypeDef *USBx, uint8_t *dest, uint16_t len);