Skip to content

Fix USB Host issues #42

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Dec 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/USBHost/IUSBEnumerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class IUSBEnumerator
virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) = 0; //Must return true if the interface should be parsed
virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) = 0; //Must return true if the endpoint will be used
virtual void parseConfigEntry(uint8_t type, uint8_t sub_type, uint8_t *data, uint32_t len) {};
virtual void setEnumeratingDeviceIndex(int index) {};
};

#endif /*IUSBENUMERATOR_H_*/
Expand Down
3 changes: 3 additions & 0 deletions src/USBHost/USBHost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,8 @@ void USBHost::usb_process()

if ((i < MAX_DEVICE_CONNECTED) && !too_many_hub) {
deviceInUse[i] = true;
if(device_connected_callback)
device_connected_callback(i);
}

} while(0);
Expand Down Expand Up @@ -960,6 +962,7 @@ USB_TYPE USBHost::enumerate(USBDeviceConnected * dev, IUSBEnumerator* pEnumerato
dev->setPid(data[10] | (data[11] << 8));
USB_DBG("CLASS: %02X \t VID: %04X \t PID: %04X", data[4], data[8] | (data[9] << 8), data[10] | (data[11] << 8));

pEnumerator->setEnumeratingDeviceIndex(index);
pEnumerator->setVidPid( data[8] | (data[9] << 8), data[10] | (data[11] << 8) );

res = getConfigurationDescriptor(dev, data, sizeof(data), &total_conf_descr_length);
Expand Down
11 changes: 11 additions & 0 deletions src/USBHost/USBHost.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,15 @@ class USBHost : public USBHALHost {
}
}


/**
* Callback for connected device index
*/
void setDeviceConnectedCallback(mbed::Callback<void(uint8_t uDeviceIndex)> callback)
{
device_connected_callback = callback;
}

/**
* Instantiate to protect USB thread from accessing shared objects (USBConnectedDevices and Interfaces)
*/
Expand Down Expand Up @@ -287,6 +296,8 @@ class USBHost : public USBHALHost {
// buffer for conf descriptor
uint8_t data[415];

mbed::Callback<void(uint8_t uDeviceIndex)> device_connected_callback = nullptr;

/**
* Add a transfer on the TD linked list associated to an ED
*
Expand Down
2 changes: 2 additions & 0 deletions src/USBHost/USBHostConf.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#ifndef USBHOST_CONF_H
#define USBHOST_CONF_H

#define ARC_USB_FULL_SIZE (1)

#include "mbed_config.h"
#include "Callback.h"
#include "Arduino.h"
Expand Down
2 changes: 1 addition & 1 deletion src/USBHost/dbg.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
#define USB_DEBUG_H

//Debug is disabled by default
#define DEBUG 0 /*INFO,ERR,WARN*/
#define DEBUG 4 /*INFO,ERR,WARN*/
#define DEBUG_TRANSFER 0
#define DEBUG_EP_STATE 0
#define DEBUG_EVENT 0
Expand Down
2 changes: 1 addition & 1 deletion src/USBHostHub/USBHostHub.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ void USBHostHub::disconnect()
if ((hub_intf == -1) &&
(intf_class == HUB_CLASS) &&
(intf_subclass == 0) &&
(intf_protocol == 0)) {
((intf_protocol == 0) || (intf_protocol == 1))) {
hub_intf = intf_nb;
return true;
}
Expand Down
5 changes: 5 additions & 0 deletions src/targets/TARGET_STM/USBEndpoint_STM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,12 @@ USB_TYPE USBEndpoint::queueTransfer()
}
ep_queue.get(0);
MBED_ASSERT(*addr == 0);
#if ARC_USB_FULL_SIZE
transfer_len = td_current->size;
#else
transfer_len = td_current->size <= max_size ? td_current->size : max_size;
#endif

buf_start = (uint8_t *)td_current->currBufPtr;

//Now add this free TD at this end of the queue
Expand Down
142 changes: 140 additions & 2 deletions src/targets/TARGET_STM/USBHALHost_STM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,98 @@ 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
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)
{
constexpr uint32_t uRetryCount = 10;

uint32_t endpointType = pHcd->hc[uChannel].ep_type;

if ((endpointType == EP_TYPE_INTR))
{
// Disable the channel interrupt and retransfer below
pTransferDescriptor->state = USB_TYPE_IDLE ;
HAL_HCD_DisableInt(pHcd, uChannel);
}
else if ((endpointType == EP_TYPE_BULK) || (endpointType == EP_TYPE_CTRL))
{
switch(urbState)
{
case URB_NOTREADY:
{
// If we have transferred any data then disable retries
if(pHcd->hc[uChannel].xfer_count > 0)
pTransferDescriptor->retry = 0xffffffff; // Disable retries
else
{
// if the retry count is 0 then initialize downward counting retry
// otherwise decrement retry count
if(pTransferDescriptor->retry == 0)
pTransferDescriptor->retry = uRetryCount;
else
pTransferDescriptor->retry--;
}

// If our retry count has got down to 0 or we are an Ack then submit request again
if((pTransferDescriptor->retry == 0) || (pTransferDescriptor->size==0))
{
// initialize downward counting retry
pTransferDescriptor->retry = uRetryCount;

// resubmit the request.
HAL_HCD_HC_SubmitRequest(pHcd, uChannel, pHcd->hc[uChannel].ep_is_in, endpointType, !pTransferDescriptor->setup, (uint8_t *) pTransferDescriptor->currBufPtr, pTransferDescriptor->size, 0);
HAL_HCD_EnableInt(pHcd, uChannel);
}
}
break;

case URB_DONE:
{
// 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)
{
// Disable retrues
pTransferDescriptor->retry = 0;

// Update transfer descriptor buffer pointer
pTransferDescriptor->currBufPtr += HAL_HCD_HC_GetXferCount(pHcd, uChannel);

// Call transferCompleted on correct object
void (USBHALHost::*func)(volatile uint32_t addr) = pPriv->transferCompleted;
(pPriv->inst->*func)(reinterpret_cast<std::uintptr_t>(pTransferDescriptor));
}
}
}
#else
void HAL_HCD_HC_NotifyURBChange_Callback(HCD_HandleTypeDef *hhcd, uint8_t chnum, HCD_URBStateTypeDef urb_state)
{
USBHALHost_Private_t *priv = (USBHALHost_Private_t *)(hhcd->pData);
Expand Down Expand Up @@ -168,6 +260,7 @@ void HAL_HCD_HC_NotifyURBChange_Callback(HCD_HandleTypeDef *hhcd, uint8_t chnum,
}
}
}
#endif

USBHALHost *USBHALHost::instHost;

Expand Down Expand Up @@ -346,8 +439,53 @@ void USBHALHost::_usbisr(void)
}
}


void USBHALHost::UsbIrqhandler()
{
HAL_HCD_IRQHandler((HCD_HandleTypeDef *)usb_hcca);
}
#if ARC_USB_FULL_SIZE
// 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;
HCD_HandleTypeDef* hhcd = (HCD_HandleTypeDef *)usb_hcca;

if (__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_SOF) && hhcd->Init.dma_enable == 0)
{
for (ch_num = 0; ch_num < hhcd->Init.Host_channels; ch_num++)
{
// workaround the interrupts flood issue: re-enable NAK interrupt
USBx_HC(ch_num)->HCINTMSK |= USB_OTG_HCINT_NAK;

// workaround the interrupts flood issue: re-enable CHH interrupt
if(hhcd->hc[ch_num].ep_type == EP_TYPE_CTRL)
USBx_HC(ch_num)->HCINTMSK |= USB_OTG_HCINT_CHH;
}
}


HAL_HCD_IRQHandler((HCD_HandleTypeDef *)usb_hcca);

if (__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_HCINT) && hhcd->Init.dma_enable == 0)
{
for (ch_num = 0; ch_num < hhcd->Init.Host_channels; ch_num++)
{
if ((hhcd->hc[ch_num].ep_type == EP_TYPE_CTRL) || (hhcd->hc[ch_num].ep_type == EP_TYPE_BULK))
{
if (USBx_HC(ch_num)->HCINT & USB_OTG_HCINT_NAK)
{
// workaround the interrupts flood issue: disable NAK interrupt
USBx_HC(ch_num)->HCINTMSK &= ~USB_OTG_HCINT_NAK;
}

if ((USBx_HC(ch_num)->HCINT & USB_OTG_HCINT_CHH) && (hhcd->hc[ch_num].ep_type == EP_TYPE_CTRL))
{
// workaround the interrupts flood issue: disable CHH interrupt
USBx_HC(ch_num)->HCINTMSK &= ~USB_OTG_HCINT_CHH;
}
}
}
}
#else
HAL_HCD_IRQHandler((HCD_HandleTypeDef *)usb_hcca);
#endif
}
#endif