USB Device Firmware Update (DFU) Device

The USB device stack includes a device firmware update interface for implementing the device firmware update class. The interface support for both the runtime and DFU modes of operation.

The DFU interface performs all of the required state management and communications with the connected host. The interface calls upon the application using signals.

  • SIGNAL_DFUDDETACH
    The signal is set when the host has requested the device to switch modes. The host can request a switch from DFU to runtime mode or vise versa.
  • SIGNAL_DFUDDOWNLOAD
    The signal is set when a block of data has been received by a host and is to be downloaded into the device. The application is responsible for storing this data and must call DFUD_DownloadComplete() when operation has completed. The application can choose to either commit this data to non-volatile memory immediately, or it can cache it and wait for the manifestation phase.
  • SIGNAL_DFUDUPLOAD
    The signal is set when the host has requested to upload a block of data from the device. The application is responsible for providing the program data to the interface data block. The application must call DFUD_UploadComplete() upon completion.
  • SIGNAL_DFUDMANIFEST
    The signal is set when the host has requested manifestation of the downloaded firmware and occurs after all download events have been completed. Once the application has completed the manifestation, it must call DFUD_ManifestComplete().

Example Usage

The code snippet below demonstrates the use of a DFU interface as needed within a bootloader application to provide the ability to update the device's firmware/software. The snippet utilizes the signaling provided by the DFU interface.

#include "USB/Device/usbd_dfu.h"
#include "Bootloader/boot.h"
#include <string.h>
#include <assert.h>

static USBDDEVICE usb;                                              /* Allocate a USB device stack instance */
static DFUDINTERFACE dfu;                                           /* Allocate a DFU interface */

/* Main application thread */
void APP_Main(void* arg)
{
    STATUS status;
    UINT32 signals;
    DFUDBLOCK* blk;


    APP_InitUSB();                                                  /* Initialize the start the USB connection */

    for (;;) {

        status = DFUD_Wait(&dfu, &signals, INFINITE);               /* Wait for a DFU event */


        if (status == SUCCESS) {
            
            if (signals & SIGNAL_DFUDDOWNLOAD) {                    /* Download block completed? */
                
                blk = DFUD_GetDataBlock(&dfu);                      /* Get the data that has been received from the host */
                if (blk) {        
                    APP_Download(blk);                              /* Download the block to flash memory */
                    DFUD_DownloadComplete(&dfu);                    /* Indicate the download operation is complete */
                }
            }
            
            if (signals & SIGNAL_DFUDMANIFEST) {                    /* Manifest firmware stage? */
                DFUD_ManifestComplete(&dfu);                        /* Signal manifest stage complete */
            }
            
            if (signals & SIGNAL_DFUDDETACH) {
                
                USBD_Close(&usbd);                                  /* Close and disconnect the USB connection (host will see this) */
                BOOT_ExecuteRuntime();                              /* Attempt to execute the runtime application */
                
                DFUD_SetError(&dfu, DFUERROR_FIRMWARE);             /* Failed to switch to runtime application, go to error state */
            }
            
            if (signals & SIGNAL_DFUDUPLOAD) {
                blk = DFUD_GetDataBlock(&dfu);                      /* Get the data that has been received from the host */
                if (blk) {
                    APP_Upload(blk);                                /* Read the flash memory and write it to the DFU block */
                    DFUD_UploadComplete(&dfu);                      /* Indicate the upload data is ready to be sent to the host */
                }
            }
        }
    }
}

/* Initializes the USB interface for a DFU bootloader application */
static void APP_InitUSB(void)
{
    ALIGNED(64) static BYTE dfubuf[CFG_DFUDTRANSFERSIZE];       /* Allocate a buffer for download/upload data over USB DFU */
    STATUS status;


    status = USBD_Create(&usb,                                  /* Initialize the USB device stack instance */
                         0,                                     /* Port number */
                         0x0000,                                /* Vendor ID */ 
                         0x0010);                               /* Product ID */
   
    assert(status == SUCCESS);
    
    status = USBD_SetDeviceName(&usb,                           /* Assign name strings for the device */
                                "DZX",                          /* Manufacturer Name */
                                "BOOTLOADER DEMO",              /* Product Name */
                                NULL);                          /* Serial Number (none, so NULL) */

    assert(status == SUCCESS);

    status = DFUD_CreateInterface(&usb,                         /* A pointer to the usb device stack to receive the interface */
                                  &dfu,                         /* A pointer to the interface to be initialized */
                                  MODE_DFU,                     /* The mode of the application (DFU mode) */
                                  dfubuf,                       /* The buffer to be used for data download/upload transfers */
                                  sizeof(dfubuf));              /* The size, in bytes, of the transfer buffer */

    assert(status == SUCCESS);

    status = USBD_SetMicrosoftDescriptorSupport(&usb, TRUE);    /* Enable automatic loading of WinUSB driver on Microsoft Windows */
    assert(status == SUCCESS);

    status = USBD_Open(&usb);                                   /* Open the port and start communications */
    assert(status == SUCCESS);
}

Runtime Mode

The DFU interface can be used within the runtime application in the runtime mode to provide the ability to automatically switch execution to the bootloader application (DFU mode). The code snippet below demonstrates using the DFU interface to receive a DETACH signal. Upon receiving the signal, the thread closes the USB connection and switches execution to the bootloader application.

#include "USB/Device/usbd_dfu.h"
#include "Bootloader/boot.h"
#include <assert.h>

static USBDDEVICE usb;                                          /* Allocate a USB device stack instance */
static DFUDINTERFACE dfu;                                       /* Allocate a DFU interface */

/* Main application thread */
void APP_Main(void* arg)
{
    STATUS status;
    UINT32 signals;


    APP_InitUSB();                                              /* Initialize the start the USB connection */

    for (;;) {

        status = DFUD_Wait(&dfu, &signals, INFINITE);           /* Wait for a signal (event) from the DFU interface */           
        if (status == SUCCESS) {
            
            if (signals & SIGNAL_DFUDDETACH) {                  /* Received a DFU DETACH request? */
                USBD_Close(&usb);                               /* Yes, close down the port to force bus reset */
                BOOT_ExecuteBootloader();                       /* Request to switch to the bootloader application */
            }
        }
    }
}

/* Initializes the USB interface for a DFU runtime application */
static void APP_InitUSB(void)
{
    STATUS status;


    status = USBD_Create(&usb,                                  /* Initialize the USB device stack instance */
                         0,                                     /* Port number */
                         0x0000,                                /* Vendor ID */ 
                         0x0010);                               /* Product ID */
   
    assert(status == SUCCESS);
    
    status = USBD_SetDeviceName(&usb,                           /* Assign name strings for the device */
                                "DZX",                          /* Manufacturer Name */
                                "RUNTIME DEMO",                 /* Product Name */
                                NULL);                          /* Serial Number (none, so NULL) */

    assert(status == SUCCESS);

    status = DFUD_CreateInterface(&usb,                         /* A pointer to the usb device stack to receive the interface */
                                  &dfu,                         /* A pointer to the interface to be initialized */
                                  MODE_RUNTIME,                 /* The mode of the application (runtime application mode) */
                                  NULL,                         /* A buffer for download/upload transfers (none needed for runtime mode) */
                                  0);                           /* Size of the transfer buffer */

    assert(status == SUCCESS);

    status = USBD_SetMicrosoftDescriptorSupport(&usb, TRUE);    /* Enable automatic loading of WinUSB driver on Microsoft Windows */
    assert(status == SUCCESS);

    status = USBD_Open(&usb);                                   /* Open the port and start communications */
    assert(status == SUCCESS);
}

More Information

API Reference

STATUS DFUD_CreateInterface(USBD* device, DFUDINTERFACE* intf, BYTE mode, void* buf, UINT32 bufsize)
Creates and initializes a Device Firmware Update (DFU) interface for a USB device.
PARAMETERS
device A pointer to a USB device that will receive the interface.
intf A pointer to a caller allocated DFU interface to be initialized.
mode The DFU mode to be implemented by the class.
MODE_RUNTIME Indicates the device is in the runtime mode.
MODE_DFU Indicates the device is in the DFU mode.
buf A pointer to a buffer used to hold data that has been downloaded or to be uploaded from the interface. Can be NULL for runtime mode.
bufsize The size, in bytes, of the buffer. This is also the default transfer size for the interface.
RETURNS
SUCCESS The interface was created and initialized.
ERR_NULLREFERENCE The argument 'device', 'intf', or 'callback' was found to be NULL.
STATUS DFUD_Wait(DFUDINTERFACE* intf, UINT32* signals, UINT32 timeout)
Waits for any event signals for a device firmware update (DFU) interface to be set.
PARAMETERS
intf A pointer to the interface that will receive the signals.
signals A pointer to a caller allocated signal array to receive the returned signals.
timeout The maximum amount of time, in kernel ticks, to wait for a signal to be received. Use '0' to return immediately without blocking and use INFINITE to wait indefinitely.
RETURNS
SUCCESS At least one signal has been received.
ERR_NULLREFERENCE The argument 'intf' or 'signals' was found to be NULL.
ERR_INVALIDCONTEXT The operation is not supported from the context of an interrupt service routine (ISR).
ERR_TIMEOUT The maximum allowable time has elapsed prior to the specified signal being received.
const DFUDSETTINGS* DFUD_Settings(DFUDINTERFACE* intf)
Returns the current settings for a USB device DFU interface.
PARAMETERS
intf A pointer to the interface that contains the settings to be returned.
RETURNS
A pointer to the settings for the specified interface upon success; otherwise NULL.
STATUS DFUD_SetSettings(DFUDINTERFACE* intf, DFUDSETTINGS* settings)
Assigns new settings to a Device Firmware Update (DFU) interface.
PARAMETERS
intf A pointer to the interface to receive the settings.
settings A pointer to the new settings that should be applied.
RETURNS
SUCCESS The new settings have been applied.
ERR_NULLREFERENCE The argument 'intf' or 'settings' was found to be NULL.
STATUS DFUD_DownloadComplete(DFUDINTERFACE* intf)
Signals to a device DFU interface that a download operation has been handled and is complete.
PARAMETERS
intf A pointer to the target interface.
RETURNS
SUCCESS The interface state has been updated.
ERR_NULLREFERENCE The argument 'intf' was found to be NULL.
STATUS DFUD_UploadComplete(DFUDINTERFACE* intf)
Signals to a device firmware update (DFU) interface that the upload operation has been handled and is complete.
PARAMETERS
intf A pointer to the target interface.
RETURNS
SUCCESS The interface state has been updated.
ERR_NULLREFERENCE The argument 'intf' was found to be NULL.
STATUS DFUD_ManifestComplete(DFUDINTERFACE* intf)
Signals to a device DFU interface that the manifest operation has been handled and is complete.
PARAMETERS
intf A pointer to the target interface.
RETURNS
SUCCESS The interface state has been updated.
ERR_NULLREFERENCE The argument 'intf' was found to be NULL.
STATUS DFUD_SetError(DFUDINTERFACE* intf, DFUERROR error)
Sets a DFU interface into an error state with the specified status.
PARAMETERS
intf A pointer to the target interface to receive the error state.
error The error status for the interface.
RETURNS
SUCCESS The interface error has been assigned.
ERR_NULLREFERENCE The argument 'intf' was found to be NULL.
DFUDBLOCK* DFUD_GetDataBlock(DFUDINTERFACE* intf)
Returns the current data block for a device DFU interface. The data block contains the data that has most recently been downloaded or uploaded.
PARAMETERS
intf A pointer to the target interface.
RETURNS
A pointer to the data block upon success; otherwise NULL.