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.

How to add USB DFU for TM4C1294 project?

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

I tried to figure out how to add USB UFD to an example TiVa project, usb_dev_bulk

Following advice on http://ww w.ti.com/lit/ug/spmu301a/spmu301a.pdf, I found bl_usb.c in TiVaware folder and added to the project.

next, I added #define USB_ENABLE_UPDATE

bl_usb.c needs bl_config.h. There is template in the boot_loader folder that requires configuration according to the target, but there is none in the TiVa tm4c1294 example folder.


Any pointer for the next step or reading?


Thanks!



  • Hello David,

    Yes, that has been an issue that the boot examples do not exist for the EK-TM4C1294XL and EK-TM4C123GXL boards and this has been fixed for TivaWare 2.1.2 (I can't promise a date). However to be able to do so, you can take the example code boot_usb from DK-TM4C123G and have to make changes for the device part number and revision (PART_TM4C1294NCDPT and TARGET_IS_TM4C129_RA2) besides the pin and board changes for the EK-TM4C1294XL.

    Regards
    Amit
  • Could you leak some info on the example before the formal release of 2.12? or give the detailed modification outlines?

    A guessing game from my end is not a very safe approach, and it may lead to bugs for the end users.
  • Hello David,

    Without the new boot loaders the bl_config.h would break the compilation. However I did find one unmodified bl_config.h (not sure if it will work for you)

    bl_config.h

    Regards

    Amit

  • In that case, I will wait a few weeks for the formal release
  • Hello David

    As I mentioned earlier, it would be tough putting out a date. I can suggest that you make the changes as described in the post and the file, and I can assist you in case there is any issue

    Regards
    Amit
  • After importing boot_usb from TM4C123G, where/what should I change? (I don't follow your comment above)

    Also, comparing the bl_config.h in your post and the one from boot_usb from TM4C123G, although both were supposed for TM4C123, they not the same, starting from CRYSTAL_FREQ (16M vs 25M) and APP_START_ADDRESS (0x2800 vs 0x4000)

    Any comment?
  • Hello David,

    The bl_config.h is device and board dependent. TM4C123 boards came with 16Mhz crystal and TM4C129 come with 25MHz crystal. Also the sector size on TM4C123 is 1KB while it is 16KB on TM4C129.

    You need to copy the bl_config.h to the TM4C123 example (over write the bl_config.h of tm4c123 example). Add the defines as mentioned above to the compile flow.

    I hope you are using TivaWare 2.1.1.71

    Regards
    Amit
  • Thanks, and I will update my TiVaWare first
  • Hello David,

    Yes, that is very important as without that it would be a nightmare updating the boot loader (almost all major files will result in Bus Fault)

    Regards
    Amit
  • Replaced the original one with the bl_config.h you gave me
    Replaced the defines referring to TM4C123 in project->properties->CCS Build->ARM Compiler->Advanced Options->Predefined Symbols with PART_TM4C1294NCDPT and TARGET_IS_TM4C129_RA2

    When I build the project, I get:

    Description Resource Path Location Type
    #20 identifier "INT_USB0_" is undefined bl_usbfuncs.c /boot_usb/boot_loader line 634 C/C++ Problem
    #20 identifier "USB_ID_PERIPH" is undefined bl_usbfuncs.c /boot_usb/boot_loader line 506 C/C++ Problem
    #20 identifier "USB_VBUS_PERIPH" is undefined bl_usbfuncs.c /boot_usb/boot_loader line 506 C/C++ Problem

    I must missed something...
  • Hello David,

    Can you attach the compilation log for the project?

    Regards
    Amit
  • **** Build of configuration Debug for project boot_usb ****

    "C:\\ti\\ccsv6\\utils\\bin\\gmake" -k all
    'Building file: C:/ti/TivaWare_C_Series-2.1.1.71/boot_loader/bl_usbfuncs.c'
    'Invoking: ARM Compiler'
    "C:/ti/ccsv6/tools/compiler/arm_5.1.9/bin/armcl" -mv7M4 --code_state=16 --float_support=FPv4SPD16 --abi=eabi -me -O2 --include_path="C:/ti/ccsv6/tools/compiler/arm_5.1.9/include" --include_path="C:/Users/Chen/workspace_v6_0/boot_usb" --include_path="c:/ti/TivaWare_C_Series-2.1.1.71" --include_path="c:/ti/TivaWare_C_Series-2.1.1.71/boot_loader" -g --gcc --define=ccs="ccs" --define=PART_TM4C1294NCDPT --define=TARGET_IS_TM4C129_RA2 --display_error_number --diag_warning=225 --diag_wrap=off --gen_func_subsections=on --ual --preproc_with_compile --preproc_dependency="boot_loader/bl_usbfuncs.pp" --obj_directory="boot_loader" "C:/ti/TivaWare_C_Series-2.1.1.71/boot_loader/bl_usbfuncs.c"
    "C:/ti/TivaWare_C_Series-2.1.1.71/boot_loader/bl_usbfuncs.c", line 506: error #20: identifier "USB_VBUS_PERIPH" is undefined
    "C:/ti/TivaWare_C_Series-2.1.1.71/boot_loader/bl_usbfuncs.c", line 506: error #20: identifier "USB_ID_PERIPH" is undefined
    "C:/ti/TivaWare_C_Series-2.1.1.71/boot_loader/bl_usbfuncs.c", line 634: warning #225-D: function "INT_RESOLVE" declared implicitly
    "C:/ti/TivaWare_C_Series-2.1.1.71/boot_loader/bl_usbfuncs.c", line 634: error #20: identifier "INT_USB0_" is undefined
    3 errors detected in the compilation of "C:/ti/TivaWare_C_Series-2.1.1.71/boot_loader/bl_usbfuncs.c".

    >> Compilation failure
    gmake: *** [boot_loader/bl_usbfuncs.obj] Error 1
    gmake: Target `all' not remade because of errors.

    **** Build Finished ****
  • Hello David,

    I think you are not using VBUS and ID on the USB PHY. If that is correct then replace the line 506 with the following

    while((HWREG(SYSCTL_RCGCGPIO) & (USB_DP_PERIPH | USB_DM_PERIPH)) !=
    (USB_DP_PERIPH | USB_DM_PERIPH));

    This issue has already been fixed for the next TivaWare release.

    For the remaining one error can you attach the bl_usbfuncs.c file for inspection?

    Regards
    Amit
  • I think VBUS and ID are used in the launch pad, but I guess I can take them out the line if it helps

    bl_usbfuncs.c is attached below:

    //*****************************************************************************
    //
    // bl_usbfuncs.c - The subset of USB library functions required by the USB DFU
    // boot loader.
    //
    // Copyright (c) 2008-2015 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.1.1.71 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_RCGCGPIO) & (USB_VBUS_PERIPH | USB_ID_PERIPH | USB_DP_PERIPH | USB_DM_PERIPH)) !=
    (USB_VBUS_PERIPH | USB_ID_PERIPH | USB_DP_PERIPH | USB_DM_PERIPH));

    //
    // 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 | (7 << 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
  • Hello David,

    After removing the 2 earlier mentioned lines, I used the bl_usbfuncs.c and it was passing compilation

    C:/tinotouch/TivaWare_C_Series-2.1.1.71/boot_loader/bl_usbfuncs.c'
    'Invoking: ARM Compiler'
    "C:/ti/ccsv6/tools/compiler/arm_5.1.8/bin/armcl" -mv7M4 --code_state=16 --float_support=FPv4SPD16 --abi=eabi -me -O2 --include_path="C:/ti/ccsv6/tools/compiler/arm_5.1.8/include" --include_path="C:/Users/a0876236/workspace_v6_0/boot_usb" --include_path="C:/tinotouch/TivaWare_C_Series-2.1.1.71" --include_path="C:/tinotouch/TivaWare_C_Series-2.1.1.71/boot_loader" -g --gcc --define=ccs="ccs" --define=PART_TM4C1294NCPDT --define=TARGET_IS_TM4C129_RA1 --display_error_number --diag_warning=225 --diag_wrap=off --gen_func_subsections=on --embedded_constants=on --ual --preproc_with_compile --preproc_dependency="boot_loader/bl_usbfuncs.pp" --obj_directory="boot_loader" "C:/tinotouch/TivaWare_C_Series-2.1.1.71/boot_loader/bl_usbfuncs.c"
    'Finished building: C:/tinotouch/TivaWare_C_Series-2.1.1.71/boot_loader/bl_usbfuncs.c'

    Can you please try a clean and re build?

    Regards
    Amit
  • I noticed you changed TARGET_IS_TM4C129_RA2 to TARGET_IS_TM4C129_RA1, but even with same definition, it will not compile on mine.

    **** Build of configuration Debug for project boot_usb ****

    "C:\\ti\\ccsv6\\utils\\bin\\gmake" -k all
    'Building file: C:/ti/TivaWare_C_Series-2.1.1.71/boot_loader/bl_usbfuncs.c'
    'Invoking: ARM Compiler'
    "C:/ti/ccsv6/tools/compiler/arm_5.1.9/bin/armcl" -mv7M4 --code_state=16 --float_support=FPv4SPD16 --abi=eabi -me -O2 --include_path="C:/ti/ccsv6/tools/compiler/arm_5.1.9/include" --include_path="C:/Users/Chen/workspace_v6_0/boot_usb" --include_path="c:/ti/TivaWare_C_Series-2.1.1.71" --include_path="c:/ti/TivaWare_C_Series-2.1.1.71/boot_loader" -g --gcc --define=ccs="ccs" --define=PART_TM4C1294NCDPT --define=TARGET_IS_TM4C129_RA2 --display_error_number --diag_warning=225 --diag_wrap=off --gen_func_subsections=on --ual --preproc_with_compile --preproc_dependency="boot_loader/bl_usbfuncs.pp" --obj_directory="boot_loader" "C:/ti/TivaWare_C_Series-2.1.1.71/boot_loader/bl_usbfuncs.c"
    "C:/ti/TivaWare_C_Series-2.1.1.71/boot_loader/bl_usbfuncs.c", line 634: warning #225-D: function "INT_RESOLVE" declared implicitly
    "C:/ti/TivaWare_C_Series-2.1.1.71/boot_loader/bl_usbfuncs.c", line 634: error #20: identifier "INT_USB0_" is undefined
    1 error detected in the compilation of "C:/ti/TivaWare_C_Series-2.1.1.71/boot_loader/bl_usbfuncs.c".

    >> Compilation failure
    gmake: *** [boot_loader/bl_usbfuncs.obj] Error 1
    gmake: Target `all' not remade because of errors.

    **** Build Finished ****
  • Hello David,

    My mistake (big time). PART_TM4C1294NCDPT was wrong. The correct part number is PART_TM4C1294NCPDT (D and P got swapped in my first post)

    Regards
    Amit
  • Now that it compiled, Thanks!

    Any pointer (or reading) on how to integrate it to an existing project?
  • Hello David,

    You can use the boot_demo2 under dk-tm4c123g as a starting point. I made a two blinky examples such that

    1. If USR_SW2 is pressed then application exits to the flash boot loader
    2. If not pressed then it blinks D1 at 1 sec or D2 at 1 sec based on which application image it is.

    I got rid of all graphics library and enabled the GPIO Pull Up to detect a key press.

    Regards
    Amit
  • I imported boot_demo2, and took a quick look.

    I can see the APP_BASE in boot_demo2_ccs.cmd is set to 0x2800 to make room for the boot loaders. Since the APP_START_ADDRESS of bl_config.h in 1294 version we were working on is 0x4000, should I set APP_BASE to 0x4000 to match that?

    Since the boot_usb project is separated from the demo, I also expect the boot_demo2 link to include the object code of its boot_usb project, but I didn't find it, did I miss it? 

  • Hello David

    Yes, it needs to have the changes as applicable for TM4C129x devices.

    As for the object code, it does not need to be there for the boot_demo2 as long as the boot_usb is in place at 0x0 location of flash.

    Regards
    Amit
  • I see, so the procedure is to flash the boot loader in first and the new project is always flashed to the new location (avoiding the boot loader)

    With this approach, during the manufacturing, we have to flash the firmware twice, one for the boot loader and one for the application. Do you have a link option to include both to the same firmware image so that we can use it once on a bland new 1294? (we will still take your suggestion above for DFU)
  • Hello David,

    No. We do not have the option to do so. One thing is that you can use bin utilities to merge the two images during post processing to get a single image file for one time flashing at manufacturing.

    Regards
    Amit
  • That should work

    I flashed in boot_usb into 1294, 

    Now, after I build boot_demo2, if I use CCS instead of LM Flash programer to flash in the codes, I assume I need to change Properties->Debug->Flash Settings->Program Load Settings->Erase Method from Use teh Erase Options Specified Below to Necessary Page Only (so that CCS will not erase the resident boot_usb)?

  • Hello David,

    Yes, that is correct.

    Regards
    Amit
  • It seems to work, but I was using an old .bin file from another project.

    I tried to convert the .out or .hex from my active project to .bin to be used by LMFlashProgrammer, but I can't find the utility

    according to e2e.ti.com/.../68158, I should use hex470.exe, but it was not in any TI folder and that link was very old. Does TI has something newer?
  • Hello David

    The out to bin converter is in CCS. You can load one of the CCS examples like interrupt example and check the exact syntax to be used.

    Regards
    Amit
  • Here it is, to save time for others:

    Add the following line to Project->Properties->C/C++ Build->Settings->Post-Build Steps to generate .bin file

    "${CCE_INSTALL_ROOT}/utils/tiobj2bin/tiobj2bin" "${BuildArtifactFileName}" "${BuildArtifactFileBaseName}.bin" "${CG_TOOL_ROOT}/bin/armofd" "${CG_TOOL_ROOT}/bin/armhex" "${CCE_INSTALL_ROOT}/utils/tiobj2bin/mkhex4bin"
  • Hello Amit,

    When I installed the software for my TiVa 1294 launch pad, I got the Stellaris Firmware Upgrade USB driver so that I can use LM Flash Programmer for DFU.

    Now my customer wants to know if they can just download the Stellaris Firmware Upgrade USB driver instead of the full TiVa software from TI directly.

    I looked into 1294's page www.ti.com/.../ek-tm4c1294xl, but didn't see it.

    Any pointer?

    Thanks!
  • Hello David,

    Yes, that should be possible. I have not tried this so far as my machines always have TivaWare.

    Regards
    Amit
  • He downloaded and installed LM Flash Programmer, but the Stellaris Firmware Upgrade USB driver is NOT installed along with the package

    When he ran LM Flash Programmer, it suggested to get the USB driver from the following web page

    www.ti.com/stellaris_software

    Unfortunately, that page didn't exist so TI redirected it to a page that doesn't really solve the problem

    I guess we still need your help on this for deploying it
  • Hello David,

    Can he download the stellaris_icdi_drivers and then check?

    www.ti.com/.../tools_software.page

    Regards
    Amit
  • works, thanks!
  • Hi Amit,

    I got a request to use LED indicator to indicate the device enters the DFU mode, so I added the following modification to bl_check.c


    1. I defined ENABLE_UPDATE_CHECK, so CheckGPIOForceUpdate() will be called
    2. I added white_led(); before exiting CheckGPIOForceUpdate(); (actually, I made it so that it will call white_led all the time)

    where white_led is defined as

    void white_led(void)
    {

    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOP);
    MAP_GPIOPinTypeGPIOOutput(GPIO_PORTP_BASE, GPIO_PIN_3);
    MAP_GPIOPinTypeGPIOOutput(GPIO_PORTP_BASE, GPIO_PIN_5);
    MAP_GPIOPinTypeGPIOOutput(GPIO_PORTP_BASE, GPIO_PIN_4);

    MAP_GPIOPinWrite(GPIO_PORTP_BASE,GPIO_PIN_4, 0); //LED ON
    MAP_GPIOPinWrite(GPIO_PORTP_BASE,GPIO_PIN_5, 0); //LED ON
    MAP_GPIOPinWrite(GPIO_PORTP_BASE,GPIO_PIN_3, 0); //LED ON
    }

    I verified the hardware (LED) works when used in my other project, but it will not work here, it seems the GPIO was not initialized/configured properly with the above code. Maybe ROM_api is not available here? if so, could you please show me how to convert them to some hardcoding? thanks!

  • Hello David

    Add a delay loop or wait for peripheral ready to be true before configuring the GPIO Port P. Also it would be good to check by manually toggling the pins that LEDs are working.

    Regards
    Amit
  • Hi Amit, I added delay and changed white_led to the following, but still has no LED

    void white_led(void)
    {

    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOP);
    MAP_GPIOPinTypeGPIOOutput(GPIO_PORTP_BASE, GPIO_PIN_3);
    MAP_GPIOPinTypeGPIOOutput(GPIO_PORTP_BASE, GPIO_PIN_5);
    MAP_GPIOPinTypeGPIOOutput(GPIO_PORTP_BASE, GPIO_PIN_4);
    delay(1000);
    MAP_GPIOPinWrite(GPIO_PORTP_BASE,GPIO_PIN_4, 0); //LED ON
    MAP_GPIOPinWrite(GPIO_PORTP_BASE,GPIO_PIN_5, 0); //LED ON
    MAP_GPIOPinWrite(GPIO_PORTP_BASE,GPIO_PIN_3, 0); //LED ON
    delay(1000);
    MAP_GPIOPinWrite(GPIO_PORTP_BASE,GPIO_PIN_4, GPIO_PIN_4); //LED OFF
    MAP_GPIOPinWrite(GPIO_PORTP_BASE,GPIO_PIN_5, GPIO_PIN_5); //LED OFF
    MAP_GPIOPinWrite(GPIO_PORTP_BASE,GPIO_PIN_3, GPIO_PIN_3); //LED OFF
    delay(1000);
    MAP_GPIOPinWrite(GPIO_PORTP_BASE,GPIO_PIN_4, 0); //LED ON
    MAP_GPIOPinWrite(GPIO_PORTP_BASE,GPIO_PIN_5, 0); //LED ON
    MAP_GPIOPinWrite(GPIO_PORTP_BASE,GPIO_PIN_3, 0); //LED ON
    delay(1000);

    }

  • Hello David,

    Are the LED's working? Also change the code as follows

    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOP);
    delay(1000);
    MAP_GPIOPinTypeGPIOOutput(GPIO_PORTP_BASE, GPIO_PIN_3);
    MAP_GPIOPinTypeGPIOOutput(GPIO_PORTP_BASE, GPIO_PIN_5);
    MAP_GPIOPinTypeGPIOOutput(GPIO_PORTP_BASE, GPIO_PIN_4);

    Regards
    Amit
  • This seems to fix it, thanks!
  • Hello David,

    The issue must have been that the Peripheral clock is started and before the clock actually starts the CPU accesses the peripheral register.

    Regards
    Amit
  • I am ready to release my software, and I would like to take your suggestion of merging the two images into a single one during calibration procedure

    do you know any bin utility that can merge the two images directly?

    If not, I guess I will have to write one, then what is the format of the bin file of the flash image? I used hex editor and took a quick look and didn't see anything obvious, especially the one sitting on top of the DFU, I can't tell how to figure out the initial offset of the image, here is the beginning of the image

    78 3D 02 20 61 DB 00 00 A1 DB 00 00 91 DB 00 00
    99 DB 00 00 99 DB 00 00 99 DB 00 00 00 00 00 00
    00 00 00 00 00 00 00 00 00 00 00 00 99 DB 00 00
    99 DB 00 00 00 00 00 00 99 DB 00 00 59 B0 00 00
    ....

    Thanks for pointers and wishing you a merry Christmas!

  • Hello David,

    The format of display is big endian. If you open it in NotePad++ with hex viewer plugin, then in 32-bit LE format you will see

    0x2002783D 0x0000DB61 0x0000DBA1 0x0000DB91

    and so on.

    There are some freeware tools but I haven't used it so far.

    Regards
    Amit
  • I still don't know how to combine the two .bin files (FLASH images) since I can't tell the address of the data (intel hex file clearly specifies that), and I doubt I can simply combine them using the old DOS command.

    I think I lost your points here. Could you give more pointers on this? 

  • Hello David,

    Which points are you referring to?
    The bin file is a simple format as explained in the following link.

    en.wikipedia.org/.../Binary_file

    Regards
    Amit
  • I understand the definition of binary files, but to write the binary image to the micro, I assume it should at least specify the starting address.
  • Hello David

    Let us take 2 binaries files. The first binary file is to be from 0x0 to 0x1C and the next binary file is from 0x1000 to 0x101C. When you view the same in a hex viewer it will appear something like (assume A, B, C, D, X, Y, Z and W to be 32 bit words)

    File-1: From 0x0 to 0x1c
    0x0: A B C D
    0x10: A B C D

    File-2: From 0x1000 to 0x101c
    0x0: X Y Z W
    0x10: X Y Z W

    To merge them correctly
    0x0: A B C D
    0x10: A B C D
    0x20: FILL FILL FILL FILL
    0x30: FILL FILL FILL FILL
    ...
    0xFE0: FILL FILL FILL FILL
    0xFF0: FILL FILL FILL FILL
    0x1000: X Y Z W
    0x1010: X Y Z W

    Now when using LMFlashProgrammer the start address has to be 0x0 if erasing the entire flash

    Alternatively, if the binary images are page aligned, then you may use the Erase Page only option and then flash each of the binary images w.r.t the start address of the page (Simpler..)

    Regards
    Amit
  • How do you know where to start, which you pick 0x1000, the second image by just looking at the second .bin file?
  • Hello David,

    No. This is based on the linker command file which contains the Start Address of each image.

    Regards
    Amit
  • For example, we picked 0x4000 as the APP_BASE for the project running on top of DFU, but when I run LMFlashProgramer, I don't need to specify 0x4000 as the starting point for the image. The utility picks up this start address from the .bin file, this is the point I am missing.
  • Hello David,

    Please check the Program Address Offset value in the LMFlashProgrammer. If there is a Flash based boot loader then 0x0 cannot be used as it will try to overwrite the Flash boot loader.

    Regards
    Amit
  • I ran LMFlashProgrammer again, and I found out:

    Once DFU is activated, when LMFlashProgrammer is started, it will query DFU and find out the starting address, which is 0x4000, and it will NOT allow 0x0 to be entered to the starting offset to protect the DFU, in fact, it will not even let you to modify this address to 0x5000.

    The second image will be stored to the starting retrieved from DFU query, regardless how the image was created (by linker option).