PORTS Forum
Ports and Interfaces => USB => Topic started by: Nik on March 13, 2014, 10:30:21 am
-
Hello all,
As I had posted earlier too, I am trying to implement a USB CDC peripheral using MAX3421 and a FPGA.
My requirement is simple - Sending and receiving raw data from the virtual com port.
Now my question is : In the CDC config descriptor, can I have only one interface and two descriptors (bulk IN and OUT) ?
To elaborate more, can I have my config descriptor as below :
//Configuration Descriptor
0x09, // bLength
0x02, // bDescriptorType = Config
0x20,0x00, // wTotalLength(L/H)
0x01, // bNumInterfaces
0x01, // bConfigValue
0x00, // iConfiguration
0xC0, // bmAttributes. b7=1 b6=Bus-powered b5=RWU supported
0x32, // Max current
// INTERFACE Descriptor
0x09, // length = 9
0x04, // type = IF
0x00, // IF #0
0x00, // bAlternate Setting
0x02, // bNum Endpoints
0x02, // bInterfaceClass = CDC
0x00, // bInterfaceSubClass,
0x00, // bInterfaceProtocol
0x00, // iInterface
//Endpoint descriptor BULK OUT
0x07, // Size of descriptor
0x05, // Type of descriptor
0x01, // Address of descriptor Bit- 7 1-IN/0-OUT Bit-0-3 endpoint no.
0x02, // bmAtributts Bit- 0-1 indicate transfer type 10-bulk
0x40, // LSB Packet size
0x00, // MSB Packet size
0x00, // Polling interval 0 ms
//Endpoint descriptor BULK IN
0x07, // Size of descriptor
0x05, // Type of descriptor
0x82, // Address of descriptor Bit- 7 1-IN/0-OUT Bit-0-3 endpoint no.
0x02, // bmAtributts Bit- 0-1 indicate transfer type 10-bulk
0x40, // LSB Packet size
0x00, // MSB Packet size
0x00 // Polling interval 0 ms
One more issue is - if I specify bInterfaceClass = 0x0A for Data Interface Class, I get Error 10 on windows.
And if I continue with bInterfaceClass = 0x02 for CDC like above, I do not receive any data (Data IN) on the VCOM port. However, I am able to send the data from VCOM (Data OUT).
What am I missing ?
Grateful for your time.
- Nik
-
You need two interfaces, CDC and data.
For a virtual serial port, the CDC interface has these descriptors:
header functional
abstract control model
union functional
call management functional
endpoint (interrupt IN)
The data interface has the two data endpoints
-
Thanks for the reply Jan.
I had tried that earlier with the same result.
However, using an analyzer, I found out that the VCOM port receives exactly 3kB of data and then it stops sending IN token packets.
Second thing, in the Data Interface Descriptor, on writing 0x0A for // Class: CDC host throws error 10.
Regards,
Nik
-
Be sure bNumInterfaces in the configuration descriptor = 2.
-
Jan,
With the descriptor below it is failing enumeration.
//Configuration Descriptor
0x09, // bLength
0x02, // bDescriptorType = Config
0x43,0x00, // wTotalLength(L/H) = 67 bytes
0x02, // bNumInterfaces
0x01, // bConfigValue
0x00, // iConfiguration
0xC0, // bmAttributes. b7=1 b6=Bus-powered b5=RWU supported
0x32, // MaxPower
// INTERFACE Descriptor
0x09, // length = 9
0x04, // type = IF
0x00, // IF #0
0x00, // bAlternate Setting
0x01, // bNum Endpoints
0x02, // bInterfaceClass = CDC
0x02, // bInterfaceSubClass,
0x00, // bInterfaceProtocol
0x00, // iInterface
// CDC class specific Descriptor
0x05, // bLength
0x24, // bDescriptorType
0x00, // CDC Header function descriptor
0x10, 0x01, // Rev 1.1
0x05, // bLength
0x24, // bDescriptorType
0x01, //Call Management function descriptor
0x01,
0x01,
0x04, // bLength
0x24, // bDescriptorType
0x02, // Abstract control function descriptor
0x06,
0x05, // bLength
0x24, // bDescriptorType
0x06, // Union function descriptor
0x00,
0x01,
//Endpoint Descriptor - INTERRUPT
0x07, // Size of descriptor
0x05, // Type of descriptor
0x83, // Address of descriptor Bit- 7 1-IN/0-OUT Bit-0-3 endpoint no.
0x03, // bmAtributts Bit- 0-1 indicate transfer type 11-interrupt
0x0A, // LSB Packet size
0x00, // MSB Packet size
0x0A, // Polling interval 10 ms
// INTERFACE Descriptor
0x09, // length = 9
0x04, // type = IF
0x01, // IF #1
0x00, // bAlternate Setting
0x02, // bNum Endpoints
0x0A, // bInterfaceClass = DIC
0x00, // bInterfaceSubClass,
0x00, // bInterfaceProtocol
0x00, // iInterface
//Endpoint descriptor BULK OUT
0x07, // Size of descriptor
0x05, // Type of descriptor
0x01, // Address of descriptor Bit- 7 1-IN/0-OUT Bit-0-3 endpoint no.
0x02, // bmAtributts Bit- 0-1 indicate transfer type 10-bulk
0x40, // LSB Packet size
0x00, // MSB Packet size
0x00, // Polling interval 0 ms
//Endpoint descriptor BULK IN
0x07, // Size of descriptor
0x05, // Type of descriptor
0x82, // Address of descriptor Bit- 7 1-IN/0-OUT Bit-0-3 endpoint no.
0x02, // bmAtributts Bit- 0-1 indicate transfer type 10-bulk
0x40, // LSB Packet size
0x00, // MSB Packet size
0x00 // Polling interval 0 ms
What can be possibly wrong ?
Thank you again.
-
Try these changes:
Jan,
With the descriptor below it is failing enumeration.
//Configuration Descriptor
0x09, // bLength
0x02, // bDescriptorType = Config
0x43,0x00, // wTotalLength(L/H) = 67 bytes
0x02, // bNumInterfaces
0x01, // bConfigValue
0x00, // iConfiguration
0xC0, // bmAttributes. b7=1 b6=Bus-powered b5=RWU supported
0x32, // MaxPower
// INTERFACE Descriptor
0x09, // length = 9
0x04, // type = IF
0x00, // IF #0
0x00, // bAlternate Setting
0x01, // bNum Endpoints
0x02, // bInterfaceClass = CDC
0x02, // bInterfaceSubClass,
0x00, // bInterfaceProtocol
0x00, // iInterface
// CDC class specific Descriptor
0x05, // bLength
0x24, // bDescriptorType
0x00, // CDC Header function descriptor
0x10, 0x01, // Rev 1.1
0x05, // bLength
0x24, // bDescriptorType
0x01, //Call Management function descriptor
0x00,
0x01,
0x04, // bLength
0x24, // bDescriptorType
0x02, // Abstract control function descriptor
0x02,
0x05, // bLength
0x24, // bDescriptorType
0x06, // Union function descriptor
0x00,
0x01,
//Endpoint Descriptor - INTERRUPT
0x07, // Size of descriptor
0x05, // Type of descriptor
0x83, // Address of descriptor Bit- 7 1-IN/0-OUT Bit-0-3 endpoint no.
0x03, // bmAtributts Bit- 0-1 indicate transfer type 11-interrupt
0x0A, // LSB Packet size
0x00, // MSB Packet size
0x0A, // Polling interval 10 ms
// INTERFACE Descriptor
0x09, // length = 9
0x04, // type = IF
0x01, // IF #1
0x00, // bAlternate Setting
0x02, // bNum Endpoints
0x0A, // bInterfaceClass = DIC
0x00, // bInterfaceSubClass,
0x00, // bInterfaceProtocol
0x00, // iInterface
//Endpoint descriptor BULK OUT
0x07, // Size of descriptor
0x05, // Type of descriptor
0x01, // Address of descriptor Bit- 7 1-IN/0-OUT Bit-0-3 endpoint no.
0x02, // bmAtributts Bit- 0-1 indicate transfer type 10-bulk
0x40, // LSB Packet size
0x00, // MSB Packet size
0x00, // Polling interval 0 ms
//Endpoint descriptor BULK IN
0x07, // Size of descriptor
0x05, // Type of descriptor
0x82, // Address of descriptor Bit- 7 1-IN/0-OUT Bit-0-3 endpoint no.
0x02, // bmAtributts Bit- 0-1 indicate transfer type 10-bulk
0x40, // LSB Packet size
0x00, // MSB Packet size
0x00 // Polling interval 0 ms
What can be possibly wrong ?
Thank you again.
Also be sure bDeviceClass in the device descriptor = 2.
-
:(
Still the same !
-
Our CDC device does enumerate, there was some trickiness with inf getting Windows to recognize it. I compared your descriptors to our, and the differences are below.
The only one I'd expect to make a difference are the interface protocol, or maybe the capabilities. We accept some commands only to ignore them.
In the interface descriptor
0x00, // bInterfaceProtocol
0x00, // iInterface
We have protocol set to 1, which is AT commands protocol (i.e. modem). We also have an interface string, but I wouldn't expect that to make a difference.
For the class specific interface descriptor it is
0x04, // bLength
0x24, // bDescriptorType
0x02, // Abstract control function descriptor
0x02,
We have zero for the last byte, seems to be bmCapabilities, not exactly sure what capabilities I'm not declaring
For the interrupt pipe we use 32 bytes and a polling interval of 2.
We have a string for the interface (again, I wouldn't expect that to make a difference).
We declare the bulk pipes in the other order, and again they're 32 bytes.
-
I'll also say that Windows wasn't happy until I did accept the set_line_coding etc commands. I just make a note of what I'm told, send them back if asked, but otherwise ignore them.
-
Thanks for the response Barry !
I have now a strange situation.
Here are my descriptors :
const unsigned char DD[]= // DEVICE Descriptor
{
0x12, // bLength = 18d
0x01, // bDescriptorType = Device (1)
0x00,0x02, // bcdUSB(L/H) USB spec rev (BCD)
0x02, // bDeviceClass,
0x00, // bDeviceSubClass,
0x00, // bDeviceProtocol
0x40, // bMaxPacketSize0 EP0 is 64 bytes
0xD8, 0x04, // idVendor(L/H)
0x0A, 0x00, // idProduct(L/H)
0x02,0x00, // bcdDevice
0x01, // iManufacturer
0x02, // iProduct,
0x00, // iSerialNumber
0x01 // bNumConfigurations
};
const unsigned char CD[]= // CONFIGURATION Descriptor
{
//Configuration Descriptor
0x09, // bLength
0x02, // bDescriptorType = Config
0x3C,0x00, // wTotalLength(L/H) = 60 bytes
0x02, // bNumInterfaces
0x01, // bConfigValue
0x00, // iConfiguration
0xC0, // bmAttributes. b7=1 b6=Bus-powered b5=RWU supported
0x32, // MaxPower is 2 ma
// INTERFACE Descriptor
0x09, // length = 9
0x04, // type = IF
0x00, // IF #0
0x00, // bAlternate Setting
0x01, // bNum Endpoints
0x02, // bInterfaceClass = CDC
0x02, // bInterfaceSubClass,
0x01, // bInterfaceProtocol
0x00, // iInterface
// CDC class specific Descriptor
0x05, // bLength
0x24, // bDescriptorType
0x00, // CDC Header function descriptor
0x10, 0x01, // Rev 1.1
0x05, // bLength
0x24, // bDescriptorType
0x01, // Call Management function descriptor
0x01,
0x01,
0x04, // bLength
0x24, // bDescriptorType
0x02, // Abstract control function descriptor
0x00,
0x05, // bLength
0x24, // bDescriptorType
0x06, // Union function descriptor
0x00,
0x01,
//Endpoint Descriptor - INTERRUPT
0x07, // Size of descriptor
0x05, // Type of descriptor
0x83, // Address of descriptor Bit- 7 1-IN/0-OUT Bit-0-3 endpoint no.
0x03, // bmAtributts Bit- 0-1 indicate transfer type 11-interrupt
0x0A, // LSB Packet size
0x00, // MSB Packet size
0x01, // Polling interval 10 ms
// INTERFACE Descriptor
0x09, // length = 9
0x04, // type = IF
0x01, // IF #1
0x00, // bAlternate Setting
0x02, // bNum Endpoints
0x0A, // bInterfaceClass = CDC
0x00, //bInterfaceSubClass,
0x00, // bInterfaceProtocol
0x00, // iInterface
//Endpoint descriptor BULK OUT
0x07, // Size of descriptor
0x05, // Type of descriptor
0x01, // Address of descriptor Bit- 7 1-IN/0-OUT Bit-0-3 endpoint no.
0x02, // bmAtributts Bit- 0-1 indicate transfer type 10-bulk
0x40, // LSB Packet size
0x00, // MSB Packet size
0x00, // Polling interval 0 ms
//Endpoint descriptor BULK IN
0x07, // Size of descriptor
0x05, // Type of descriptor
0x82, // Address of descriptor Bit- 7 1-IN/0-OUT Bit-0-3 endpoint no.
0x02, // bmAtributts Bit- 0-1 indicate transfer type 10-bulk
0x40, // LSB Packet size
0x00, // MSB Packet size
0x00 // Polling interval 0 ms
};
So, the maximum EP0 size is 64 bytes and my config descriptor is of 67 bytes.
For the descriptors above, 60 bytes is the best that is working for me. The device is enumerated properly and works with VCOM port - however, without and BULK IN endpoint.
Hence, I can send the data on BULK OUT but cannot receive on BULK IN.
I tried increasing the size in Device Descriptor as 67, but as MAX3421 has the endpoint size of 64-bytes, enumeration failed.
Any other workaround ???
Thanks for your precious time !
- Nik
-
Now that I am sending 67 bytes as 64 bytes and then 3 bytes,
Windows XP says : Unknown device
Windows 7 says : This device cannot start. (Code 10).
Any clue ?
Thanks.
Nik
-
That was one of my other thoughts I forgot to mention. With a 67 byte descriptor set, the data for the SETUP transaction is split over two packets. If your SETUP handling doesn't cope with this, you won't get enumerated correctly. It took me a bit of effort to sort out that for our device.
Make the descriptors 67 bytes again and then check that its being transferred correctly. This is where a hardware analyser is essential. If it isn't transferred correctly, you need to fix that before doing anything else.
-
Hi Barry,
Thanks for your time.
This is what the hardware analyzer is showing :
Host sends : Get config descriptor request
Device sends : ACK
Host sends : IN Token
Device sends : 64 bytes config data
Host sends : ACK
Host sends : IN Token
Device sends : 3 bytes config data
Host sends : ACK
Host sends : OUT Token
Host sends : 0 byte data
Device sends : ACK
Is there any issue here.
Thank you again.
Regards,
Nik
-
The setupapilog file might have a clue:
http://support.microsoft.com/kb/927521
-
Thanks Jan, but I could not find anything. :(
One very fundamental question to the CDC.
To get my device enumerated, do I need to implement responses to these too? :
SEND_ENCAPSULATED_COMMAND
GET_LINE_CODING
SET_LINE_CODING
SET_CONTROL_LINE_STATE
SEND_BREAK
etc.
I thought only the Device Descriptor and Config Descriptor were enough.
Regards,
Nik
-
You couldn't find the file or you didn't see anything useful in it?
Support for SEND_ENCAPSULATED_COMMAND and GET_ENCAPSULATED_COMMAND is required for abstract control model devices. However, if AT commands aren't implemented, the host has no reason to send these requests.
Support for the other requests are optional. If not supported, the device should return STALL.
-
Jan I could not find the file at C:\WINDOWS\setupapi.log
In my case, as I only need to send and receive raw bytes from the VCOM port, is Abstract Control Model ?
Secondly, I thought that these requests are post enumeration events. So at least my device should enumerate properly.
What am I missing ? :'(
Regards,
Nik
-
Look in windows\inf
Yes, use abstract control model for virtual com port.
The device has enumerated successfully if endpoint 0 has ACKed a Set_configuation request > 0.
-
Jan,
Apparently, there is no SET_CONFIGURATION request in my case.
Could not my hardware analyzer report with the reply.
-
As the enumeration is failing, there is no data logged in setupapi.dev.log
-
Here is one more observation :
When the config descriptor is <= 64, the device enumerates but the virtual com port shows : Error (code 10).
But if the config descriptor is >64, the device does not enumerate.
So, clearly it is an issue of greater than 64 bytes packet. However, I think I am sending it the way it is supposed to be.
- Nik
-
Hi Barry,
Thanks for your time.
This is what the hardware analyzer is showing :
Host sends : Get config descriptor request
Device sends : ACK
Host sends : IN Token
Device sends : 64 bytes config data
Host sends : ACK
Host sends : IN Token
Device sends : 3 bytes config data
Host sends : ACK
Host sends : OUT Token
Host sends : 0 byte data
Device sends : ACK
Is there any issue here
That would depend on the toggle of the data packets. The 64 byte packet should have DATA1 (all SETUP transfers start with a DATA1), the 3 byte packet should have DATA0 (toggles should alternate except the first one). That the host sends the OUT token is a good sign, unless its substantially later than the 3 byte packet. With a bad data toggle, the host would accept the packet, and discard it. Then you'd see further IN tokens, which would probably be NAKed. After sometime NAKing, the host can timeout and send the OUT token. The timeout is probably between 500ms and 5s.
-
Hi Barry,
Yes the 64 bytes have DATA1 and 3 bytes have DATA0.
The OUT token sent by the host is after 2msec.
But after receiving the first 64 bytes the host sends ACK. Then host send 42 IN Tokens which are NAKed and at 43rd IN Token, the device sends rest of the 3 bytes.
Thanks.
Nik
-
Be sure bInterfaceClass in the Device desrcriptor = 2.
If you have changed your descriptors over time, change the Product ID, as Windows will "remember" previous descriptors.
-
Jan, Barry and everybody else !
Issue fixed !
The issues was - delay in sending the remaining 3 bytes of config descriptor data.
After sending first 64 bytes, I was checking the interrupt bit to make sure if the 64 bytes have been sent.
Removing this check fixed it !
Here is the code of sending config descriptor :
if ((desclen!=0)) // one of the case statements above filled in a value
{
sendlen = (reqlen <= desclen) ? reqlen : desclen; // send the smaller of requested and avaiable
//Send length is less than or equal to 64
if(sendlen<=64)
{
WriteBytes(rEP0FIFO,sendlen,pDdata);
WriteMax3421RegAS(rEP0BC,sendlen); // load EP0BC to arm the EP0-IN transfer & ACKSTAT
}
//Send length is greater than
else
{
do
{
sendlen = 64;
WriteBytes(rEP0FIFO,sendlen,pDdata);
WriteMax3421RegAS(rEP0BC,sendlen); // load EP0BC to arm the EP0-IN transfer & ACKSTAT
desclen=desclen-sendlen;
pDdata=pDdata+sendlen;
}while(desclen>64);
sendlen = desclen;
//while(!ReadMax3421Reg(rEPIRQ& bmIN0BAVIRQ));
if(sendlen>0) WriteBytes(rEP0FIFO,sendlen,pDdata);
WriteMax3421RegAS(rEP0BC,sendlen);
}
Commenting the line in red worked for me.
Thank you all for your precious time !
Regards,
Nik
-
Glad you got it fixed. Thanks for letting us know what you found!