STM32 -- Multiple USB CDC (USB IAD)

it2022-05-14  61

Multiple USB CDC (USB IAD)

One CDC function requires 2 IN / 1 OUT endpoints (interrupt IN/ bulk IN/ bulk OUT), other than the default EP.Available endpoints of each STM32F family are,STM32F102/103 - FS Device core: 7 IN / 7 OUTSTM32F105/107 - OTG_FS: 3 IN / 3 OUTSTM32F2xx/4xx - OTG_FS: 3 IN / 3 OUTSTM32F2xx/4xx - OTG_HS: 5 IN / 5 OUT

STM32F102/103 - 3x CDC composite [ 6 IN - 3 OUT ]STM32F105/107 - just one CDC [ 2 IN - 1 OUT ]STM32F2xx/4xx - 2x CDC composite on OTG_HS [ 4 IN - 2 OUT ]

Starting from ST's example, it isn't so hard, to make them a CDC composite device, 

if you would know where and how to touch on the source code :-)

OK, then let's start here on this thread.The agenda of modification is,1) Descriptors and INF file2) Bulk IN/OUT endpoints3) Class requestsThe base ST example is STM32F10x and STM32L1xx USB full-speed device library v3.4.0http://www.st.com/internet/com/SOFTWARE_RESOURCES/SW_COMPONENT/FIRMWARE/stm32_usb-fs-device_lib.zip\STM32_USB-FS-Device_Lib_V3.4.0\Project\Virtual_COM_PortWe'll make 3x CDC composite device.1) DescriptorsFirst the device descriptor is modified at class/subclass/protocol and VID/PID (idVendor/idProduct) fields.We assign temporary VID/PID just for this development. Get official VID/PID afterward.Virtual_Com_Port_DeviceDescriptor() is replaced, as follows.usb_desc.c

/* USB Standard Device Descriptor */ const uint8_t Virtual_Com_Port_DeviceDescriptor[] = { 0x12, /* bLength */ USB_DEVICE_DESCRIPTOR_TYPE, /* bDescriptorType */ 0x00, 0x02, /* bcdUSB = 2.00 */ 0xEF, /* bDeviceClass (Misc) */ 0x02, /* bDeviceSubClass (common) */ 0x01, /* bDeviceProtocol (IAD) */ 0x40, /* bMaxPacketSize0 */ 0x83, 0x02, /* idVendor = 0xFF02 */ 0xFF, 0x01, /* idProduct = 0x0001 */ 0x00, 0x02, /* bcdDevice = 2.00 */ 1, /* Index of string descriptor describing manufacturer */ 2, /* Index of string descriptor describing product */ 3, /* Index of string descriptor describing the device's serial number */ 0x01 /* bNumConfigurations */ };

 

Next, the Configuration descriptor set is heavy, because we have to repeat three sets of IAD / CDC interfaces. We make them macros

#define WBVAL(x) (x & 0xFF),((x >> 8) & 0xFF) #define USB_CONFIGUARTION_DESC_SIZE 9 #define USB_INTERFACE_DESC_SIZE 9 #define USB_ENDPOINT_DESC_SIZE 7 #define USB_ENDPOINT_TYPE_BULK 0x02 #define USB_ENDPOINT_TYPE_INTERRUPT 0x03 #define USB_CONFIG_BUS_POWERED 0x80 #define USB_CONFIG_SELF_POWERED 0xC0 #define USB_CONFIG_POWER_MA(mA) ((mA)/2) #define CDC_COMMUNICATION_INTERFACE_CLASS 0x02 #define CDC_DATA_INTERFACE_CLASS 0x0A #define CDC_ABSTRACT_CONTROL_MODEL 0x02 #define CDC_CS_INTERFACE 0x24 #define CDC_HEADER 0x00 #define CDC_CALL_MANAGEMENT 0x01 #define CDC_ABSTRACT_CONTROL_MANAGEMENT 0x02 #define CDC_UNION 0x06 #define CDC_IF_DESC_SET_SIZE \( USB_INTERFACE_DESC_SIZE + 0x05 + 0x05 + 0x04 + 0x05 + USB_ENDPOINT_DESC_SIZE + USB_INTERFACE_DESC_SIZE + 2 * USB_ENDPOINT_DESC_SIZE ) #define CDC_IF_DESC_SET( comIfNum, datIfNum, comInEp, datOutEp, datInEp ) \ /* CDC Communication Interface Descriptor */ \ USB_INTERFACE_DESC_SIZE, /* bLength */ \ USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ \ comIfNum, /* bInterfaceNumber */ \ 0x00, /* bAlternateSetting */ \ 0x01, /* bNumEndpoints */ \ CDC_COMMUNICATION_INTERFACE_CLASS, /* bInterfaceClass */ \ CDC_ABSTRACT_CONTROL_MODEL, /* bInterfaceSubClass */ \ 0x01, /* bInterfaceProtocol */ \ 0x00, /* iInterface */ \ /* Header Functional Descriptor */ \ 0x05, /* bLength */ \ CDC_CS_INTERFACE, /* bDescriptorType */ \ CDC_HEADER, /* bDescriptorSubtype */ \ WBVAL(CDC_V1_10), /* 1.10 */ /* bcdCDC */ \ /* Call Management Functional Descriptor */ \ 0x05, /* bFunctionLength */ \ CDC_CS_INTERFACE, /* bDescriptorType */ \ CDC_CALL_MANAGEMENT, /* bDescriptorSubtype */ \ 0x03, /* bmCapabilities */ \ datIfNum, /* bDataInterface */ \ /* Abstract Control Management Functional Descriptor */ \ 0x04, /* bFunctionLength */ \ CDC_CS_INTERFACE, /* bDescriptorType */ \ CDC_ABSTRACT_CONTROL_MANAGEMENT, /* bDescriptorSubtype */ \ 0x02, /* bmCapabilities */ \ /* Union Functional Descriptor */ \ 0x05, /* bFunctionLength */ \ CDC_CS_INTERFACE, /* bDescriptorType */ \ CDC_UNION, /* bDescriptorSubtype */ \ comIfNum, /* bMasterInterface */ \ datIfNum, /* bSlaveInterface0 */ \ /* Endpoint, Interrupt IN */ /* event notification */ \ USB_ENDPOINT_DESC_SIZE, /* bLength */ \ USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ \ comInEp, /* bEndpointAddress */ \ USB_ENDPOINT_TYPE_INTERRUPT, /* bmAttributes */ \ WBVAL(0x000A), /* wMaxPacketSize */ \ 0x01, /* bInterval */ \ \ /* CDC Data Interface Descriptor */ \ USB_INTERFACE_DESC_SIZE, /* bLength */ \ USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ \ datIfNum, /* bInterfaceNumber */ \ 0x00, /* bAlternateSetting */ \ 0x02, /* bNumEndpoints */ \ CDC_DATA_INTERFACE_CLASS, /* bInterfaceClass */ \ 0x00, /* bInterfaceSubClass */ \ 0x00, /* bInterfaceProtocol */ \ 0x00, /* iInterface */ \ /* Endpoint, Bulk OUT */ \ USB_ENDPOINT_DESC_SIZE, /* bLength */ \ USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ \ datOutEp, /* bEndpointAddress */ \ USB_ENDPOINT_TYPE_BULK, /* bmAttributes */ \ WBVAL(VIRTUAL_COM_PORT_DATA_SIZE), /* wMaxPacketSize */ \ 0x00, /* bInterval */ \ /* Endpoint, Bulk IN */ \ USB_ENDPOINT_DESC_SIZE, /* bLength */ \ USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ \ datInEp, /* bEndpointAddress */ \ USB_ENDPOINT_TYPE_BULK, /* bmAttributes */ \ WBVAL(VIRTUAL_COM_PORT_DATA_SIZE), /* wMaxPacketSize */ \ 0x00 /* bInterval */ #define IAD_CDC_IF_DESC_SET_SIZE ( 8 + CDC_IF_DESC_SET_SIZE ) #define IAD_CDC_IF_DESC_SET( comIfNum, datIfNum, comInEp, datOutEp, datInEp ) \ /* Interface Association Descriptor */ \ 0x08, /* bLength */ \ 0x0B, /* bDescriptorType */ \ comIfNum, /* bFirstInterface */ \ 0x02, /* bInterfaceCount */ \ CDC_COMMUNICATION_INTERFACE_CLASS, /* bFunctionClass */ \ CDC_ABSTRACT_CONTROL_MODEL, /* bFunctionSubClass */ \ 0x01, /* bFunctionProcotol */ \ 0x00, /* iInterface */ \ /* CDC Interface descriptor set */ \ CDC_IF_DESC_SET( comIfNum, datIfNum, comInEp, datOutEp, datInEp )

Now that the configuration descriptor set is simplified. Virtual_Com_Port_ConfigDescriptor[] is replaced as follows, usb_desc.c

// Interface numbers enum { USB_CDC_CIF_NUM0, USB_CDC_DIF_NUM0, USB_CDC_CIF_NUM1, USB_CDC_DIF_NUM1, USB_CDC_CIF_NUM2, USB_CDC_DIF_NUM2, USB_NUM_INTERFACES // number of interfaces }; const uint8_t Virtual_Com_Port_ConfigDescriptor[] = { /* Configuration 1 */ USB_CONFIGUARTION_DESC_SIZE, /* bLength */ USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType */ WBVAL( /* wTotalLength */ USB_CONFIGUARTION_DESC_SIZE + 3 * IAD_CDC_IF_DESC_SET_SIZE ), USB_NUM_INTERFACES, /* bNumInterfaces */ 0x01, /* bConfigurationValue: 0x01 is used to select this configuration */ 0x00, /* iConfiguration: no string to describe this configuration */ USB_CONFIG_BUS_POWERED /*|*/ /* bmAttributes USB_CONFIG_REMOTE_WAKEUP*/, USB_CONFIG_POWER_MA(100), /* bMaxPower, device power consumption is 100 mA */ IAD_CDC_IF_DESC_SET( USB_CDC_CIF_NUM0, USB_CDC_DIF_NUM0, USB_ENDPOINT_IN(1), USB_ENDPOINT_OUT(2), USB_ENDPOINT_IN(2) ), IAD_CDC_IF_DESC_SET( USB_CDC_CIF_NUM1, USB_CDC_DIF_NUM1, USB_ENDPOINT_IN(3), USB_ENDPOINT_OUT(4), USB_ENDPOINT_IN(4) ), IAD_CDC_IF_DESC_SET( USB_CDC_CIF_NUM2, USB_CDC_DIF_NUM2, USB_ENDPOINT_IN(5), USB_ENDPOINT_OUT(6), USB_ENDPOINT_IN(6) ), };

 

Auu, I remember that the packet buffer of STM32F102/103 is limited to 512 bytes.

To pack all of endpoint packet buffers into this size,

we have to shrink EP0 bMaxPacketSize0 on the Device Descriptor from 0x40 to 0x08 (minimum)

/* USB Standard Device Descriptor */ const uint8_t Virtual_Com_Port_DeviceDescriptor[] = { 0x12, /* bLength */ USB_DEVICE_DESCRIPTOR_TYPE, /* bDescriptorType */ 0x00, 0x02, /* bcdUSB = 2.00 */ 0xEF, /* bDeviceClass (Misc) */ 0x02, /* bDeviceSubClass (common) */ 0x01, /* bDeviceProtocol (IAD) */ 0x08, /* bMaxPacketSize0 */ // <----------- 0x83, 0x02, /* idVendor = 0xFF02 */ 0xFF, 0x01, /* idProduct = 0x0001 */ 0x00, 0x02, /* bcdDevice = 2.00 */ 1, /* Index of string descriptor describing manufacturer */ 2, /* Index of string descriptor describing product */ 3, /* Index of string descriptor describing the device's serial number */ 0x01 /* bNumConfigurations */ };

 

Next, enable all endpoints in Virtual_Com_Port_Reset() Here, packet buffer is allocated for each endpoint.

\inc\usb_conf.h

/*-------------------------------------------------------------*/ /* -------------- Buffer Description Table -----------------*/ /*-------------------------------------------------------------*/ /* buffer table base address */ /* buffer table base address */ #define BTABLE_ADDRESS (0x00) /* EP0 */ /* rx/tx buffer base address */ #define ENDP0_RXADDR (0x40) #define ENDP0_TXADDR (0x48) /* EP1 */ /* tx buffer base address */ #define ENDP1_TXADDR (0x50) #define ENDP2_TXADDR (0x60) #define ENDP2_RXADDR (0xA0) #define ENDP3_TXADDR (0xE0) #define ENDP4_TXADDR (0xF0) #define ENDP4_RXADDR (0x130) #define ENDP5_TXADDR (0x170) #define ENDP6_TXADDR (0x180) #define ENDP6_RXADDR (0x1C0)

usb_prop.c

/******************************************************************************* * Function Name : Virtual_Com_Port_Reset * Description : Virtual_Com_Port Mouse reset routine * Input : None. * Output : None. * Return : None. *******************************************************************************/ void Virtual_Com_Port_Reset(void) { /* Set Virtual_Com_Port DEVICE as not configured */ pInformation->Current_Configuration = 0; /* Current Feature initialization */ pInformation->Current_Feature = Virtual_Com_Port_ConfigDescriptor[7]; /* Set Virtual_Com_Port DEVICE with the default Interface*/ pInformation->Current_Interface = 0; SetBTABLE(BTABLE_ADDRESS); /* Initialize Endpoint 0 */ SetEPType(ENDP0, EP_CONTROL); SetEPTxStatus(ENDP0, EP_TX_STALL); SetEPRxAddr(ENDP0, ENDP0_RXADDR); SetEPTxAddr(ENDP0, ENDP0_TXADDR); Clear_Status_Out(ENDP0); SetEPRxCount(ENDP0, Device_Property.MaxPacketSize); SetEPRxValid(ENDP0); /* Initialize Endpoint 1 */ SetEPType(ENDP1, EP_INTERRUPT); SetEPTxAddr(ENDP1, ENDP1_TXADDR); SetEPTxStatus(ENDP1, EP_TX_NAK); SetEPRxStatus(ENDP1, EP_RX_DIS); /* Initialize Endpoint 2 */ SetEPType(ENDP2, EP_BULK); SetEPTxAddr(ENDP2, ENDP2_TXADDR); SetEPTxStatus(ENDP2, EP_TX_NAK); SetEPRxAddr(ENDP2, ENDP2_RXADDR); SetEPRxCount(ENDP2, VIRTUAL_COM_PORT_DATA_SIZE); SetEPRxStatus(ENDP2, EP_RX_VALID); /* Initialize Endpoint 3 */ SetEPType(ENDP3, EP_INTERRUPT); SetEPTxAddr(ENDP3, ENDP3_TXADDR); SetEPTxStatus(ENDP3, EP_TX_NAK); SetEPRxStatus(ENDP3, EP_RX_DIS); /* Initialize Endpoint 4 */ SetEPType(ENDP4, EP_BULK); SetEPTxAddr(ENDP4, ENDP4_TXADDR); SetEPTxStatus(ENDP4, EP_TX_NAK); SetEPRxAddr(ENDP4, ENDP4_RXADDR); SetEPRxCount(ENDP4, VIRTUAL_COM_PORT_DATA_SIZE); SetEPRxStatus(ENDP4, EP_RX_VALID); /* Initialize Endpoint 5 */ SetEPType(ENDP5, EP_INTERRUPT); SetEPTxAddr(ENDP5, ENDP5_TXADDR); SetEPTxStatus(ENDP5, EP_TX_NAK); SetEPRxStatus(ENDP5, EP_RX_DIS); /* Initialize Endpoint 6 */ SetEPType(ENDP6, EP_BULK); SetEPTxAddr(ENDP6, ENDP6_TXADDR); SetEPTxStatus(ENDP6, EP_TX_NAK); SetEPRxAddr(ENDP6, ENDP6_RXADDR); SetEPRxCount(ENDP6, VIRTUAL_COM_PORT_DATA_SIZE); SetEPRxStatus(ENDP6, EP_RX_VALID); /* Set this device to response on default address */ SetDeviceAddress(0); bDeviceState = ATTACHED; }

And the last of this section, INF file for windows. Now that our device should appear on Windows. :-)

STM32-CDC-Composite.inf

; ; STM32-CDC-Composite.inf Communication Device Class driver installation file ; [Version] Signature="$Windows NT$" Class=Ports ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318} Provider=%MICHELE% ;;; LayoutFile=layout.inf ;; not supported in Vista and later DriverVer =04/14/2008, 5.1.2600.5512 ; CatalogFile=STM32-CDC-Composite.cat [Manufacturer] %MICHELE%=DeviceList,ntamd64 ;------------------------------------------------------------------------------ ; Device list ;------------------------------------------------------------------------------ [DeviceList]
转载请注明原文地址: https://win8.8miu.com/read-1493574.html

最新回复(0)