This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

F28M35H52C: possible F28M35 usblib bug with DMA endpoints

Part Number: F28M35H52C

I have a board with F28M35H52C1 configured as usb host to a 4-port usb hub, barcode scanner, usb flash drive, and a custom usb bulk device.  The USB MSC part of the project was derived from USB MSC example in control suite.

The issue is related to an endpoint configured to use DMA.  If an endpoint is configured to use DMA and that end point ends up with a pipe index >= 3, then the data transfers fail.  USBHCDPipeRead or USBHCDPipeWrite will hang in an infinite loop waiting for: while(g_sUSBHCD.USBINPipes[ulPipeIdx].eState == PIPE_READING)  -- in the case of in pipe.

The problem starts in USBHCDPipeAllocSize() and applies to both "IN" and "OUT" pipes.  Relevant code from that function is here:

if(ulEndpointType & EP_PIPE_USE_UDMA)
{
//
// First three endpoints have fixed channels on some
// parts so bias the pipes to match this as best is
// possible.
//
if(lIdx < 3)
{
//
// Check if the fixed channel is available for this
// USB pipe.
//
if(g_sUSBHCD.ucDMAChannels[lIdx * 2] ==
USBHCD_DMA_UNUSED)
{
//
// The default channel was available so use it.
//
g_sUSBHCD.ucDMAChannels[lIdx * 2] = lIdx;
g_sUSBHCD.USBINPipes[lIdx].ucDMAChannel = lIdx * 2;
}
else
{
//
// Go to the next USB pipe if the fixed one was not
// available.
//
continue;
}
}
else
{
//
// Either the fixed channel was not available or the
// pipe index was more than the first 3 pipes that are
// available on all parts.
//
for(lDMAIdx = 0; lDMAIdx < MAX_NUM_DMA_CHANNELS;
lDMAIdx += 2)
{
//
// Find any available channel.
//
if(g_sUSBHCD.ucDMAChannels[lDMAIdx] ==
USBHCD_DMA_UNUSED)
{
//
// Save the index and the DMA channel
// information.
//
g_sUSBHCD.ucDMAChannels[lDMAIdx] = lIdx;
g_sUSBHCD.USBINPipes[lIdx].ucDMAChannel =
lDMAIdx;
}
}
}

When lIdx >= 3, then the else branch runs the for loop to find another available channel that was not used at a lower index.  If an unused channel is found, then the appropriate setup occurs.  However, the loop execution doesn't break and the loop continues for each available channel.

I added a break in both the "IN" and "OUT" pipe setup to stop this from happening.  However, when i rebuild the usblib and run the code there is still a hang condition in pipe read and pipe writes.

In USBHCDPipeRead() and USBHCDPipeWrite(), there is no reference to g_sUSBHCD.USBINPipes[lIdx].ucDMAChannel which is the actual dma channel to use for the in/out pipe transfers.  Instead the code assumes the pipe index was less than 3 and it can use the default index into the USB DMA endpoints.  For example these lines:

uDMAChannelTransferSet(UDMA_CHANNEL_USBEP1RX + (ulPipeIdx * 2), UDMA_MODE_AUTO, (void *)USBFIFOAddrGet(USB0_BASE, ulEndpoint), pucData, ulBytesRead);

OR

uDMAChannelEnable(UDMA_CHANNEL_USBEP1RX + (ulPipeIdx * 2));

(ulPipeIdx * 2) is used to calculate the offset which is incorrect.  I think the code should reference  g_sUSBHCD.USBINPipes[ulPipeIdx].ucDMAChannel to get the correct dma channel.

I realize hosting 3 usb devices and a hub is likely an extreme use case for the m3, but i wanted to point this out in case someone else runs into an issue like this.  In my case, as a short term workaround I plan to modify USBHCDPipeAllocSize() to disable DMA use if index is >= 3.  I can control the USB port usage in normal product use to force the usb flash drive to be connected to the first USB hub port.