This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

LPC4357 USB device raw transfers over endpoint (without class support)

Hi!

I'm trying to use LPC4357 USB device without class support (HID, CDC, MSC e.t.c.) in MDK-4.72a. It looks like the standard RL-USB sources do not allow doing that: when I uncheck all checkboxes (class support) in the USB configuration file usb_config_USB0.c, the compiler show an error message line "size of array cannot be zero" or something like that (because USBD_IF_NUM definition becames 0 if no class is selected).

The only thing I need is one BULK IN & one BULK OUT endpoints for thansfers between ARM & PC (I'm using WinDriver 10.21 on the PC for USB support). I have done that on LPC2148, but then I had complete code sources of the USB driver. Unfortunately LPC4357 USB library comes in .LIB-file USB_CM3.lib and there is no way to edit it.

Is there a simple way to disable any class support in the USB device without complete editting of the source code of the driver?

I tried to use CDC ACM class for raw packet endpoint transfers but I got an issue: OUT packets are normally received by ARM (using fnc. USBD_CDC_ACM_DataAvailable & USBD_CDC_ACM_DataRead), but IN packets (sent by USBD_CDC_ACM_DataSend) are not received by the PC: USB driver on the PC side shows a BABBLE_DETECT error when I try to read out a packet (don't know what exectly that means).

An ideal solution for me would be the ability to simply handle EVT_BULK_IN & EVT_BULK_OUT events for an endpoint and transfer data packets using USB_WriteEP & USB_ReadEP low-level functions. But I couldon't find a mechanism of catching these events correctly.

Has anyone experienced such a problem? Thanks in advance.

  • > The only thing I need is one BULK IN & one BULK OUT endpoints for thansfers between ARM & PC

    Usually, it's done by bulk IN/OUT endpoints on a vendor specific interface.
    On the RL-USB,
    1) in usb_config_USB0.c,
    - enable "Class Support"
    #define USBD_CLASS_ENABLE 1

    - enable "Custom Class Device"
    #define USBD_CLS_ENABLE 1

    2) Override Config descriptors (ie. declare config descriptor arrays in your code)
    - for full-speed,

    const U8 USBD_ConfigDescriptor[] = {
    /* Configuration 1 */
      USB_CONFIGUARTION_DESC_SIZE,          /* bLength */
      USB_CONFIGURATION_DESCRIPTOR_TYPE,    /* bDescriptorType */
      WBVAL(USBD_WTOTALLENGTH),             /* wTotalLength */
      USBD_IF_NUM,                          /* bNumInterfaces */
      0x01,                                 /* bConfigurationValue: 0x01 is used to select this configuration */
      0x00,                                 /* iConfiguration: no string to describe this configuration */
      USBD_CFGDESC_BMATTRIBUTES |           /* bmAttributes */
      (USBD_POWER << 6),
      USBD_CFGDESC_BMAXPOWER,               /* bMaxPower, device power consumption */
      ... // interface
      ... // endpoints
    /* Terminator */                                                                           0
    };
    

    - For high-speed,

    const U8 USBD_ConfigDescriptor_HS[] = {
    /* Configuration 1 */
      USB_CONFIGUARTION_DESC_SIZE,          /* bLength */
      USB_CONFIGURATION_DESCRIPTOR_TYPE,    /* bDescriptorType */
      WBVAL(USBD_WTOTALLENGTH),             /* wTotalLength */
      USBD_IF_NUM,                          /* bNumInterfaces */
      0x01,                                 /* bConfigurationValue: 0x01 is used to select this configuration */
      0x00,                                 /* iConfiguration: no string to describe this configuration */
      USBD_CFGDESC_BMATTRIBUTES |           /* bmAttributes */
      (USBD_POWER << 6),
      USBD_CFGDESC_BMAXPOWER,               /* bMaxPower, device power consumption */
      ... // interface
      ... // endpoints
    /* Terminator */                                                                           0
    };
    

    3) Override endpoint callback(s)

    void USBD_EndPoint1 (U32 event)
    {
      switch( event ) {
        case USBD_EVT_OUT:
           //
           // come to here by OUT EP1 interrupt
           //
           break;
        case USBD_EVT_IN:
           //
           // come to here by IN EP1 interrupt
           //
           break;
      }
    }
    

    Tsuneo

  • It looks like exectly what I need! I didn't know that USB descriptor arrays can be overridden. Now I see that every decriptor has a __weak attribute.
    Thanks a lot for the great idea :)

  • Now everything works well.

    There are some specific things that should be mentioned:

    1) USBD_EP_NUM must be corrected according to your settings in the descriptor (file usb_config_USB0.c for USB0 interface).
    2) If no class specified in configuration file, no memory will be allocted for read/write buffers. You can do one of two things: a) USBD_VENDOR_ENABLE must be defined in usb_config_USB0.c. This will allocate a user defined buffer in 4 kB (see EPBufPool[ ] variable in usbd_LPC43xx_USB0.c). b) Another way is to update file like this:

    uint8_t __align(4096) EPBufPool[
                                    USBD_MAX_PACKET0                                                                                                     * 2 +
                                    USBD_HID_ENABLE     *  (HS(USBD_HID_HS_ENABLE)     ? USBD_HID_HS_WMAXPACKETSIZE      : USBD_HID_WMAXPACKETSIZE)      * 2 +
                                    USBD_MSC_ENABLE     *  (HS(USBD_MSC_HS_ENABLE)     ? USBD_MSC_HS_WMAXPACKETSIZE      : USBD_MSC_WMAXPACKETSIZE)      * 2 +
                                    USBD_ADC_ENABLE     *  (HS(USBD_ADC_HS_ENABLE)     ? USBD_ADC_HS_WMAXPACKETSIZE      : USBD_ADC_WMAXPACKETSIZE)          +
                                    USBD_CDC_ACM_ENABLE * ((HS(USBD_CDC_ACM_HS_ENABLE) ? USBD_CDC_ACM_HS_WMAXPACKETSIZE  : USBD_CDC_ACM_WMAXPACKETSIZE)      +
                                                           (HS(USBD_CDC_ACM_HS_ENABLE) ? USBD_CDC_ACM_HS_WMAXPACKETSIZE1 : USBD_CDC_ACM_WMAXPACKETSIZE1) * 2)+
                                    USBD_CLS_ENABLE  *  (HS(USBD_CLS_HS_ENABLE)     ? USBD_CLS_HS_WMAXPACKETSIZE      : USBD_CLS_WMAXPACKETSIZE)      * 2 ];
    

    3) Read & Write operation should be done like this (example for endpoint 2):

    __task void USBD_RTX_EndPoint2(void)
    {
            U32 size;
            U16 timeout = 300;      // 3 sec
            static U8 tmpbuf[USBD_CLS_WMAXPACKETSIZE];
    
            while(1)
            {
                    // read input data
                    os_evt_wait_or(USBD_EVT_OUT, 0xffff);
                    size = USBD_ReadEP(2, tmpbuf);
    
                    //
                    // process input data
                    //
    
                    // write output data
                    USBD_WriteEP(2 | 0x80, tmpbuf, size);
                    if(os_evt_wait_or(USBD_EVT_IN, timeout) != OS_R_EVT)
                    {
                            // I/O error
                    }
            }
    }
    

  • 4) Add descriptor definition strings to usb_lib.c file:

    #define CLS_DESC                                                                                            \ 
    /* Interface, Alternate Setting 0 */                                                                        \ 
      USB_INTERFACE_DESC_SIZE,              /* bLength */                                                       \ 
      USB_INTERFACE_DESCRIPTOR_TYPE,        /* bDescriptorType */                                               \ 
      USBD_CLS_IF_NUM,                      /* bInterfaceNumber */                                              \ 
      0x00,                                 /* bAlternateSetting */                                             \ 
      0x02,                                 /* bNumEndpoints */                                                 \ 
      USB_DEVICE_CLASS_VENDOR_SPECIFIC,     /* bInterfaceClass */                                               \ 
      0xFF,                                 /* bInterfaceSubClass: USB_SUBCLASS_CODE_UNKNOWN */                 \ 
      0xFF,                                 /* bInterfaceProtocol: USB_PROTOCOL_CODE_UNKNOWN */                 \ 
      0x00,                                 /* iInterface: 0=no string to describe this configuration */
    
    #define CLS_EP                          /* CLS Endpoints for Low-speed/Full-speed */                        \ 
    /* Endpoint, EP Bulk IN */                                                                                  \ 
      USB_ENDPOINT_DESC_SIZE,               /* bLength */                                                       \ 
      USB_ENDPOINT_DESCRIPTOR_TYPE,         /* bDescriptorType */                                               \ 
      USB_ENDPOINT_IN(USBD_CLS_EP_BULKIN),  /* bEndpointAddress */                                              \ 
      USB_ENDPOINT_TYPE_BULK,               /* bmAttributes */                                                  \ 
      WBVAL(USBD_CLS_WMAXPACKETSIZE),       /* wMaxPacketSize */                                                \ 
      0x00,                                 /* bInterval: ignore for Bulk transfer */                           \ 
                                                                                                                \ 
    /* Endpoint, EP Bulk OUT */                                                                                 \ 
      USB_ENDPOINT_DESC_SIZE,               /* bLength */                                                       \ 
      USB_ENDPOINT_DESCRIPTOR_TYPE,         /* bDescriptorType */                                               \ 
      USB_ENDPOINT_OUT(USBD_CLS_EP_BULKOUT),/* bEndpointAddress */                                              \ 
      USB_ENDPOINT_TYPE_BULK,               /* bmAttributes */                                                  \ 
      WBVAL(USBD_CLS_WMAXPACKETSIZE),       /* wMaxPacketSize */                                                \ 
      0x00,                                 /* bInterval: ignore for Bulk transfer */
    
    #define CLS_EP_HS                       /* CLS Endpoints for High-speed */                                  \ 
    /* Endpoint, EP Bulk IN */                                                                                  \ 
      USB_ENDPOINT_DESC_SIZE,               /* bLength */                                                       \ 
      USB_ENDPOINT_DESCRIPTOR_TYPE,         /* bDescriptorType */                                               \ 
      USB_ENDPOINT_IN(USBD_CLS_EP_BULKIN),  /* bEndpointAddress */                                              \ 
      USB_ENDPOINT_TYPE_BULK,               /* bmAttributes */                                                  \ 
      WBVAL(USBD_CLS_HS_WMAXPACKETSIZE),    /* wMaxPacketSize */                                                \ 
      USBD_CLS_HS_BINTERVAL,                /* bInterval */                                                     \ 
                                                                                                                \ 
    /* Endpoint, EP Bulk OUT */                                                                                 \ 
      USB_ENDPOINT_DESC_SIZE,               /* bLength */                                                       \ 
      USB_ENDPOINT_DESCRIPTOR_TYPE,         /* bDescriptorType */                                               \ 
      USB_ENDPOINT_OUT(USBD_CLS_EP_BULKOUT),/* bEndpointAddress */                                              \ 
      USB_ENDPOINT_TYPE_BULK,               /* bmAttributes */                                                  \ 
      WBVAL(USBD_CLS_HS_WMAXPACKETSIZE),    /* wMaxPacketSize */                                                \ 
      USBD_CLS_HS_BINTERVAL,                /* bInterval */
    

    ...and update configuration descriptor like this:

    const U8 USBD_ConfigDescriptor[] = {
    /* Configuration 1 */
      USB_CONFIGUARTION_DESC_SIZE,          /* bLength */
      USB_CONFIGURATION_DESCRIPTOR_TYPE,    /* bDescriptorType */
      WBVAL(USBD_WTOTALLENGTH),             /* wTotalLength */
      USBD_IF_NUM,                          /* bNumInterfaces */
      0x01,                                 /* bConfigurationValue: 0x01 is used to select this configuration */
      0x00,                                 /* iConfiguration: no string to describe this configuration */
      USBD_CFGDESC_BMATTRIBUTES |           /* bmAttributes */
      (USBD_POWER << 6),
      USBD_CFGDESC_BMAXPOWER,               /* bMaxPower, device power consumption */
    
    #if (USBD_ADC_ENABLE)
    #if (USBD_MULTI_IF)
      ADC_DESC_IAD(USBD_ADC_CIF_NUM,2)
    #endif
      ADC_DESC
      ADC_EP
    #endif
    
    #if (USBD_CDC_ACM_ENABLE)
    #if (USBD_MULTI_IF)
      CDC_ACM_DESC_IAD(USBD_CDC_ACM_CIF_NUM,2)
    #endif
      CDC_ACM_DESC_IF0
      CDC_ACM_EP_IF0
      CDC_ACM_DESC_IF1
      CDC_ACM_EP_IF1
    #endif
    
    #if (USBD_HID_ENABLE)
      HID_DESC
    #if (USBD_HID_EP_INTOUT != 0)
      HID_EP_INOUT
    #else
      HID_EP
    #endif
    #endif
    
    #if (USBD_MSC_ENABLE)
      MSC_DESC
      MSC_EP
    #endif
    
    #if (USBD_CLS_ENABLE)
      CLS_DESC
      CLS_EP
    #endif
    
    /* Terminator */                                                                                            \ 
      0                                     /* bLength */                                                       \ 
    };
    

  • Ah, you are working on RL-RTX-USB.

    In the USBD_RTX_EndPoint2 task, there are two "waits", which block the task.
    Single "wait" minimizes timing interference between IN and OUT EPs.

    __task void USBD_RTX_EndPoint2(void)
    {
      while(1) {
        if ( os_evt_wait_or( USBD_EVT_OUT | USBD_EVT_IN, 0xffff ) == OS_R_EVT ) {
          switch ( os_evt_get() ) {
            case USBD_EVT_OUT:
                //
                // come to here by OUT EP2 completion
                //
                break;
            case USBD_EVT_IN:
                //
                // come to here by IN EP2 completion
                //
                break;
          }
        }
      }
    }
    

    Tsuneo

  • Yes, you're right about minimize timing.

    I just wanted to pay attention to the need of waiting for USBD_EVT_OUT event before any read operation, and USBD_EVT_IN event after any write operation.