cancel
Showing results for 
Search instead for 
Did you mean: 

Multiple USB CDC (USB IAD). How?

baranovay
Associate
Posted on June 10, 2010 at 07:46

Multiple USB CDC (USB IAD). How?

#iad #cdc #stm32f103 #dual-cdc-with-stm32l152 #usb-cdc-duart
24 REPLIES 24
michele77
Associate II
Posted on July 30, 2012 at 15:39

Hello Tsuneo,

Please call me Michele 🙂 I modified a bit more the code.. 1) I duplicated the EP callbacks and I now have EP2_IN_Callback EP4_IN_Callback EP6_IN_Callback EP2_OUT_Callback EP4_OUT_Callback EP6_OUT_Callback defined like this:

void
EP2_IN_Callback (
void
) {
uint16_t USB_Tx_ptr;
uint16_t USB_Tx_length;
if
(CDC1_Tx_State == 1) {
if
(VCP1_Rx_length == 0) {
CDC1_Tx_State = 0;
} 
else
{
if
(VCP1_Rx_length > VIRTUAL_COM_PORT_DATA_SIZE) {
USB_Tx_ptr = VCP1_Rx_ptr_out;
USB_Tx_length = VIRTUAL_COM_PORT_DATA_SIZE;
VCP1_Rx_ptr_out += VIRTUAL_COM_PORT_DATA_SIZE;
VCP1_Rx_length -= VIRTUAL_COM_PORT_DATA_SIZE;
} 
else
{
USB_Tx_ptr = VCP1_Rx_ptr_out;
USB_Tx_length = VCP1_Rx_length;
VCP1_Rx_ptr_out += VCP1_Rx_length;
VCP1_Rx_length = 0;
}
UserToPMABufferCopy(&VCP1_Rx_Buffer[USB_Tx_ptr], ENDP2_TXADDR, USB_Tx_length);
SetEPTxCount(ENDP2, USB_Tx_length);
SetEPTxValid(ENDP2);
}
}
}

and

void
EP2_OUT_Callback(
void
) {
uint16_t USB_Rx_Cnt;
/* Get the received data buffer and update the counter */
USB_Rx_Cnt = USB_SIL_Read(EP2_OUT, USB_Rx_Buffer);
/* USB data will be immediately processed, this allow next USB traffic being 
NAKed till the end of the USART Xfer */
USB_To_VCP1_Send_Data(USB_Rx_Buffer, USB_Rx_Cnt);
/* Enable the receive of data on EP2 */
SetEPRxValid(ENDP2);
}

similarly I modified Handle_USBAsynchXfer()as follows:

void
Handle_USBAsynchXfer (
void
) {
uint16_t USB_Tx_ptr;
uint16_t USB_Tx_length;
// -------------------- VCP1
if
(CDC1_Tx_State != 1) {
if
(VCP1_Rx_ptr_out == VCP1_Rx_DATA_SIZE) {
VCP1_Rx_ptr_out = 0;
}
if
(VCP1_Rx_ptr_out == VCP1_Rx_ptr_in) {
CDC1_Tx_State = 0;
// return;
} 
else
{
if
(VCP1_Rx_ptr_out > VCP1_Rx_ptr_in) { 
/* rollback */
VCP1_Rx_length = VCP1_Rx_DATA_SIZE - VCP1_Rx_ptr_out;
} 
else
{
VCP1_Rx_length = VCP1_Rx_ptr_in - VCP1_Rx_ptr_out;
}
if
(VCP1_Rx_length > VIRTUAL_COM_PORT_DATA_SIZE) {
USB_Tx_ptr = VCP1_Rx_ptr_out;
USB_Tx_length = VIRTUAL_COM_PORT_DATA_SIZE;
VCP1_Rx_ptr_out += VIRTUAL_COM_PORT_DATA_SIZE;
VCP1_Rx_length -= VIRTUAL_COM_PORT_DATA_SIZE;
} 
else
{
USB_Tx_ptr = VCP1_Rx_ptr_out;
USB_Tx_length = VCP1_Rx_length;
VCP1_Rx_ptr_out += VCP1_Rx_length;
VCP1_Rx_length = 0;
}
CDC1_Tx_State = 1;
UserToPMABufferCopy(&VCP1_Rx_Buffer[USB_Tx_ptr], ENDP2_TXADDR, USB_Tx_length);
SetEPTxCount(ENDP2, USB_Tx_length);
SetEPTxValid(ENDP2);
}
}
// -------------------- VCP2
if
(CDC2_Tx_State != 1) {
if
(VCP2_Rx_ptr_out == VCP2_Rx_DATA_SIZE) {
VCP2_Rx_ptr_out = 0;
}
if
(VCP2_Rx_ptr_out == VCP2_Rx_ptr_in) {
CDC2_Tx_State = 0;
// return;
} 
else
{
if
(VCP2_Rx_ptr_out > VCP2_Rx_ptr_in) { 
/* rollback */
VCP2_Rx_length = VCP2_Rx_DATA_SIZE - VCP2_Rx_ptr_out;
} 
else
{
VCP2_Rx_length = VCP2_Rx_ptr_in - VCP2_Rx_ptr_out;
}
if
(VCP2_Rx_length > VIRTUAL_COM_PORT_DATA_SIZE) {
USB_Tx_ptr = VCP2_Rx_ptr_out;
USB_Tx_length = VIRTUAL_COM_PORT_DATA_SIZE;
VCP2_Rx_ptr_out += VIRTUAL_COM_PORT_DATA_SIZE;
VCP2_Rx_length -= VIRTUAL_COM_PORT_DATA_SIZE;
} 
else
{
USB_Tx_ptr = VCP2_Rx_ptr_out;
USB_Tx_length = VCP2_Rx_length;
VCP2_Rx_ptr_out += VCP2_Rx_length;
VCP2_Rx_length = 0;
}
CDC2_Tx_State = 1;
UserToPMABufferCopy(&VCP2_Rx_Buffer[USB_Tx_ptr], ENDP4_TXADDR, USB_Tx_length);
SetEPTxCount(ENDP4, USB_Tx_length);
SetEPTxValid(ENDP4);
}
}
// -------------------- VCP3
if
(CDC3_Tx_State != 1) {
if
(VCP3_Rx_ptr_out == VCP3_Rx_DATA_SIZE) {
VCP3_Rx_ptr_out = 0;
}
if
(VCP3_Rx_ptr_out == VCP3_Rx_ptr_in) {
CDC3_Tx_State = 0;
// return;
} 
else
{
if
(VCP3_Rx_ptr_out > VCP3_Rx_ptr_in) { 
/* rollback */
VCP3_Rx_length = VCP3_Rx_DATA_SIZE - VCP3_Rx_ptr_out;
} 
else
{
VCP3_Rx_length = VCP3_Rx_ptr_in - VCP3_Rx_ptr_out;
}
if
(VCP3_Rx_length > VIRTUAL_COM_PORT_DATA_SIZE) {
USB_Tx_ptr = VCP3_Rx_ptr_out;
USB_Tx_length = VIRTUAL_COM_PORT_DATA_SIZE;
VCP3_Rx_ptr_out += VIRTUAL_COM_PORT_DATA_SIZE;
VCP3_Rx_length -= VIRTUAL_COM_PORT_DATA_SIZE;
} 
else
{
USB_Tx_ptr = VCP3_Rx_ptr_out;
USB_Tx_length = VCP3_Rx_length;
VCP3_Rx_ptr_out += VCP3_Rx_length;
VCP3_Rx_length = 0;
}
CDC3_Tx_State = 1;
UserToPMABufferCopy(&VCP3_Rx_Buffer[USB_Tx_ptr], ENDP6_TXADDR, USB_Tx_length);
SetEPTxCount(ENDP6, USB_Tx_length);
SetEPTxValid(ENDP6);
}
}
}

There something else to modify I think... in fact I don't see where the interrupt endpoints are handled at all! It still does not work completely but on Windows7 64bit I can see this: 0690X000006051IQAQ.png Please note that I did not install any driver.. this comes up by default. I tried linking those serial ports to the ST VCP driver with no luck.. I guess Win7 64bit is picky. On Linux, when plugging my device I have the following:

[ 074217] usb 2-1.2: new full-speed USB device number 3 using ehci_hcd

[ 196449] cdc_acm 2-1.2:1.0: ttyACM0: USB ACM device [ 196945] cdc_acm 2-1.2:1.2: ttyACM1: USB ACM device [ 197586] cdc_acm 2-1.2:1.4: ttyACM2: USB ACM device [ 197992] usbcore: registered new interface driver cdc_acm [ 197997] cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters and three virtual COM ports appear at ttyACM0, ttyACM1, ttyACM2. But nothing flows through them. Getting there? Cheers, Michele
x8932
Associate II
Posted on October 04, 2012 at 15:50

Hi guys,

can you publish ready to use example for IAD ?

Thanks in advance

x8932
Associate II
Posted on January 26, 2013 at 03:11

I publish working example for dual CDC (as composite device).

http://akb77.com/g/stm32/stm32f103-cdc/

shengyiyangfeng
Associate
Posted on February 24, 2013 at 17:38

Hello.

As we know,the vcp demo(one cdc) needs three eps,but interrupt IN is declared in the descriptor but the related endpoint is not used. And up to 16 mono-directional or 8 bidirectional endpoints can be used.So if more CDC composite can be implemented,for example 5 cdc to use all uart?

Yangfeng

tsuneo
Senior
Posted on February 26, 2013 at 07:10

> but interrupt IN is declared in the descriptor but the related endpoint is not used.

The interrupt IN EP should be enabled, even if the firmware doesn't handle it.

Windows CDC driver (usbser.sys) polls the interrupt IN EP repeatedly.

When the EP returns no response, usbser.sys stops to read out the bulk IN EP, after a couple of transfers on the bulk EP.

Tsuneo

shengyiyangfeng
Associate
Posted on February 26, 2013 at 16:40

to be migrated, sourceId: 28478:697285D7-A9CA-445D-B16C-F23BF0E3B1A3

ryankjohnson
Associate
Posted on December 22, 2013 at 19:04

I want to thank 

Tsuneo for his detailed walk-through on this. I found his notes very helpful in getting a MSC + CDC composite device created on the STM32F4 Discovery.

Cheers!

-- Ryan

deanos
Associate II
Posted on February 10, 2014 at 04:35

Also thanks to Tsuneo and others for sharing valuable info here.

Ryan, any chance of sharing your MSC + CDC example? - I'm sure many in this community including me would greatly appreciate it.

Thanks.

highimpedance
Associate III
Posted on August 21, 2014 at 12:03

Hello,

I am trying your nice example to run on stm32L152 mcu? is it possible? Will Number of EPs (IN/OUT)  be problem for me? thx

sdim
Associate III
Posted on January 13, 2015 at 18:55

I have made a similar project based on STM32F4.

It works fine on windows XP, it even works with shared interrupt endpoint.

However, I cannot install it on Windows 8.1 x64.

Have you tried to install your device on Windows 8.1 x64?