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.

TM4C129XKCZAD: USBHCDPipeWrite() behaving oddly when used with DMA

Part Number: TM4C129XKCZAD

I'm writing a host driver that has to send a lot of data from the network to a vendor-specific full-speed device.

My device enumerates, and I can do bulk IN transactions with DMA.

I've been reading up on the existing bugs in usbhostenum.c, and I've patched it for non-DMA use.   Its working OK for that.

Whats not working is DMA mode for output.

Here's my Pipe config code:

		// Output Pipe for sending data.
		DFUInfo.ui32BulkOutPipe = USBHCDPipeAlloc(0,
			    USBHCD_PIPE_BULK_OUT_DMA,psDevice,DFUPipeCallback); 

		// Configure the pipe for use with endpoint 4.
		if ( DFUInfo.ui32BulkOutPipe != 0 ) {
			int ret = USBHCDPipeConfig(DFUInfo.ui32BulkOutPipe,
			64, //  uint32_t ui32MaxPayload - Observed in descriptors.
			0,   // uint32_t ui32Interval
			4    //  uint32_t ui32TargetEndpoint
            );
            // Make sure it worked...
		if ( ret != 0 ) {
			USBHCDPipeFree(DFUInfo.ui32BulkOutPipe);
			DFUInfo.ui32BulkOutPipe = -1;
			}
		}

What I'm seeing is that short writes (32 bytes) never send data onto the bus.        Longer writes get stuck in the while(1) loop inside USBHCDPipeWrite() while it 'Waits for a status change" - this makes sense, because the signs are that the DMA write never happens.

The docs for 

USBHCDPipeSchedule() say that its for IN transactions, but the code says that it also handles OUT.  Is that the right way to go here?

  • Hello R Sexton,

    I think it may be. I am not very familiar with the DMA + USB process but just by looking through the USB library and our host examples it looks like the Audio example uses it USBHCDPipeSchedule for both IN and OUT operatons:

        //
        // Schedule the data to be written out to the FIFO.
        //
        ui32Bytes = USBHCDPipeSchedule(psAudioInstance->ui32IsochOutPipe, pvBuffer,
                                       ui32Size);

    I think it would make sense for you to try that approach and see if that helps with the output of pipe data w/ DMA, as I don't see any other API's which stick out to me as useful for this within the usbhostenum.c file and it does include code for the ePipeWriteDMASend state which would indicate it could be used for OUT as well.

  • No luck. USBHCDPipeSchedule() hangs for OUT transactions. Something is broken here. I see from the data sheet that the USB controller on the TM4C129 has an integrated DMA controller, so there is no chance of channel contention.
  • Hello R Sexton,

    I agree, there shouldn't be channel contention. Though I suspect what is broken is on the implementation side and not the library side as this is the first time such an issue has arose from what I can see through searching the forums for similar issues. While I have knowledge of the USB library I didn't write it so unfortunately I don't always know how all the pieces fit together. I can look into it further next week, but I am out of office on Monday and likely will have little time to deep dive the library on Tues/Wed, so it may be quite a few days before I can assist further on this topic.

    In the meantime if you want to debug on your end further, I would suggest following along through the usbhostenum.c file and look for the usage of ePipeWriteDMA* states (Send mostly, but others as well) and see if you can ID any missing piece from the implementation that way. If you have specific questions on findings, please post them here and I will at least try and clarify any points I can until I have more bandwidth available.
  • Hello R Sexton,

    I have been (and still am) on business travel so it's a bit hard for me to piece together all your various threads. Did your recent breakthrough post from the prior night solve this issue? Post in question: e2e.ti.com/.../679752
  • No. So far I've wasted about three days trying to get the USB library to perform at any level beyond proof of concept. Between the poor documentation, incorrect documentation, and errors in library code, its been very slow, maddening work.

    I've been working with these parts for over five years, and I've shipped over 100k of them. The USB code has been a tremendous disappointment, especially after several good years of experience with the best-in-class DriverLib. Its the first time that I've had to read library source code to figure out an API.
  • Hello R Sexton,

    As someone who has been tasked to come in and support the usblib as it is currently, I can understand the frustrations about the state of documentation and library code... while the USB applications that are provided as TivaWare examples are strong, especially for device applications, the host side seems has few such examples. Also when the application deviates from the well tested USB examples then challenges can occur.

    Just so we remain on the same page since I will be diving into this once more tomorrow when back from travel, the issue at hand is then summarized as: "What I'm seeing is that short writes (32 bytes) never send data onto the bus."?
  • I've been instrumenting the TI Code, and I've determined that that USBHCDPipeWrite() doesn't necessarily use DMA.   It attempts to use DMA if specified, and if there are problems it falls back to non-DMA behavior.   That may explain the unreliable behavior I've seen with large transfers.

    The core of the problem appears to be this little bit of undocumented code from usblib/usbdma.c - I'm using a part with internal USB DMA, and not uDMA.

    //*****************************************************************************
    //
    // 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);
        }
    
        //
    

    iDMAUSBTransfer() is doing an alignment check on the buffer and returning if the buffer isn't aligned.    

    My buffers aren't aligned, and I don't have control over them.   They belong to the network stack.   

    What I can't see is any documentation that says USB buffers have to be aligned.   If they actually do have to be aligned, I'm stuck with a low-performance solution.

  • Ralph,

    Thanks for your patience. I'm pretty sure that the dropped 32-byte writes were my fault.

    It looks like the oddness that I'm experiencing with DMA is related to the fact that the USB controller requires that all DMA transfers be word-aligned and multiples of four bytes. This is a pretty big limitation that negates a lot of the benefits of DMA for real world applications. Its not explicitly documented anywhere, but you can deduce it from the datasheet by reading the register definitions.

    I'm in the midst of making one last attempt to getting this interface working with DMA because that has a large impact on system performance in my application. The DMA alignment requirement means that I have to re-design some things to deal with that.

    - Robert
  • Hi Robert,

    I sent you an E2E friend request. There are a few points regarding the USB portion of the datasheet I want to run by you off the public forum.