| USBD ROM Stack 2.0 ROM based USB device stack

How to implement simple DFU device ?

The DFU (Device Firmware Upgrade) class consists primarily of devices that are required for device firmware update capability.

# Initialization

After successfully initializing the USBD ROM stack i.e. USBD_HW_API_T::Init, the DFU class driver needs to be initialized as follows:

- Configure initialization parameters of the DFU class driver
  USBD_DFU_INIT_PARAM_T dfu_param;
  memset((void *) &dfu_param, 0, sizeof(USBD_DFU_INIT_PARAM_T));
- Set the memory location where the DFU class driver can allocate buffers and global variables. All the init() routines of the ROM components are written in such a way that the mem_base and mem_size members of XXX_INIT_PARAM_T are updated with free location and size before returning. So that the next component XXX_INIT_PARAM_T can use the update values for its init() routine. Applications can cascade the component initialization this way without worrying about memory wastage/overlap issues.
  dfu_param.mem_base = usb_param.mem_base;
  dfu_param.mem_size = usb_param.mem_size;
  dfu_param.wTransferSize = USB_DFU_XFER_SIZE;
- Obtain the address location of the interface descriptor, within the device configuration descriptor array, to which the class driver has to be attached.
  pIntfDesc =
  (USB_INTERFACE_DESCRIPTOR*)(&USB_FsConfigDescriptor[sizeof(USB_CONFIGURATION_DESCRIPTOR)]);
  /* check we are referencing to the proper interface descriptor */
  if ((pIntfDesc == 0) || (pIntfDesc->bInterfaceClass != USB_DEVICE_CLASS_APP) ||
  (pIntfDesc->bInterfaceSubClass != USB_DFU_SUBCLASS) ) {
  return ERR_FAILED;
  }
  dfu_param.intf_desc = (uint8_t*)pIntfDesc;
- Define and set the DFU class callback routines. The dfu_wr, dfu_rd, dfu_done, and dfu_detach callback routines are mandated by the USBD stack, if these callback handles are not provided the DFU Init will fail.
  /* user defined functions */
  dfu_param.DFU_Write = dfu_wr;
  dfu_param.DFU_Read = dfu_rd;
  dfu_param.DFU_Done = dfu_done;
  dfu_param.DFU_Detach = dfu_detach;
- Now call the USBD_DFU_API_T::init routine of the DFU class.
  ret = USBD_API->dfu->init(hUsb, &dfu_param);
  if (ret != LPC_OK) {
  vCatchError(0); //"usb DFU init error!!!"
  }
- After a successful DFU Init update the memory base address and memory size from the DFU Init Param to the USB Init Param, so that any other class driver could start using the memory from the right location.
  usb_param.mem_base = dfu_param.mem_base;
  usb_param.mem_size = dfu_param.mem_size;

## Defining USB Descriptors

The following example shows the configuration descriptor for a USB DFU device:

/* USB FSConfiguration Descriptor */
const uint8_t USB_FsConfigDescriptor[] = {
/* Configuration 1 */
USB_CONFIGURATION_DESC_SIZE, /* bLength */
USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType */
WBVAL( /* wTotalLength */
1 * USB_CONFIGURATION_DESC_SIZE +
1 * USB_INTERFACE_DESC_SIZE +
DFU_FUNC_DESC_SIZE
),
0x01, /* bNumInterfaces */
0x01, /* bConfigurationValue */
0x00, /* iConfiguration */
USB_CONFIG_BUS_POWERED, /* bmAttributes */
USB_CONFIG_POWER_MA(100), /* bMaxPower */
/* Interface 0, Alternate Setting 0, DFU Class */
USB_INTERFACE_DESC_SIZE, /* bLength */
USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
0x00, /* bInterfaceNumber */
0x00, /* bAlternateSetting */
0x00, /* bNumEndpoints */
USB_DEVICE_CLASS_APP, /* bInterfaceClass */
USB_DFU_SUBCLASS, /* bInterfaceSubClass */
0x02, /* bInterfaceProtocol */
0x04, /* iInterface */
/* DFU RunTime/DFU Mode Functional Descriptor */
DFU_FUNC_DESC_SIZE, /* bLength */
USB_DFU_DESCRIPTOR_TYPE, /* bDescriptorType */
USB_DFU_CAN_DOWNLOAD | USB_DFU_WILL_DETACH, /* bmAttributes */
WBVAL(0xFF00), /* wDetachTimeout */
WBVAL(USB_DFU_XFER_SIZE), /* wTransferSize */
WBVAL(0x0110), /* bcdDFUVersion */
0 /* Terminator */
};

# Execution

After a successful DFU Initialization the stack is ready to receive the packets from host. Even if the device is physically connected to the host using an USB cable the host does not recognize the presence of device until the D+ line is pulled up using 1.5K ohm resistor (LPC device controllers operate in high-speed or full-speed mode only). To enable the connection the application software should call USBD_HW_API_T::Connect with enable set to 1. Before enabling the connection the application should enable the USB interrupt.

NVIC_EnableIRQ(USB0_IRQn); // enable USB0 interrupts
/* now connect */
USBD_API->hw->Connect(g_hUsb, 1);

After connection the DFU class executes through callback functions setup during initialization. The application could also have a task waiting for download to complete and execute the newly downloaded image after completion.

## Installing IRQ handlers

USBD ROM stack implements the interrupt handler for USB device controller and invokes the USBD ROM stack routines according to the event type. Hence application should connect this handler to the application vector table. This is done by calling USBD_HW_API_T::ISR from the USB IRQ handler as shown in the code snippet below. The USBD ROM handle passed to the ISR() routine is the one obtained in previous step.

void USB0_IRQHandler(void)
{
USBD_API->hw->ISR(g_hUsb);
}

# Implementing callback

Subsections:

- Page_DFUDemo