AnsweredAssumed Answered

LPC11U35 composite USB, multiple VCOM

Question asked by Jens Dender on Mar 17, 2017
Latest reply on Mar 24, 2017 by jeremyzhou



I am trying to get multiple virtual COM ports on a single LPC11U35.
Windows detects the device, agrees that there are 2 COM ports (and a mouse, which is rudimentary from the example code). The COM port that came with the example works well. I modified the code to get the second one working, but it fails at configuration (opening the port). The example project I used was "nxp_lpcxpresso_11u14_usbd_lib_composite" from ""


Using breakpoints, I looked up the path what a working port should follow. I have determined that when opening the port, the working one goes all the way to its "VCOM_SetLineCode" function, however the failing one does not get past "USB_EndPoint0" ("USB_EvtOutHandler" never gets called). Here is a screenshot of the working chain:
vcom opening function chain

Parts of code that may be of interest:
From main:

ret = USBD_API->hw->Init(&g_hUsb, &desc, &usb_param);
    if (ret == LPC_OK) {

        ret = Mouse_Init(g_hUsb, (USB_INTERFACE_DESCRIPTOR *) find_IntfDesc(desc.high_speed_desc, USB_DEVICE_CLASS_HUMAN_INTERFACE), &usb_param.mem_base, &usb_param.mem_size);
        if (ret == LPC_OK) {
            /* Init VCOM interface */
            ret = vcom_init_multi(g_hUsb, &desc, &usb_param, &g_vCOM, USB_CDC_IN_EP, USB_CDC_OUT_EP);
            if (ret == LPC_OK) {
                ret = vcom_init_multi(g_hUsb, &desc, &usb_param, &g_vCOM2, USB_CDC2_IN_EP, USB_CDC2_OUT_EP);
                if (ret == LPC_OK) {
                                /*  enable USB interrrupts */
                                /* now connect */
                                USBD_API->hw->Connect(g_hUsb, 1);


Initialization function:

ErrorCode_t vcom_init_multi(USBD_HANDLE_T hUsb, USB_CORE_DESCS_T *pDesc, USBD_API_INIT_PARAM_T *pUsbParam, VCOM_DATA_T *vCOMused, uint8_t ep_in, uint8_t ep_out){
    int static comPortCounter = 0;


    USBD_CDC_INIT_PARAM_T cdc_param;

    ErrorCode_t ret = LPC_OK;
    uint32_t ep_indx;

    VCOM_DATA_T *localVCOM = vCOMused;

    //g_vCOM.hUsb = hUsb; //example what was before for next line
    localVCOM->hUsb = hUsb;

    memset((void *) &cdc_param, 0, sizeof(USBD_CDC_INIT_PARAM_T));

    cdc_param.mem_base = pUsbParam->mem_base;
    cdc_param.mem_size = pUsbParam->mem_size;
    cdc_param.cif_intf_desc = (uint8_t *) find_IntfDesc(pDesc->high_speed_desc, CDC_COMMUNICATION_INTERFACE_CLASS);
    cdc_param.dif_intf_desc = (uint8_t *) find_IntfDesc(pDesc->high_speed_desc, CDC_DATA_INTERFACE_CLASS);

    if(comPortCounter==1)         cdc_param.SetLineCode = VCOM_SetLineCode;
    else                          cdc_param.SetLineCode = VCOM_SetLineCode2;

    ret = USBD_API->cdc->init(hUsb, &cdc_param, &(localVCOM->hCdc));

    if (ret == LPC_OK) {
        /* allocate transfer buffers */
        localVCOM->rx_buff = (uint8_t *) cdc_param.mem_base;
        cdc_param.mem_base += VCOM_RX_BUF_SZ;
        cdc_param.mem_size -= VCOM_RX_BUF_SZ;

        /* register endpoint interrupt handler */
        ep_indx = (((ep_in & 0x0F) << 1) + 1);
        if(comPortCounter==1) ret = USBD_API->core->RegisterEpHandler(hUsb, ep_indx, VCOM_bulk_in_hdlr, localVCOM);
        else ret = USBD_API->core->RegisterEpHandler(hUsb, ep_indx, VCOM_bulk_in_hdlr2, localVCOM);
        if (ret == LPC_OK) {
            /* register endpoint interrupt handler */
            ep_indx = ((ep_out & 0x0F) << 1);
            if(comPortCounter==1) ret = USBD_API->core->RegisterEpHandler(hUsb, ep_indx, VCOM_bulk_out_hdlr, localVCOM);
            else ret = USBD_API->core->RegisterEpHandler(hUsb, ep_indx, VCOM_bulk_out_hdlr2, localVCOM);


        /* update mem_base and size variables for cascading calls. */
        pUsbParam->mem_base = cdc_param.mem_base;
        pUsbParam->mem_size = cdc_param.mem_size;

    return ret;


SetLinecode functions:

/* Set line coding call back routine */
static ErrorCode_t VCOM_SetLineCode(USBD_HANDLE_T hCDC, CDC_LINE_CODING *line_coding)

    VCOM_DATA_T *pVcom = &g_vCOM;
    /* Called when baud rate is changed/set. Using it to know host connection state */
    pVcom->tx_flags = VCOM_TX_CONNECTED;    /* reset other flags */

    return LPC_OK;

static ErrorCode_t VCOM_SetLineCode2(USBD_HANDLE_T hCDC, CDC_LINE_CODING *line_coding)
    //This function does not get called when comport opens, for some reason!?

    VCOM_DATA_T *pVcom = &g_vCOM2;
    /* Called when baud rate is changed/set. Using it to know host connection state */
    pVcom->tx_flags = VCOM_TX_CONNECTED;    /* reset other flags */

    return LPC_OK;


A section from app_usbd_cfg.h

/* HID In/Out Endpoint Address */
#define HID_EP_IN                           0x81
#define USB_HID_IF_NUM                      0
/** Interval between mouse reports expressed in milliseconds for full-speed device. */
/* bInterval value used in descriptor. For HS this macro will differ from HID_MOUSE_REPORT_INTERVAL_MS macro. */
#define HID_MOUSE_REPORT_INTERVAL           10
/* Manifest constants defining interface numbers and endpoints used by a
   CDC class interfaces in this application.
#define USB_CDC_CIF_NUM                     3
#define USB_CDC_DIF_NUM                     4
#define USB_CDC_IN_EP                       0x81 //0x81 is EP1_IN
#define USB_CDC_OUT_EP                      0x01 //0x01 is EP1_OUT?
#define USB_CDC_INT_EP                      0x82

//added to try to get second vcom
#define USB_CDC2_CIF_NUM                     1
#define USB_CDC2_DIF_NUM                     2
#define USB_CDC2_IN_EP                       0x83
#define USB_CDC2_OUT_EP                      0x03
#define USB_CDC2_INT_EP                      0x84

(NB, I see that mouse and one CDC share the same EP_IN value, however this is the one that works. As I understand, they should not share the EP value)


Hopefully this is enough information. Please let me know if something else could be of assistance. I hope someone else has stumbled across this issue and can direct me forward.