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.

TMS320F28377D: USB Bulk Transfer Max Rate

Part Number: TMS320F28377D

We are send data from the TMS320F28377D as a slave to a PC.
We are using bulk transfer mode starting from the "usb_dev_bulk" example.
No other USB devices are connected externally to the PC.
We are currently only sending data not receiving any data.
We are not running short of realtime and no other interrupts have been added to the example.
This is being done on the F28377D controlCARD.
Last year we had a conference call with TI representatives and they had said that they had been able to get ~10Mbs transfers.
I would like to get 8.4Mbs transfers and I am stuck at 5.8Mbs without losing data.
The buffer is just not emptying fast enough...

Is it possible to get an example of the 28377D sending bulk data at maximum rate?

Thanks...John

  • Hi John,

    We are only able to achieve between 7-8 Mbs. We canot get more than 8 Mbs.

    I may be able to send some code to you, but need to speak with my manager and also get some time to work on this. I will have to reply back later concerning this example.

    sal
  • Thanks Sal,

    I have some ideas, but most will really eat up realtime.

    Any pointers or examples you can provide will be appreciated...John

  • Hi John,

    USB is not a good real-time communication peripheral/protocol.

    The USB interrupts can vary between 1-50us. Please see this thread.
    e2e.ti.com/.../581179

    sal
  • Thanks for the warning Sal,

    We currently plan to have CPU1 doing fault checking/logging and communications with the real-time control code running on CPU2 and CPU2.CLA.
    We plan to have a mode where CPU1 can send data over USB for our engineers to analyze in problems cases.

    CPU1s real-time is really just being able to keep checking for faults and communicate in this mode.

    We are hoping with the 28377D USB to eliminate a lot of external hardware to support this data capture and give customers the ability to monitor also without special equipment.

    The original requirement was 2.3Mbs with a stretch goal of 4.6Mbs, but my boss likes to move the goal line if you get to it to fast.
    I'm currently trying to convince him that 5.8-6 Mbs is enough.

    ...John
  • Hi John,

    Because I do not have much time to run the tests again, I am attaching the test device source code and host Visual Studio project source code I have used to run the tests.

    Please use these to profile the performance and see if USB will meet your needs.

    //*****************************************************************************
    //
    // usb_bulk_example.c - A very simple command line application that attempts
    //      to open the Luminary Micro Generic Bulk USB device and exchange data
    //      with it.
    //
    // Copyright (c) 2008-2009 Luminary Micro, Inc.  All rights reserved.
    // Software License Agreement
    // 
    // Luminary Micro, Inc. (LMI) is supplying this software for use solely and
    // exclusively on LMI's microcontroller products.
    // 
    // The software is owned by LMI and/or its suppliers, and is protected under
    // applicable copyright laws.  All rights are reserved.  You may not combine
    // this software with "viral" open-source software in order to form a larger
    // program.  Any use in violation of the foregoing restrictions may subject
    // the user to criminal sanctions under applicable laws, as well as to civil
    // liability for the breach of the terms and conditions of this license.
    // 
    // THIS SOFTWARE IS PROVIDED "AS IS".  NO WARRANTIES, WHETHER EXPRESS, IMPLIED
    // OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
    // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
    // LMI SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
    // CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
    // 
    // This is part of revision 4674 of the Stellaris Firmware Development Package.
    //
    //*****************************************************************************
    
    //****************************************************************************
    //
    // If the device is successfully opened, the user is prompted for a string
    // which is then sent to the device. The device toggles the case of any
    // alphabet characters in the the data and sends it back. We receive this
    // and print out the result.
    //
    // Communication with the device is carried out via a simple DLL, lmusbdll,
    // which is responsible for opening and closing the device and for
    // sending and receiving blocks of data.  This structure allows the
    // application code to be kept independent of the underlying USB driver
    // in use.  In this implementation, Microsoft's WinUSB interface is used
    // but a switch to another stack, for example the open source libusb-win32
    // interface could be made merely be replacing the lmusbdll.dll with
    // another version writing to the different USB stack.
    //
    // One downside to using WinUSB is that it requires you to have the Windows
    // Device Driver Kit (DDK) installed to build applications which use the
    // interface. This is a very large download making it awkward for people
    // with slow internet connections. The use of lmusbdll.dll also offers
    // the advantage that applications using it can still be modified and
    // rebuilt even without the DDK installed on the development system.  To
    // update and rebuild lmusbdll itself, however, the DDK is still required.
    //
    //****************************************************************************
    #include <windows.h>
    #include <strsafe.h>
    #include <initguid.h>
    #include "tiusbdll.h"
    #include "ti_guids.h"
    
    //****************************************************************************
    //
    // Buffer size definitions.
    //
    //****************************************************************************
    #define MAX_STRING_LEN 65536
    #define MAX_ENTRY_LEN 65536
    
    //****************************************************************************
    //
    // The build version number
    //
    //****************************************************************************
    #define BLDVER "4674"
    
    //****************************************************************************
    //
    // The number of bytes we read and write per transaction if in echo mode.
    //
    //****************************************************************************
    #define ECHO_PACKET_SIZE 65535
    
    //****************************************************************************
    //
    // Buffer into which error messages are written.
    //
    //****************************************************************************
    TCHAR g_pcErrorString[MAX_STRING_LEN];
    
    //****************************************************************************
    //
    // The number of bytes transfered in the last measurement interval.
    //
    //****************************************************************************
    ULONG g_ulByteCount = 0;
    
    //****************************************************************************
    //
    // The total number of packets transfered.
    //
    //****************************************************************************
    ULONG g_ulPacketCount = 0;
    
    //****************************************************************************
    //
    // Return a string describing the supplied system error code.
    //
    // \param dwError is a Windows system error code.
    //
    // This function returns a pointer to a string describing the error code
    // passed in the dwError parameter. If no description string can be found
    // the string "Unknown" is returned.
    //
    // \return Returns a pointer to a string describing the error.
    //
    //****************************************************************************
    LPTSTR GetSystemErrorString(DWORD dwError)
    {
        DWORD dwRetcode;
    
        //
        // Ask Windows for the error message description.
        //
        dwRetcode = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, "%0", dwError, 0,
                                  g_pcErrorString, MAX_STRING_LEN, NULL);
    
        if(dwRetcode == 0)
        {
            return((LPTSTR)L"Unknown");
        }
        else
        {
            //
            // Remove the trailing "\n\r" if present.
            //
            if(dwRetcode >= 2)
            {
                if(g_pcErrorString[dwRetcode - 2] == '\r')
                {
                    g_pcErrorString[dwRetcode - 2] = '\0';
                }
            }
    
            return(g_pcErrorString);
        }
    }
    
    //****************************************************************************
    //
    // Print the throughput in terms of Kbps once per second.
    //
    //****************************************************************************
    void UpdateThroughput(void)
    {
        static ULONG ulStartTime = 0;
        static ULONG ulLast = 0;
        ULONG ulNow;
        ULONG ulElapsed;
        SYSTEMTIME sSysTime;
    
        //
        // Get the current system time.
        //
        GetSystemTime(&sSysTime);
        ulNow = (((((sSysTime.wHour * 60) +
                   sSysTime.wMinute) * 60) +
                  sSysTime.wSecond) * 1000) + sSysTime.wMilliseconds;
    
        //
        // If this is the first call, set the start time.
        //
        if(ulStartTime == 0)
        {
            ulStartTime = ulNow;
            ulLast = ulNow;
            return;
        }
    
        //
        // How much time has elapsed since the last measurement?
        //
        ulElapsed = (ulNow > ulStartTime) ? (ulNow - ulStartTime) : (ulStartTime - ulNow);
    
        //
        // We dump a new measurement every second.
        //
        if(ulElapsed > 1000)
        {
    
            printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
            printf("%6dKbps Packets: %10d ", ((g_ulByteCount * 8) / ulElapsed), g_ulPacketCount);
            g_ulByteCount = 0;
            ulStartTime = ulNow;
        }
    }
    
    //****************************************************************************
    //
    // The main application entry function.
    //
    // \param None.
    //
    // This function forms the main entry point of the example application. It
    // initializes the USB bulk device, prompts the user for an ASCII string,
    // sends this string to the device, reads the response from the device (which
    // will be the same string with the character order reversed if using the
    // sample device provided by Luminary Micro) and displays the returned
    // string.
    //
    // \return Set the exit code to 0 of no errors cause the application to end
    // or a non-zero value otherwise.
    //
    //****************************************************************************
    int main(int argc, char *argv[])
    {
        BOOL bResult;
        BOOL bDriverInstalled;
        BOOL bEcho;
        char szBuffer[MAX_ENTRY_LEN];
        ULONG ulWritten;
        ULONG ulRead;
        ULONG ulLength;
        DWORD dwError;
    	TIUSB_HANDLE hUSB;
    
        //
        // Are we operating in echo mode or not? The "-e" parameter tells the
        // app to echo everything it receives back to the device unchanged.
        //
        bEcho = ((argc > 1) && (argv[1][1] == 'e')) ? TRUE : FALSE;
    
        //
        // Print a cheerful welcome.
        //
        printf("\nLuminary Micro Bulk USB Device Example\n");
        printf("--------------------------------------\n\n");
        printf("Version %s\n\n", BLDVER);
        if(!bEcho)
        {
            printf("This is a partner application to the usb_dev_bulk example\n");
            printf("shipped with StellarisWare software releases for USB-enabled\n");
            printf("boards. Strings entered here are sent to the board which\n");
            printf("inverts the case of the characters in the string and returns\n");
            printf("them to the host.\n\n");
        }
        else
        {
            printf("If run with the \"-e\" command line switch, this application\n");
            printf("echoes all data received on the bulk IN endpoint to the bulk\n");
            printf("OUT endpoint.  This feature may be helpful during development\n");
            printf("and debug of your own USB devices.  Note that this will not\n");
            printf("do anything exciting if run with the usb_dev_bulk example\n");
            printf("device attached since it expects the host to initiate transfers.\n\n");
        }
    
        //
        // Find our USB device and prepare it for communication.
        //
        hUSB = InitializeDevice(BULK_VID, BULK_PID,
                                (LPGUID)&(GUID_DEVINTERFACE_LUMINARY_BULK),
                                &bDriverInstalled);
    
        if(hUSB)
        {
            //
            // Are we operating in echo mode or not? The "-e" parameter tells the
            // app to echo everything it receives back to the device unchanged.
            //
            if(bEcho)
            {
                //
                // Yes - we are in echo mode.
                //
                printf("Running in echo mode. Press Ctrl+C to exit.\n\n"
                    "Throughput:      0Kbps Packets:           0");
    
                while(1)
                {
                    //
                    // Read a packet of data from the device.
                    //
                    dwError = ReadUSBPacket(hUSB, szBuffer, ECHO_PACKET_SIZE, &ulRead,
                                            INFINITE, NULL);
    
                    if(dwError != ERROR_SUCCESS)
                    {
                        //
                        // We failed to read from the device.
                        //
                        printf("\n\nError %d (%S) reading from bulk IN pipe.\n", dwError,
                               GetSystemErrorString(dwError));
                        break;
                    }
                    else
                    {
                        //
                        // Update our byte and packet counters.
                        //
                        g_ulByteCount += ulRead;
                        g_ulPacketCount++;
    					szBuffer[ulRead] = '\0';
    
                        //printf("\nReturned string: \"%s\"\n", szBuffer);
                        //
                        // Write the data back out to the device.
                        //
    
    					//COMMENTED OUT FOR DEVICE TO HOST THROUGHPUT TEST!  NO ECHO BACK TO DEVICE!!
                        /*
    					bResult = WriteUSBPacket(hUSB, szBuffer, ulRead, &ulWritten);
                        if(!bResult)
                        {
                            //
                            // We failed to write the data for some reason.
                            //
                            dwError = GetLastError();
                            printf("\n\nError %d (%S) writing to bulk OUT pipe.\n", dwError,
                                   GetSystemErrorString(dwError));
                            break;
                        }
    					*/
    					//COMMENTED OUT FOR DEVICE TO HOST THROUGHPUT TEST!  NO ECHO BACK TO DEVICE!!
    
                        //
                        // Display the throughput.
                        //
                        UpdateThroughput();
                    }
                }
            }
            else
            {
                //
                // We are running in normal mode.  Keep sending and receiving
                // strings until the user indicates that it is time to exit.
                //
                while(1)
                {
    
                    //
                    // The device was found and successfully configured. Now get a string from
                    // the user...
                    //
                    do
                    {
                        printf("\nEnter a string (EXIT to exit): ");
                        fgets(szBuffer, MAX_ENTRY_LEN, stdin);
                        printf("\n");
    
                        //
                        // How many characters were entered (including the trailing '\n')?
                        //
                        ulLength = (ULONG)strlen(szBuffer);
    
                        if(ulLength <= 1)
                        {
                            //
                            // The string is either nothing at all or a single '\n' so reprompt the user.
                            //
                            printf("\nPlease enter some text.\n");
                            ulLength = 0;
                        }
                        else
                        {
                            //
                            // Get rid of the trailing '\n' if there is one there.
                            //
                            if(szBuffer[ulLength - 1] == '\n')
                            {
                                szBuffer[ulLength - 1] = '\0';
                                ulLength--;
                            }
                        }
                    }
                    while(ulLength == 0);
    
                    //
                    // Are we being asked to exit the application?
                    //
                    if(!(strcmp("EXIT", szBuffer)))
                    {
                        //
                        // Yes - drop out and exit.
                        //
                        printf("Exiting on user request.\n");
                        break;
                    }
    
                    //
                    // Write the user's string to the device.
                    //
                    bResult = WriteUSBPacket(hUSB, szBuffer, ulLength, &ulWritten);
                    if(!bResult)
                    {
                        //
                        // We failed to write the data for some reason.
                        //
                        dwError = GetLastError();
                        printf("Error %d (%S) writing to bulk OUT pipe.\n", dwError,
                               GetSystemErrorString(dwError));
                    }
                    else
                    {
                        //
                        // We wrote data successfully so now read it back.
                        //
                        printf("Wrote %d bytes to the device. Expected %d\n",
                               ulWritten, ulLength);
    
                        //
                        // We expect the same number of bytes as we just sent.
                        //
                        dwError = ReadUSBPacket(hUSB, szBuffer, ulWritten, &ulRead,
                                                INFINITE, NULL);
    
                        if(dwError != ERROR_SUCCESS)
                        {
                            //
                            // We failed to read from the device.
                            //
                            printf("Error %d (%S) reading from bulk IN pipe.\n", dwError,
                                   GetSystemErrorString(dwError));
                        }
                        else
                        {
                            //
                            // Add a string terminator to the returned data (this
                            // should already be there but, just in case...)
                            //
                            szBuffer[ulRead] = '\0';
    
                            printf("Read %d bytes from device. Expected %d\n",
                                   ulRead, ulWritten);
                            printf("\nReturned string: \"%s\"\n", szBuffer);
                        }
                    }
                }
            }
        }
        else
        {
            //
            // An error was reported while trying to connect to the device.
            //
            dwError = GetLastError();
    
            printf("\nUnable to initialize the Luminary Bulk USB Device.\n");
            printf("Error code is %d (%S)\n\n", dwError, GetSystemErrorString(dwError));
            printf("Please make sure you have a Luminary Stellaris USB-enabled\n");
            printf("evaluation or development kit running the usb_dev_bulk example\n");
            printf("application connected to this system via the \"USB OTG\" or\n");
            printf("\"USB DEVICE\" connectors. Once the device is connected, run\n");
            printf("this application again.\n\n");
    
            printf("\nPress \"Enter\" to exit: ");
            fgets(szBuffer, MAX_STRING_LEN, stdin);
            printf("\n");
            return(2);
        }
    
        TerminateDevice(hUSB);
    
        return(0);
    }
    

    //###########################################################################
    // FILE:   usb_dev_bulk.c
    // TITLE:  Main routines for the generic bulk device example.
    //###########################################################################
    // $TI Release: F28M3Xx Support Library v110 $
    // $Release Date: December 12, 2011 $
    //###########################################################################
    
    #include "F28x_Project.h"
    #include <stdbool.h>
    #include <stdint.h>
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "driverlib/debug.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/systick.h"
    #include "driverlib/uart.h"
    #include "driverlib/usb.h"
    #include "driverlib/usb_hal.h"
    #include "driverlib/rom.h"
    #include "usblib/usblib.h"
    #include "usblib/usb-ids.h"
    #include "usblib/device/usbdevice.h"
    #include "usblib/device/usbdbulk.h"
    #include "utils/uartstdio.h"
    #include "usb_bulk_structs.h"
    
    
    //*****************************************************************************
    //! \addtogroup cpu01_example_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 115,200,
    //! 8-N-1, is used to display messages from this application.
    //!
    //! A Windows INF file for the device is provided in ControlSUITE.  This
    //! INF contains information required to install the WinUSB subsystem on
    //! WindowsXP and Windows 7.  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
    //! F28X7x_common/tools/usb_bulk_example/Release.
    //*****************************************************************************
    
    //*****************************************************************************
    //
    // The system tick rate expressed both as ticks per second and a millisecond
    // period.
    //
    //*****************************************************************************
    #define SYSTICKS_PER_SECOND     100
    #define SYSTICK_PERIOD_MS       (1000 / SYSTICKS_PER_SECOND)
    
    //*****************************************************************************
    //
    // The global system tick counter.
    //
    //*****************************************************************************
    volatile uint32_t g_ui32SysTickCount = 0;
    
    //*****************************************************************************
    //
    // Variables tracking transmit and receive counts.
    //
    //*****************************************************************************
    volatile uint32_t g_ui32TxCount = 0;
    volatile uint32_t g_ui32RxCount = 0;
    #ifdef DEBUG
    uint32_t g_ui32UARTRxErrors = 0;
    #endif
    
    //*****************************************************************************
    //
    // The current USB operating mode - Host, Device or unknown.
    //
    //*****************************************************************************
    tUSBMode g_eCurrentUSBMode;
    
    //*****************************************************************************
    //
    // Debug-related definitions and declarations.
    //
    // Debug output is available via UART0 if DEBUG is defined during build.
    //
    //*****************************************************************************
    #ifdef DEBUG
    //*****************************************************************************
    //
    // Map all debug print calls to UARTprintf in debug builds.
    //
    //*****************************************************************************
    #define DEBUG_PRINT UARTprintf
    
    #else
    
    //*****************************************************************************
    //
    // Compile out all debug print calls in release builds.
    //
    //*****************************************************************************
    #define DEBUG_PRINT while(0) ((int32_t (*)(char *, ...))0)
    #endif
    
    //*****************************************************************************
    //
    // Flags used to pass commands from interrupt context to the main loop.
    //
    //*****************************************************************************
    #define COMMAND_PACKET_RECEIVED 0x00000001
    #define COMMAND_STATUS_UPDATE   0x00000002
    
    volatile uint32_t g_ui32Flags = 0;
    char *g_pcStatus;
    unsigned char g_bConnected = 0;
    
    //*****************************************************************************
    //
    // Global flag indicating that a USB configuration has been set.
    //
    //*****************************************************************************
    static volatile bool g_bUSBConfigured = false;
    
    unsigned char buffer[256];
    
    //*****************************************************************************
    //
    // The error routine that is called if the driver library encounters an error.
    //
    //*****************************************************************************
    #ifdef DEBUG
    void
    __error__(char *pcFilename, uint32_t ui32Line)
    {
        UARTprintf("Error at line %d of %s\n", ui32Line, pcFilename);
        while(1)
        {
        }
    }
    
    #endif
    
    //*****************************************************************************
    //
    // Interrupt handler for the system tick counter.
    //
    //*****************************************************************************
    __interrupt void
    SysTickIntHandler(void)
    {
        //
        // Update our system tick counter.
        //
        g_ui32SysTickCount++;
        PieCtrlRegs.PIEACK.all |= 1;
    }
    
    //*****************************************************************************
    //
    // Receive new data and echo it back to the host.
    //
    // \param psDevice points to the instance data for the device whose data is to
    // be processed.
    // \param pi8Data points to the newly received data in the USB receive buffer.
    // \param ui32NumBytes is the number of bytes of data available to be processed.
    //
    // This function is called whenever we receive a notification that data is
    // available from the host. We read the data, byte-by-byte and swap the case
    // of any alphabetical characters found then write it back out to be
    // transmitted back to the host.
    //
    // \return Returns the number of bytes of data processed.
    //
    //*****************************************************************************
    static uint32_t
    EchoNewDataToHost(tUSBDBulkDevice *psDevice, uint8_t *pi8Data,
                      uint_fast32_t ui32NumBytes)
    {
        uint_fast32_t ui32Loop, ui32Space, ui32Count;
        uint_fast32_t ui32ReadIndex;
        uint_fast32_t ui32WriteIndex;
        tUSBRingBufObject sTxRing;
    
        //
        // Get the current buffer information to allow us to write directly to
        // the transmit buffer (we already have enough information from the
        // parameters to access the receive buffer directly).
        //
        USBBufferInfoGet(&g_sTxBuffer, &sTxRing);
    
        //
        // How much space is there in the transmit buffer?
        //
        ui32Space = USBBufferSpaceAvailable(&g_sTxBuffer);
    
        //
        // How many characters can we process this time round?
        //
        ui32Loop = (ui32Space < ui32NumBytes) ? ui32Space : ui32NumBytes;
        ui32Count = ui32Loop;
    
        //
        // Update our receive counter.
        //
        g_ui32RxCount += ui32NumBytes;
    
        //
        // Dump a debug message.
        //
        DEBUG_PRINT("Received %d bytes\n", ui32NumBytes);
    
        //
        // Set up to process the characters by directly accessing the USB buffers.
        //
        ui32ReadIndex = (uint32_t)(pi8Data - g_pui8USBRxBuffer);
        ui32WriteIndex = sTxRing.ui32WriteIndex;
    
        while(ui32Loop)
        {
            //
            // Copy from the receive buffer to the transmit buffer converting
            // character case on the way.
            //
    
            //
            // Is this a lower case character?
            //
            if((g_pui8USBRxBuffer[ui32ReadIndex] >= 'a') &&
               (g_pui8USBRxBuffer[ui32ReadIndex] <= 'z'))
            {
                //
                // Convert to upper case and write to the transmit buffer.
                //
                g_pui8USBTxBuffer[ui32WriteIndex] =
                    (g_pui8USBRxBuffer[ui32ReadIndex] - 'a') + 'A';
            }
            else
            {
                //
                // Is this an upper case character?
                //
                if((g_pui8USBRxBuffer[ui32ReadIndex] >= 'A') &&
                   (g_pui8USBRxBuffer[ui32ReadIndex] <= 'Z'))
                {
                    //
                    // Convert to lower case and write to the transmit buffer.
                    //
                    g_pui8USBTxBuffer[ui32WriteIndex] =
                        (g_pui8USBRxBuffer[ui32ReadIndex] - 'Z') + 'z';
                }
                else
                {
                    //
                    // Copy the received character to the transmit buffer.
                    //
                    g_pui8USBTxBuffer[ui32WriteIndex] =
                        g_pui8USBRxBuffer[ui32ReadIndex];
                }
            }
    
            //
            // Move to the next character taking care to adjust the pointer for
            // the buffer wrap if necessary.
            //
            ui32WriteIndex++;
            ui32WriteIndex =
                (ui32WriteIndex == BULK_BUFFER_SIZE) ? 0 : ui32WriteIndex;
    
            ui32ReadIndex++;
            ui32ReadIndex = (ui32ReadIndex == BULK_BUFFER_SIZE) ? 0 : ui32ReadIndex;
    
            ui32Loop--;
        }
    
        //
        // We've processed the data in place so now send the processed data
        // back to the host.
        //
        USBBufferDataWritten(&g_sTxBuffer, ui32Count);
    
        DEBUG_PRINT("Wrote %d bytes\n", ui32Count);
    
        //
        // We processed as much data as we can directly from the receive buffer so
        // we need to return the number of bytes to allow the lower layer to
        // update its read pointer appropriately.
        //
        return(ui32Count);
    }
    
    //*****************************************************************************
    //
    // 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 we are being notified about.
    // \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)
    {
    	uint32_t ui32Space;
        //
        // We are not required to do anything in response to any transmit event
        // in this example. All we do is update our transmit counter.
        //
        if(ui32Event == USB_EVENT_TX_COMPLETE)
        {
    //        g_ui32TxCount += ui32MsgValue;
    		ui32Space = USBDBulkTxPacketAvailable(&g_sBulkDevice);
    
    		if(ui32Space)
    			USBDBulkPacketWrite(&g_sBulkDevice, buffer, ui32Space, true);
        }
    
        //
        // Dump a debug message.
        //
    //    DEBUG_PRINT("TX complete %d\n", 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 we are being notified about.
    // \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 are we being sent?
        //
        switch(ui32Event)
        {
            //
            // We are connected to a host and communication is now possible.
            //
        case USB_EVENT_CONNECTED:
        {
            g_bUSBConfigured = true;
                g_pcStatus = "Host connected.";
                g_ui32Flags |= COMMAND_STATUS_UPDATE;
    
                //
            // Flush our buffers.
                //
    //        USBBufferFlush(&g_sTxBuffer);
    //        USBBufferFlush(&g_sRxBuffer);
            g_bConnected = true;
    
            break;
        }
    
            //
        // The host has disconnected.
            //
        case USB_EVENT_DISCONNECTED:
        {
            g_bUSBConfigured = false;
                g_pcStatus = "Host disconn.";
                g_ui32Flags |= COMMAND_STATUS_UPDATE;
                g_bConnected = 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);
    }
    
    #ifdef DEBUG
    //*****************************************************************************
    //
    // Configure the UART and its pins.  This must be called before UARTprintf().
    //
    //*****************************************************************************
    void
    ConfigureUART(void)
    {
        //
        // Enable UART0
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_SCI1);
    
        //
        // Configure GPIO Pins for UART mode.
        //
        EALLOW;
        GpioCtrlRegs.GPAMUX2.bit.GPIO28 = 1;
        GpioCtrlRegs.GPAPUD.bit.GPIO28 = 0;
        GpioCtrlRegs.GPAQSEL2.bit.GPIO28 = 3;
        GpioCtrlRegs.GPADIR.bit.GPIO28 = 0;
    
        GpioCtrlRegs.GPAMUX2.bit.GPIO29 = 1;
        GpioCtrlRegs.GPAPUD.bit.GPIO29 = 0;
        GpioCtrlRegs.GPADIR.bit.GPIO29 = 1;
        EDIS;
    
        //
        // Initialize the UART for console I/O.
        //
        UARTStdioConfig(0, 115200, SysCtlLowSpeedClockGet(SYSTEM_CLOCK_SPEED));
    
    }
    #endif
    
    //*****************************************************************************
    //
    // 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;
    
    }
    
    //*****************************************************************************
    //
    // This is the main application entry function.
    //
    //*****************************************************************************
    int
    main(void)
    {
    	unsigned char index, firstPacket;
    	unsigned long ui32Space;
    
    	firstPacket = 1;
    
    	for(index = 0; index < 256; index++){
    		buffer[index] = index;
    	}
    
    #ifdef _FLASH
    // Copy time critical code and Flash setup code to RAM
    // This includes the following functions:  InitFlash();
    // The  RamfuncsLoadStart, RamfuncsLoadSize, and RamfuncsRunStart
    // symbols are created by the linker. Refer to the device .cmd file.
        memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize);
    #endif
        //
        // Set the clocking to run from the PLL at 50MHz
        //
        SysCtlClockSet(SYSCTL_OSCSRC_XTAL | SYSCTL_PLL_ENABLE | SYSCTL_IMULT(20) | SYSCTL_SYSDIV(2));
        SysCtlAuxClockSet(SYSCTL_OSCSRC_XTAL | SYSCTL_PLL_ENABLE | SYSCTL_IMULT(12) | SYSCTL_SYSDIV(4));
    
    
    #ifdef _FLASH
    // Call Flash Initialization to setup flash waitstates
    // This function must reside in RAM
        InitFlash();
    #endif
    
        //
        // Initialize interrupt controller and vector table
        //
        InitPieCtrl();
        InitPieVectTable();
    
    #ifdef DEBUG
        //
        // Configure the UART for debug output.
        //
        ConfigureUART();
    #endif
    
        //
        // Not configured initially.
        //
        g_bUSBConfigured = false;
    
        //
        // Enable the GPIO peripheral used for USB, and configure the USB
        // pins.
        //
        USBGPIOEnable();
        USBIntRegister(USB0_BASE, f28x_USB0DeviceIntHandler);
    
        //
        // Enable the system tick.
        //
    //    SysTickInit();
    //    SysTickPeriodSet(SysCtlClockGet(SYSTEM_CLOCK_SPEED) / SYSTICKS_PER_SECOND);
    //    SysTickIntRegister(SysTickIntHandler);
    //    SysTickIntEnable();
    //    SysTickEnable();
    
        //
        // Show the application name on the display and UART output.
        //
        DEBUG_PRINT("\nC2000 F2837x Series USB bulk device example\n");
        DEBUG_PRINT("---------------------------------\n\n");
    
        //
        // Initialize the transmit and receive buffers.
        //
    //    USBBufferInit(&g_sTxBuffer);
    //    USBBufferInit(&g_sRxBuffer);
        
        USBStackModeSet(0, eUSBModeForceDevice, ModeCallback);
    
        //
        // Pass our device information to the USB library and place the device
        // on the bus.
        //
        USBDBulkInit(0, &g_sBulkDevice);
    
        //
        // Enable global interrupts
        //
        IntMasterEnable();
    
        //
        // Main application loop.
        //
        while(1)
        {
        	//
        	// Nothing to do...everything happens in the interrupt context.
        	//
        	if(g_bConnected)
        	{
    			//
    			// How much space is there in the transmit buffer?
    			//
        		if(firstPacket)
        		{
    				ui32Space = USBDBulkTxPacketAvailable(&g_sBulkDevice);
    
    				if(ui32Space)
    					USBDBulkPacketWrite(&g_sBulkDevice, buffer, ui32Space, true);
    
    				firstPacket = 0;
        		}
    
    //			USBEndpointDataPut(USB0_BASE, USB_EP_1, buffer, 64);
    //			USBEndpointDataSend(USB0_BASE, USB_EP_1, USB_TRANS_IN);
        	}
        }
    }
    

    sal