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.

TMS320F28388D: Where does one use USBEndpointDMAEnable() in one's code?

Part Number: TMS320F28388D
Other Parts Discussed in Thread: C2000WARE

Hi,

I am still in the process of making a personal working example of using the CM uDMA with USB and I could use some advice to speed up the development.

At first I followed the existing examples that involve uDMA and did my best to infer what needed to be done to have it interact with the USB peripheral. Of course, I quickly ran into complications.

I assumed that USBEndpointDMAEnable() simply makes the USB peripheral available to the uDMA and that without calling any uDMA functions there would be no effect on the application. What I've discovered is that after calling USBEndpointDMAEnable() with the desired endpoint and direction, is that the application enters into an unending interrupt loop where the USB ISR keep getting called. When I halted the debugger in the USB interrupt handler function I found that the USBDMARIS and USBDMAISC registers had values indicating the device has finished transmitting data (0x2 for both registers). Combined with the default USBDMAIM register value, a USB interrupt will occur as a result. To break out of the loop, I had to modify the default CM_USB0DeviceIntHandler() ISR (provided by the usb_ex4_device_bulk_cm example) to call USBEndpointDMADisable() and USBDMAInterruptStatusClear().

From what I can tell, an empty TX FIFO results in an USB_DMAA_TX_DONE event (even though the application has yet to put any data into the TX FIFO), is that correct? If so, how should I call USBEndpointDMAEnable() to avoid this kind of pre-mature interrupt?

Sincerely,

Howard Li

EDIT:

Alright, I've tried using a software triggered uDMA transfer to load some data into the transmit FIFO. It did not work as the endpoint status register remained unchanged when I do not call USBEndpointDMAEnable(). When I do call that function and mask out the interrupt to avoid the interrupt loop, the endpoint status register showed that the endpoint has stalled (regardless of how the transfer trigger, by the way).

Currently, I have no idea how one is suppose to configure the USB peripheral to work with uDMA, as there are no examples provided by C2000Ware and online searches revealed no additional useful information. I really want to know how to get at least one byte into the transmit FIFO using uDMA.

  • Hi Howard,

    Ideally, USB_DMAA_TX_DONE event should occur when the data in the TX FIFO becomes empty and not when it is already empty. What are the parameters that you are passing to the USBEndpointDMAEnable function.?

    The USB controller does not generate an interrupt if the endpoint is configured in DMA mode 0.  If the transfer has been stalled, it

    Currently there is no example provided in C2000Ware for USB with DMA, will look into adding such an example in a future release of C2000Ware.

    Best Regards

    Siddharth

  • I called USBEndpointDMAEnable(USB0_BASE, USB_EP_1, USB_EP_DEV_IN);

    Also I decided to see what would happen if I called USBEndpointDMAEnable() without calling USBDBulkInit() first.

    Apparently, there is no interrupt loop or other abnormal behavior; the application successfully settled into its main loop. While this setup means that the controlCARD won't work as a bulk USB device, it reveals that USBDBulkInit() did something to the USB peripheral configuration that will result in an undesirable interrupt loop when USBEndpointDMAEnable() is called.

    EDIT: Nevermind, the USB_DMAA_TX_DONE is still occurring as the bit in the USBDMARIS and USBDMAISC is still being set. What is happening is that the USB interrupt is not enabled so there are no interrupts being generated, but if it were enabled then the application would be caught in the interrupt loop.

  • For your reference, this is the C file containing the main function I am using to try and get uDMA to work with USB.

    It is a modified usb_ex4_device_bulk_cm.c provided by the usb_ex4_device_bulk_cm example project.

    EDIT: The issue isn't caused by the controlCARD revision. Both Rev. A and Rev. B controlCARDs have the USB_DMAA_TX_DONE event occurring even though no transfers have happened yet.

    EDIT2: I finally managed to get uDMA working with USB but it required using a software trigger along with a UDMA ISR to call USBEndpointDataSend() send out the bytes. This is still workable but not the optimal solution because if want to send more than one packet worth of data I will have to perform multiple uDMA transfers.

    //##############################################################################
    //
    // FILE:   usb_ex4_device_bulk_cm.c
    //
    // TITLE:  Main routines for the generic bulk device example.
    //
    //! \addtogroup driver_example_cm_list
    //! <h1>USB Generic Bulk Device (usb_dev_bulk)</h1>
    //!
    //! This example provides a generic USB device offering simple bulk data
    //! transfer to and from the host.  The device uses a vendor-specific class ID
    //! and supports a single bulk IN endpoint and a single bulk OUT endpoint.
    //! Data received from the host is assumed to be ASCII text and it is
    //! echoed back with the case of all alphabetic characters swapped.
    //!
    //! UART0, connected to the FTDI virtual COM port and running at 115200,
    //! 8-N-1, is used to display messages from this application.
    //!
    //! A Windows INF file for the device is provided in C2000Ware.  This
    //! INF contains information required to install the WinUSB subsystem on
    //! Windows.  WinUSB is a Windows subsystem allowing user mode applications
    //! to access the USB device without the need for a vendor-specific kernel
    //! mode driver. 
    //!
    //! A sample Windows command-line application, usb_bulk_example, illustrating
    //! how to connect to and communicate with the bulk device is also provided.
    //! Project files are included to allow the examples to be built using Microsoft
    //! VisualStudio.  Source code for this application can be found in directory
    //! MWare/tools/usb_bulk_example.
    //!
    //
    //##############################################################################
    // $TI Release: F2838x Support Library v3.02.00.00 $
    // $Release Date: Tue May 26 17:21:56 IST 2020 $
    // $Copyright:
    // Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/
    //
    // Redistribution and use in source and binary forms, with or without 
    // modification, are permitted provided that the following conditions 
    // are met:
    // 
    //   Redistributions of source code must retain the above copyright 
    //   notice, this list of conditions and the following disclaimer.
    // 
    //   Redistributions in binary form must reproduce the above copyright
    //   notice, this list of conditions and the following disclaimer in the 
    //   documentation and/or other materials provided with the   
    //   distribution.
    // 
    //   Neither the name of Texas Instruments Incorporated nor the names of
    //   its contributors may be used to endorse or promote products derived
    //   from this software without specific prior written permission.
    // 
    // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
    // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
    // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
    // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
    // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
    // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
    // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
    // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    // $
    //##############################################################################
    
    #include <string.h>
    #include "cm.h"
    #include "usblib.h"
    #include "device/usbdevice.h"
    #include "device/usbdbulk.h"
    #include "usb_hal.h"
    #include "usb_ex4_device_bulk_structs.h"
    
    //******************************************************************************
    //
    // Variables tracking transmit and receive counts.
    //
    //******************************************************************************
    volatile uint32_t g_ui32TxCount = 0;
    volatile uint32_t g_ui32RxCount = 0;
    
    tUSBMode g_eCurrentUSBMode;   // The current USB operating mode - Host, Device
                                  // or unknown.
    
    //******************************************************************************
    //
    // Global flag indicating that a USB configuration has been set.
    //
    //******************************************************************************
    static volatile bool g_bUSBConfigured = false;
    
    //*****************************************************************************
    //
    // Handles bulk driver notifications related to the transmit channel (data to
    // the USB host).
    //
    // \param pvCBData is the client-supplied callback pointer for this channel.
    // \param ui32Event identifies the event that has been sent.
    // \param ui32MsgValue is an event-specific value.
    // \param pvMsgData is an event-specific pointer.
    //
    // This function is called by the bulk driver to notify us of any events
    // related to operation of the transmit data channel (the IN channel carrying
    // data to the USB host).
    //
    // \return The return value is event-specific.
    //
    //******************************************************************************
    uint32_t
    TxHandler(void *pvCBData, uint32_t ui32Event, uint32_t ui32MsgValue,
              void *pvMsgData)
    {
        //
        // No action is required in response to any transmit event in this example.
        // All that is done is to update the transmit counter.
        //
        if(ui32Event == USB_EVENT_TX_COMPLETE)
        {
            g_ui32TxCount += ui32MsgValue;
        }
    
        return(0);
    }
    
    //******************************************************************************
    //
    // Handles bulk driver notifications related to the receive channel (data from
    // the USB host).
    //
    // \param pvCBData is the client-supplied callback pointer for this channel.
    // \param ui32Event identifies the event that has been sent.
    // \param ui32MsgValue is an event-specific value.
    // \param pvMsgData is an event-specific pointer.
    //
    // This function is called by the bulk driver to notify us of any events
    // related to operation of the receive data channel (the OUT channel carrying
    // data from the USB host).
    //
    // \return The return value is event-specific.
    //
    //******************************************************************************
    uint32_t
    RxHandler(void *pvCBData, uint32_t ui32Event, uint32_t ui32MsgValue,
              void *pvMsgData)
    {
        //
        // Which event was sent?
        //
        switch(ui32Event)
        {
            //
            // The host has connected.
            //
            case USB_EVENT_CONNECTED:
            {
                g_bUSBConfigured = true;
    
                //
                // Flush our buffers.
                //
                USBBufferFlush(&g_sTxBuffer);
                USBBufferFlush(&g_sRxBuffer);
    
                break;
            }
    
            //
            // The host has disconnected.
            //
            case USB_EVENT_DISCONNECTED:
            {
                g_bUSBConfigured = false;
                break;
            }
    
            //
            // A new packet has been received.
            //
            case USB_EVENT_RX_AVAILABLE:
            {
    //            tUSBDBulkDevice *psDevice;
    //
    //            //
    //            // Get a pointer to our instance data from the callback data
    //            // parameter.
    //            //
    //            psDevice = (tUSBDBulkDevice *)pvCBData;
    //
    //            //
    //            // Read the new packet and echo it back to the host.
    //            //
    //            return(EchoNewDataToHost(psDevice, pvMsgData, ui32MsgValue));
            }
    
            //
            // Ignore SUSPEND and RESUME for now.
            //
            case USB_EVENT_SUSPEND:
            case USB_EVENT_RESUME:
            {
                break;
            }
    
            //
            // Ignore all other events and return 0.
            //
            default:
            {
                break;
            }
        }
    
        return(0);
    }
    
    //******************************************************************************
    // ModeCallback - USB Mode callback
    //
    // \param ui32Index is the zero-based index of the USB controller making the
    //        callback.
    // \param eMode indicates the new operating mode.
    //
    // This function is called by the USB library whenever an OTG mode change
    // occurs and, if a connection has been made, informs us of whether we are to
    // operate as a host or device.
    //
    // \return None.
    //
    //******************************************************************************
    void
    ModeCallback(uint32_t ui32Index, tUSBMode eMode)
    {
        //
        // Save the new mode.
        //
        g_eCurrentUSBMode = eMode;
    }
    
    //#pragma DATA_ALIGN(ucControlTable, 1024)
    //UDMA_ControlTable ucControlTable[64];
    
    //******************************************************************************
    //
    // This is the main application entry function.
    //
    //******************************************************************************
    int
    main(void)
    {
        //
        // Initialize device clock and peripherals
        //
        CM_init();
    
        //
        // Register the interrupt handler, for USB.
        //
        Interrupt_registerHandler(INT_USB0, &CM_USB0DeviceIntHandler);
    
        //
        // Not configured initially.
        //
        g_bUSBConfigured = false;
    
        //
        // Initialize the transmit and receive buffers.
        //
        USBBufferInit(&g_sTxBuffer);
        USBBufferInit(&g_sRxBuffer);
    
        //
        // Set the USB stack mode to Device mode with VBUS monitoring.
        //
        USBStackModeSet(0, eUSBModeForceDevice, ModeCallback);
    
        //
        // Pass our device information to the USB library and place the device
        // on the bus.
        //
    
        // NOTE TO TI: I have disable making the controlCARD into a USB device to demonstrate that USBEndpointDMAEnable() alone is responsible for the issues that I currently face.
        /*USBDBulkInit(0, &g_sBulkDevice);*/
    
        // NOTE TO TI: I have gone with the minimum amount of ui32Config options.
        USBEndpointDMAConfigSet(USB0_BASE, USB_EP_1, USB_EP_DEV_IN);
    
        //
        // Enable interrupts now that the application is ready to start.
        //
        Interrupt_enableInProcessor();
    
        USBEndpointDMAEnable(USB0_BASE, USB_EP_1, USB_EP_DEV_IN);
    
        // NOTE TO TI:
        // Nothing else is going to happen from this point other than to settle into the main loop.
        // The main loop in this case does nothing but update an integer variable holding the USBDMAISC register value.
        // Ideally, that value should be 0 as no DMA transfers have occurred (nor will they ever) in this application.
        // But somehow bit 1 is being set resulting in a value of 0x2 existing in that register.
    
        uint16_t stat;
    
        //
        // Main application loop.
        //
    
        while(1)
        {
            stat = USBDMAInterruptStatus(USB0_BASE);
        }
    }
    

  • Hi Howard,

    Glad that you were able to get it working. Am out of office for the next 5 days, will take a look at the C file that you have shared once I am back in office and see if any improvement can be done to avoid multiple uDMA transfers.

    Best Regards

    Siddharth