This section introduces you to CDC (Communications Device Class) application development using USB ROM stack. The topics in this section provide step-by-step instructions on implementing a simple CDC class USB device using USB ROM stack.
Initialization
After successfully initializing the USBD ROM stack i.e. USBD_HW_API_T::Init, the CDC class driver needs to be initialized as follows:
- Configure initialization parameters of the CDC class driver
- Set the memory location where the CDC 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.
cdc_param.mem_base = usb_param.mem_base;
cdc_param.mem_size = usb_param.mem_size;
- Obtain the address location of the interface descriptor, both communication interface and data interface, within the device configuration descriptor array, to which the class driver has to be attached.
cdc_param.cif_intf_desc = (uint8_t *) find_IntfDesc(pDesc->full_speed_desc, CDC_COMMUNICATION_INTERFACE_CLASS);
cdc_param.dif_intf_desc = (uint8_t *) find_IntfDesc(pDesc->full_speed_desc, CDC_DATA_INTERFACE_CLASS);
- Define and set the CDC class callback routines. Optionally the application can also register its own class handler by providing the handle in the CDC Init Parameters, the USBD stack returns the default handler in the same parameter after the CDC initialization call. So the application could override or implement specific class requests and could call the default handler for requests that there not handled. Refer Customizing USBD ROM Core Layer to understand how to change the default stack behavior by implementing custom overrides.
cdc_param.SetLineCode = VCOM_SetLineCode;
- Now call the USBD_CDC_API_T::init routine of the CDC class.
ret = USBD_API->cdc->init(hUsb, &cdc_param);
vCatchError(0);
}
- After a successful CDC Init, allocating the transfer buffer of CDC class and register your own endpoint handler for BULK_IN and BULK_OUT data over the USB bus are needed.
g_vCOM.rx_buff = (uint8_t *) cdc_param.mem_base;
cdc_param.mem_base += VCOM_RX_BUF_SZ;
cdc_param.mem_size -= VCOM_RX_BUF_SZ;
ep_indx = (((USB_CDC_IN_EP & 0x0F) << 1) + 1);
ret = USBD_API->core->RegisterEpHandler(hUsb, ep_indx, VCOM_bulk_in_hdlr, &g_vCOM);
ep_indx = ((USB_CDC_OUT_EP & 0x0F) << 1);
ret = USBD_API->core->RegisterEpHandler(hUsb, ep_indx, VCOM_bulk_out_hdlr, &g_vCOM);
}
- CDC class updates the memory base address and memory size from the CDC Init Param to the USB Init Param and after allocating buffer for data transfer, so that any other class driver could start using the memory from the right location.
usb_param.mem_base = cdc_param.mem_base;
usb_param.mem_size = cdc_param.mem_size;
Defining USB Descriptors
The following example shows the configuration descriptor for the USB CDC class device:
ALIGNED(4) uint8_t USB_FsConfigDescriptor[] = {
USB_CONFIGURATION_DESC_SIZE,
WBVAL(
USB_CONFIGURATION_DESC_SIZE +
USB_INTERFACE_ASSOC_DESC_SIZE +
USB_INTERFACE_DESC_SIZE +
0x0013 +
1 * USB_ENDPOINT_DESC_SIZE +
USB_INTERFACE_DESC_SIZE +
2 * USB_ENDPOINT_DESC_SIZE +
0
),
0x02,
0x01,
0x00,
USB_INTERFACE_ASSOC_DESC_SIZE,
USB_CDC_CIF_NUM,
0x02,
CDC_COMMUNICATION_INTERFACE_CLASS,
CDC_ABSTRACT_CONTROL_MODEL,
0x00,
0x04,
USB_INTERFACE_DESC_SIZE,
USB_CDC_CIF_NUM,
0x00,
0x01,
CDC_COMMUNICATION_INTERFACE_CLASS,
CDC_ABSTRACT_CONTROL_MODEL,
0x00,
0x04,
0x05,
CDC_CS_INTERFACE,
CDC_HEADER,
WBVAL(CDC_V1_10),
0x05,
CDC_CS_INTERFACE,
CDC_CALL_MANAGEMENT,
0x01,
USB_CDC_DIF_NUM,
0x04,
CDC_CS_INTERFACE,
CDC_ABSTRACT_CONTROL_MANAGEMENT,
0x02,
0x05,
CDC_CS_INTERFACE,
CDC_UNION,
USB_CDC_CIF_NUM,
USB_CDC_DIF_NUM,
USB_ENDPOINT_DESC_SIZE,
USB_CDC_INT_EP,
WBVAL(0x0010),
0x02,
USB_INTERFACE_DESC_SIZE,
USB_CDC_DIF_NUM,
0x00,
0x02,
CDC_DATA_INTERFACE_CLASS,
0x00,
0x00,
0x04,
USB_ENDPOINT_DESC_SIZE,
USB_CDC_OUT_EP,
WBVAL(USB_FS_MAX_BULK_PACKET),
0x00,
USB_ENDPOINT_DESC_SIZE,
USB_CDC_IN_EP,
WBVAL(64),
0x00,
0
};
Execution
After a successful CDC 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);
USBD_API->hw->Connect(g_hUsb, 1);
After connection the CDC class executes through callback functions setup during initialization.
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
The CDC Class executes by calling callback routines setup during CDC initialization. The callbacks used in CDC are:
-VCOM_SetLineCode: Called when a line coding request is sent from the host indicating a new connection over the USB bus. Over the line coding request, it could indicate a new set of UART parameters such as baud rate, number of data bits, start bit, stop bits, etc.
-VCOM_bulk_in_hdlr: Called when a BULK IN request is sent from the host, once the connection is established and line is not busy, hardware API WriteEP() should be called to send data back to the host.
-VCOM_bulk_out_hdlr: Called when a BULK_OUT request is sent from the host, hardware API ReadEP() should be called to collect data from the host
Subsections: