From 3672be06078e6c7bc7f34afbf19ba0d6184635c4 Mon Sep 17 00:00:00 2001 From: AndrewCapon Date: Fri, 15 Dec 2023 11:58:35 +0000 Subject: [PATCH 1/3] Initial version --- src/USBHost/USBHostConf.h | 3 +- src/targets/TARGET_STM/USBEndpoint_STM.cpp | 22 ++++- src/targets/TARGET_STM/USBHALHost_STM.cpp | 110 ++++++++++++++++++++- 3 files changed, 130 insertions(+), 5 deletions(-) diff --git a/src/USBHost/USBHostConf.h b/src/USBHost/USBHostConf.h index 17c830d..1b4316b 100644 --- a/src/USBHost/USBHostConf.h +++ b/src/USBHost/USBHostConf.h @@ -17,7 +17,8 @@ #ifndef USBHOST_CONF_H #define USBHOST_CONF_H -#define ARC_USB_FULL_SIZE (1) +#define ARC_USB_FULL_SIZE (0) +#define ARC_FS_OVER_HS (1) #include "mbed_config.h" #include "Callback.h" diff --git a/src/targets/TARGET_STM/USBEndpoint_STM.cpp b/src/targets/TARGET_STM/USBEndpoint_STM.cpp index f427e44..4248cb4 100644 --- a/src/targets/TARGET_STM/USBEndpoint_STM.cpp +++ b/src/targets/TARGET_STM/USBEndpoint_STM.cpp @@ -178,10 +178,28 @@ USB_TYPE USBEndpoint::queueTransfer() } ep_queue.get(0); MBED_ASSERT(*addr == 0); -#if ARC_USB_FULL_SIZE + +#if ARC_FS_OVER_HS +// +// In the underlying HAL code there are the following issues when running FS using the HS interface: +// This effects the GIGA as it has no external PHY which is required in order to run at HS. +// +// 1. Transmitting length larger then packetsize can cause future issues reading, the NAK nightmare. +// 2. Receiving multiple seperate packets can lead to lost data and the need to retry. +// +// So for transmitting we split the data into sizes of <= packet size, we initially set of a single transfer here +// and HAL_HCD_HC_NotifyURBChange_Callback() will then handle subsequent transfers if needed. +// +// For receiving we receive all the data. +// + if(dir == OUT) + transfer_len = td_current->size <= max_size ? td_current->size : max_size; + else + transfer_len = td_current->size; +#elif ARC_USB_FULL_SIZE transfer_len = td_current->size; #else - transfer_len = td_current->size <= max_size ? td_current->size : max_size; + transfer_len = td_current->size <= max_size ? td_current->size : max_size; #endif buf_start = (uint8_t *)td_current->currBufPtr; diff --git a/src/targets/TARGET_STM/USBHALHost_STM.cpp b/src/targets/TARGET_STM/USBHALHost_STM.cpp index 2d13f9f..56eca9d 100644 --- a/src/targets/TARGET_STM/USBHALHost_STM.cpp +++ b/src/targets/TARGET_STM/USBHALHost_STM.cpp @@ -91,7 +91,113 @@ uint32_t HAL_HCD_HC_GetType(HCD_HandleTypeDef *hhcd, uint8_t chnum) // - URB_NOTREADY = a NAK, NYET, or not more than a couple of repeats of some of the errors that will // become URB_ERROR if they repeat several times in a row // -#if ARC_USB_FULL_SIZE +#if ARC_FS_OVER_HS +// +// In the underlying HAL code there are the following issues when running FS using the HS interface: +// This effects the GIGA as it has no external PHY which is required in order to run at HS. +// +// 1. Transmitting length larger then packetsize can cause future issues reading, the NAK nightmare. +// 2. Receiving multiple seperate packets can lead to lost data and the need to retry. +// +// So for transmitting we split the data into sizes of <= packet size and individually transfer them, only calling pPriv->transferCompleted() when all data is sent. +// For receiving we receive all the data and call pPriv->transferCompleted(). +// +// If we get NAKS on the control OUT EPs we make sure that USB_OTG_HCCHAR_CHDIS ans USB_OTG_HCCHAR_CHENA are reset to the correct values. +// +void HAL_HCD_HC_NotifyURBChange_Callback(HCD_HandleTypeDef *pHcd, uint8_t uChannel, HCD_URBStateTypeDef urbState) +{ + USBHALHost_Private_t *pPriv = (USBHALHost_Private_t *)(pHcd->pData); + + HCTD *pTransferDescriptor = (HCTD *)pPriv->addr[uChannel]; + + + if (pTransferDescriptor) + { + uint32_t endpointType = pHcd->hc[uChannel].ep_type; + + if ((endpointType == EP_TYPE_INTR)) + { + // Disable the channel interrupt and retransfer below + // TOD: really this retransfer should be queued up and transfered on the SOF interupt based on interval from descriptor. + pTransferDescriptor->state = USB_TYPE_IDLE ; + HAL_HCD_DisableInt(pHcd, uChannel); + } + else if ((endpointType == EP_TYPE_BULK) || (endpointType == EP_TYPE_CTRL)) + { + uint8_t uEpIsInput = pHcd->hc[uChannel].ep_is_in; + + switch(urbState) + { + case URB_NOTREADY: + { + if(!uEpIsInput) + { + // make sure that USB_OTG_HCCHAR_CHDIS and USB_OTG_HCCHAR_CHENA are reset to the correct values + uint32_t tmpreg; + tmpreg = USBx_HC(uChannel)->HCCHAR; + tmpreg &= ~USB_OTG_HCCHAR_CHDIS; + tmpreg |= USB_OTG_HCCHAR_CHENA; + USBx_HC(uChannel)->HCCHAR = tmpreg; + } + } + break; + + case URB_DONE: + { + // first calculate how much we transferred, HAL metrics aonly work for IN EPs + uint16_t uPacketSize = pHcd->hc[uChannel].max_packet; + uint16_t uTransferredCount; + + if(uEpIsInput) + uTransferredCount = HAL_HCD_HC_GetXferCount(pHcd, uChannel); + else + uTransferredCount = (pTransferDescriptor->size > uPacketSize) ? uPacketSize : pTransferDescriptor->size; + + // update transfer descriptor + pTransferDescriptor->size -= uTransferredCount; + pTransferDescriptor->currBufPtr += uTransferredCount; + + // if we are an OUT EP and there is still more data, send next packet + if(!uEpIsInput && pTransferDescriptor->size ) + { + uint16_t uTransferSize = (pTransferDescriptor->size > uPacketSize) ? uPacketSize : pTransferDescriptor->size; + HAL_HCD_HC_SubmitRequest(pHcd, uChannel, uEpIsInput, endpointType, !pTransferDescriptor->setup, (uint8_t *) pTransferDescriptor->currBufPtr, uTransferSize, 0); + HAL_HCD_EnableInt(pHcd, uChannel); + } + else + { + // this will be handled below for USB_TYPE_IDLE + pTransferDescriptor->state = USB_TYPE_IDLE; + } + } + break; + + case URB_ERROR: + { + // While USB_TYPE_ERROR in the endpoint state is used to activate error recovery, this value is actually never used. + // Going here will lead to a timeout at a higher layer, because of ep_queue.get() timeout, which will activate error + // recovery indirectly. + pTransferDescriptor->state = USB_TYPE_ERROR; + } + break; + + default: + { + pTransferDescriptor->state = USB_TYPE_PROCESSING; + } + break; + } + } + + if (pTransferDescriptor->state == USB_TYPE_IDLE) + { + // Call transferCompleted on correct object + void (USBHALHost::*func)(volatile uint32_t addr) = pPriv->transferCompleted; + (pPriv->inst->*func)(reinterpret_cast(pTransferDescriptor)); + } + } +} +#elif ARC_USB_FULL_SIZE void HAL_HCD_HC_NotifyURBChange_Callback(HCD_HandleTypeDef *pHcd, uint8_t uChannel, HCD_URBStateTypeDef urbState) { USBHALHost_Private_t *pPriv = (USBHALHost_Private_t *)(pHcd->pData); @@ -442,7 +548,7 @@ void USBHALHost::_usbisr(void) void USBHALHost::UsbIrqhandler() { -#if ARC_USB_FULL_SIZE +#if ARC_USB_FULL_SIZE || ARC_FS_OVER_HS // fix from Lix Paulian : https://community.st.com/t5/stm32-mcus-products/stm32f4-stm32f7-usb-host-core-interrupt-flood/td-p/436225/page/4 // Change to also stop flooding of channel halt interrupt uint32_t ch_num; From f6d051aad9bc49e38e687fca3bce41f842a9c738 Mon Sep 17 00:00:00 2001 From: AndrewCapon Date: Fri, 15 Dec 2023 16:02:01 +0000 Subject: [PATCH 2/3] Fix interupt EP tranfer len issue --- src/targets/TARGET_STM/USBHALHost_STM.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/targets/TARGET_STM/USBHALHost_STM.cpp b/src/targets/TARGET_STM/USBHALHost_STM.cpp index 56eca9d..0a69ad2 100644 --- a/src/targets/TARGET_STM/USBHALHost_STM.cpp +++ b/src/targets/TARGET_STM/USBHALHost_STM.cpp @@ -121,6 +121,7 @@ void HAL_HCD_HC_NotifyURBChange_Callback(HCD_HandleTypeDef *pHcd, uint8_t uChann // TOD: really this retransfer should be queued up and transfered on the SOF interupt based on interval from descriptor. pTransferDescriptor->state = USB_TYPE_IDLE ; HAL_HCD_DisableInt(pHcd, uChannel); + pTransferDescriptor->currBufPtr += HAL_HCD_HC_GetXferCount(pHcd, uChannel); } else if ((endpointType == EP_TYPE_BULK) || (endpointType == EP_TYPE_CTRL)) { From ac8c565b4bbbc132636a0a66827f743936babc1e Mon Sep 17 00:00:00 2001 From: AndrewCapon Date: Mon, 18 Dec 2023 06:21:44 +0000 Subject: [PATCH 3/3] Add ARC_NO_RESUBMITREQUEST, if 0 will resbmit transfers on NAK --- src/USBHost/USBHostConf.h | 1 + src/targets/TARGET_STM/USBHALHost_STM.cpp | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/src/USBHost/USBHostConf.h b/src/USBHost/USBHostConf.h index 1b4316b..9c4af2c 100644 --- a/src/USBHost/USBHostConf.h +++ b/src/USBHost/USBHostConf.h @@ -19,6 +19,7 @@ #define ARC_USB_FULL_SIZE (0) #define ARC_FS_OVER_HS (1) +#define ARC_NO_RESUBMITREQUEST (0) #include "mbed_config.h" #include "Callback.h" diff --git a/src/targets/TARGET_STM/USBHALHost_STM.cpp b/src/targets/TARGET_STM/USBHALHost_STM.cpp index 0a69ad2..f69dec5 100644 --- a/src/targets/TARGET_STM/USBHALHost_STM.cpp +++ b/src/targets/TARGET_STM/USBHALHost_STM.cpp @@ -133,12 +133,20 @@ void HAL_HCD_HC_NotifyURBChange_Callback(HCD_HandleTypeDef *pHcd, uint8_t uChann { if(!uEpIsInput) { +#if ARC_NO_RESUBMITREQUEST // make sure that USB_OTG_HCCHAR_CHDIS and USB_OTG_HCCHAR_CHENA are reset to the correct values uint32_t tmpreg; tmpreg = USBx_HC(uChannel)->HCCHAR; tmpreg &= ~USB_OTG_HCCHAR_CHDIS; tmpreg |= USB_OTG_HCCHAR_CHENA; USBx_HC(uChannel)->HCCHAR = tmpreg; +#else + // Submit the same request again, because the device wasn't ready to accept the last one + uint16_t uPacketSize = pHcd->hc[uChannel].max_packet; + uint16_t uTransferSize = (pTransferDescriptor->size > uPacketSize) ? uPacketSize : pTransferDescriptor->size; + HAL_HCD_HC_SubmitRequest(pHcd, uChannel, uEpIsInput, endpointType, !pTransferDescriptor->setup, (uint8_t *) pTransferDescriptor->currBufPtr, uTransferSize, 0); + HAL_HCD_EnableInt(pHcd, uChannel); +#endif } } break;