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.
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.