There is a need to implement on stm32 usb composite device. The problem is that all USB devices are the same, will not work in parallel (three smart card readers connected to one UART). That is, you just need to track which device the command is sent to and do some machinations outside the USB logic (turn on the selected card, turn off the rest).

It seems to me that the full implementation of USB Composite device complicates the code too much, and I can not defeat it in any way.

Is there an easier option to implement this task without unnecessary code complications?

Once again, you need to display 3 USB devices in the device Manager, each of which will accept commands, but from the microcontroller they will act on the same algorithm.


The problem is this. At the present time one unit uses 3 end points. In total, I should have three - it's 9 endpoints + zero.

And stm only supports 7. I need to somehow at the software level to display three connected devices, but from the stm side to process the data coming to them through one processor.

For my purposes, I need only some device ID, which was accessed from the host (address, index, anything). Is it possible to do this without increasing the number of endpoints and not prescribing each individual device initialization and handler?

Hope, so a bit clearer)

Give the device descriptor

  0x09,   /* bLength: Configuration Descriptor size */
  USB_DESC_TYPE_CONFIGURATION,   /* bDescriptorType: Configuration */

  0x01,   /* bNumInterfaces: 1 interface */
  0x01,   /* bConfigurationValue: */
  0x04,   /* iConfiguration: */
  0x80,         /*bmAttributes: bus powered */
  0x32,   /* MaxPower 100 mA */

 /********************  CCID **** interface ********************/
 0x09,   /* bLength: Interface Descriptor size */
 0x04,   /* bDescriptorType: */
 0x00,   /* bInterfaceNumber: Number of Interface */
 0x00,   /* bAlternateSetting: Alternate setting */
 0x03,   /* bNumEndpoints: 3 endpoints used */
 0x0B,   /* bInterfaceClass: user's interface for CCID */
 0x00,   /* bInterfaceSubClass : */
 0x00,   /* nInterfaceProtocol : None */
 0x05,   /* iInterface: */

 /*******************  CCID class descriptor ********************/
 0x36,   /* bLength: CCID Descriptor size */
 0x21,    /* bDescriptorType: Functional Descriptor type. */
 0x10,    /* bcdCCID(LSB): CCID Class Spec release number (1.00) */
 0x01,   /* bcdCCID(MSB) */

 0x02,    /* bMaxSlotIndex :highest available slot on this device */
 0x03,    /* bVoltageSupport: bit Wise OR for 01h-5.0V 02h-3.0V
                                04h 1.8V*/

 0x01,0x00,0x00,0x00,   /* dwProtocols: 0001h = Protocol T=0 */
 0x10,0x0E,0x00,0x00,   /* dwDefaultClock: 3.6Mhz = 3600kHz = 0x0E10, 
                         for 4 Mhz the value is (0x00000FA0) : 
                        This is used in ETU and waiting time calculations*/
 0x10,0x0E,0x00,0x00,   /* dwMaximumClock: Maximum supported ICC clock frequency  
                         in KHz. So, 3.6Mhz = 3600kHz = 0x0E10, 
                                       4 Mhz (0x00000FA0) : */
 0x00,          /* bNumClockSupported : no setting from PC 
                         If the value is 00h, the 
                        supported clock frequencies are assumed to be the 
                        default clock frequency defined by dwDefaultClock 
                        and the maximum clock frequency defined by 
                        dwMaximumClock */

 0xCD,0x25,0x00,0x00,   /* dwDataRate: Default ICC I/O data rate in bps
                        9677 bps = 0x25CD 
                        for example 10752 bps (0x00002A00) */

 0xCD,0x25,0x00,0x00,   /* dwMaxDataRate: Maximum supported ICC I/O data 
                        rate in bps */
 0x00,                 /* bNumDataRatesSupported :
                     The number of data rates that are supported by the CCID
                     If the value is 00h, all data rates between the default 
                     data rate dwDataRate and the maximum data rate 
                     dwMaxDataRate are supported.
                     Dont support GET_CLOCK_FREQUENCIES

 0x00,0x00,0x00,0x00,   /* dwMaxIFSD: 0 (T=0 only)   */
 0x00,0x00,0x00,0x00,   /* dwSynchProtocols  */
 0x00,0x00,0x00,0x00,   /* dwMechanical: no special characteristics */

                     /* dwFeatures: clk, baud rate, voltage : automatic */
                     /* 00000008h Automatic ICC voltage selection 
                     00000010h Automatic ICC clock frequency change
                     00000020h Automatic baud rate change according to 
                     active parameters provided by the Host or self 
                     determined 00000100h CCID can set 
                     ICC in clock stop mode      

                     Only one of the following values may be present to 
                     select a level of exchange:
                     00010000h TPDU level exchanges with CCID
                     00020000h Short APDU level exchange with CCID
                     00040000h Short and Extended APDU level exchange 
                     If none of those values : character level of exchange*/
 0x0F,0x01,0x00,0x00,  /* dwMaxCCIDMessageLength: Maximum block size + header*/
                     /* 261 + 10   */

 0x00,          /* bClassGetResponse*/
 0x00,          /* bClassEnvelope */
 0x00,0x00,     /* wLcdLayout : 0000h no LCD. */
 0x00,          /* bPINSupport : no PIN verif and modif  */
 0x03,          /* bMaxCCIDBusySlots    */

 /********************  CCID   Endpoints ********************/
 0x07,   /*Endpoint descriptor length = 7*/
 0x05,   /*Endpoint descriptor type */
 CCID_BULK_IN_EP,   /*Endpoint address (IN, address 1) */
 0x02,   /*Bulk endpoint type */
 0x00,   /*Polling interval in milliseconds */

 0x07,   /*Endpoint descriptor length = 7 */
 0x05,   /*Endpoint descriptor type */
 CCID_BULK_OUT_EP,   /*Endpoint address (OUT, address 1) */
 0x02,   /*Bulk endpoint type */
 0x00,   /*Polling interval in milliseconds*/

 0x07,   /*bLength: Endpoint Descriptor size*/
 0x05,   /*bDescriptorType:*/
 CCID_INTR_IN_EP,    /*bEndpointAddress: Endpoint Address (IN)*/
 0x03,   /* bmAttributes: Interrupt endpoint */
 0x18    /*Polling interval in milliseconds */

In response to RDR_to_PC_NotifySlotChange, I send the answer 3F, which, in theory, should mean that I have three slots with cards, each of which is inserted into the slot and works. However, windows displays and sees only one slot. In General,that is why it was decided to try to make a composite device.


Well, the previous idea was bad. What could be the error of the multi-slot approach? As I understand it, the maximum slot index is set in the descriptor, and the state of each of the available slots is passed to RDR_to_PC_NotifySlotChange. But why change these values in the required Windows stubbornly continues to appeal only to the zero slot number and ignores the rest (checked on the UWP app, in debug it is visible that Windows only gets one card). Maybe I'm missing something?

  • 1
    \$\begingroup\$ It's not really clear what you're trying to do? Do you want to have 3x usb-cdc, or 1x usb-cdc + software multiplexing? Any approach will require code to be written. \$\endgroup\$
    – domen
    Jun 3, 2019 at 8:31
  • \$\begingroup\$ I want the least energy-intensive reproduction of one device for several. The only task that would distinguish its duplicated copies from a single instance is a certain marker, which would make it clear how the device was accessed (marker or index). Writing code does not bother me, I am confused by the extra complexity. The problem is that it is a CID device, information on which is not particularly. Thanks for the tip, first time I hear about multiplexing device, I'll go read about it. \$\endgroup\$ Jun 3, 2019 at 8:43
  • \$\begingroup\$ The USB CCID specs (which is probably what you should implement, since your goal is to provide smart card reader interfaces) allows for multi-slot. Why not implement a single CCID device with three smart card slots, instead of a composite device acting as a triple CCID device? It isn't clear. \$\endgroup\$
    – dim
    Jun 3, 2019 at 14:05
  • \$\begingroup\$ windows somehow does not display the rest of the slots, as well as the programs that I found \$\endgroup\$ Jun 4, 2019 at 3:56
  • \$\begingroup\$ It will be quite difficult for you to exceed the number of endpoints available on your chosen STM32. In order to "trick" the host into thinking you have more endpoints than you really do you would have to do trickery on the protocol level (or somehow predict which endpoint would be accessed next and change the address on the fly, which is very hard if not impossible). You might want to reconsider your design: Either figuring out what's wrong with the multi-slot approach or choosing a new microcontroller. \$\endgroup\$ Jun 4, 2019 at 6:37


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.