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.

EK-TM4C1294XL: USB DFU

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

I am trying to get the steps down for using the DFU. I tried the following:

1. Start with project boot_serial

2. Enable USB update define statements in bl_config.h

3. Build project and flash into EK-TM4C1294XL

4. dfuprog -m switches to dfu mode

5. dfuprog -e displayed only one device in DFU mode

6. dfuprog -I deviceNum -f program.bin -a 0x1800 works both from command line and LM Flash programmer

In the device manager, the Stellaris COM port is not seen any more. What went wrong?

If I try to change the jumper to OTG mode and connect the USB cable to USB port U7, I don't see any COM port either.

I appreciate help getting the correct sequence down. I want to be able to enter and exit DFU mode when needed and also be able to use the Stellaris ICDI when needed.

Thanks,

Priya

  • Hello Priya,

    In the device manager, the Stellaris COM port is not seen any more. What went wrong?

    It sounds like programmed the ICDI MCU instead of your intended target. 

    4. dfuprog -m switches to dfu mode

    5. dfuprog -e displayed only one device in DFU mode

    If step 4 was dfuprog -i index -m then you did these steps in reverse:

    //! To illustrate runtime DFU capability, use the <tt>dfuprog</tt> tool which
    //! is part of the Tiva Windows USB Examples package (SW-USB-win-xxxx.msi)
    //! Assuming this package is installed in the default location, the
    //! <tt>dfuprog</tt> executable can be found in the
    //! <tt>C:/Program Files/Texas Instruments/Tiva/usb_examples</tt> or 
    //! <tt>C:/Program Files (x86)/Texas Instruments/Tiva/usb_examples</tt>
    //! directory.
    //!
    //! With the device connected to your PC and the device driver installed, enter
    //! the following command to enumerate DFU devices:
    //!
    //! <tt>dfuprog -e</tt>
    //!
    //! This will list all DFU-capable devices found and you should see that you
    //! have one or two devices available which are in ``Runtime'' mode.
    //!
    //! *** IMPORTANT - PLEASE READ ***
    //! If you see two devices, it is strongly recommended that you disconnect
    //! ICDI debug port from the PC, and change the POWER_SELECT jumper (JP1) 
    //! from 'ICDI' to 'OTG' in order to power the LaunchPad from the USB
    //! OTG port. The reason for this is that the ICDI chip on the board is
    //! a DFU-capable TM4C129x device, and if not careful, the firmware on the
    //! ICDI chip could be accidently erased which can not restored easily.
    //! As a result, debug capabilities would be lost!
    //! *** IMPORTANT - PLEASE READ ***
    //!
    //! If IDCI debug port is disconnected from your PC, you should see only one
    //! device from above command, and its index should be 0, and should be named
    //! as ``Mouse with Device Firmware Upgrade''. 
    //! If for any reason you need to keep the ICDI port connected, the above
    //! command should show two devices. The second device is probably named as
    //! ``In-Circuit Debug interface'', and we need to be careful not to update
    //! the firmware on that device. So please take careful note of the index for
    //! the device ``Mouse with Device Firmware Upgrade'', it could be 0 or 1, we
    //! will need this index number for the following command. 
    //! Entering the following command will switch this device into DFU mode and
    //! leave it ready to receive a new firmware image:
    //!
    //! <tt>dfuprog -i index -m</tt>
    //!
    //! After entering this command, you should notice that the device disconnects
    //! from the USB bus and reconnects again.  Running ``<tt>dfuprog -e</tt>'' a
    //! second time will show that the device is now in DFU mode and ready to
    //! receive downloads.  At this point, either LM Flash Programmer or dfuprog
    //! may be used to send a new application binary to the device.

    If I try to change the jumper to OTG mode and connect the USB cable to USB port U7, I don't see any COM port either.

    Plug your ICDI cable to the DEBUG side of the board, use LM Flash Programmer and go to Other Utilities and then in the bottom portion of this tab you will see a button underneath ICDI Firmware Update. Click that Update button to restore the ICDI.

    I appreciate help getting the correct sequence down. I want to be able to enter and exit DFU mode when needed and also be able to use the Stellaris ICDI when needed.

    Follow the sequence I posted above which comes from our boot_demo_usb example and you should be fine. Though one more thing:

    6. dfuprog -I deviceNum -f program.bin -a 0x1800 works both from command line and LM Flash programmer

    For TM4C129x that should be 0x4000 as that is the minimum size of Flash block in the MCU. 0x1800 is for TM4C123x MCUs.

  • For clarity can you post a list of steps in the correct sequence?

  • Hello Priya,

    I did - please read through the code block on my post. That is the full sequence including how to avoid triggering DFU on the ICDI.

  • Here is what I tried. I get an error at the end of file download. What does this mean?

    EK-TM4C1294 XL Steps for USB DFU

    1. Start with project boot_serial
    2. Enable USB update define statements in bl_config.h
    3. Build project and flash into EK-TM4C1294XL
    4. dfuprog -e Confirm only one device is displayed in DFU mode
    5. dfuprog -m switches to dfu mode
    6. dfuprog -i deviceNum -f program.bin -a 0x4000 works both from command line and LM Flash programmer

     

    What does Error DFU_ERR_UNKNOWN (-4) reported during file download mean?

    To switch to ICDI mode, LM flash programmer other utilities update ICDI firmware works.

  • Hello Priya,

    I followed those steps but with one modification for Step 5:

    dfuprog -i 1 -m

    You should use dfuprog -i for the the -m commands.

    But aside from that change I did every step you did and it worked for me.

    I am not sure exactly what is triggering the DFU_ERR_UNKNOWN (-4)... usually that means the USB interface isn't available like the device is unresponsive for some reason. If you didn't do the -i on your dfuprog -m, you may have triggered the ICDI to go into boot mode again?

  • I flash bootserial into the EK. When I type dfuprog -e only one device shows up which is the ICDI interface, please see the capture pasted below. So when I am switching to bootloader mode, is it the ICDI that is entering bootloader? How do I access the other USB device if it is not listed with an index?

    I am hesitant to try a another new EK before I understand this clearly.

    Thanks,

    Priya


    USB Device Firmware Upgrade Example
    Copyright (c) 2008-2017 Texas Instruments Incorporated. All rights reserved.

    Scanning USB buses for supported DFU devices...


    <<<< Device 0 >>>>

    VID: 0x1cbe PID: 0x00fd
    Device Name: In-Circuit Debug Interface
    Manufacturer: Texas Instruments
    DFU Interface: <<Unknown>>
    Serial Num: 0F00D8DC
    Max Transfer: 1024 bytes
    Mode: Runtime
    Attributes:
    Will Detach: Yes
    Manifest Tolerant: Yes
    Upload Capable: Yes
    Download Capable: Yes

    Found 1 device.

  • Hello Priya,

    Do you have a USB cable plugged into the Target USB port opposite from the Debug port?

    If you only see one device then that is an issue for sure, there needs to be either two devices or if only one device, then it should not be the ICDI - which would be the case if you plugged in the USB cable to the Target USB port and changed the power jumper for the LaunchPad to be powered from OTG instead of ICDI.

  • The only cable I have is plugged in is the debug USB port. I have not changed jumper settings to OTG. I am seeing only one device after flashing boot serial which is the ICDI. 

    At one point, I have tried using the target USB with the OTG jumper, but then the device manager does not recognize this target USB port.

  • Hello Priya,

    USB DFU only works from Target USB port. It is impossible to get it to work from ICDI port.

    Do you have two cables? Can you connect both ports?

    If not, you will need to change back and forth.

    Device manager should recognize it if you setup the project correctly. Have you installed the latest drivers from TivaWare 2.2.0.295? You may need to be manually update the driver in Device Manager.

    Can you post your bl_config.h file? I can review it. Post the file as an attachment if possible since it is so long, thanks!

  • 6562.bl_config.h

    bl_config.h attached. I will get another cable and try.

    The COM port on the target USB port is not seen in the device manager or in dfuprog. Something must be missing from my config file. 

    Thanks,

    Priya

  • Hello Priya,

    Your bl_config has some errors which is why the port enumerate.

    1) Don't enable the USB_MUX features, comment those all out.

    2) You have the wrong port selected here:

    //#define USB_DP_PORT            GPIO_PORTL_BASE            // For EK-TM4C1294XL
    #define USB_DP_PORT            GPIO_PORTD_BASE            // For EK-TM4C1294XL

    Port D is for EK-TM4C123GXL.

    I am attaching my bl_config for EK-TM4C1294XL I used to do USB DFU for this post:

    3630.bl_config.h

  • Thank you for the corrected config file. I am still seeing only the ICDI interface when I flash boot_serial. I have 2 USB cables hooked up to the EK. I don't have the OTG jumper selected. There must be more to setting up the config file. 

  • Hello Priya,

    What are you seeing in device manager? Do you have a USB port that could not enumerate anywhere?

  • I continue to see only the ICDI as an USB device. I don't yet see the target USB. Device manager screenshot attached.

  • Hello Priya,

    Did you use my exact config file or try and pull in the changes? I tested again and I see the DFU interface show up.

    Is the target device for your boot_serial project the TM4C1294NCPDT?

    What shows up if you use dfuprog -e?

    Can you try programming this binary file which I confirmed works on my hardware?

    7024.boot_serial.bin

  • With the bin file you sent, I can see two USB devices and program a bin file with DFU. After this, I went back to the boot serial I have and the device manager now shows what is attached.

    I tried updating windows drivers in the tivaware2.2.0.295 windows drivers, maybe there is another patch I need to run?

    Or if you can export your boot_serial project for EK-TM4C1294XL, I will work with it.

    Thanks,

    Priya

  • Ralph,

    Please let me know what I can do if I get the unknown device descriptor displayed. I erased and re-imported the project to my workspace, I updated the driver, I uninstalled the unknown USB device and scanned for hardware changes. It is still showing up as unknown USB device. I need to be able to compile and download the boot_serial in my setup. Thanks.

  • Hello Priya,

    When you tried to update driver, did you go into properties of the Unknown device, go under Drivers, select "Update Driver" and then manually browsed your computer to point to the TivaWare windows_drivers folder?

    Right now boot_serial is likely working and the issue is with enumeration.

  • Yes and the message I get when I do this is best drivers for this device are already installed. 

    What are strategies to fix enumeration problems?

  • Hi Priya,

    Gonna take a long shot attempt here but try the drivers here: http://software-dl.ti.com/tiva-c/SW-TM4C/latest/exports/SW-TM4C-2.1.4.178.PATCH-1.0.zip

    If that doesn't work I'd suggest trying a different USB cable followed by trying to restart your PC.

    I have seen faulty USB cables cause enumeration issues before (and some of those were cables that came with the LaunchPad kit)

  • Ralph,

    I tried everything-- uninstalling unknown device, restarting PC, applying the patch with a brand new EK. I have spent a fortune on Tiva 1294 Eks....... Still the enumeration is failing. Can you please help here? I don't know what else to try.

    Thanks,

    Priya

  • Hi Priya,

    Sorry you have had such troubles with this. Were all those tests using the binary I sent?

    I ask because I was looking through possible issues and one other USB DFU issue with TM4C1294 EK was reported but it shouldn't impact the .bin file I sent. In any case, you should make this update on your end.

    In bl_usbfuncs.c, find Line 619 and replace the existing line of:

    HWREG(USB0_BASE + USB_O_CC) = (USB_CC_CLKEN | (7 << USB_CC_CLKDIV_S));

    With the following line of:

    HWREG(USB0_BASE + USB_O_CC) = (USB_CC_CLKEN | (3 << USB_CC_CLKDIV_S));

    If you were using your own project, then try and re-compile and re-load with that because it address an issue with the USB clock configuration for the Flash boot loader.

    One other issue I see which may impact you that isn't resolved on my .bin file is that in bl_config, the Flash Page Size is not set right. It should be:

    #define FLASH_PAGE_SIZE         0x00004000

    I am attaching a new binary with that resolved:

    2806.boot_serial.bin

  • I am still trying to get the boot_serial build on my workspace to work. I changed the USB clock and the flash page size. Device manager still says unknown USB device (invalid configurations descriptor this time). The bin files from you work OK. Can you provide an exported project for EK-TM4C1294 XL?

    I used the exact bl_config.h file that you sent.

    Thanks,

    Priya

  • Hello Priya,

    Find the CCS project attached: 3276.boot_serial.zip

    You will still need to make the change I outlined in bl_usbfuncs.c.

  • thank you for the project. The project would not import into ccs 10.2. (red x) It did import into ccs 9.2. I made the change to usbfuncs.c, built and flashed it. USB device still shows as unknown, invalid configuration descriptor. I also tried flashing the bin file in the debug folder of your project and I am getting the same error. same result with two EKs. (different USB cables). Maybe I need to try a different laptop. Sorry for being impossible with my replies.

    Although the two earlier bootserial bin files you gave me work fine.

    Attached is the USB tree view of the failed enumeration.

    invalidConfiguration.txt
      =========================== USB Port1 ===========================
    
    Connection Status        : 0x02 (Device failed enumeration)
    Port Chain               : 1-1
    Properties               : 0x01
     IsUserConnectable       : yes
     PortIsDebugCapable      : no
     PortHasMultiCompanions  : no
     PortConnectorIsTypeC    : no
    ConnectionIndex          : 0x01 (Port 1)
    CompanionIndex           : 0
     CompanionHubSymLnk      : USB#ROOT_HUB30#4&ddd72e7&0&0#{f18a0e88-c30c-11d0-8815-00a0c906bed8}
     CompanionPortNumber     : 0x11 (Port 17)
     -> CompanionPortChain   : 1-17
    
          ========================== Summary =========================
    Vendor ID                : 0x0000 (USB Implementers Forum)
    Product ID               : 0x0000
    USB version              : 1.10
    Port maximum Speed       : High-Speed (Companion Port 1-17 supports SuperSpeed)
    Device maximum Speed     : Full-Speed
    Device Connection Speed  : Full-Speed
    Device Manager Problem   : 43 (CM_PROB_FAILED_POST_START)
    Used Endpoints           : 1
    
          ======================== USB Device ========================
    
            +++++++++++++++++ Device Information ++++++++++++++++++
    Device Description       : Unknown USB Device (Invalid Configuration Descriptor)
    Device ID                : USB\VID_0000&PID_0006\5&2F869293&0&1
    Hardware IDs             : USB\CONFIGURATION_DESCRIPTOR_VALIDATION_FAILURE
    Driver KeyName           : {36fc9e60-c465-11cf-8056-444553540000}\0038 (GUID_DEVCLASS_USB)
    Driver Inf               : C:\WINDOWS\inf\usb.inf
    Legacy BusType           : PNPBus
    Class                    : USB
    Class GUID               : {36fc9e60-c465-11cf-8056-444553540000} (GUID_DEVCLASS_USB)
    Enumerator               : USB
    PDO                      : \Device\USBPDO-10
    Location Info            : Port_#0001.Hub_#0001
    Manufacturer Info        : (Standard USB Host Controller)
    Capabilities             : 0x64 (Removable, SilentInstall, RawDeviceOK)
    Status                   : 0x01806400 (DN_HAS_PROBLEM, DN_DISABLEABLE, DN_REMOVABLE, DN_NT_ENUMERATOR, DN_NT_DRIVER)
    Problem Code             : 43 (CM_PROB_FAILED_POST_START)
    Address                  : 1
    HcDisableSelectiveSuspend: 0
    EnableSelectiveSuspend   : 0
    SelectiveSuspendEnabled  : 0
    EnhancedPowerMgmtEnabled : 0
    IdleInWorkingState       : 0
    WakeFromSleepState       : 0
    Power State              : D3 (supported: D0, D3, wake from D0)
    
            ---------------- Connection Information ---------------
    Connection Index         : 0x01 (Port 1)
    Connection Status        : 0x02 (DeviceFailedEnumeration)
    Current Config Value     : 0x00 (Configuration 0)
    Device Address           : 0x3E (62)
    Is Hub                   : 0x00 (no)
    Device Bus Speed         : 0x01 (Full-Speed)
    Number Of Open Pipes     : 0x00 (0 pipes to data endpoints)
    Data (HexDump)           : 01 00 00 00 12 01 10 01 FF 00 00 40 00 00 00 00   ...........@....
                               00 00 01 02 03 01 00 01 00 3E 00 00 00 00 00 02   .........>......
                               00 00 00                                          ...
    
            --------------- Connection Information V2 -------------
    Connection Index         : 0x01 (1)
    Length                   : 0x10 (16 bytes)
    SupportedUsbProtocols    : 0x03
     Usb110                  : 1 (yes, port supports USB 1.1)
     Usb200                  : 1 (yes, port supports USB 2.0)
     Usb300                  : 0 (no, port not supports USB 3.0) -> but Companion Port 1-17 does
     ReservedMBZ             : 0x00
    Flags                    : 0x00
     DevIsOpAtSsOrHigher     : 0 (Device is not operating at SuperSpeed or higher)
     DevIsSsCapOrHigher      : 0 (Device is not SuperSpeed capable or higher)
     DevIsOpAtSsPlusOrHigher : 0 (Device is not operating at SuperSpeedPlus or higher)
     DevIsSsPlusCapOrHigher  : 0 (Device is not SuperSpeedPlus capable or higher)
     ReservedMBZ             : 0x00
    Data (HexDump)           : 01 00 00 00 10 00 00 00 03 00 00 00 00 00 00 00   ................
    
        ---------------------- Device Descriptor ----------------------
    bLength                  : 0x12 (18 bytes)
    bDescriptorType          : 0x01 (Device Descriptor)
    bcdUSB                   : 0x110 (USB Version 1.10)
    bDeviceClass             : 0xFF (Vendor Specific)
    bDeviceSubClass          : 0x00
    bDeviceProtocol          : 0x00
    bMaxPacketSize0          : 0x40 (64 bytes)
    idVendor                 : 0x0000 (USB Implementers Forum)
    idProduct                : 0x0000
    bcdDevice                : 0x0000
    iManufacturer            : 0x01 (String Descriptor 1)
    iProduct                 : 0x02 (String Descriptor 2)
    iSerialNumber            : 0x03 (String Descriptor 3)
    bNumConfigurations       : 0x01 (1 Configuration)
    Data (HexDump)           : 12 01 10 01 FF 00 00 40 00 00 00 00 00 00 01 02   .......@........
                               03 01                                             ..
    
          -------------------- String Descriptors -------------------
    String descriptors are not available  (because the device has problem code CM_PROB_FAILED_POST_START)
    

  • Hi Priya,

    What version TivaWare do you have right now? 2.2.0 or 2.1.4?

    I think the bin I sent before came from 2.1.4 because I still had it handy from before.

    The project I sent is from 2.2.0.

    Let me attach another bin here that I verified on my PC and is from 2.2.0: 1185.boot_serial.bin

  • The project you sent me uses tivaware 2.2.0. I have this on my computer. But I don't know why the project you sent gives me an enumeration error. The pre-compiled bin files usually don't have issues, I need a project that I can build and enumerate.

  • Hi Priya,

    So to be clear...

    The boot_serial zip file does not work for you but the boot_serial.bin file from 4/14 works?

    If so then you probably don't have the bl_usbfuncs.c file saved correctly in TivaWare 2.2.0.295.

    I will attach mine here: 

    bl_usbfuncs.c
    //*****************************************************************************
    //
    // bl_usbfuncs.c - The subset of USB library functions required by the USB DFU
    //                 boot loader.
    //
    // Copyright (c) 2008-2020 Texas Instruments Incorporated.  All rights reserved.
    // Software License Agreement
    // 
    // Texas Instruments (TI) is supplying this software for use solely and
    // exclusively on TI's microcontroller products. The software is owned by
    // TI and/or its suppliers, and is protected under applicable copyright
    // laws. You may not combine this software with "viral" open-source
    // software in order to form a larger program.
    // 
    // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
    // 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. TI SHALL NOT, UNDER ANY
    // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
    // DAMAGES, FOR ANY REASON WHATSOEVER.
    // 
    // This is part of revision 2.2.0.295 of the Tiva Firmware Development Package.
    //
    //*****************************************************************************
    
    #include <stdbool.h>
    #include <stdint.h>
    #include "inc/hw_types.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_usb.h"
    #include "inc/hw_sysctl.h"
    #include "inc/hw_nvic.h"
    #include "inc/hw_ints.h"
    #include "inc/hw_gpio.h"
    #include "bl_config.h"
    #include "boot_loader/bl_usbfuncs.h"
    
    //*****************************************************************************
    //
    //! \addtogroup bl_usb_api
    //! @{
    //
    //*****************************************************************************
    #if defined(USB_ENABLE_UPDATE) || defined(DOXYGEN)
    
    //*****************************************************************************
    //
    // Local functions prototypes.
    //
    //*****************************************************************************
    static void USBDGetStatus(tUSBRequest *pUSBRequest);
    static void USBDClearFeature(tUSBRequest *pUSBRequest);
    static void USBDSetFeature(tUSBRequest *pUSBRequest);
    static void USBDSetAddress(tUSBRequest *pUSBRequest);
    static void USBDGetDescriptor(tUSBRequest *pUSBRequest);
    static void USBDSetDescriptor(tUSBRequest *pUSBRequest);
    static void USBDGetConfiguration(tUSBRequest *pUSBRequest);
    static void USBDSetConfiguration(tUSBRequest *pUSBRequest);
    static void USBDGetInterface(tUSBRequest *pUSBRequest);
    static void USBDSetInterface(tUSBRequest *pUSBRequest);
    static void USBDEP0StateTx(void);
    static int32_t USBDStringIndexFromRequest(uint16_t ui16Lang,
                                              uint16_t ui16Index);
    
    //*****************************************************************************
    //
    // This structure holds the full state for the device enumeration.
    //
    //*****************************************************************************
    typedef struct
    {
        //
        // The devices current address, this also has a change pending bit in the
        // MSB of this value specified by DEV_ADDR_PENDING.
        //
        volatile uint32_t ui32DevAddress;
    
        //
        // This holds the current active configuration for this device.
        //
        uint32_t ui32Configuration;
    
        //
        // This holds the current alternate interface for this device. We only have
        // 1 interface so only need to hold 1 setting.
        //
        uint8_t ui8AltSetting;
    
        //
        // This is the pointer to the current data being sent out or received
        // on endpoint zero.
        //
        uint8_t *pui8EP0Data;
    
        //
        // This is the number of bytes that remain to be sent from or received
        // into the g_sUSBDeviceState.pui8EP0Data data buffer.
        //
        volatile uint32_t ui32EP0DataRemain;
    
        //
        // The amount of data being sent/received due to a custom request.
        //
        uint32_t ui32OUTDataSize;
    
        //
        // Holds the current device status.
        //
        uint8_t ui8Status;
    
        //
        // This flag indicates whether or not remote wakeup signalling is in
        // progress.
        //
        bool bRemoteWakeup;
    
        //
        // During remote wakeup signalling, this counter is used to track the
        // number of milliseconds since the signalling was initiated.
        //
        uint8_t ui8RemoteWakeupCount;
    }
    tDeviceState;
    
    //*****************************************************************************
    //
    // The states for endpoint zero during enumeration.
    //
    //*****************************************************************************
    typedef enum
    {
        //
        // The USB device is waiting on a request from the host controller on
        // endpoint zero.
        //
        USB_STATE_IDLE,
    
        //
        // The USB device is sending data back to the host due to an IN request.
        //
        USB_STATE_TX,
    
        //
        // The USB device is receiving data from the host due to an OUT
        // request from the host.
        //
        USB_STATE_RX,
    
        //
        // The USB device has completed the IN or OUT request and is now waiting
        // for the host to acknowledge the end of the IN/OUT transaction.  This
        // is the status phase for a USB control transaction.
        //
        USB_STATE_STATUS,
    
        //
        // This endpoint has signaled a stall condition and is waiting for the
        // stall to be acknowledged by the host controller.
        //
        USB_STATE_STALL
    }
    tEP0State;
    
    //*****************************************************************************
    //
    // Define the max packet size for endpoint zero.
    //
    //*****************************************************************************
    #define EP0_MAX_PACKET_SIZE     64
    
    //*****************************************************************************
    //
    // This is a flag used with g_sUSBDeviceState.ui32DevAddress to indicate that a
    // device address change is pending.
    //
    //*****************************************************************************
    #define DEV_ADDR_PENDING        0x80000000
    
    //*****************************************************************************
    //
    // This label defines the default configuration number to use after a bus
    // reset.
    //
    //*****************************************************************************
    #define DEFAULT_CONFIG_ID       1
    
    //*****************************************************************************
    //
    // This label defines the number of milliseconds that the remote wakeup signal
    // must remain asserted before removing it. Section 7.1.7.7 of the USB 2.0 spec
    // states that "the remote wakeup device must hold the resume signaling for at
    // least 1ms but for no more than 15ms" so 10mS seems a reasonable choice.
    //
    //*****************************************************************************
    #define REMOTE_WAKEUP_PULSE_MS 10
    
    //*****************************************************************************
    //
    // This label defines the number of milliseconds between the point where we
    // assert the remote wakeup signal and calling the client back to tell it that
    // bus operation has been resumed.  This value is based on the timings provided
    // in section 7.1.7.7 of the USB 2.0 specification which indicates that the host
    // (which takes over resume signalling when the device's initial signal is
    // detected) must hold the resume signalling for at least 20mS.
    //
    //*****************************************************************************
    #define REMOTE_WAKEUP_READY_MS 20
    
    //*****************************************************************************
    //
    // The buffer for reading data coming into EP0
    //
    //*****************************************************************************
    static uint8_t g_pui8DataBufferIn[EP0_MAX_PACKET_SIZE];
    
    //*****************************************************************************
    //
    // This global holds the current state information for the USB device.
    //
    //*****************************************************************************
    static volatile tDeviceState g_sUSBDeviceState;
    
    //*****************************************************************************
    //
    // This global holds the current state of endpoint zero.
    //
    //*****************************************************************************
    static volatile tEP0State g_eUSBDEP0State = USB_STATE_IDLE;
    
    //*****************************************************************************
    //
    // Function table to handle standard requests.
    //
    //*****************************************************************************
    static const tStdRequest g_ppfnUSBDStdRequests[] =
    {
        USBDGetStatus,
        USBDClearFeature,
        0,
        USBDSetFeature,
        0,
        USBDSetAddress,
        USBDGetDescriptor,
        USBDSetDescriptor,
        USBDGetConfiguration,
        USBDSetConfiguration,
        USBDGetInterface,
        USBDSetInterface,
    };
    
    //*****************************************************************************
    //
    // Amount to shift the RX interrupt sources by in the flags used in the
    // interrupt calls.
    //
    //*****************************************************************************
    #define USB_INT_RX_SHIFT        8
    
    //*****************************************************************************
    //
    // Amount to shift the status interrupt sources by in the flags used in the
    // interrupt calls.
    //
    //*****************************************************************************
    #define USB_INT_STATUS_SHIFT    24
    
    //*****************************************************************************
    //
    // Amount to shift the RX endpoint status sources by in the flags used in the
    // calls.
    //
    //*****************************************************************************
    #define USB_RX_EPSTATUS_SHIFT   16
    
    //*****************************************************************************
    //
    // Converts from an endpoint specifier to the offset of the endpoint's
    // control/status registers.
    //
    //*****************************************************************************
    #define EP_OFFSET(Endpoint)     (Endpoint - 0x10)
    
    //*****************************************************************************
    //
    // Retrieves data from endpoint 0's FIFO.
    //
    // \param pui8Data is a pointer to the data area used to return the data from
    // the FIFO.
    // \param pui32Size is initially the size of the buffer passed into this call
    // via the \e pui8Data parameter.  It will be set to the amount of data
    // returned in the buffer.
    //
    // This function will return the data from the FIFO for endpoint 0.
    // The \e pui32Size parameter should indicate the size of the buffer passed in
    // the \e pui32Data parameter.  The data in the \e pui32Size parameter will be
    // changed to match the amount of data returned in the \e pui8Data parameter.
    // If a zero byte packet was received this call will not return a error but
    // will instead just return a zero in the \e pui32Size parameter.  The only
    // error case occurs when there is no data packet available.
    //
    // \return This call will return 0, or -1 if no packet was received.
    //
    //*****************************************************************************
    int32_t
    USBEndpoint0DataGet(uint8_t *pui8Data, uint32_t *pui32Size)
    {
        uint32_t ui32ByteCount;
    
        //
        // Don't allow reading of data if the RxPktRdy bit is not set.
        //
        if((HWREGH(USB0_BASE + USB_O_CSRL0) & USB_CSRL0_RXRDY) == 0)
        {
            //
            // Can't read the data because none is available.
            //
            *pui32Size = 0;
    
            //
            // Return a failure since there is no data to read.
            //
            return(-1);
        }
    
        //
        // Get the byte count in the FIFO.
        //
        ui32ByteCount = HWREGH(USB0_BASE + USB_O_COUNT0 + USB_EP_0);
    
        //
        // Determine how many bytes we will actually copy.
        //
        ui32ByteCount = (ui32ByteCount < *pui32Size) ? ui32ByteCount : *pui32Size;
    
        //
        // Return the number of bytes we are going to read.
        //
        *pui32Size = ui32ByteCount;
    
        //
        // Read the data out of the FIFO.
        //
        for(; ui32ByteCount > 0; ui32ByteCount--)
        {
            //
            // Read a byte at a time from the FIFO.
            //
            *pui8Data++ = HWREGB(USB0_BASE + USB_O_FIFO0 + (USB_EP_0 >> 2));
        }
    
        //
        // Success.
        //
        return(0);
    }
    
    //*****************************************************************************
    //
    // Acknowledge that data was read from endpoint 0's FIFO.
    //
    // \param bIsLastPacket indicates if this is the last packet.
    //
    // This function acknowledges that the data was read from the endpoint 0's
    // FIFO.  The \e bIsLastPacket parameter is set to a \b true value if this is
    // the last in a series of data packets.  This call can be used if processing
    // is required between reading the data and acknowledging that the data has
    // been read.
    //
    // \return None.
    //
    //*****************************************************************************
    void
    USBDevEndpoint0DataAck(bool bIsLastPacket)
    {
        //
        // Clear RxPktRdy, and optionally DataEnd, on endpoint zero.
        //
        HWREGB(USB0_BASE + USB_O_CSRL0) =
            USB_CSRL0_RXRDYC | (bIsLastPacket ? USB_CSRL0_DATAEND : 0);
    
    }
    
    //*****************************************************************************
    //
    // Puts data into endpoint 0's FIFO.
    //
    // \param pui8Data is a pointer to the data area used as the source for the
    // data to put into the FIFO.
    // \param ui32Size is the amount of data to put into the FIFO.
    //
    // This function will put the data from the \e pui8Data parameter into the FIFO
    // for endpoint 0.  If a packet is already pending for transmission then
    // this call will not put any of the data into the FIFO and will return -1.
    //
    // \return This call will return 0 on success, or -1 to indicate that the FIFO
    // is in use and cannot be written.
    //
    //*****************************************************************************
    int32_t
    USBEndpoint0DataPut(uint8_t *pui8Data, uint32_t ui32Size)
    {
        //
        // Don't allow transmit of data if the TxPktRdy bit is already set.
        //
        if(HWREGB(USB0_BASE + USB_O_CSRL0 + USB_EP_0) & USB_CSRL0_TXRDY)
        {
            return(-1);
        }
    
        //
        // Write the data to the FIFO.
        //
        for(; ui32Size > 0; ui32Size--)
        {
            HWREGB(USB0_BASE + USB_O_FIFO0 + (USB_EP_0 >> 2)) = *pui8Data++;
        }
    
        //
        // Success.
        //
        return(0);
    }
    
    //*****************************************************************************
    //
    // Starts the transfer of data from endpoint 0's FIFO.
    //
    // \param ui32TransType is set to indicate what type of data is being sent.
    //
    // This function will start the transfer of data from the FIFO for
    // endpoint 0.  This is necessary if the \b USB_EP_AUTO_SET bit was not enabled
    // for the endpoint.  Setting the \e ui32TransType parameter will allow the
    // appropriate signaling on the USB bus for the type of transaction being
    // requested.  The \e ui32TransType parameter should be one of the following:
    //
    // - USB_TRANS_OUT for OUT transaction on any endpoint in host mode.
    // - USB_TRANS_IN for IN transaction on any endpoint in device mode.
    // - USB_TRANS_IN_LAST for the last IN transactions on endpoint zero in a
    //   sequence of IN transactions.
    // - USB_TRANS_SETUP for setup transactions on endpoint zero.
    // - USB_TRANS_STATUS for status results on endpoint zero.
    //
    // \return This call will return 0 on success, or -1 if a transmission is
    // already in progress.
    //
    //*****************************************************************************
    int32_t
    USBEndpoint0DataSend(uint32_t ui32TransType)
    {
        //
        // Don't allow transmit of data if the TxPktRdy bit is already set.
        //
        if(HWREGB(USB0_BASE + USB_O_CSRL0 + USB_EP_0) & USB_CSRL0_TXRDY)
        {
            return(-1);
        }
    
        //
        // Set TxPktRdy in order to send the data.
        //
        HWREGB(USB0_BASE + USB_O_CSRL0 + USB_EP_0) = ui32TransType & 0xff;
    
        //
        // Success.
        //
        return(0);
    }
    
    #if defined(USB_VBUS_CONFIG) || defined(USB_ID_CONFIG) || \
        defined(USB_DP_CONFIG) || defined(USB_DM_CONFIG) || defined(DOXYGEN)
    //*****************************************************************************
    //
    //! Initialize the pins used by USB functions.
    //!
    //! This function configures the pins for USB functions depending on defines
    //! from the bl_config.h file.
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    USBConfigurePins(void)
    {
        //
        // Enable the clocks to the GPIOs.
        //
        HWREG(SYSCTL_RCGCGPIO) |=
            (0x0 |
    #if defined(USB_VBUS_CONFIG)
             USB_VBUS_PERIPH |
    #endif
    #if defined(USB_ID_CONFIG)
             USB_ID_PERIPH |
    #endif
    #if defined(USB_DP_CONFIG)
             USB_DP_PERIPH |
    #endif
    #if defined(USB_DM_CONFIG)
             USB_DM_PERIPH
    #endif
            );
    
        //
        // Wait for the Peripherals to be Ready before accessing the register
        // address space.
        //
        while((HWREG(SYSCTL_PRGPIO) &
              (0x0 |
    #if defined(USB_VBUS_CONFIG)
               USB_VBUS_PERIPH |
    #endif
    #if defined(USB_ID_CONFIG)
               USB_ID_PERIPH |
    #endif
    #if defined(USB_DP_CONFIG)
               USB_DP_PERIPH |
    #endif
    #if defined(USB_DM_CONFIG)
               USB_DM_PERIPH
    #endif
            )) !=
                (0x0 |
    #if defined(USB_VBUS_CONFIG)
                 USB_VBUS_PERIPH |
    #endif
    #if defined(USB_ID_CONFIG)
                 USB_ID_PERIPH |
    #endif
    #if defined(USB_DP_CONFIG)
                 USB_DP_PERIPH |
    #endif
    #if defined(USB_DM_CONFIG)
                 USB_DM_PERIPH
    #endif
                ));
    
        // 
        // Setup the pins based on bl_config.h
        //
    #if defined(USB_VBUS_CONFIG)
        //
        // Set the VBUS pin to be an analog input.
        // 
        HWREG(USB_VBUS_PORT + GPIO_O_DIR) &= ~(1 << USB_VBUS_PIN);
        HWREG(USB_VBUS_PORT + GPIO_O_AMSEL) |= (1 << USB_VBUS_PIN);
    #endif
    
    #if defined(USB_ID_CONFIG)
        //
        // Set the ID pin to be an analog input.
        // 
        HWREG(USB_ID_PORT + GPIO_O_DIR) &= ~(1 << USB_ID_PIN);
        HWREG(USB_ID_PORT + GPIO_O_AMSEL) |= (1 << USB_ID_PIN);
    #endif
        
    #if defined(USB_DP_CONFIG)
        //
        // Set the DP pin to be an analog input.
        // 
        HWREG(USB_DP_PORT + GPIO_O_DIR) &= ~(1 << USB_DP_PIN);
        HWREG(USB_DP_PORT + GPIO_O_AMSEL) |= (1 << USB_DP_PIN);
    #endif
    
    #if defined(USB_DM_CONFIG)
        //
        // Set the DM pin to be an analog input.
        // 
        HWREG(USB_DM_PORT + GPIO_O_DIR) &= ~(1 << USB_DM_PIN);
        HWREG(USB_DM_PORT + GPIO_O_AMSEL) |= (1 << USB_DM_PIN);
    #endif
    
    }
    #endif
    
    //*****************************************************************************
    //
    //! Initialize the boot loader USB functions.
    //!
    //! This function initializes the boot loader USB functions and places the DFU
    //! device onto the USB bus.
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    USBBLInit(void)
    {
        //
        // Configure the USB Pins based on the bl_config.h settings.
        //
    #if defined(USB_VBUS_CONFIG) || defined(USB_ID_CONFIG) || \
        defined(USB_DP_CONFIG) || defined(USB_DM_CONFIG)
        USBConfigurePins();
    #endif
    
        //
        // Initialize a couple of fields in the device state structure.
        //
        g_sUSBDeviceState.ui32Configuration = DEFAULT_CONFIG_ID;
    
        //
        // Enable the USB controller.
        //
        HWREG(SYSCTL_RCGCUSB) = SYSCTL_RCGCUSB_R0;
    
        //
        // Wait for the peripheral ready
        //
        while((HWREG(SYSCTL_PRUSB) & SYSCTL_PRUSB_R0) != SYSCTL_PRUSB_R0)
        {
        }
    
    #if defined(TARGET_IS_TM4C129_RA0) ||                                         \
        defined(TARGET_IS_TM4C129_RA1) ||                                         \
        defined(TARGET_IS_TM4C129_RA2)
        //
        // Turn on USB Phy clock from PLL VCO
        //
        HWREG(USB0_BASE + USB_O_CC) = (USB_CC_CLKEN | (3 << USB_CC_CLKDIV_S));
    #else
        //
        // Turn on USB Phy clock.
        //
        HWREG(SYSCTL_RCC2) &= ~SYSCTL_RCC2_USBPWRDN;
    #endif
    
        //
        // Clear any pending interrupts.
        //
        HWREGH(USB0_BASE + USB_O_TXIS);
        HWREGB(USB0_BASE + USB_O_IS);
    
        //
        // Enable USB Interrupts.
        //
        HWREGH(USB0_BASE + USB_O_TXIE) = USB_TXIS_EP0;
        HWREGB(USB0_BASE + USB_O_IE) = (USB_IS_DISCON | USB_IS_RESET);
    
        //
        // Default to the state where remote wakeup is disabled.
        //
        g_sUSBDeviceState.ui8Status = 0;
        g_sUSBDeviceState.bRemoteWakeup = false;
    
        //
        // Determine the self- or bus-powered state based on bl_config.h setting.
        //
    #if USB_BUS_POWERED
        g_sUSBDeviceState.ui8Status &= ~USB_STATUS_SELF_PWR;
    #else
        g_sUSBDeviceState.ui8Status |= USB_STATUS_SELF_PWR;
    #endif
    
        //
        // Attach the device using the soft connect.
        //
        HWREGB(USB0_BASE + USB_O_POWER) |= USB_POWER_SOFTCONN;
    
        //
        // Enable the USB interrupt.
        //
        HWREG(NVIC_EN1) = 1 << (INT_USB0 - 48);
    }
    
    //*****************************************************************************
    //
    // This function starts the request for data from the host on endpoint zero.
    //
    // \param pui8Data is a pointer to the buffer to fill with data from the USB
    // host.
    // \param ui32Size is the size of the buffer or data to return from the USB
    // host.
    //
    // This function handles retrieving data from the host when a custom command
    // has been issued on endpoint zero.  When the requested data is received,
    // the function HandleEP0Data() will be called.
    //
    // \return None.
    //
    //*****************************************************************************
    void
    USBBLRequestDataEP0(uint8_t *pui8Data, uint32_t ui32Size)
    {
        //
        // Enter the RX state on end point 0.
        //
        g_eUSBDEP0State = USB_STATE_RX;
    
        //
        // Save the pointer to the data.
        //
        g_sUSBDeviceState.pui8EP0Data = pui8Data;
    
        //
        // Location to save the current number of bytes received.
        //
        g_sUSBDeviceState.ui32OUTDataSize = ui32Size;
    
        //
        // Bytes remaining to be received.
        //
        g_sUSBDeviceState.ui32EP0DataRemain = ui32Size;
    }
    
    //*****************************************************************************
    //
    //! This function requests transfer of data to the host on endpoint zero.
    //!
    //! \param pui8Data is a pointer to the buffer to send via endpoint zero.
    //! \param ui32Size is the amount of data to send in bytes.
    //!
    //! This function handles sending data to the host when a custom command is
    //! issued or non-standard descriptor has been requested on endpoint zero.
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    USBBLSendDataEP0(uint8_t *pui8Data, uint32_t ui32Size)
    {
        //
        // Return the externally provided device descriptor.
        //
        g_sUSBDeviceState.pui8EP0Data = pui8Data;
    
        //
        // The size of the device descriptor is in the first byte.
        //
        g_sUSBDeviceState.ui32EP0DataRemain = ui32Size;
    
        //
        // Save the total size of the data sent.
        //
        g_sUSBDeviceState.ui32OUTDataSize = ui32Size;
    
        //
        // Now in the transmit data state.
        //
        USBDEP0StateTx();
    }
    
    //*****************************************************************************
    //
    //! This function generates a stall condition on endpoint zero.
    //!
    //! This function is typically called to signal an error condition to the host
    //! when an unsupported request is received by the device.  It should be
    //! called from within the callback itself (in interrupt context) and not
    //! deferred until later since it affects the operation of the endpoint zero
    //! state machine.
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    USBBLStallEP0(void)
    {
        //
        // Perform a stall on endpoint zero.
        //
        HWREGB(USB0_BASE + USB_O_CSRL0) |= (USB_CSRL0_STALL | USB_CSRL0_RXRDYC);
    
        //
        // Enter the stalled state.
        //
        g_eUSBDEP0State = USB_STATE_STALL;
    }
    
    //*****************************************************************************
    //
    // This internal function reads a request data packet and dispatches it to
    // either a standard request handler or the registered device request
    // callback depending upon the request type.
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDReadAndDispatchRequest(void)
    {
        uint32_t ui32Size;
        tUSBRequest *pRequest;
    
        //
        // Cast the buffer to a request structure.
        //
        pRequest = (tUSBRequest *)g_pui8DataBufferIn;
    
        //
        // Set the buffer size.
        //
        ui32Size = EP0_MAX_PACKET_SIZE;
    
        //
        // Get the data from the USB controller end point 0.
        //
        USBEndpoint0DataGet(g_pui8DataBufferIn, &ui32Size);
    
        if(!ui32Size)
        {
            return;
        }
    
        //
        // See if this is a standard request or not.
        //
        if((pRequest->bmRequestType & USB_RTYPE_TYPE_M) != USB_RTYPE_STANDARD)
        {
            //
            // Pass this non-standard request on to the DFU handler
            //
            HandleRequests(pRequest);
        }
        else
        {
            //
            // Assure that the jump table is not out of bounds.
            //
            if((pRequest->bRequest <
                (sizeof(g_ppfnUSBDStdRequests) / sizeof(tStdRequest))) &&
               (g_ppfnUSBDStdRequests[pRequest->bRequest] != 0))
            {
                //
                // Jump table to the appropriate handler.
                //
                g_ppfnUSBDStdRequests[pRequest->bRequest](pRequest);
            }
            else
            {
                //
                // If there is no handler then stall this request.
                //
                USBBLStallEP0();
            }
        }
    }
    
    //*****************************************************************************
    //
    // This is the low level interrupt handler for endpoint zero.
    //
    // This function handles all interrupts on endpoint zero in order to maintain
    // the state needed for the control endpoint on endpoint zero.  In order to
    // successfully enumerate and handle all USB standard requests, all requests
    // on endpoint zero must pass through this function.  The endpoint has the
    // following states: \b USB_STATE_IDLE, \b USB_STATE_TX, \b USB_STATE_RX,
    // \b USB_STATE_STALL, and \b USB_STATE_STATUS.  In the \b USB_STATE_IDLE
    // state the USB controller has not received the start of a request, and once
    // it does receive the data for the request it will either enter the
    // \b USB_STATE_TX, \b USB_STATE_RX, or \b USB_STATE_STALL depending on the
    // command.  If the controller enters the \b USB_STATE_TX or \b USB_STATE_RX
    // then once all data has been sent or received, it must pass through the
    // \b USB_STATE_STATUS state to allow the host to acknowledge completion of
    // the request.  The \b USB_STATE_STALL is entered from \b USB_STATE_IDLE in
    // the event that the USB request was not valid.  Both the \b USB_STATE_STALL
    // and \b USB_STATE_STATUS are transitional states that return to the
    // \b USB_STATE_IDLE state.
    //
    // \return None.
    //
    // USB_STATE_IDLE -*--> USB_STATE_TX -*-> USB_STATE_STATUS -*->USB_STATE_IDLE
    //                 |                  |                     |
    //                 |--> USB_STATE_RX -                      |
    //                 |                                        |
    //                 |--> USB_STATE_STALL ---------->---------
    //
    //  ----------------------------------------------------------------
    // | Current State       | State 0           | State 1              |
    // | --------------------|-------------------|----------------------
    // | USB_STATE_IDLE      | USB_STATE_TX/RX   | USB_STATE_STALL      |
    // | USB_STATE_TX        | USB_STATE_STATUS  |                      |
    // | USB_STATE_RX        | USB_STATE_STATUS  |                      |
    // | USB_STATE_STATUS    | USB_STATE_IDLE    |                      |
    // | USB_STATE_STALL     | USB_STATE_IDLE    |                      |
    //  ----------------------------------------------------------------
    //
    //*****************************************************************************
    void
    USBDeviceEnumHandler(void)
    {
        uint32_t ui32EPStatus;
    
        //
        // Get the TX portion of the endpoint status.
        //
        ui32EPStatus = HWREGH(USB0_BASE + EP_OFFSET(USB_EP_0) + USB_O_TXCSRL1);
    
        //
        // Get the RX portion of the endpoint status.
        //
        ui32EPStatus |=
            ((HWREGH(USB0_BASE + EP_OFFSET(USB_EP_0) + USB_O_RXCSRL1)) <<
             USB_RX_EPSTATUS_SHIFT);
    
        //
        // What state are we currently in?
        //
        switch(g_eUSBDEP0State)
        {
            //
            // Handle the status state, this is a transitory state from
            // USB_STATE_TX or USB_STATE_RX back to USB_STATE_IDLE.
            //
            case USB_STATE_STATUS:
            {
                //
                // Just go back to the idle state.
                //
                g_eUSBDEP0State = USB_STATE_IDLE;
    
                //
                // If there is a pending address change then set the address.
                //
                if(g_sUSBDeviceState.ui32DevAddress & DEV_ADDR_PENDING)
                {
                    //
                    // Clear the pending address change and set the address.
                    //
                    g_sUSBDeviceState.ui32DevAddress &= ~DEV_ADDR_PENDING;
                    HWREGB(USB0_BASE + USB_O_FADDR) =
                        (uint8_t)g_sUSBDeviceState.ui32DevAddress;
                }
    
                //
                // If a new packet is already pending, we need to read it
                // and handle whatever request it contains.
                //
                if(ui32EPStatus & USB_DEV_EP0_OUT_PKTRDY)
                {
                    //
                    // Process the newly arrived packet.
                    //
                    USBDReadAndDispatchRequest();
                }
                break;
            }
    
            //
            // In the IDLE state the code is waiting to receive data from the host.
            //
            case USB_STATE_IDLE:
            {
                //
                // Is there a packet waiting for us?
                //
                if(ui32EPStatus & USB_DEV_EP0_OUT_PKTRDY)
                {
                    //
                    // Yes - process it.
                    //
                    USBDReadAndDispatchRequest();
                }
                break;
            }
    
            //
            // Data is still being sent to the host so handle this in the
            // EP0StateTx() function.
            //
            case USB_STATE_TX:
            {
                USBDEP0StateTx();
                break;
            }
    
            //
            // Handle the receive state for commands that are receiving data on
            // endpoint zero.
            //
            case USB_STATE_RX:
            {
                uint32_t ui32DataSize;
    
                //
                // Set the number of bytes to get out of this next packet.
                //
                if(g_sUSBDeviceState.ui32EP0DataRemain > EP0_MAX_PACKET_SIZE)
                {
                    //
                    // Don't send more than EP0_MAX_PACKET_SIZE bytes.
                    //
                    ui32DataSize = EP0_MAX_PACKET_SIZE;
                }
                else
                {
                    //
                    // There was space so send the remaining bytes.
                    //
                    ui32DataSize = g_sUSBDeviceState.ui32EP0DataRemain;
                }
    
                //
                // Get the data from the USB controller end point 0.
                //
                USBEndpoint0DataGet(g_sUSBDeviceState.pui8EP0Data, &ui32DataSize);
    
                //
                // If there we not more that EP0_MAX_PACKET_SIZE or more bytes
                // remaining then this transfer is complete.  If there were exactly
                // EP0_MAX_PACKET_SIZE remaining then there still needs to be
                // null packet sent before this is complete.
                //
                if(g_sUSBDeviceState.ui32EP0DataRemain < EP0_MAX_PACKET_SIZE)
                {
                    //
                    // Need to ack the data on end point 0 in this case
                    // without setting data end.
                    //
                    USBDevEndpoint0DataAck(true);
    
                    //
                    // Return to the idle state.
                    //
                    g_eUSBDEP0State =  USB_STATE_IDLE;
    
                    //
                    // If there is a receive callback then call it.
                    //
                    if(g_sUSBDeviceState.ui32OUTDataSize != 0)
                    {
                        //
                        // Call the receive handler to handle the data
                        // that was received.
                        //
                        HandleEP0Data(g_sUSBDeviceState.ui32OUTDataSize);
    
                        //
                        // Indicate that there is no longer any data being waited
                        // on.
                        //
                        g_sUSBDeviceState.ui32OUTDataSize = 0;
                    }
                }
                else
                {
                    //
                    // Need to ack the data on end point 0 in this case
                    // without setting data end.
                    //
                    USBDevEndpoint0DataAck(false);
                }
    
                //
                // Advance the pointer.
                //
                g_sUSBDeviceState.pui8EP0Data += ui32DataSize;
    
                //
                // Decrement the number of bytes that are being waited on.
                //
                g_sUSBDeviceState.ui32EP0DataRemain -= ui32DataSize;
    
                break;
            }
            //
            // The device stalled endpoint zero so check if the stall needs to be
            // cleared once it has been successfully sent.
            //
            case USB_STATE_STALL:
            {
                //
                // If we sent a stall then acknowledge this interrupt.
                //
                if(ui32EPStatus & USB_DEV_EP0_SENT_STALL)
                {
                    //
                    // Clear the stall condition.
                    //
                    HWREGB(USB0_BASE + USB_O_CSRL0) &= ~(USB_DEV_EP0_SENT_STALL);
    
                    //
                    // Reset the global end point 0 state to IDLE.
                    //
                    g_eUSBDEP0State = USB_STATE_IDLE;
    
                }
                break;
            }
            //
            // Halt on an unknown state, but only in DEBUG mode builds.
            //
            default:
            {
    #ifdef DEBUG
                while(1);
    #endif
                break;
            }
        }
    }
    
    //*****************************************************************************
    //
    // This function handles bus reset notifications.
    //
    // This function is called from the low level USB interrupt handler whenever
    // a bus reset is detected.  It performs tidy-up as required and resets the
    // configuration back to defaults in preparation for descriptor queries from
    // the host.
    //
    // \return None.
    //
    //*****************************************************************************
    void
    USBDeviceEnumResetHandler(void)
    {
        //
        // Disable remote wakeup signalling (as per USB 2.0 spec 9.1.1.6).
        //
        g_sUSBDeviceState.ui8Status &= ~USB_STATUS_REMOTE_WAKE;
        g_sUSBDeviceState.bRemoteWakeup = false;
    
        //
        // Call the device dependent code to indicate a bus reset has occurred.
        //
        HandleReset();
    
        //
        // Reset the default configuration identifier and alternate function
        // selections.
        //
        g_sUSBDeviceState.ui32Configuration = DEFAULT_CONFIG_ID;
        g_sUSBDeviceState.ui8AltSetting = 0;
    }
    
    //*****************************************************************************
    //
    // This function handles the GET_STATUS standard USB request.
    //
    // \param pUSBRequest holds the request type and endpoint number if endpoint
    // status is requested.
    //
    // This function handles responses to a Get Status request from the host
    // controller.  A status request can be for the device, an interface or an
    // endpoint.  If any other type of request is made this function will cause
    // a stall condition to indicate that the command is not supported.  The
    // \e pUSBRequest structure holds the type of the request in the
    // bmRequestType field.  If the type indicates that this is a request for an
    // endpoint's status, then the wIndex field holds the endpoint number.
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDGetStatus(tUSBRequest *pUSBRequest)
    {
        uint16_t ui16Data;
    
        //
        // Determine what type of status was requested.
        //
        switch(pUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M)
        {
            //
            // This was a Device Status request.
            //
            case USB_RTYPE_DEVICE:
            {
                //
                // Return the current status for the device.
                //
                ui16Data = g_sUSBDeviceState.ui8Status;
    
                break;
            }
    
            //
            // This was a Interface status request.
            //
            case USB_RTYPE_INTERFACE:
            {
                //
                // Interface status always returns 0.
                //
                ui16Data = 0;
    
                break;
            }
    
            //
            // This was an unknown request or a request for an endpoint (of which
            // we have none) so set a stall.
            //
            case USB_RTYPE_ENDPOINT:
            default:
            {
                //
                // Anything else causes a stall condition to indicate that the
                // command was not supported.
                //
                USBBLStallEP0();
                return;
            }
        }
    
        //
        // Send the two byte status response.
        //
        g_sUSBDeviceState.ui32EP0DataRemain = 2;
        g_sUSBDeviceState.pui8EP0Data = (uint8_t *)&ui16Data;
    
        //
        // Send the response.
        //
        USBDEP0StateTx();
    }
    
    //*****************************************************************************
    //
    // This function handles the CLEAR_FEATURE standard USB request.
    //
    // \param pUSBRequest holds the options for the Clear Feature USB request.
    //
    // This function handles device or endpoint clear feature requests.  The
    // \e pUSBRequest structure holds the type of the request in the bmRequestType
    // field and the feature is held in the wValue field.  For device, the only
    // clearable feature is the Remote Wake feature.  This device request
    // should only be made if the descriptor indicates that Remote Wake is
    // implemented by the device.  For endpoint requests the only clearable
    // feature is the ability to clear a halt on a given endpoint.  If any other
    // requests are made, then the device will stall the request to indicate to
    // the host that the command was not supported.
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDClearFeature(tUSBRequest *pUSBRequest)
    {
        //
        // Determine what type of status was requested.
        //
        switch(pUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M)
        {
            //
            // This is a clear feature request at the device level.
            //
            case USB_RTYPE_DEVICE:
            {
                //
                // Only remote wake is clearable by this function.
                //
                if(USB_FEATURE_REMOTE_WAKE & pUSBRequest->wValue)
                {
                    //
                    // Clear the remote wake up state.
                    //
                    g_sUSBDeviceState.ui8Status &= ~USB_STATUS_REMOTE_WAKE;
    
                    //
                    // Need to ack the data on end point 0.
                    //
                    USBDevEndpoint0DataAck(true);
                }
                else
                {
                    USBBLStallEP0();
                }
                break;
            }
    
            //
            // This is an unknown request or one destined for an invalid endpoint.
            //
            case USB_RTYPE_ENDPOINT:
            default:
            {
                USBBLStallEP0();
                return;
            }
        }
    }
    
    //*****************************************************************************
    //
    // This function handles the SET_FEATURE standard USB request.
    //
    // \param pUSBRequest holds the feature in the wValue field of the USB
    // request.
    //
    // This function handles device or endpoint set feature requests.  The
    // \e pUSBRequest structure holds the type of the request in the bmRequestType
    // field and the feature is held in the wValue field.  For device, the only
    // settable feature is the Remote Wake feature.  This device request
    // should only be made if the descriptor indicates that Remote Wake is
    // implemented by the device.  For endpoint requests the only settable feature
    // is the ability to issue a halt on a given endpoint.  If any other requests
    // are made, then the device will stall the request to indicate to the host
    // that the command was not supported.
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDSetFeature(tUSBRequest *pUSBRequest)
    {
        //
        // Determine what type of status was requested.
        //
        switch(pUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M)
        {
            //
            // This is a set feature request at the device level.
            //
            case USB_RTYPE_DEVICE:
            {
                //
                // Only remote wake is setable by this function.
                //
                if(USB_FEATURE_REMOTE_WAKE & pUSBRequest->wValue)
                {
                    //
                    // Set the remote wakeup state.
                    //
                    g_sUSBDeviceState.ui8Status |= USB_STATUS_REMOTE_WAKE;
    
                    //
                    // Need to ack the data on end point 0.
                    //
                    USBDevEndpoint0DataAck(true);
                }
                else
                {
                    USBBLStallEP0();
                }
                break;
            }
    
            //
            // This is an unknown request or one destined for an invalid endpoint.
            //
            case USB_RTYPE_ENDPOINT:
            default:
            {
                USBBLStallEP0();
                return;
            }
        }
    }
    
    //*****************************************************************************
    //
    // This function handles the SET_ADDRESS standard USB request.
    //
    // \param pUSBRequest holds the new address to use in the wValue field of the
    // USB request.
    //
    // This function is called to handle the change of address request from the
    // host controller.  This can only start the sequence as the host must
    // acknowledge that the device has changed address.  Thus this function sets
    // the address change as pending until the status phase of the request has
    // been completed successfully.  This prevents the devices address from
    // changing and not properly responding to the status phase.
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDSetAddress(tUSBRequest *pUSBRequest)
    {
        //
        // The data needs to be acknowledged on end point 0 without setting data
        // end because there is no data coming.
        //
        USBDevEndpoint0DataAck(true);
    
        //
        // Save the device address as we cannot change address until the status
        // phase is complete.
        //
        g_sUSBDeviceState.ui32DevAddress = pUSBRequest->wValue | DEV_ADDR_PENDING;
    
        //
        // Transition directly to the status state since there is no data phase
        // for this request.
        //
        g_eUSBDEP0State = USB_STATE_STATUS;
    
        //
        // Clear the DFU status just in case we were in an error state last time
        // the device was accessed and we were unplugged and replugged (for a self-
        // powered implementation, of course).
        //
        HandleSetAddress();
    }
    
    //*****************************************************************************
    //
    // This function handles the GET_DESCRIPTOR standard USB request.
    //
    // \param pUSBRequest holds the data for this request.
    //
    // This function will return all configured standard USB descriptors to the
    // host - device, config and string descriptors.  Any request for a descriptor
    // which is not available will result in endpoint 0 being stalled.
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDGetDescriptor(tUSBRequest *pUSBRequest)
    {
        uint32_t ui32Stall;
    
        //
        // Default to no stall.
        //
        ui32Stall = 0;
    
        //
        // Which descriptor are we being asked for?
        //
        switch(pUSBRequest->wValue >> 8)
        {
            //
            // This request was for a device descriptor.
            //
            case USB_DTYPE_DEVICE:
            {
                //
                // Return the externally provided device descriptor.
                //
                g_sUSBDeviceState.pui8EP0Data =
                    (uint8_t *)g_pui8DFUDeviceDescriptor;
    
                //
                // The size of the device descriptor is in the first byte.
                //
                g_sUSBDeviceState.ui32EP0DataRemain =
                    g_pui8DFUDeviceDescriptor[0];
                break;
            }
    
            //
            // This request was for a configuration descriptor.
            //
            case USB_DTYPE_CONFIGURATION:
            {
                uint8_t ui8Index;
    
                //
                // Which configuration are we being asked for?
                //
                ui8Index = (uint8_t)(pUSBRequest->wValue & 0xFF);
    
                //
                // Is this valid?
                //
                if(ui8Index != 0)
                {
                    //
                    // This is an invalid configuration index.  Stall EP0 to
                    // indicate a request error.
                    //
                    USBBLStallEP0();
                    g_sUSBDeviceState.pui8EP0Data = 0;
                    g_sUSBDeviceState.ui32EP0DataRemain = 0;
                }
                else
                {
                    //
                    // Start by sending data from the beginning of the first
                    // descriptor.
                    //
    
                    g_sUSBDeviceState.pui8EP0Data =
                        (uint8_t *)g_pui8DFUConfigDescriptor;
    
                    //
                    // Get the size of the config descriptor (remembering that in
                    // this case, we only have a single section)
                    //
                    g_sUSBDeviceState.ui32EP0DataRemain =
                        *(uint16_t *)&(g_pui8DFUConfigDescriptor[2]);
                }
                break;
            }
    
            //
            // This request was for a string descriptor.
            //
            case USB_DTYPE_STRING:
            {
                int32_t i32Index;
    
                //
                // Determine the correct descriptor index based on the requested
                // language ID and index.
                //
                i32Index = USBDStringIndexFromRequest(pUSBRequest->wIndex,
                                                      pUSBRequest->wValue & 0xFF);
    
                //
                // If the mapping function returned -1 then stall the request to
                // indicate that the request was not valid.
                //
                if(i32Index == -1)
                {
                    USBBLStallEP0();
                    break;
                }
    
                //
                // Return the externally specified configuration descriptor.
                //
                g_sUSBDeviceState.pui8EP0Data =
                    (uint8_t *)g_ppui8StringDescriptors[i32Index];
    
                //
                // The total size of a string descriptor is in byte 0.
                //
                g_sUSBDeviceState.ui32EP0DataRemain =
                    g_ppui8StringDescriptors[i32Index][0];
    
                break;
            }
    
            //
            // Any other request is not handled by the default enumeration handler
            // so see if it needs to be passed on to another handler.
            //
            default:
            {
                //
                // All other requests are not handled.
                //
                USBBLStallEP0();
                ui32Stall = 1;
                break;
            }
        }
    
        //
        // If there was no stall, ACK the data and see if data needs to be sent.
        //
        if(ui32Stall == 0)
        {
            //
            // Need to ack the data on end point 0 in this case without
            // setting data end.
            //
            USBDevEndpoint0DataAck(false);
    
            //
            // If this request has data to send, then send it.
            //
            if(g_sUSBDeviceState.pui8EP0Data)
            {
                //
                // If there is more data to send than is requested then just
                // send the requested amount of data.
                //
                if(g_sUSBDeviceState.ui32EP0DataRemain > pUSBRequest->wLength)
                {
                    g_sUSBDeviceState.ui32EP0DataRemain = pUSBRequest->wLength;
                }
    
                //
                // Now in the transmit data state.  Be careful to call the correct
                // function since we need to handle the config descriptor
                // differently from the others.
                //
                USBDEP0StateTx();
            }
        }
    }
    
    //*****************************************************************************
    //
    // This function determines which string descriptor to send to satisfy a
    // request for a given index and language.
    //
    // \param ui16Lang is the requested string language ID.
    // \param ui16Index is the requested string descriptor index.
    //
    // When a string descriptor is requested, the host provides a language ID and
    // index to identify the string ("give me string number 5 in French").  This
    // function maps these two parameters to an index within our device's string
    // descriptor array which is arranged as multiple groups of strings with
    // one group for each language advertised via string descriptor 0.
    //
    // We assume that there are an equal number of strings per language and
    // that the first descriptor is the language descriptor and use this fact to
    // perform the mapping.
    //
    // \return The index of the string descriptor to return or -1 if the string
    // could not be found.
    //
    //*****************************************************************************
    static int32_t
    USBDStringIndexFromRequest(uint16_t ui16Lang, uint16_t ui16Index)
    {
        tString0Descriptor *pLang;
        uint32_t ui32NumLangs;
        uint32_t ui32NumStringsPerLang;
        uint32_t ui32Loop;
    
        //
        // First look for the trivial case where descriptor 0 is being
        // requested.  This is the special case since descriptor 0 contains the
        // language codes supported by the device.
        //
        if(ui16Index == 0)
        {
            return(0);
        }
    
        //
        // How many languages does this device support?  This is determined by
        // looking at the length of the first descriptor in the string table,
        // subtracting 2 for the header and dividing by two (the size of each
        // language code).
        //
        ui32NumLangs = (g_ppui8StringDescriptors[0][0] - 2) / 2;
    
        //
        // We assume that the table includes the same number of strings for each
        // supported language.  We know the number of entries in the string table,
        // so how many are there for each language?  This may seem an odd way to
        // do this (why not just have the application tell us in the device info
        // structure?) but it's needed since we didn't want to change the API
        // after the first release which did not support multiple languages.
        //
        ui32NumStringsPerLang = ((NUM_STRING_DESCRIPTORS - 1) / ui32NumLangs);
    
        //
        // Just to be sure, make sure that the calculation indicates an equal
        // number of strings per language.  We expect the string table to contain
        // (1 + (strings_per_language * languages)) entries.
        //
        if((1 + (ui32NumStringsPerLang * ui32NumLangs)) != NUM_STRING_DESCRIPTORS)
        {
            return(-1);
        }
    
        //
        // Now determine which language we are looking for.  It is assumed that
        // the order of the groups of strings per language in the table is the
        // same as the order of the language IDs listed in the first descriptor.
        //
        pLang = (tString0Descriptor *)(g_ppui8StringDescriptors[0]);
    
        //
        // Look through the supported languages looking for the one we were asked
        // for.
        //
        for(ui32Loop = 0; ui32Loop < ui32NumLangs; ui32Loop++)
        {
            //
            // Have we found the requested language?
            //
            if(pLang->wLANGID[ui32Loop] == ui16Lang)
            {
                //
                // Yes - calculate the index of the descriptor to send.
                //
                return((ui32NumStringsPerLang * ui32Loop) + ui16Index);
            }
        }
    
        //
        // If we drop out of the loop, the requested language was not found so
        // return -1 to indicate the error.
        //
        return(-1);
    }
    
    //*****************************************************************************
    //
    // This function handles the SET_DESCRIPTOR standard USB request.
    //
    // \param pUSBRequest holds the data for this request.
    //
    // This function currently is not supported and will respond with a Stall
    // to indicate that this command is not supported by the device.
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDSetDescriptor(tUSBRequest *pUSBRequest)
    {
        //
        // This function is not handled by default.
        //
        USBBLStallEP0();
    }
    
    //*****************************************************************************
    //
    // This function handles the GET_CONFIGURATION standard USB request.
    //
    // \param pUSBRequest holds the data for this request.
    //
    // This function responds to a host request to return the current
    // configuration of the USB device.  The function will send the configuration
    // response to the host and return.  This value will either be 0 or the last
    // value received from a call to SetConfiguration().
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDGetConfiguration(tUSBRequest *pUSBRequest)
    {
        uint8_t ui8Value;
    
        //
        // If we still have an address pending then the device is still not
        // configured.
        //
        if(g_sUSBDeviceState.ui32DevAddress & DEV_ADDR_PENDING)
        {
            ui8Value = 0;
        }
        else
        {
            ui8Value = (uint8_t)g_sUSBDeviceState.ui32Configuration;
        }
    
        g_sUSBDeviceState.ui32EP0DataRemain = 1;
        g_sUSBDeviceState.pui8EP0Data = &ui8Value;
    
        //
        // Send the single byte response.
        //
        USBDEP0StateTx();
    }
    
    //*****************************************************************************
    //
    // This function handles the SET_CONFIGURATION standard USB request.
    //
    // \param pUSBRequest holds the data for this request.
    //
    // This function responds to a host request to change the current
    // configuration of the USB device.  The actual configuration number is taken
    // from the structure passed in via \e pUSBRequest.
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDSetConfiguration(tUSBRequest *pUSBRequest)
    {
        //
        // Cannot set the configuration to one that does not exist so check the
        // enumeration structure to see how many valid configurations are present.
        //
        if(pUSBRequest->wValue > 1)
        {
            //
            // The passed configuration number is not valid.  Stall the endpoint to
            // signal the error to the host.
            //
            USBBLStallEP0();
        }
        else
        {
            //
            // Need to ack the data on end point 0.
            //
            USBDevEndpoint0DataAck(true);
    
            //
            // Save the configuration.
            //
            g_sUSBDeviceState.ui32Configuration = pUSBRequest->wValue;
    
            //
            // If passed a configuration other than 0 (which tells us that we are
            // not currently configured), configure the endpoints (other than EP0)
            // appropriately.
            //
            if(g_sUSBDeviceState.ui32Configuration)
            {
                //
                // Set the power state
                //
    #if USB_BUS_POWERED
                g_sUSBDeviceState.ui8Status &= ~USB_STATUS_SELF_PWR;
    #else
                g_sUSBDeviceState.ui8Status |= USB_STATUS_SELF_PWR;
    #endif
            }
    
            //
            // Do whatever needs to be done as a result of the config change.
            //
            HandleConfigChange(g_sUSBDeviceState.ui32Configuration);
        }
    }
    
    //*****************************************************************************
    //
    // This function handles the GET_INTERFACE standard USB request.
    //
    // \param pUSBRequest holds the data for this request.
    //
    // This function is called when the host controller request the current
    // interface that is in use by the device.  This simply returns the value set
    // by the last call to SetInterface().
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDGetInterface(tUSBRequest *pUSBRequest)
    {
        uint8_t ui8Value;
    
        //
        // If we still have an address pending then the device is still not
        // configured.
        //
        if(g_sUSBDeviceState.ui32DevAddress & DEV_ADDR_PENDING)
        {
            ui8Value = 0;
        }
        else
        {
            //
            // Is the interface number valid?
            //
            if(pUSBRequest->wIndex == 0)
            {
                //
                // Read the current alternate setting for the required interface.
                //
                ui8Value = g_sUSBDeviceState.ui8AltSetting;
            }
            else
            {
                //
                // An invalid interface number was specified.
                //
                USBBLStallEP0();
                return;
            }
        }
    
        //
        // Send the single byte response.
        //
        g_sUSBDeviceState.ui32EP0DataRemain = 1;
        g_sUSBDeviceState.pui8EP0Data = &ui8Value;
    
        //
        // Send the single byte response.
        //
        USBDEP0StateTx();
    }
    
    //*****************************************************************************
    //
    // This function handles the SET_INTERFACE standard USB request.
    //
    // \param pUSBRequest holds the data for this request.
    //
    // The DFU device supports a single interface with no alternate settings so
    // this handler is hardcoded assuming this configuration.
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDSetInterface(tUSBRequest *pUSBRequest)
    {
        if((pUSBRequest->wIndex == 0) && (pUSBRequest->wValue == 0))
        {
            //
            // We were passed a valid interface number so acknowledge the request.
            //
            USBDevEndpoint0DataAck(true);
        }
        else
        {
            //
            // The values passed were not valid so stall endpoint 0.
            //
            USBBLStallEP0();
        }
    }
    
    //*****************************************************************************
    //
    // This internal function handles sending data on endpoint zero.
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDEP0StateTx(void)
    {
        uint32_t ui32NumBytes;
        uint8_t *pui8Data;
    
        //
        // In the TX state on endpoint zero.
        //
        g_eUSBDEP0State = USB_STATE_TX;
    
        //
        // Set the number of bytes to send this iteration.
        //
        ui32NumBytes = g_sUSBDeviceState.ui32EP0DataRemain;
    
        //
        // Limit individual transfers to 64 bytes.
        //
        if(ui32NumBytes > EP0_MAX_PACKET_SIZE)
        {
            ui32NumBytes = EP0_MAX_PACKET_SIZE;
        }
    
        //
        // Save the pointer so that it can be passed to the USBEndpointDataPut()
        // function.
        //
        pui8Data = g_sUSBDeviceState.pui8EP0Data;
    
        //
        // Advance the data pointer and counter to the next data to be sent.
        //
        g_sUSBDeviceState.ui32EP0DataRemain -= ui32NumBytes;
        g_sUSBDeviceState.pui8EP0Data += ui32NumBytes;
    
        //
        // Put the data in the correct FIFO.
        //
        USBEndpoint0DataPut(pui8Data, ui32NumBytes);
    
        //
        // If this is exactly 64 then don't set the last packet yet.
        //
        if(ui32NumBytes == EP0_MAX_PACKET_SIZE)
        {
            //
            // There is more data to send or exactly 64 bytes were sent, this
            // means that there is either more data coming or a null packet needs
            // to be sent to complete the transaction.
            //
            USBEndpoint0DataSend(USB_TRANS_IN);
        }
        else
        {
            //
            // Now go to the status state and wait for the transmit to complete.
            //
            g_eUSBDEP0State = USB_STATE_STATUS;
    
            //
            // Send the last bit of data.
            //
            USBEndpoint0DataSend(USB_TRANS_IN_LAST);
            g_sUSBDeviceState.ui32OUTDataSize = 0;
        }
    }
    
    //*****************************************************************************
    //
    // Close the Doxygen group.
    //! @}
    //
    //*****************************************************************************
    #endif // USB_ENABLE_UPDATE
    

  • Ralph,

    I copied the usb_funcs.c to the boot_serial project. I am still getting USB device not recognized. I have exported the project in my workspace to this post.boot_serialPN.zip

  • Hello Priya,

    Your project compiled and worked fine on my EK-TM4C1294XL on my Windows 10 PC.

    I'm at a bit of a loss here. Either your hardware connections aren't good, the Windows PC has an issue for some reason that isn't being cleared up, or the EK-TM4C1294XL you have has been damaged in some manner. I would say use both USB ports at the same time and try a new PC and see if you can get it to work that way...

  • I will try this on a different laptop. I have paid attention to all the steps involved in USB DFU and listed them here, a possible EK damage seems very concerning. I am working with 4 newly ordered EKs currently. If the EKs are the problem, TI needs to replace them. Is the anitvirus on the laptop a possible cause of enumeration problems?

    Laptop 2 same issue. The USB device not recognized, it  malfunctioned and windows does not recognize it. 

  • Hello Priya,

    Four EK's wouldn't cause that issue. Maybe one could but four certainly not.

    Can you try and create a new workspace in Code Composer and re-import the project I sent?

    I haven't heard of anti-virus stopping enumeration but that isn't something we can broadly test.

    Unfortunately because I am not able to re-create this as the project to sent to me works just fine, I am running out of ideas of what can be going amiss here...

  • I am slow to think of this-- if there is a way to flash the boot_serial.bin in the Tiva, then dfu_prog will take care of programming the application bin file, correct? I don't need a project in CCS to generate boot_serial. If this is the case, I will close this ticket.

    Appreciate your help with this issue.

  • Hello Priya,

    Yes you can use LM Flash Programmer to do so.

    https://www.ti.com/tool/LMFLASHPROGRAMMER

  • Ralph-- I am able to enter and program using DFU. If I program blink.bin, the program isn't working after DFU download. If I flash from CCS, then blinky works OK. Why is this?

  • Hello Priya,

    Have you adjusted the start address for the blinky CCS project in the linker file? See Section 6.1 of our TivaWare's User Guide: https://www.ti.com/lit/pdf/spmu373

    Note that for TM4C129x the APP_START_ADDRESS would be 0x4000.

  • #define APP_BASE 0x4000 in blinky_ccs.cmd

    Yes, I changed this, but I am seeing blinky work only from CCS, not through DFU.

  • Hmm. Attach the project please? Slight smile I will test!

  • blinkyPN.zip

    blinky project attached. Works only when flashed from CCS, not through DFU.

  • Hello Priya,

    Are you power cycling the board after the DFU?

    It works fine for me, but it does require a power cycle.

    You can also use LMFlash to flash the .bin over DFU.

  • Yes, I power cycled the board after programming. I tried this with dfuprog and with USB DFU on LMFlash programmer. blinky doesn't work for me unless I use the ICDI. And I am picking the correct DFU device to program.

  • In LM Flash you should only get one option:

  • Yes, In my case, I see device 0. 1 is the index for ICDI.

  • Interesting. I know I have seen the ICDI show up before but right now it is not. Can you unplug the ICDI cable, power from OTG jumper, and try that way? I don't think that should matter, but as mentioned, it worked for me...

    I also redownloaded your project and used the exact bin you sent me without recompiling to be sure and it worked as expected.