I'm trying to debug why after some random large amount of data / time - I start to see USB freezing, using code based on the evkbimxrt1050_dev_cdc_vcom_freertos demo in MCUXpresso.
My problem seems MAYBE similar to what caused other's to start threads: USB isochronous EP stuck
and https://community.nxp.com/thread/498477
and K22 USB device CDC and HID problem
But I don't see a clear workaround for the RT1052's USB stack.
In that the USB is getting stuck in a busy state in USB_DeviceCdcAcmSend() .
If I follow this, I THINK that isBusy is set in usb_device_dci.c in
static usb_status_t USB_DeviceTransfer(usb_device_handle handle,
uint8_t endpointAddress,
uint8_t *buffer,
uint32_t length)
{
usb_device_struct_t *deviceHandle = (usb_device_struct_t *)handle;
usb_status_t error = kStatus_USB_Error;
uint8_t endpoint = endpointAddress & USB_ENDPOINT_NUMBER_MASK;
uint8_t direction = (endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >>
USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT;
OSA_SR_ALLOC();
if (NULL == deviceHandle)
{
return kStatus_USB_InvalidHandle;
}
if (NULL != deviceHandle->controllerInterface)
{
if (deviceHandle->epCallback[(uint8_t)((uint32_t)endpoint << 1U) | direction].isBusy)
{
return kStatus_USB_Busy;
}
OSA_ENTER_CRITICAL();
deviceHandle->epCallback[(uint8_t)((uint32_t)endpoint << 1U) | direction].isBusy = 1U;
OSA_EXIT_CRITICAL();
if (endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK)
{
#if (defined(USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE > 0U))
if (length)
{
DCACHE_CleanByRange((uint32_t)buffer, length);
}
#endif
/* Call the controller send interface, the callbackFn is initialized in
USB_DeviceGetControllerInterface */
error = deviceHandle->controllerInterface->deviceSend(deviceHandle->controllerHandle, endpointAddress,
buffer, length);
}
else
{
#if (defined(USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE > 0U))
if (length)
{
DCACHE_CleanInvalidateByRange((uint32_t)buffer, length);
}
#endif
/* Call the controller receive interface, the callbackFn is initialized in
USB_DeviceGetControllerInterface */
error = deviceHandle->controllerInterface->deviceRecv(deviceHandle->controllerHandle, endpointAddress,
buffer, length);
}
if (kStatus_USB_Success != error)
{
OSA_ENTER_CRITICAL();
deviceHandle->epCallback[(uint8_t)((uint32_t)endpoint << 1U) | direction].isBusy = 0U;
OSA_EXIT_CRITICAL();
}
}
else
{
error = kStatus_USB_ControllerNotFound;
}
return error;
}
How could it be that isBusy is not getting reset back to 0 in rare cases?
Is it the timing issues mentioned in the threads I linked to above? or are there a set of common cases that cause USB's interface to get stuck on isBusy == 1?
When looking on the USB packet analyzer, all traffic appears to be fine, just when I'm sending many packets from the RT1052's USB, as noted above, occasionally (like after a few thousand packets) the RT1052 just stops sending data and is stuck in the isBusy state.
I found the same problem, also with CDC class. And in my case, I can observe the problem when I have a sending task enabled, (`USB_DEVICE_CONFIG_USE_TASK = 1U` in `usb_device_config.h`). When I had this task disabled, the problem does not occur.
Just to show where I am in code:
and if i force isBusy to 0 (as noted using the debug view):
isBusy is still set elsewhere...
The USB stack is pretty complex - so if I could get some pointers on where isBusy should be cleared when I'm only sending data over the bulk endpoint from the RT1052 to a computer (not receiving anything when this state is hit), and what would cause this to not be cleared... maybe that would help me debug.
Hi Andrew:
I noticed one thread about the possible race condition on usb_device_dci.c. Please refer to below link
Posible race condition on usb_device_dci.c
Did you try the solution by janbertran?
USB_OSA_ENTER_CRITICAL();
if (deviceHandle->epCallback[(uint8_t)((uint32_t)endpoint << 1U) | direction].isBusy)
{
USB_OSA_EXIT_CRITICAL();
return kStatus_USB_Busy;
}
Regards
Daniel
Hi danielchen@fsl,
Thanks for the feedback -
What I ended up doing to get this to work for me was: create a separate FreeRTOS task for sending, and then send via FreeRTOS queues - which seems to avoid race conditions for me