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.

TM4C1294NCPDT: How to customize USB descriptor for ROM_UpdateUSB

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

Do you have any example code for customizing the USB strings for the ROM DFU bootloader?

In the TivaTmCSeriesTM4C129x ROM User's guide, the following documentation is provided:

In the TivaTmCSeriesTM4C123x ROM User's guide, I found what seems to be how this configuration should look:


Using this, I have been able to change the VID and PID etc, but I have not been able to change the string table. I have tried with both custom strings, but also providing 0 as the address to the string table, which per documentation should point to the default strings:
"The values for the custom strings are contained in apointer at the end of the structure passed to the bootloader. If the application wants to use the default strings, this pointer should beset to 0."

When calling ROM_UpdateUSB(0), I get the following InstanceID in windows:
USB\VID_1CBE&PID_00FF\00000000 and I also get a BusReportedDeviceDesc: Tiva Device Firmware Update 

When calling ROM_UpdateUSB(pui8USBBootROMInfo), I get the following InstanceID in windows:
USB\VID_1CBE&PID_00FF\7&3AF01874&0&2 and no BusReportedDeviceDesc at all.

Example code for creating custom descriptor strings would be greatly appreciated.

  • Hi,

      I must admit that I have not used ROM_UpdateUSB  by passing the pointer pui8USBBootROMInfo as a argument before.  Have you tried the example shown in the ROM user's guide?

    uint8_t pui8Strings[] =
    {
    (1 * 2) + 2, // One Language (1 * 2) + 2
    USB_DTYPE_STRING,
    0x09, 0x04, // Language code for US English.
    (17 * 2) + 2, // Size of Manufacturer String.
    // "Texas Instruments"
    USB_DTYPE_STRING,
    ’T’, 0, ’e’, 0, ’x’, 0, ’a’, 0, ’s’, 0, ’ ’, 0, ’I’, 0, ’n’, 0,
    ’s’, 0, ’t’, 0, ’r’, 0, ’u’, 0, ’m’, 0, ’e’, 0, ’n’, 0, ’t’, 0,
    ’s’, 0,
    (23 * 2) + 2, // Size of Product String.
    USB_DTYPE_STRING,
    // "Device Firmware Upgrade"
    ’D’, 0, ’e’, 0, ’v’, 0, ’i’, 0, ’c’, 0, ’e’, 0, ’ ’, 0, ’F’, 0,
    ’i’, 0, ’r’, 0, ’m’, 0, ’w’, 0, ’a’, 0, ’r’, 0, ’e’, 0, ’ ’, 0,
    ’U’, 0, ’p’, 0, ’g’, 0, ’r’, 0, ’a’, 0, ’d’, 0, ’e’, 0,
    (3 * 2) + 2, // Size of Serial Number.
    USB_DTYPE_STRING,
    // "1.0"
    ’1’, 0, ’.’, 0, ’0’, 0
    };
    uint8_t pui8USBBootROMInfo[] =
    {
    0xbe, 0x1c, // TI VID
    0xff, 0x00, // Tiva DFU PID
    0x00, 0x02, // USB version 2.0
    0x00, // 0mA of Bus power
    0xC0, // Self powered using no bus power
    pui8Strings // Address of the string table
    }
    //
    // Call to ROM USB boot loader.
    //
    ROM_UpdateUSB(pui8USBBootROMInfo);

  • Yes I have tried this, but as I unfortunately:

    " I have not been able to change the string table. I have tried with both custom strings, but also providing 0 as the address to the string table, which per documentation should point to the default strings"

    So I am hoping you could provide me with some known-to-work code.

  • Hi,

      We don't have other examples other what is shown in the ROM user's guide and I have not used the custom table myself for ROM_UpdateUSB(). 

      Did you try the example(the one I pasted above) as is without modification? What do you get?

      If you modify to customize your string table then can you show your string table structure?

      Can you cross verify if your customized table conforms to the table definition as follows?

  • Yes,

    I've used the example from the ROM user's guide directly, this is what I'm referring to as custom strings. This is also why have have tried using 0, 0, 0, 0 as address to the string table to use the default strings, to at least see that I could get the same behavior as with not using customized pointer, but no.

    As I posted, both when using pui8Stringtable as address and 0 as address, windows is not able to read the usb string descriptors.

    Running dfu-util --list gives error message:
    "Broken LANGID string descriptor"

    lm flash programmer is not able to recognize the device as a USB DFU unless I use ROM_UpdateUSB(0);

    I am able to change VID and PID and the other parameters, but the strings does not seem to work to change.

    Perhaps you could test it at your end?

  • Hi,

      I have modified a USB example to call ROM_UpdateUSB with pui8USBBootROMInfo. For the moment I'm having problem to even get ROM_UpdateUSB(0) work. I may have other issues I need to debug. However, I'm working remotely in a foreign country right now. I will be able to try out other boards once I get back to my home country next week. 

      Here is the code that I use. Perhaps your is somewhat similar. Please let me know what did you see. 

    boot_demo_usb.zip

  • Thank you Charles,

    I use gcc, so I just copied your code from boot_demo_usb.c into TivaWare_C_Series-2.2.0.295\examples\boards\ek-tm4c1294xl\boot_demo_usb

    I also added some extra 0s to the end of pui8USBBootROMInfo to make sure it was 12 bytes of valid data as stated in the documentation:

    Unfortunately, the results looks the same as my tests, and it shows up as runtime DFU device, but when put into DFU mode, but the strings are still not showing up:

    Broken LANGID string descriptor

  • Hi,

      I will run it to confirm the same when I have a good working board next week. Having said that, I'm not sure if there is an issue with the ROM_UpdateUSB. Please note that ROM_UpdateUSB is a API stored in the ROM. There is no chance to modify the ROM code unless a silicon respin which is not possible. In the meantime, can you please try the flash-based USB bootloader?

  • I know a flash based USB bootloader would work, but we really wanted to make use of the ROM-based loader for simplicity. 

    I assumed that TI had some kind of example code and had tested this feature in-house as it is documented in the user's guide. Is there maybe someone else who has more knowledge of the ROM based bootloader than you?

  • I will get back to you when I can try on a working board. I did notice that the example you referred is documented in the TM4C123 ROM User's guide. Reading the TM4C129 ROM user's guide https://www.ti.com/lit/pdf/spmu363, the example is somehow missing. I don't know what this entails to although the ROM_UpdateUSB() should work for both MCUs. 

  • Hi,

     I found a working board and did an experiment. 

    I loaded the flash with the example I attached here earlier. 

    I do a dfuprog.exe -e and find the DFU device. 

    I then do dfuprog.exe -m to switch from Run mode to DFU mode. 

    Next I do dfuprog.exe -e again to show connected devices. This times it displays the new PID as 0xFF. However, it shows <Unknown" for Device Name, Manufacture, DFU Interface and Serial Num. 

    If I try to upgrade a new firmware by giving the command dfuprog.exe -f blinky.bin, it will load the new firmware. Here I simply try to upgrade the firmware with a simple blinky example to see if a download is successful. I can see the LED blinking on the LaunchPad board. 

    Having done this example, I don't know why the string is shown as unknown. I wonder if the ROM bootloader really contains the default strings as described in the user's guide. 

  • Thanks Charles, glad to see you have been able to reproduce the same issues that i've seen.

    It would be great if you could escalate the issue to someone with more knowledge of the ROM_UpdateUSB functionality.

  • Hi,

      I must admit I'm not an expert in the implementation for ROM_UpdateUSB and unfortunately I can't find anyone who has more knowledge to assist me in diagnosing the problem. I have searched the form archive to no avail as you are very likely the first one to customize string table using ROM_UpdateUSB. The ROM code was part of the silicon that was released perhaps 8-10 years ago. I hope it is not an unknown ROM code issue as there will not be a silicon re-spin. I will dig around to see if I can find new information about this matter. 

  • Hi Charles, Have you found any more information?

  • Hi,

      Can you show me your snippet of code on how you declare the pui8Strings and pui8USBBootROMInfo?  If I use the code as is presented on user's guide, I  have a compile issue with a warming that says: warning #145-D: a value of type "uint8_t *" cannot be used to initialize an entity of type "uint8_t". As a result of the warning, the pointer to pui8Strings is not correct. As you can see in mine, the pui8Strings starts at 0x20000510. Are you getting any warning?

  • Hi,

    yes the example does not compile as is, the address of the string table needs 4 bytes.

    That's also why I added extra 0s to the end of pui8USBBootROMInfo when trying use the builtin string table to make sure all 12 bytes of the info are valid.

    const uint8_t pui8Strings[]= {
         (1*2)+2,           //OneLanguage(1*2)+2
         USB_DTYPE_STRING,
         0x09,0x04,         //LanguagecodeforUSEnglish.
         (17*2)+2,          //SizeofManufacturerString.
                            //"TexasInstruments"
        USB_DTYPE_STRING,
        'T',0,'e',0,'x',0,'a',0,'s',0,' ',0,'I',0,'n',0,
        's',0,'t',0,'r',0,'u',0,'m',0,'e',0,'n',0,'t',0,
        's',0, (23*2)+2,    //SizeofProductString.
        USB_DTYPE_STRING,   //"DeviceFirmwareUpgrade"
        'D',0,'e',0,'v',0,'i',0,'c',0,'e',0,' ',0,'F',0,
        'i',0,'r',0,'m',0,'w',0,'a',0,'r',0,'e',0,' ',0,
        'U',0,'p',0,'g',0,'r',0,'a',0,'d',0,'e',0,
        (3*2)+2,            //SizeofSerialNumber.
        USB_DTYPE_STRING,   //"1.0"
        '1',0,'.',0,'0',0
    };
    uint8_t pui8USBBootROMInfo[12] = {  
        0xad, 0xde,
        0xef, 0xbe,
        0x00, 0x02,
        0x00,
        0x80,
        (uint8_t)(((uint32_t)pui8Strings & 0xff000000) << 24),
        (uint8_t)(((uint32_t)pui8Strings & 0xff0000) << 16),
        (uint8_t)(((uint32_t)pui8Strings & 0xff00) << 8),
        (uint8_t((uint32_t)pui8Strings & 0xff)),

    };
  •     (uint8_t)(((uint32_t)pui8Strings & 0xff000000) << 24),
        (uint8_t)(((uint32_t)pui8Strings & 0xff0000) << 16),
        (uint8_t)(((uint32_t)pui8Strings & 0xff00) << 8),
        (uint8_t((uint32_t)pui8Strings & 0xff)),

    I tried your above code and I think there is a mistake. You try to type-cast to uint8_t. This will result a 0x0 after you type-cast from 32bit to 8 bits. You should change from << to >> as follows.

    (uint8_t)(((uint32_t)pui8Strings & 0xff000000) >> 24),
    (uint8_t)(((uint32_t)pui8Strings & 0xff0000) >> 16),
    (uint8_t)(((uint32_t)pui8Strings & 0xff00) >> 8),
    (uint8_t)(((uint32_t)pui8Strings & 0xff))

    Having done that, it does not solve the problem either when I tried it. If I use dfuprog.exe -m to switch to DFU mode and then then dfuprog.exe -e again I will see garbage unreadable characters for the strings. However, it will enumerate as a DFU device and I'm able to download new firmware through USB device port. Please give a try and see what you get on your side. 

  • Yes, you're right. 

    Wrong copy pasteStuck out tongue

    But yes, I have tried the correct version, which does not give out any strings as you've also seen. 

    Have you been able to talk to someone else about this? 

  • I found the source code for ROM_UpdateUSB that is stored in the ROM. If you look at line 37, &pui8ROMInfo[8] is assigned to g_pcStringDescriptors. I think this is wrong. &pui8ROMInfo[8] is actually a pointer address for the 8th element in the pui8USBBootROMInfo array. It is not the content of 8th element in the array. As it is, I don't know how to work around it. Please bear in mind ROM content is not changeable unless a silicon re-spin. If you come up with a software workaround that I miss out, please do let me know and I'm keen to learn something new. 

    //*****************************************************************************
    //
    // The application entry point.
    //
    //*****************************************************************************
    void
    UpdaterUSB(uint8_t *pui8ROMInfo)
    {
        //
        // Configure the USB controller.
        //
        USBBLInit();
    
        //
        // Only customize if the pointer is not 0.
        //
        if(pui8ROMInfo)
        {
            //
            // Fix up the device descriptor.
            //
            g_pDFUDeviceDescriptor[8] = pui8ROMInfo[0];
            g_pDFUDeviceDescriptor[9] = pui8ROMInfo[1];
    
            g_pDFUDeviceDescriptor[10] = pui8ROMInfo[2];
            g_pDFUDeviceDescriptor[11] = pui8ROMInfo[3];
    
            g_pDFUDeviceDescriptor[12] = pui8ROMInfo[4];
            g_pDFUDeviceDescriptor[13] = pui8ROMInfo[5];
    
            //
            // Fix up the configuration descriptor.
            //
            g_pDFUConfigDescriptor[7] = pui8ROMInfo[6];
            g_pDFUConfigDescriptor[8] = pui8ROMInfo[7];
    
            g_pcStringDescriptors = &pui8ROMInfo[8];
        }
        else
        {
            //
            // Default back to the ROM strings.
            //
            g_pcStringDescriptors = (uint8_t *)g_pcDefaultStringDescriptors;
        }
    
        //
        // Enable the USB controller now that the descriptors have been fixed up.
        //
        USBControllerInit();
    
        //
        // Call the main update routine.
        //
        while(1)
        {
            USBTick();
        }
    }

  • Thank you, that helps!

    As the ROM code uses the address of the end of the romInfo table, we can just place the strings directly in the table:

    uint8_t pui8USBBootROMInfo[] =
    {
    0xbe, 0x1c, // TI VID
    0xff, 0x00, // Tiva DFU PID
    0x00, 0x02, // USB version 2.0
    0x00, // 0mA of Bus power
    0xC0, // Self powered using no bus power
         (1*2)+2,           //OneLanguage(1*2)+2
         USB_DTYPE_STRING,
         0x09,0x04,         //LanguagecodeforUSEnglish.
         (17*2)+2,          //SizeofManufacturerString.
                            //"TexasInstruments"
        USB_DTYPE_STRING,
        'T',0,'e',0,'x',0,'a',0,'s',0,' ',0,'I',0,'n',0,
        's',0,'t',0,'r',0,'u',0,'m',0,'e',0,'n',0,'t',0,
        's',0, (23*2)+2,    //SizeofProductString.
        USB_DTYPE_STRING,   //"DeviceFirmwareUpgrade"
        'D',0,'e',0,'v',0,'i',0,'c',0,'e',0,' ',0,'F',0,
        'i',0,'r',0,'m',0,'w',0,'a',0,'r',0,'e',0,' ',0,
        'U',0,'p',0,'g',0,'r',0,'a',0,'d',0,'e',0,
        (3*2)+2,            //SizeofSerialNumber.
        USB_DTYPE_STRING,   //"1.0"
        '1',0,'.',0,'0',0
    };
    And then I get the correct serial number listed in dfu-util Smiley

    So that means that the documentation needs some updates as it is not correct. It is also not possible to use default strings when the rest of the table is custom.
     
     
  • I found another error in the documentation:
     
    uint8_t pui8USBBootROMInfo[] =
    {
    0xbe, 0x1c, // TI VID
    0xff, 0x00, // Tiva DFU PID
    0x00, 0x02, // USB version 2.0
    0x00, // 0mA of Bus power
    0xC0, // Self powered using no bus power
    0
    };
    Bus power current and whether the device is self-powered of bus powered are swapped in the table.
    Also, 0xc0 means both bus and self powered, bus powered is 0x80 and self powered is 0x40.
  • Hi,

      Thank you for the feedback.  I'm curious if you get it to work after you swap?  I see the assignment for pui8ROMInfo[6] and pui8ROMInfo[7] to g_pDFUConfigDescriptor[7] and g_pDFUConfigDescriptor[8] respectively. 

    if(pui8ROMInfo)
    {
    //
    // Fix up the device descriptor.
    //
    g_pDFUDeviceDescriptor[8] = pui8ROMInfo[0];
    g_pDFUDeviceDescriptor[9] = pui8ROMInfo[1];

    g_pDFUDeviceDescriptor[10] = pui8ROMInfo[2];
    g_pDFUDeviceDescriptor[11] = pui8ROMInfo[3];

    g_pDFUDeviceDescriptor[12] = pui8ROMInfo[4];
    g_pDFUDeviceDescriptor[13] = pui8ROMInfo[5];

    //
    // Fix up the configuration descriptor.
    //
    g_pDFUConfigDescriptor[7] = pui8ROMInfo[6];
    g_pDFUConfigDescriptor[8] = pui8ROMInfo[7];

    g_pcStringDescriptors = &pui8ROMInfo[8];
    }

    g_pDFUConfigDescriptor is of type g_pROMConfigDescriptor where the definition is as follows. The g_pDFUConfigDescriptor[7] corresponds to the maximum current while  g_pDFUConfigDescriptor[8] corresponds to length of the Interface Descriptor. If you swap the pui8USBBootROMInfo[6] and pui8USBBootROMInfo[7] from (0x0, 0xC0) to (0xC0, 0x0) then you can get the Bus/Self power field to work but I'm afraid the g_pDFUConfigDescriptor[8] will become 0 by mistake which will affect the length of the Interface Descriptor. 

    const uint8_t g_pROMConfigDescriptor[] =
    {
    //
    // Configuration descriptor header.
    //
    9,                       // Size of the configuration descriptor.      [0]
    USB_DTYPE_CONFIGURATION, // Type of this descriptor.                   [1]
    USBShort(27),            // The total size of this full structure.     [2]
    1,                       // The number of interfaces in this           [3]
                             // configuration.
    1,                       // The unique value for this configuration.   [4]
    0,                       // The string identifier that describes this  [5]
                             // configuration.
    USB_CONF_ATTR_SELF_PWR,  // Self Powered                               [6]
    0,                       // The maximum power in 2mA increments.       [7]

    //
    // Interface descriptor.
    //
    9,                       // Length of this descriptor.                 [8]
    USB_DTYPE_INTERFACE,     // This is an interface descriptor.
    0, // Interface number .
    0, // Alternate setting number.
    0, // Number of endpoints (only endpoint 0 used)
    USB_CLASS_APP_SPECIFIC, // Application specific interface class
    USB_DFU_SUBCLASS, // Device Firmware Upgrade subclass
    USB_DFU_PROTOCOL, // DFU protocol
    0, // No interface description string present.

    //
    // Device Firmware Upgrade functional descriptor.
    //
    9, // Length of this descriptor.
    0x21, // DFU Functional descriptor type
    (DFU_ATTR_CAN_DOWNLOAD | // DFU attributes.
    DFU_ATTR_CAN_UPLOAD |
    DFU_ATTR_MANIFEST_TOLERANT),
    USBShort(0xFFFF), // Detach timeout (set to maximum).
    USBShort(DFU_TRANSFER_SIZE),// Transfer size 1KB.
    USBShort(0x0110) // DFU Version 1.1
    };

  • Hi Charles,

    The third entry of g_pROMConfigDescriptor: USBShort(27) is a macro which creates two entries in the table:

    #define USBShort(ui16Value)     (ui16Value & 0xff), (ui16Value >> 8)

    meaning that Self Powered is entry 7 and maximum power is entry 8.

    So when the ROM code is copying this into the g_pDFUConfigDescriptor, it copies pui8ROMInfo[6] into self powered and pui8ROMInfo[7] into maximum power. Meaning that entry 6 and 7 are swapped in the documentation for pui8ROMInfo:

    Testing shows that this is indeed what's happening:


    Using original:

        uint8_t info[] =
        {
        0xbe, 0x1c, // TI VID
        0xff, 0x00, // Tiva DFU PID
        0x00, 0x02, // USB version 2.0
        0x00, // 0mA of Bus power
        0xC0, // Self powered using no bus power

    Gives the following output in usbview.exe:

    ===>Configuration Descriptor<===
    bLength: 0x09
    bDescriptorType: 0x02
    wTotalLength: 0x001B -> Validated
    bNumInterfaces: 0x01
    bConfigurationValue: 0x01
    iConfiguration: 0x00
    bmAttributes: 0x00 -> Bus Powered

    *!*ERROR: Bit 7 is reserved and must be set
    MaxPower: 0xC0 = 384 mA

    Swapping self powered attribute and bus power:

     uint8_t info[] =
        {
        0xbe, 0x1c, // TI VID
        0xff, 0x00, // Tiva DFU PID
        0x00, 0x02, // USB version 2.0
        0xc0, // Self powered using no bus power
        0x00, // 0mA of Bus power

    results in this output in usbview.exe:
    ===>Configuration Descriptor<===
    bLength: 0x09
    bDescriptorType: 0x02
    wTotalLength: 0x001B -> Validated
    bNumInterfaces: 0x01
    bConfigurationValue: 0x01
    iConfiguration: 0x00
    bmAttributes: 0xC0 -> Self Powered
    MaxPower: 0x00 = 0 mA

    sending in a nullptr to ROM_UpdateUSB to use the default config results in the same:
    ===>Configuration Descriptor<===
    bLength: 0x09
    bDescriptorType: 0x02
    wTotalLength: 0x001B -> Validated
    bNumInterfaces: 0x01
    bConfigurationValue: 0x01
    iConfiguration: 0x00
    bmAttributes: 0xC0 -> Self Powered
    MaxPower: 0x00 = 0 mA

  • Hi,

    The third entry of g_pROMConfigDescriptor: USBShort(27) is a macro which creates two entries in the table:

    Thank you so much. I fail to investigate the actual size of USBShort(27) which takes up two bytes. In that case, swapping will work.