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.

TM4C123GXL DFU USB

Other Parts Discussed in Thread: EK-TM4C123GXL, LMFLASHPROGRAMMER, TM4C123GE6PZ

I have a Tiva C TM4C123GXL Launchpad EK and I'm trying to figure out how to us the DFU.  I'm able to flash the device via CCS in debug mode and using the LM Flash Programmer but I'd like to be able to see how it will work on my board and we will not be using the JTAG.  I thought I could simply flash the boot_usb program and after reset see the device on the Device USB port and not just the DEBUG USB port using the dfuprog application.  On our board we plan to use the USB to load user programs and not necessarily have the JTAG support.  

I can use the Bulk example to run the echo program through the Device USB port.  Is it possible to also program the flash from this port?  If so what am I missing?  I want to be able to run the dfuprog app to access this USB port.  What does this require?

  • I think I may have figured it out.  I read:

    "The boot loader is used as an initial program loader (when the Flash memory is empty) as well as

    an application-initiated firmware upgrade mechanism (by calling back to the boot loader). "

    I simply erased flash and it ran.  How do I "call back to the boot loader"?  Is it possible to accidentally clobber the boat loader is it truly in ROM? I'm afraid to try flashing through this port and bricking my EK.

  • I've been unable to get into DFU mode from an application.  I can only reach it by erasing flash at this point.

    I'm starting with boot_demo1 and modifying it from what I can piece together from various forum posts but I'm still missing something.  

    From the ROM guide I found;

    enable the main PLL and configure it as the system clock,
    enable the USB PLL,
    enable the USB controller,
    enable the USB D+ and D- pins on the microcontroller.
    If the main application is already acting as a USB device,
    the application must remove the device from the bus by calling the DriverLib function
    ROM_USBDevDisconnect() prior to entering the boot loader.  I don't believe this is the case but may be in the future.  As of now I simply try to jump to BOOT ROM

    I currently have:

    ROM_FPULazyStackingEnable();

    ROM_SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ |
    SYSCTL_OSC_MAIN);

    ROM_SysCtlUSBPLLEnable();

    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0);

    //The code I've used to enable the USB D+ and D- pins has varied and I think may be the key but i can't find the proper initializations steps

    HWREG(NVIC_DIS0) = 0xffffffff;
    HWREG(NVIC_DIS1) = 0xffffffff;

    ROM_UpdateUSB(pui8USBBootROMInfo);   //uint8_t *pui8USBBootROMInfo = NULL;

    Am I missing anything besides the D+/- enable?

    Any ideas what this entails?  I trued the PinMux app but it generates code with defines that don't seem to exist anywhere.  Other attempts have proven just as fruitless.  

  • Tim,

    In TivaWare, there is a more in depth example for the DK-TM4C129x called boot_demo_usb that shows how to use the USB boot loader in ROM.  Although this device is different from the EK-TM4C123GXL, the basic concept is still there.

    The ROM Boot Loader "listens" for whatever peripheral you are trying to use.  You must use the PLL for your system clock, turn on the USB PLL and the USB peripheral clock (all of these steps are present in your code).  Enabling the D+/D- pins is done when you initialize the USB.  In most cases, a USB application would be running before switching over to the ROM boot loader.  This is done in the boot_demo_usb example.

    -Rebecca

  • I intend to make use of the ROM bootloader too. My current thought is as follows.

    I will dedicate one of the otherwise unused GIOP as my to-boot-or-not-to-boot pin. I will also alter the contents of the non-volatile register BOOTCFG. NW is of course cleared. The PORT and PIN fields designate my to-boot-or-not-to-boot pin. POL bit can be either way as desired. NW bit is cleared. KEY, DBG1 and DBG0 are unchanged.

    After that, I can try various Application code. The Application code may have the option to initiate the ROM bootloader. But even if it failed to do so or does not have this option, I can still start ROM bootloader manually.

    Is this scheme okay?

  • I've been able to jump to Boot ROM and execute the DFU functionality using some of your other posts for different but similar boards.  I think one of my hang ups was not realizing I had to use the power switch in the non-debug mode for it to work properly.  I had no idea this would affect the functionality as other functionality seems fine.  In debug mode the code would jump into a fault isr or just seem to get lost.  

    But....as you mentioned I will be using the chip in a mode with the USB already running.  I gather that this requires some different steps to jump to DFU mode in the Boot ROM.   I do plan on the chip acting as a bulk USB device to accept commands and respond.  One such command would be to jump to Boot ROM in the case where a software update to the code is needed.

    I'm unable to find a software project  'DK-TM4C129x - boot_demo_usb' on the ti website.  Is this something that can be found without purchasing that demo board as well?

  • I tried using the usb_dev_bulk project to get into DFU mode but no luck.  Like I said before I can load a program that will simply enable the SB and jump to BootROM to enter DFU mode but when I try to do the same in the usb_dev_bulk project it doesn't work.  I simply modified the code to respond to a certain character to switch modes.  WHen this command is received I call:

    USBDBulkTerm(pvBulkDevice);

    and then I simply follow the steps I used in my basic boot project.  What additional steps are needed?  If I can find the 'boot_demo_usb' project will it have more information on the differences?


    My call to USBDBulkTerm(pvBulkDevice); definitely unloads the USB device, as I see it fall from my driver list,  but the following steps that work in another simply project fail to yield the same results and successfully reboot into DFU mode.

  • Sorry for the delayed response.

    old_cow_yellow,

    Yes, this sounds correct.  You just have to make a call to ROM_Update<Peripheral> to call the ROM boot loader from your application.  Otherwise, the ROM boot loader will be called if your Flash memory is empty.  If you have any issues, let me know.

    Tim,

    The boot_demo_usb project can be found in TivaWare.  If you download the full version of TivaWare, it is in the default path C:\ti\TivaWare_C_Series-2.0\examples\boards\dk-tm4c129x\boot_demo_usb.  You do not have to purchase the board to have access to this code, you'll just have to port it over to your LaunchPad.

    If you look at this example, it turns the board into a composite USB device supporting a mouse via HID class.  The device listens for a request from the host (DETACH) and then the reenumerates as a DFU device.  After receiving the DETACH request, the device is detached from the bus (using USBDCDTerm(0)), disables interrupts and processor interrupts, enables and resets the USB peripheral, re-enables interrupts at the NVIC level, then makes a call to the USB boot loader in ROM.  Try working off of this example; I think it will be more clear.

    -Rebecca

  • I always seem to get the USB device being seen as an 'Unknown USB Device' it won't show up as a DFU Device.  It only works using the simple boot_demo1 example I modified.  If I use the usb_dev_bulk and try to follow the DETACH example as a basis to switch to DFU mode it comes back as an unknown usb device.

    This is what I'm trying and shows the modifications I made:

    // Terminate the USB device and take us off the bus.
    USBDBulkTerm(0);     //USBDCDTerm(0);

    // Disable all interrupts.
    ROM_IntMasterDisable();

    // Disable SysTick and its interrupt.
    ROM_SysTickIntDisable();
    ROM_SysTickDisable();

    // Disable all processor interrupts. Instead of disabling them one at a
    // time, a direct write to NVIC is done to disable all peripheral interrupts.
    HWREG(NVIC_DIS0) = 0xffffffff;
    HWREG(NVIC_DIS1) = 0xffffffff;

    // Enable and reset the USB peripheral.
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0);
    ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_USB0);
    // ROM_USBClockEnable(USB0_BASE, 8, USB_CLOCK_INTERNAL);
    ROM_SysCtlUSBPLLEnable();

    // Wait for about a second.

    //ROM_SysCtlDelay(ui32SysClock / 3);
    ROM_SysCtlDelay(ROM_SysCtlClockGet() / 3);

    // Re-enable interrupts at the NVIC level.
    ROM_IntMasterEnable();

    // Call the USB boot loader.
    ROM_UpdateUSB(0);

  • I've tried quite a few variations on this too.  Adding steps I use in the simple example that goes straight to DFU mode but I always get Unknown USB device.  I can't figure out what is missing.   The examples I've found aren't working for me.

  • Tim,

    I tried this on my end by modifying the usb_dev_bulk example (.c file attached).  The only difference I can see between your code and my code is that I used USBDCDTerm(0); instead of USBBulkTerm(o);.  I would recommend doing this.  I'm not sure where your code was added as this can also make a difference.  I was able to see my LaunchPad come up as a Stellaris Device Firmware Upgrade device in the Device Manager and was able to reprogram it with a different binary file using dfuprog.exe (instructions on how to use this and where to find it can be found in the readme.txt in the boot_demo_usb project folder for the dk-tm4c129x).  Make sure to program your binary to the board using the ICDI Debug USB port and then switch power to power from the Device USB port on your LaunchPad, as to not confuse the number of DFU devices found.

    0474.usb_dev_bulk.c
    //*****************************************************************************
    //
    // usb_dev_bulk.c - Main routines for the generic bulk device example.
    //
    // Copyright (c) 2012-2013 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.0 of the EK-TM4C123GXL Firmware Package.
    //
    //*****************************************************************************
    
    #include <stdbool.h>
    #include <stdint.h>
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "driverlib/debug.h"
    #include "driverlib/fpu.h"
    #include "driverlib/gpio.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/systick.h"
    #include "driverlib/timer.h"
    #include "driverlib/uart.h"
    #include "driverlib/rom.h"
    #include "usblib/usblib.h"
    #include "usblib/usb-ids.h"
    #include "usblib/device/usbdevice.h"
    #include "usblib/device/usbdbulk.h"
    #include "utils/uartstdio.h"
    #include "utils/ustdlib.h"
    #include "usb_bulk_structs.h"
    #include "inc/hw_nvic.h"
    #include "driverlib/usb.h"
    
    //*****************************************************************************
    //
    //! \addtogroup example_list
    //! <h1>USB Generic Bulk Device (usb_dev_bulk)</h1>
    //!
    //! This example provides a generic USB device offering simple bulk data
    //! transfer to and from the host.  The device uses a vendor-specific class ID
    //! and supports a single bulk IN endpoint and a single bulk OUT endpoint.
    //! Data received from the host is assumed to be ASCII text and it is
    //! echoed back with the case of all alphabetic characters swapped.
    //!
    //! A Windows INF file for the device is provided on the installation CD and
    //! in the C:/ti/TivaWare-for-C-Series/windows_drivers directory of TivaWare C
    //! series releases.  This INF contains information required to install the
    //! WinUSB subsystem on Windowi16XP and Vista PCs.  WinUSB is a Windows
    //! subsystem allowing user mode applications to access the USB device without
    //! the need for a vendor-specific kernel mode driver.
    //!
    //! A sample Windows command-line application, usb_bulk_example, illustrating
    //! how to connect to and communicate with the bulk device is also provided.
    //! The application binary is installed as part of the ''Windows-side examples
    //! for USB kits'' package (SW-USB-win) on the installation CD or via download
    //! from http://www.ti.com/tivaware .  Project files are included to allow
    //! the examples to be built using Microsoft VisualStudio 2008.  Source code
    //! for this application can be found in directory
    //! TivaWare-for-C-Series/tools/usb_bulk_example.
    //
    //*****************************************************************************
    
    //*****************************************************************************
    //
    // The system tick rate expressed both as ticks per second and a millisecond
    // period.
    //
    //*****************************************************************************
    #define SYSTICKS_PER_SECOND     100
    #define SYSTICK_PERIOD_MS       (1000 / SYSTICKS_PER_SECOND)
    
    //*****************************************************************************
    //
    // The global system tick counter.
    //
    //*****************************************************************************
    volatile uint32_t g_ui32SysTickCount = 0;
    
    //*****************************************************************************
    //
    // Variables tracking transmit and receive counts.
    //
    //*****************************************************************************
    volatile uint32_t g_ui32TxCount = 0;
    volatile uint32_t g_ui32RxCount = 0;
    #ifdef DEBUG
    uint32_t g_ui32UARTRxErrors = 0;
    #endif
    
    //*****************************************************************************
    //
    // Debug-related definitions and declarations.
    //
    // Debug output is available via UART0 if DEBUG is defined during build.
    //
    //*****************************************************************************
    #ifdef DEBUG
    //*****************************************************************************
    //
    // Map all debug print calls to UARTprintf in debug builds.
    //
    //*****************************************************************************
    #define DEBUG_PRINT UARTprintf
    
    #else
    
    //*****************************************************************************
    //
    // Compile out all debug print calls in release builds.
    //
    //*****************************************************************************
    #define DEBUG_PRINT while(0) ((int (*)(char *, ...))0)
    #endif
    
    //*****************************************************************************
    //
    // Flags used to pass commands from interrupt context to the main loop.
    //
    //*****************************************************************************
    #define COMMAND_PACKET_RECEIVED 0x00000001
    #define COMMAND_STATUS_UPDATE   0x00000002
    
    volatile uint32_t g_ui32Flags = 0;
    
    //*****************************************************************************
    //
    // Global flag indicating that a USB configuration has been set.
    //
    //*****************************************************************************
    static volatile bool g_bUSBConfigured = false;
    
    //*****************************************************************************
    //
    // The error routine that is called if the driver library encounters an error.
    //
    //*****************************************************************************
    #ifdef DEBUG
    void
    __error__(char *pcFilename, uint32_t ui32Line)
    {
        UARTprintf("Error at line %d of %s\n", ui32Line, pcFilename);
        while(1)
        {
        }
    }
    #endif
    
    //*****************************************************************************
    //
    // Interrupt handler for the system tick counter.
    //
    //*****************************************************************************
    void
    SysTickIntHandler(void)
    {
        //
        // Update our system tick counter.
        //
        g_ui32SysTickCount++;
    }
    
    //*****************************************************************************
    //
    // Receive new data and echo it back to the host.
    //
    // \param psDevice points to the instance data for the device whose data is to
    // be processed.
    // \param pui8Data points to the newly received data in the USB receive buffer.
    // \param ui32NumBytes is the number of bytes of data available to be processed.
    //
    // This function is called whenever we receive a notification that data is
    // available from the host. We read the data, byte-by-byte and swap the case
    // of any alphabetical characters found then write it back out to be
    // transmitted back to the host.
    //
    // \return Returns the number of bytes of data processed.
    //
    //*****************************************************************************
    static uint32_t
    EchoNewDataToHost(tUSBDBulkDevice *psDevice, uint8_t *pui8Data,
                      uint32_t ui32NumBytes)
    {
        uint32_t ui32Loop, ui32Space, ui32Count;
        uint32_t ui32ReadIndex;
        uint32_t ui32WriteIndex;
        tUSBRingBufObject sTxRing;
    
        //
        // Get the current buffer information to allow us to write directly to
        // the transmit buffer (we already have enough information from the
        // parameters to access the receive buffer directly).
        //
        USBBufferInfoGet(&g_sTxBuffer, &sTxRing);
    
        //
        // How much space is there in the transmit buffer?
        //
        ui32Space = USBBufferSpaceAvailable(&g_sTxBuffer);
    
        //
        // How many characters can we process this time round?
        //
        ui32Loop = (ui32Space < ui32NumBytes) ? ui32Space : ui32NumBytes;
        ui32Count = ui32Loop;
    
        //
        // Update our receive counter.
        //
        g_ui32RxCount += ui32NumBytes;
    
        //
        // Dump a debug message.
        //
        DEBUG_PRINT("Received %d bytes\n", ui32NumBytes);
    
        //
        // Set up to process the characters by directly accessing the USB buffers.
        //
        ui32ReadIndex = (uint32_t)(pui8Data - g_pui8USBRxBuffer);
        ui32WriteIndex = sTxRing.ui32WriteIndex;
    
        while(ui32Loop)
        {
            //
            // Copy from the receive buffer to the transmit buffer converting
            // character case on the way.
            //
    
            //
            // Is this a lower case character?
            //
            if((g_pui8USBRxBuffer[ui32ReadIndex] >= 'a') &&
               (g_pui8USBRxBuffer[ui32ReadIndex] <= 'z'))
            {
                //
                // Convert to upper case and write to the transmit buffer.
                //
                g_pui8USBTxBuffer[ui32WriteIndex] =
                    (g_pui8USBRxBuffer[ui32ReadIndex] - 'a') + 'A';
            }
            else
            {
                //
                // Is this an upper case character?
                //
                if((g_pui8USBRxBuffer[ui32ReadIndex] >= 'A') &&
                   (g_pui8USBRxBuffer[ui32ReadIndex] <= 'Z'))
                {
                    //
                    // Convert to lower case and write to the transmit buffer.
                    //
                    g_pui8USBTxBuffer[ui32WriteIndex] =
                        (g_pui8USBRxBuffer[ui32ReadIndex] - 'Z') + 'z';
                }
                else
                {
                    //
                    // Copy the received character to the transmit buffer.
                    //
                    g_pui8USBTxBuffer[ui32WriteIndex] =
                            g_pui8USBRxBuffer[ui32ReadIndex];
                }
            }
    
            //
            // Move to the next character taking care to adjust the pointer for
            // the buffer wrap if necessary.
            //
            ui32WriteIndex++;
            ui32WriteIndex = (ui32WriteIndex == BULK_BUFFER_SIZE) ?
                             0 : ui32WriteIndex;
    
            ui32ReadIndex++;
            ui32ReadIndex = (ui32ReadIndex == BULK_BUFFER_SIZE) ?
                            0 : ui32ReadIndex;
    
            ui32Loop--;
        }
    
        //
        // We've processed the data in place so now send the processed data
        // back to the host.
        //
        USBBufferDataWritten(&g_sTxBuffer, ui32Count);
    
        DEBUG_PRINT("Wrote %d bytes\n", ui32Count);
    
        //
        // We processed as much data as we can directly from the receive buffer so
        // we need to return the number of bytes to allow the lower layer to
        // update its read pointer appropriately.
        //
        return(ui32Count);
    }
    
    //*****************************************************************************
    //
    // Handles bulk driver notifications related to the transmit channel (data to
    // the USB host).
    //
    // \param pvCBData is the client-supplied callback pointer for this channel.
    // \param ui32Event identifies the event we are being notified about.
    // \param ui32MsgValue is an event-specific value.
    // \param pvMsgData is an event-specific pointer.
    //
    // This function is called by the bulk driver to notify us of any events
    // related to operation of the transmit data channel (the IN channel carrying
    // data to the USB host).
    //
    // \return The return value is event-specific.
    //
    //*****************************************************************************
    uint32_t
    TxHandler(void *pvCBData, uint32_t ui32Event, uint32_t ui32MsgValue,
              void *pvMsgData)
    {
        //
        // We are not required to do anything in response to any transmit event
        // in this example. All we do is update our transmit counter.
        //
        if(ui32Event == USB_EVENT_TX_COMPLETE)
        {
            g_ui32TxCount += ui32MsgValue;
        }
    
        //
        // Dump a debug message.
        //
        DEBUG_PRINT("TX complete %d\n", ui32MsgValue);
    
        return(0);
    }
    
    //*****************************************************************************
    //
    // Handles bulk driver notifications related to the receive channel (data from
    // the USB host).
    //
    // \param pvCBData is the client-supplied callback pointer for this channel.
    // \param ui32Event identifies the event we are being notified about.
    // \param ui32MsgValue is an event-specific value.
    // \param pvMsgData is an event-specific pointer.
    //
    // This function is called by the bulk driver to notify us of any events
    // related to operation of the receive data channel (the OUT channel carrying
    // data from the USB host).
    //
    // \return The return value is event-specific.
    //
    //*****************************************************************************
    uint32_t
    RxHandler(void *pvCBData, uint32_t ui32Event,
                   uint32_t ui32MsgValue, void *pvMsgData)
    {
        //
        // Which event are we being sent?
        //
        switch(ui32Event)
        {
            //
            // We are connected to a host and communication is now possible.
            //
            case USB_EVENT_CONNECTED:
            {
                g_bUSBConfigured = true;
                UARTprintf("Host connected.\n");
    
                //
                // Flush our buffers.
                //
                USBBufferFlush(&g_sTxBuffer);
                USBBufferFlush(&g_sRxBuffer);
    
                break;
            }
    
            //
            // The host has disconnected.
            //
            case USB_EVENT_DISCONNECTED:
            {
                g_bUSBConfigured = false;
                UARTprintf("Host disconnected.\n");
                break;
            }
    
            //
            // A new packet has been received.
            //
            case USB_EVENT_RX_AVAILABLE:
            {
                tUSBDBulkDevice *psDevice;
    
                //
                // Get a pointer to our instance data from the callback data
                // parameter.
                //
                psDevice = (tUSBDBulkDevice *)pvCBData;
    
                //
                // Read the new packet and echo it back to the host.
                //
                return(EchoNewDataToHost(psDevice, pvMsgData, ui32MsgValue));
            }
    
            //
            // Ignore SUSPEND and RESUME for now.
            //
            case USB_EVENT_SUSPEND:
            case USB_EVENT_RESUME:
            {
                break;
            }
    
            //
            // Ignore all other events and return 0.
            //
            default:
            {
                break;
            }
        }
    
        return(0);
    }
    
    //*****************************************************************************
    //
    // Configure the UART and its pins.  This must be called before UARTprintf().
    //
    //*****************************************************************************
    void
    ConfigureUART(void)
    {
        //
        // Enable the GPIO Peripheral used by the UART.
        //
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    
        //
        // Enable UART0
        //
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    
        //
        // Configure GPIO Pins for UART mode.
        //
        ROM_GPIOPinConfigure(GPIO_PA0_U0RX);
        ROM_GPIOPinConfigure(GPIO_PA1_U0TX);
        ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    
        //
        // Use the internal 16MHz oscillator as the UART clock source.
        //
        UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
    
        //
        // Initialize the UART for console I/O.
        //
        UARTStdioConfig(0, 115200, 16000000);
    }
    
    //*****************************************************************************
    //
    // This is the main application entry function.
    //
    //*****************************************************************************
    int
    main(void)
    {
        volatile uint32_t ui32Loop;
        uint32_t ui32TxCount;
        uint32_t ui32RxCount;
    	  uint32_t ui32SysClock;
    
        //
        // Enable lazy stacking for interrupt handlers.  This allows floating-point
        // instructions to be used within interrupt handlers, but at the expense of
        // extra stack usage.
        //
        ROM_FPULazyStackingEnable();
    
        //
        // Set the clocking to run from the PLL at 50MHz
        //
        ROM_SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN |
                           SYSCTL_XTAL_16MHZ);
    	
    	 ui32SysClock = ROM_SysCtlClockGet();
    
        //
        // Enable the GPIO port that is used for the on-board LED.
        //
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    
        //
        // Enable the GPIO pins for the LED (PF2 & PF3).
        //
        ROM_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_3 | GPIO_PIN_2);
    
        //
        // Open UART0 and show the application name on the UART.
        //
        ConfigureUART();
    
        UARTprintf("\033[2JTiva C Series USB bulk device example\n");
        UARTprintf("---------------------------------\n\n");
    
        //
        // Not configured initially.
        //
        g_bUSBConfigured = false;
    
        //
        // Enable the GPIO peripheral used for USB, and configure the USB
        // pins.
        //
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
        ROM_GPIOPinTypeUSBAnalog(GPIO_PORTD_BASE, GPIO_PIN_4 | GPIO_PIN_5);
    
        //
        // Enable the system tick.
        //
        ROM_SysTickPeriodSet(ROM_SysCtlClockGet() / SYSTICKS_PER_SECOND);
        ROM_SysTickIntEnable();
        ROM_SysTickEnable();
    
        //
        // Tell the user what we are up to.
        //
        UARTprintf("Configuring USB\n");
    
        //
        // Initialize the transmit and receive buffers.
        //
        USBBufferInit(&g_sTxBuffer);
        USBBufferInit(&g_sRxBuffer);
    
        //
        // Set the USB stack mode to Device mode with VBUS monitoring.
        //
        USBStackModeSet(0, eUSBModeForceDevice, 0);
    
        //
        // Pass our device information to the USB library and place the device
        // on the bus.
        //
        USBDBulkInit(0, &g_sBulkDevice);
    
        //
        // Wait for initial configuration to complete.
        //
        UARTprintf("Waiting for host...\n");
    
        //
        // Clear our local byte counters.
        //
        ui32RxCount = 0;
        ui32TxCount = 0;
    
        //
        // Main application loop.
        //
        while(1)
        {
            //
            // See if any data has been transferred.
            //
            if((ui32TxCount != g_ui32TxCount) || (ui32RxCount != g_ui32RxCount))
            {
                //
                // Has there been any transmit traffic since we last checked?
                //
                if(ui32TxCount != g_ui32TxCount)
                {
                    //
                    // Turn on the Green LED.
                    //
                    GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, GPIO_PIN_3);
    
                    //
                    // Delay for a bit.
                    //
                    for(ui32Loop = 0; ui32Loop < 150000; ui32Loop++)
                    {
                    }
    
                    //
                    // Turn off the Green LED.
                    //
                    GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, 0);
    
                    //
                    // Take a snapshot of the latest transmit count.
                    //
                    ui32TxCount = g_ui32TxCount;
                }
    
                //
                // Has there been any receive traffic since we last checked?
                //
                if(ui32RxCount != g_ui32RxCount)
                {
                    //
                    // Turn on the Blue LED.
                    //
                    GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, GPIO_PIN_2);
    
                    //
                    // Delay for a bit.
                    //
                    for(ui32Loop = 0; ui32Loop < 150000; ui32Loop++)
                    {
                    }
    
                    //
                    // Turn off the Blue LED.
                    //
                    GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0);
    
                    //
                    // Take a snapshot of the latest receive count.
                    //
                    ui32RxCount = g_ui32RxCount;
                }
    
                //
                // Update the display of bytes transferred.
                //
                UARTprintf("\rTx: %d  Rx: %d", ui32TxCount, ui32RxCount);
            }
    				
    				// Delaying before entering DFU mode.  You can trigger it with a button
    				// press.			
    				SysCtlDelay(200000000);
    						
    				//
    				// Terminate the USB device and detach from the bus.
    				//
    				USBDCDTerm(0);
    
    				//
    				// Disable all interrupts.
    				//
    				ROM_IntMasterDisable();
    
    				//
    				// Disable SysTick and its interrupt.
    				//
    				ROM_SysTickIntDisable();
    				ROM_SysTickDisable();
    
    				//
    				// Disable all processor interrupts.  Instead of disabling them one at a
    				// time, a direct write to NVIC is done to disable all peripheral
    				// interrupts.
    				//
    				HWREG(NVIC_DIS0) = 0xffffffff;
    				HWREG(NVIC_DIS1) = 0xffffffff;
    
    				//
    				// Enable and reset the USB peripheral.
    				//
    				ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0);
    				ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_USB0);
    				ROM_SysCtlUSBPLLEnable();
    
    				//
    				// Wait for about a second.
    				//
    				ROM_SysCtlDelay(ui32SysClock / 3);
    
    				//
    				// Re-enable interrupts at the NVIC level.
    				//
    				ROM_IntMasterEnable();
    
    				//
    				// Call the USB boot loader.
    				//
    				ROM_UpdateUSB(0);
    
    				//
    				// Should never get here, but just in case.
    				//
    				while(1)
    				{
    				}
    		
    		
        }
    }
    

    -Rebecca

  • Rebecca,

    Thanks, looks like it was simply a matter of where the function is called.  I tried your code and it worked.  Then I plugged in my version in the same place and it worked as well.  I noticed you said it matters where my code is added.......Previously I was disconnecting and jumping to boot ROM from EchoNewDataToHost() when a certain command was received.  Apparently it doesn't like this.  I changed it to set a flag and instead and disconnect in main() if the flag is set and it works now.  Apparently trying to disconnect and jump to ROM from the RxHandler is not a good idea. 

    -Tim

  • Quick question,

    I'm trying to receive a command from my computer on my Tiva C device similar to you, but my Tiva C is a hid device.  I'm using the same code from this example that you guys are discussing and have also made use of flags as you have recommended.  I receive the command in my USB switch statement that processes the incoming messages.  When I send a "activate boot loader" command I enable a flag so when I get back into my main loop it eventually jumps into executing the code described in this thread.  For some reason though, I see my hid device disappear, but no DFU appears.  If I erase the chip I can see it go into DFU mode by watching the device manager.  Does this code only allow you to jump into the ROM_Boot loader if you are using the mass storage class or should this be working for me?  My hid devices looks like it is working fine.  Code is below:

    			//
    			// Terminate the USB device and detach from the bus.
    			//
    			USBDCDTerm(0);
    
    			//
    			// Disable all interrupts.
    			//
    			ROM_IntMasterDisable();
    
    			//
    			// Disable SysTick and its interrupt.
    			//
    			ROM_SysTickIntDisable();	// Not using SysTick()
    			ROM_SysTickDisable();
    
    			//
    			// Disable all processor interrupts.  Instead of disabling them one at a
    			// time, a direct write to NVIC is done to disable all peripheral
    			// interrupts.
    			//
    			HWREG(NVIC_DIS0) = 0xffffffff;
    			HWREG(NVIC_DIS1) = 0xffffffff;
    
    			//
    			// Enable and reset the USB peripheral.
    			//
    			ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0);
    			ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_USB0);
    			ROM_SysCtlUSBPLLEnable();
    
    			//
    			// Wait for about a second.
    			//
    			ROM_SysCtlDelay(Sys_Clock / 3);
    
    
    			//
    			// Re-enable interrupts at the NVIC level.
    			//
    			ROM_IntMasterEnable();
    
    			//
    			// Call the USB boot loader.
    			//
    			ROM_UpdateUSB(0);

    Thanks,

    Rob

  • So for some reason I couldn't figure this out for days and then a few hours after I post this I got it working.  Anyways...here is my solution for the above mentioned tiva part.  Just in case anyone runs into the same problem I had of the example code not working.

    			//
    			// Terminate the USB device and detach from the bus.
    			//
    			USBDCDTerm(0);
    
    			//
    			// Disable all interrupts.
    			//
    			ROM_IntMasterDisable();
    
    			//
    			// Disable SysTick and its interrupt.
    			//
    			ROM_SysTickIntDisable();	// Not using SysTick()
    			ROM_SysTickDisable();
    
    			//
    			// Disable all processor interrupts.  Instead of disabling them one at a
    			// time, a direct write to NVIC is done to disable all peripheral
    			// interrupts.
    			//
    			HWREG(NVIC_DIS0) = 0xffffffff;
    			HWREG(NVIC_DIS1) = 0xffffffff;
    		    HWREG(NVIC_DIS2) = 0xffffffff;
    		    HWREG(NVIC_DIS3) = 0xffffffff;
    		    HWREG(NVIC_DIS4) = 0xffffffff;
    
    			//
    			// Enable and reset the USB peripheral.
    			//
    			ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0);
    			ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_USB0);
    			ROM_SysCtlUSBPLLEnable();
    
    			//
    			// Wait for about a second.
    			//
    			ROM_SysCtlDelay(Sys_Clock / 3);
    
    
    			//
    			// Re-enable interrupts at the NVIC level.
    			//
    			ROM_IntMasterEnable();
    
    			//
    			// Call the USB boot loader.
    			//
    			ROM_UpdateUSB(0);
    		}

    I would like to know why I need these additional lines thought:

    		    HWREG(NVIC_DIS2) = 0xffffffff;
    		    HWREG(NVIC_DIS3) = 0xffffffff;
    		    HWREG(NVIC_DIS4) = 0xffffffff;

    Those three were the show stoppers for me.  Also, this ".cmd" file goes along with it.  I just modded the example command file to fit this chip.  The original one (one that I modified for my project) was the default one I had in my project directory so there wasn't anything special about it.

    /******************************************************************************
     *
     *****************************************************************************/
    
    --retain=g_pfnVectors
    
    #define APP_BASE 0x00000000
    #define RAM_BASE 0x20000000
    
    /*
    MEMORY
    {
        FLASH (RX) : origin = 0x00000000, length = 0x00020000
        SRAM (RWX) : origin = 0x20000000, length = 0x00008000
    }
    */
    
    
    /* System memory map */
    
    MEMORY
    {
        /* Application stored in and executes from internal flash */
        FLASH (RX) : origin = APP_BASE, length = 0x00020000
        /* Application uses internal RAM for data */
        SRAM (RWX) : origin = 0x20000000, length = 0x00008000
    }
    
    
    /* The following command line options are set as part of the CCS project.    */
    /* If you are building using the command line, or for some reason want to    */
    /* define them here, you can uncomment and modify these lines as needed.     */
    /* If you are using CCS for building, it is probably better to make any such */
    /* modifications in your CCS project and leave this file alone.              */
    /*                                                                           */
    /* --heap_size=0                                                             */
    /* --stack_size=256                                                          */
    /* --library=rtsv7M4_T_le_eabi.lib                                           */
    
    /* Section allocation in memory */
    
    SECTIONS
    {
        //.intvecs:   > 0x00000000
        .intvecs:   > APP_BASE
        .text   :   > FLASH
        .const  :   > FLASH
        .cinit  :   > FLASH
        .pinit  :   > FLASH
        .init_array : > FLASH
    
        //.vtable :   > 0x20000000
        .vtable :   > RAM_BASE
        .data   :   > SRAM
        .bss    :   > SRAM
        .sysmem :   > SRAM
        .stack  :   > SRAM
    }
    
    __STACK_TOP = __stack + 512;
    

    Maybe this will help someone else out. 

  • Rob,

    Thank you for updating the forum with your solution.  All of the processor interrupts must be disabled before making an update using the ROM USB boot loader, as the comment suggests.  If you look in your part specific data sheet or the part specific header file (in the 'inc' folder) you can find what NVIC DISn registers are available to be written to; this varies per part.  Writing a 1 to the INT[n] bits in the NVIC DISn registers disables interrupt [n].

    -Rebecca

  • Rebecca Ringhof said:
     If you look in your part specific data sheet or the part specific header file

    Kudos to Robbie for persisting - then for caringly detailing his solution.

    Suspect that, "if you look" - may not provide your client-users the full comfort & convenience (i.e. time/effort efficiency) that a more detailed, written, "safeguarding" usage note would provide...  (i.e. these MCU manuals are long, necessarily detailed - guidance/direction, "where to look" appears superior)   As most often - there's a significant divide between, "inside/factory insight" and we, "less part-specific, insightful" users - such additional "detailing" would be welcomed...

  • I have been trying to get USB DFU working on my custom made board with TM4C123GE6PZ on it. I have CCS5 with Tivaware_C_Series_2.0.1.11577 installed. Update over JTAG works, also when doing FlashErase(0x00000000) the device appears to LMFlashProgrammer and firmware can be updated. But would like to enter DFU like discussed above.

    I have experimented the code below with  different combinations. In this forum and in code examples provided in Tivaware library I have seen different solutions wrt usage of MAP_USBClockEnable, MAP_SysCtlPeripheralDisable, MAP_SysCtlUSBPLLEnable, ROM_UpdateUSB(0), (*((void (*)(void))(*(uint32_t *)0x2c)))()

    USBDCDTerm(0);
    MAP_IntMasterDisable();
    MAP_SysTickIntDisable();
    MAP_SysTickDisable();
    HWREG(NVIC_DIS0) = 0xffffffff;
    HWREG(NVIC_DIS1) = 0xffffffff;
    HWREG(NVIC_DIS2) = 0xffffffff;
    HWREG(NVIC_DIS3) = 0xffffffff;
    HWREG(NVIC_DIS4) = 0xffffffff;
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0);
    MAP_SysCtlPeripheralReset(SYSCTL_PERIPH_USB0);
    // MAP_SysCtlPeripheralDisable(SYSCTL_PERIPH_USB0);
    MAP_USBClockEnable(USB0_BASE, 8, USB_CLOCK_INTERNAL);
    MAP_SysCtlUSBPLLEnable();
    MAP_SysCtlDelay(MAP_SysCtlClockGet() / 3);
    MAP_IntMasterEnable();
    // ROM_UpdateUSB(0);
    (*((void (*)(void))(*(uint32_t *)0x2c)))();

    while(1)
    {
    }

    I cant figure out what I am missing here or somewhere else. Any help appreciated.

    Taivo.

  • Hey Taivo,

    The 0x2C entry point ((*((void (*)(void))(*(uint32_t *)0x2c)))();) for the boot loader is for flash based boot loaders, such as boot_serial. The call to enter 0x2C will not work unless you have a bootloader flashed into 0x0.  If you wish to use the ROM boot loader, just use the call ROM_UpdateUSB(0);.  

    USBClockEnable() is used with TM4C129x devices as it uses the USB Clock Configuration register, which is not present on your TM4C123x device.  Use only "MAP_SysCtlUSBPLLEnable();" to enable the USB PLL clock.

    You are using the correct number of NVIC DISn register for your device, so if using the usb_dev_bulk example I posted earlier, make sure you add 

    HWREG(NVIC_DIS2) = 0xffffffff;
    HWREG(NVIC_DIS3) = 0xffffffff;
    HWREG(NVIC_DIS4) = 0xffffffff; after HWREG(NVIC_DIS1) = 0xffffffff;, like in Robbie's example.

    -Rebecca

     

  • Hi Rebecca,

    If you confirm this is the right code to call in my main (I had to add WatchdogResetDisable, otherwise it reset the device at desired interval)...

    USBDCDTerm(0);
    MAP_WatchdogResetDisable(WATCHDOG0_BASE);
    MAP_IntMasterDisable();
    MAP_SysTickIntDisable();
    MAP_SysTickDisable();
    HWREG(NVIC_DIS0) = 0xffffffff;
    HWREG(NVIC_DIS1) = 0xffffffff;
    HWREG(NVIC_DIS2) = 0xffffffff;
    HWREG(NVIC_DIS3) = 0xffffffff;
    HWREG(NVIC_DIS4) = 0xffffffff;
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0);
    MAP_SysCtlPeripheralReset(SYSCTL_PERIPH_USB0);
    MAP_SysCtlUSBPLLEnable();
    MAP_SysCtlDelay(MAP_SysCtlClockGet() / 3);
    MAP_IntMasterEnable();
    ROM_UpdateUSB(0);

    while(1)
    {
    }

    ... and these are used includes and defines ...

    #define TARGET_IS_BLIZZARD_RB1
    #define PART_TM4C123GE6PZ

    #include "inc/hw_memmap.h"
    #include "inc/hw_nvic.h"
    #include "inc/hw_types.h"
    #include "driverlib/gpio.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/rom.h"
    #include "driverlib/rom_map.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/systick.h"
    #include "driverlib/watchdog.h"
    #include "driverlib/usb.h"
    #include "usblib/usblib.h"
    #include "usblib/device/usbdevice.h"
    #include "usblib/device/usbddfu-rt.h"

    ... then the problem should be somewhere else. Is there any other config file I should check?

    Thanks for your kind help.

    Taivo.

  • Taivo,

    In the latest version of TivaWare, there was a change made: TARGET_IS_BLIZZARD_RB1 is now TARGET_IS_TM4C123_RB1.  The portion of code to use the ROM USB boot loader looks correct.  Please try comparing your code with the usb_dev_bulk example posted earlier for the #define's and ensure that your USB device has already been properly enumerated earlier in your code.

    -Rebecca

  • Hi Rebecca,

    I replaced BLIZZARD with TM4C123 in my current Tivaware 2.0.1 and obviously it did not compile. So I upgraded to 2.1.0 but I still had to use BLIZZARD in order to get it compiled. It is strange as I did see new TM4C123 definition in rom.h and I am sure new Tivaware was used as I had to remove SysCtlADCSpeedSet from the code. So, with BLIZZARD it got compiled, but DFU still was not invoked.

    I compared once again example projects. Found that all usb projects have USB0DeviceIntHandler defined in their startup.c file, but it didnt help me.
    I tried importing several usb examples and uploading with minor modifications into my device (removing graphic and touch modules) - but I could not see the device to appear into LMFlashProgrammer.

    So I did minimal version of my project and would like you to ask to check my entire setup. Will you be able to start DFU at your side? I see it working only when I use mem_dfu() function instead of global_dfu().

    Really running out of ideas, but most likely I am missing something obvious.

    Thanks for your time,

    Taivo.

    8875.dfu.zip

  • Hi Rebecca,

    I got it solved by adding these two lines which I had commented out in my pin.c as they were not needed for normal operation, even if LMFlasher programmed correclty over USB:

    ROM_GPIOPinTypeUSBAnalog(GPIO_PORTJ_BASE, GPIO_PIN_0);

    ROM_GPIOPinTypeUSBAnalog(GPIO_PORTJ_BASE, GPIO_PIN_1);

    Thanks anyway!

    Taivo.

  • Hi,


    I embedded some of Rebecca's code and I am able to see (with lsusb -v) my device configured as DFU. Then I run LM Flash Programmer over Wine but I see no DFU option in the interface tab. Is it because of the LM version (Build 1613)? Can I program using DFU via the lmflash command line? That's what I use to program over ICDI.

    Thanks,

    Kimon

  • Hello Taivo,

    The latest version of TivaWare is 2.1.1

    When you updated to the new version did you ensure that the variables in CCS were correctly updated?

    Regards
    Amit
  • Hello Rebecca,

    Is there any extra function to call for TM4C1237D5? Your code helped to stop my application and go to bootloader mode, but in my PC it appears as Unknown device, I'm figuring out that the same driver (the one used for USB DFU when flash is empty) works for this boot mode.