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.

Compiler/TM4C1294NCPDT: Contoller hangs in USBHCDPipeWrite()

Part Number: TM4C1294NCPDT
Other Parts Discussed in Thread: EK-TM4C1294XL

Tool/software: TI C/C++ Compiler

Hi,

During our integration testing, we are finding an issue on the TM4C USB side.

When the device is started, the communication is happening fine. After some couple of transaction the device is going to a hang state.

When we debug and checked the process is halting in USBHCDPipeWrite() function in usbhostenum.c. It is staying in the while(1) loop inside
there. We printed g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].iState which is always 7 and no condition check available for this state inside this
function.

Kindly help us in debugging this issue.

Thank you,

Deepanraj.A

  • Hi,
    Can you please check this below post and see if it is relevant to your situation? If it is applicable, can you make the corresponding changes and see if it makes a difference?
    e2e.ti.com/.../679752
  • Hi Charles,

    Thanks for the support, We will try the change and come back to you in case of any issue.

    Thank you,
    Deepanraj.A
  • Hi Deepanraj,
    I will close the thread for now. If you have some updates you can just simply reply to this post to reopen the discussion.
  • Hi Charles,

    But already the fix suggested in the provided link is fixed in version 2.1.4.178 version right.

    Moreover in our case it does not enter this loop only.As we added debug print and checked bUseDMA is always true in our case.


    Thank you,
    Deepanraj.A

  • Hello Deepanraj,

    That fix is not applied in Version 2.1.4.178.

    I have helped a number of customers with issues stemming from USBHCDPipeWrite, and that fix has been successful to solve their issues thus far.
  • Hi Ralph,

    Actually in our case it does not enter the (bUseDMA r== false) condition statement for the fix to get working.

    bUseDMA is true always.

    Thank you,
    Deepanraj.A
  • Hello Deepanraj,

    If you are using DMA, I was told awhile back by a former expert of a couple other DMA impacting adjustments that were needed. One of which impacts USBHCDPipeWrite as well. Can you try to apply these? That includes additional fixes beyond what was suggested (plus a slightly cleaner fix for the prior E2E post).

    They are on our list to update on TivaWare as well.

    Replace the full functions in each file with the new ones.

    File: usblib\host\usbhostenum.c

    //*****************************************************************************
    //
    //! This function is used to write data to a USB HCD pipe.
    //!
    //! \param ui32Pipe is the USB pipe to put data into.
    //! \param pui8Data is a pointer to the data to send.
    //! \param ui32Size is the amount of data to send.
    //!
    //! This function will block until it has sent as much data as was
    //! requested using the USB pipe's FIFO.  The caller should have registered a
    //! callback with the USBHCDPipeAlloc() call in order to be informed when the
    //! data has been transmitted.  The value returned by this function can be less
    //! than the \e ui32Size requested if the USB pipe has less space available
    //! than this request is making.
    //!
    //! \return This function returns the number of bytes that were scheduled to
    //! be sent on the given USB pipe.
    //
    //*****************************************************************************
    uint32_t
    USBHCDPipeWrite(uint32_t ui32Pipe, uint8_t *pui8Data, uint32_t ui32Size)
    {
        uint32_t ui32Endpoint, ui32RemainingBytes, ui32ByteToSend, ui32PipeIdx;
        bool bUseDMA;
    
        //
        // Determine which endpoint interface that this pipe is using.
        //
        ui32Endpoint = IndexToUSBEP((EP_PIPE_IDX_M & ui32Pipe) + 1);
    
        //
        // Get index used for looking up pipe data
        //
        ui32PipeIdx = ui32Pipe & EP_PIPE_IDX_M;
    
        //
        // Set the total number of bytes to send out.
        //
        ui32RemainingBytes = ui32Size;
    
        //
        // Default to using DMA.
        //
        bUseDMA = false;
    
        //
        // Initialize the bytes to send to all of the remaining bytes.
        //
        ui32ByteToSend = ui32RemainingBytes;
    
        //
        // Send all of the requested data.
        //
        while(ui32RemainingBytes != 0)
        {
            //
            // If uDMA is not enabled for this pipe, or if the uDMA workaround
            // is applied, then don't use uDMA for this transfer.
            //
            if(ui32Pipe & EP_PIPE_USE_UDMA)
            {
                //
                // Disable the USB interrupt.
                //
                OS_INT_DISABLE(g_sUSBHCD.ui32IntNum);
    
                //
                // Start the DMA transfer.
                //
                if(USBLibDMATransfer(g_sUSBHCD.psDMAInstance,
                                g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].ui8DMAChannel,
                                pui8Data, ui32RemainingBytes) != 0)
                {
                    if(ui32RemainingBytes < g_sUSBHCD.psDMAInstance->pui32MaxPacketSize[ui32PipeIdx])
                    {
                        g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].iState =
                                                                ePipeWriteDMASend;
                    }
                    else if((ui32RemainingBytes % g_sUSBHCD.psDMAInstance->pui32MaxPacketSize[ui32PipeIdx]) == 0)
                    {
                        g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].iState =
                                                                    ePipeWriteDMA;
                    }
                    else
                    {
                        g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].iState =
                                                            ePipeWriteDMASend;
                    }
    
                    bUseDMA = true;
                }
    
                //
                // Enable the USB interrupt.
                //
                OS_INT_ENABLE(g_sUSBHCD.ui32IntNum);
            }
    
            if(bUseDMA == false)
            {
                //
                // Only send 64 bytes at a time if not using DMA.
                //
                if(ui32ByteToSend > g_sUSBHCD.psDMAInstance->pui32MaxPacketSize[ui32PipeIdx])
                {
                    ui32ByteToSend = g_sUSBHCD.psDMAInstance->pui32MaxPacketSize[ui32PipeIdx];
                }
                else
                {
                    //
                    // Send the requested number of bytes.
                    //
                    ui32ByteToSend = ui32RemainingBytes;
                }
    
                //
                // Start a write request.
                //
                g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].iState = ePipeWriting;
    
                //
                // Disable uDMA on the USB endpoint
                //
                MAP_USBEndpointDMADisable(USB0_BASE, ui32Endpoint,
                                          USB_EP_HOST_OUT);
    
                //
                // Put the data in the buffer.
                //
                MAP_USBEndpointDataPut(USB0_BASE, ui32Endpoint, pui8Data,
                                       ui32ByteToSend);
    
                //
                // Schedule the data to be sent.
                //
                MAP_USBEndpointDataSend(USB0_BASE, ui32Endpoint, USB_TRANS_OUT);
            }
    
            //
            // Wait for a status change.
            //
            while(1)
            {
                //
                // If an error event occurs then exit out of the loop.
                //
                if(g_sUSBHCD.ui32IntEvents & (INT_EVENT_DISCONNECT |
                                              INT_EVENT_VBUS_ERR |
                                              INT_EVENT_POWER_FAULT))
                {
                    //
                    // Set the pipe state to error.
                    //
                    g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].iState = ePipeError;
    
                    //
                    // Needs to be set to exit out of large while loop.
                    //
                    ui32RemainingBytes = 0;
    
                    break;
                }
                //
                // If the data was successfully sent then decrement the count and
                // continue.
                //
                else if(g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].iState ==
                        ePipeDataSent)
                {
                    //
                    // Decrement the remaining data and advance the pointer.
                    //
                    ui32RemainingBytes -= ui32ByteToSend;
                    pui8Data += ui32ByteToSend;
    
                    //
                    // If there are less than 64 bytes to send then this is the
                    // last of the data to go out.
                    //
                    if(ui32RemainingBytes < g_sUSBHCD.psDMAInstance->pui32MaxPacketSize[ui32PipeIdx])
                    {
                        ui32ByteToSend = ui32RemainingBytes;
                    }
                    break;
                }
                else if(g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].iState ==
                        ePipeStalled)
                {
                    //
                    // Zero out the size so that the caller knows that no data was
                    // written.
                    //
                    ui32Size = 0;
    
                    //
                    // Needs to be set to exit out of large while loop.
                    //
                    ui32RemainingBytes = 0;
    
                    //
                    // If DMA is being used, then disable the channel.
                    //
                    if(bUseDMA == true)
                    {
                        //
                        // Disable the DMA channel.
                        //
                        USBLibDMAChannelDisable(g_sUSBHCD.psDMAInstance,
                            g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].ui8DMAChannel);
                    }
    
                    //
                    // This is the actual endpoint number.
                    //
                    USBHCDClearFeature(
                        g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].psDevice->ui32Address,
                        ui32Pipe, USB_FEATURE_EP_HALT);
    
                    //
                    // If there was a stall, then no more data is coming so break
                    // out.
                    //
                    break;
                }
                else if(g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].iState == ePipeError)
                {
                    //
                    // An error occurred so stop this transaction and set the
                    // number of bytes to zero.
                    //
                    ui32Size = 0;
    
                    //
                    // Needs to be set to exit out of large while loop.
                    //
                    ui32RemainingBytes = 0;
    
                    break;
                }
            }
        }
    
        //
        // Go Idle once this state has been reached.
        //
        g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].iState = ePipeIdle;
    
        return(ui32Size);
    }
    
    

    File: usblib\usbdma.c

    //*****************************************************************************
    //
    // USBLibDMATransfer() for USB controllers with an integrated DMA controller.
    //
    //*****************************************************************************
    static uint32_t
    iDMAUSBTransfer(tUSBDMAInstance *psUSBDMAInst, uint32_t ui32Channel,
                    void *pvBuffer, uint32_t ui32Size)
    {
        uint32_t ui32PacketCount;
    
        if((uint32_t)pvBuffer & 0x3)
        {
            return(0);
        }
    
        //
        // Mark this channel as pending and not complete.
        //
        psUSBDMAInst->ui32Pending |= (1 << (ui32Channel - 1));
        psUSBDMAInst->ui32Complete &= ~(1 << (ui32Channel - 1));
    
        //
        // Save the pointer to the data and the byte count.
        //
        psUSBDMAInst->ppui32Data[ui32Channel - 1] = pvBuffer;
        psUSBDMAInst->pui32Count[ui32Channel - 1] = ui32Size;
    
        //
        // Set the address.
        //
        USBDMAChannelAddressSet(psUSBDMAInst->ui32Base, ui32Channel - 1, pvBuffer);
    
        //
        // Set the number of transfers.
        //
        USBDMAChannelCountSet(psUSBDMAInst->ui32Base, ui32Channel - 1, ui32Size);
    
        //
        // Set the mode based on the size of the transfer.  More than one
        // packet requires mode 1.
        //
        if(ui32Size >= psUSBDMAInst->pui32MaxPacketSize[ui32Channel - 1])
        {
            //
            // Calculate the number of packets required for this transfer.
            //
            ui32PacketCount = ui32Size /
                              psUSBDMAInst->pui32MaxPacketSize[ui32Channel - 1];
    
            if(ui32Size % psUSBDMAInst->pui32MaxPacketSize[ui32Channel - 1])
            {
                ui32PacketCount += 1;
            }
    
            USBEndpointPacketCountSet(psUSBDMAInst->ui32Base,
                                      psUSBDMAInst->pui8Endpoint[ui32Channel - 1],
                                      ui32PacketCount);
    
            //
            // Configure the USB DMA controller for mode 1.
            //
            USBEndpointDMAConfigSet(psUSBDMAInst->ui32Base,
                                    psUSBDMAInst->pui8Endpoint[ui32Channel - 1],
                                    psUSBDMAInst->pui32EPDMAMode1[ui32Channel - 1]);
    
            USBDMAChannelConfigSet(psUSBDMAInst->ui32Base, ui32Channel - 1,
                                   psUSBDMAInst->pui8Endpoint[ui32Channel - 1],
                                   psUSBDMAInst->pui32Config[ui32Channel - 1] |
                                   USB_DMA_CFG_MODE_1);
    
            //
            // Enable DMA on the endpoint.
            //
            if(psUSBDMAInst->pui32Config[ui32Channel - 1] & USB_DMA_CFG_DIR_TX)
            {
                //
                // Make sure that DMA is enabled on the endpoint.
                //
                MAP_USBEndpointDMAEnable(
                                    psUSBDMAInst->ui32Base,
                                    psUSBDMAInst->pui8Endpoint[ui32Channel - 1],
                                    USB_EP_HOST_OUT);
            }
            else
            {
                //
                // Make sure that DMA is enabled on the endpoint.
                //
                MAP_USBEndpointDMAEnable(
                                       psUSBDMAInst->ui32Base,
                                       psUSBDMAInst->pui8Endpoint[ui32Channel - 1],
                                       USB_EP_HOST_IN);
            }
    
            //
            // Enable the DMA channel.
            //
            USBDMAChannelEnable(psUSBDMAInst->ui32Base, ui32Channel - 1);
        }
        else
        {
            //
            // Configure the USB DMA controller for mode 0.
            //
            USBEndpointDMAConfigSet(psUSBDMAInst->ui32Base,
                                    psUSBDMAInst->pui8Endpoint[ui32Channel - 1],
                                    psUSBDMAInst->pui32EPDMAMode0[ui32Channel -1]);
    
            USBDMAChannelConfigSet(psUSBDMAInst->ui32Base, ui32Channel -1,
                                   psUSBDMAInst->pui8Endpoint[ui32Channel - 1],
                                   psUSBDMAInst->pui32Config[ui32Channel - 1] |
                                   USB_DMA_CFG_MODE_0);
    
            //
            // In mode 0 only enable DMA transfer for mode 0.
            //
            if(psUSBDMAInst->pui32Config[ui32Channel - 1] & USB_DMA_CFG_DIR_TX)
            {
                //
                // Make sure that DMA is enabled on the endpoint.
                //
                MAP_USBEndpointDMAEnable(
                                    psUSBDMAInst->ui32Base,
                                    psUSBDMAInst->pui8Endpoint[ui32Channel - 1],
                                    USB_EP_HOST_OUT);
                //
                // Enable the DMA channel.
                //
                USBDMAChannelEnable(psUSBDMAInst->ui32Base, ui32Channel - 1);
            }
            else
            {
                //
                // Make sure that DMA is disabled on the endpoint, it will
                // be enabled when the endpoint interrupt occurs.
                //
                MAP_USBEndpointDMADisable(
                                       psUSBDMAInst->ui32Base,
                                       psUSBDMAInst->pui8Endpoint[ui32Channel - 1],
                                       USB_EP_HOST_IN);
    
                //
                // Returns 0 so that when DMA is not used, the bUseDMA flag in the calling function
                // is set to false.
                //
                return(0);
    
            }
        }
    
        return(ui32Size);
    }

  • Hi Ralph,

    There is no change in the file "usbliub\host\usbhostenum.c ". As we think it is already been done by TI.

    But there are some minor changes in the file "usblib\usbdma.c". Which we implemented and check and found out the controller hangs at the same PipeWrite function as mentioned above.

    Thank you,
    Deepanraj.A
  • Hello Deepanraj,

    That doesn't make sense because I diff'd the changes with the current TivaWare to verify them before I posted and they are definitely not applied, are you sure those are already implemented in your system?
  • Hi Ralph,

    Yes, In our source code the changes have been already made with reference to the e2e community.

    After implementing the changes also it seemed to be in the while(1) loop inside the USBHCDPipeWrite function.

    Thank you,
    Deepanraj.A
  • Hello Deepanraj,

    Okay. After making the changes to usblib\usbdma.c, did you re-compile the USB Library? Or do you already have the USB library files directly included in your project (i.e. not using the usblib.lib file)?

    Is this project on the EK-TM4C1294XL LaunchPad? If so, you can provide it to me and then I can test to replicate and debug on my end.
  • Hi Ralph,

    Yes, We have already added the USB library file directly in our project.Actually this project is not in example code.

    We have got the RNDIS code directly from TI in order to regenerate the issue, we would need the certain devices which we have connected to the TM4c129 device. So it would be difficult for you to regenerate the same issue.

    Thank you,
    Deepanraj.A
  • Hello Deepanraj,

    Without being able to recreate the issue, it will be difficult for me to try and resolve this.

    How many bytes are being sent when the hang occurs? You mention a couple transaction, it is consistently hanging on the same transaction every time? If so, what is the difference between that transaction and the previous ones (for example, size of transaction)?
  • Hi Ralph,

    In our case, The hang occurs when we even send 4 bytes or 5 bytes of Data sometimes. Sometimes it hangs when we send a bulk data(256bytes or 384 bytes) also.
    We even tried USBHCDPipefree() function when this issue occurs so that the there wont be any data blocking the PipeWrite.But that also does not seemed to work.

    Thank you,
    Deepanraj.A
  • Hello Deepanraj,

    Can you do a comparison of all usblib files on your system to a fresh install of TivaWare and summarize any other changes that have been made?

    Also is this running on bare-metal or an RTOS like TI-RTOS?

    Right now the description you've given me, this is the first time I've ever seen an issue with PipeWrite present itself in this manner, and given that some changes had already been made to USBlib prior to this exchange, I am now concerned that perhaps there are other changes as well which could be causing this issue.
  •  Hi Ralph,

    We are running Bare Metal code.

    This is the issue we are getting and the flow how it is getting hanged.

    Thank you,

    Deepanraj

  • Hello Deepanraj,

    Going through the flow of your code, I see there are Ethernet calls as well. Were those because of an interrupt? Or is this for an Ethernet over USB application?
  • Hi Ralph,

    It is Ethernet over USB application.

    Thank you,

    Deepanraj

  • Hello Deepanraj,

    I see. We have not done Ethernet over USB applications with the TM4C, and we do not support that application. While I don't think this issue is purely related to that, I am in a tough position on trying to help with the PipeWrite issue given that:

    1) I have not been able to replicate the issue at all

    2) No other customer has come across an issue that our known fixes do not address

    I suspect the core issue here is that the way Ethernet over USB works is using PipeWrite in a manner that brings this error up, but because it's not recreatable for me, and we do not support Ethernet over USB, there is not really anything else I can do to support this issue.

    Given our lack of a support model for Ethernet over USB, you may need to consider other options for this application.

  • Hi Ralph,

    Actually in our case we are using RNDIS host protocol in our application to establish internet connection.

    When we continuously read from the USB the PipeWrite function is in a state that it continuously in the while loop.

    and is there any constrain if a bluk data or if contiously the pipe is written it might go inside the loop and it wont get any interrupt from the USB for it exit from the loop.

    Thank you,

    Deepanraj