I'm working on hosting cdc FTDI FT232R USB virtual comport.
I have managed to modify usb cdc device example and making it a host.
I have implemented usb host cdc driver and managed to send FTDI set baud rate request.
I can now send data over virtual com port using USBHCDPipeWrite.
I'm now facing a problem on receiving end.
How is the receive logic implemented and how should it be used in my case?
Device Descriptor:bcdUSB: 0x0200bDeviceClass: 0x00bDeviceSubClass: 0x00bDeviceProtocol: 0x00bMaxPacketSize0: 0x08 (8)idVendor: 0x0403 (Future Technology Devices International Limited)idProduct: 0x6001bcdDevice: 0x0600iManufacturer: 0x010x0409: "FTDI"iProduct: 0x020x0409: "MCTEST C"0x0409: "MCTEST C"iSerialNumber: 0x030x0409: "FTPBG74H"bNumConfigurations: 0x01ConnectionStatus: DeviceConnectedCurrent Config Value: 0x01Device Bus Speed: FullDevice Address: 0x01Open Pipes: 2Endpoint Descriptor:bEndpointAddress: 0x81 INTransfer Type: BulkwMaxPacketSize: 0x0040 (64)bInterval: 0x00Endpoint Descriptor:bEndpointAddress: 0x02 OUTTransfer Type: BulkwMaxPacketSize: 0x0040 (64)bInterval: 0x00Configuration Descriptor:wTotalLength: 0x0020bNumInterfaces: 0x01bConfigurationValue: 0x01iConfiguration: 0x00bmAttributes: 0xA0 (Bus Powered Remote Wakeup)MaxPower: 0x2D (90 Ma)Interface Descriptor:bInterfaceNumber: 0x00bAlternateSetting: 0x00bNumEndpoints: 0x02bInterfaceClass: 0xFFbInterfaceSubClass: 0xFFbInterfaceProtocol: 0xFFiInterface: 0x020x0409: "MCTEST C"0x0409: "MCTEST C"Endpoint Descriptor:bEndpointAddress: 0x81 INTransfer Type: BulkwMaxPacketSize: 0x0040 (64)bInterval: 0x00Endpoint Descriptor:bEndpointAddress: 0x02 OUTTransfer Type: BulkwMaxPacketSize: 0x0040 (64)bInterval: 0x00
Peter,
We are facing a similar situation and considering porting the Device CDC implementation over to the Host USB stack. we aren't using FTDI interface but the on-chip USB host controller instead but the effort to do the port should be the same as what you did. How challenging was the task and how long it take you? Is there any code you can share at all, or short of that, advice from your experinece?
Regards & thanks,
Charlie Ellis, Vanteon Corp.
Hello Charlie,
"How challenging was the task and how long it take you?"
It took me a week to communicate with FTDI chip and send out data. User guide for USB library was quite helpful.
Examples on this sites were also very helpful:http://code.google.com/p/propilot/source/browse/trunk/Microchip/USB/CDC%20Host%20Driver/usb_host_cdc.c?r=75
https://github.com/felis/USB_Host_Shield_2.0
especially felis.
"Is there any code you can share at all, or short of that, advice from your experience?"
I will put usb_host_cdc example on this post today or tomorrow.
I can now read from Bulk In Pipe by using USBHCDPipeRead and not USBHCDPipeReadNonBlocking. Somehow the second function is not returning data. Will investigate further and prepare source for share.
Best regards,
Peter
You do realize that the non-blocking versions of functions always return immediately regardless of whether they can perform the requested task. You have to check the status return to see if the call was successful. If the call was not successful (in this case because data hasn't been received yet), you need to loop back an try again.
Thanks for reply,
I have used USBHCDPipeSchedule() functionality now, by setting callback when BulkInPipe is allocated.
// // Allocate the USB Pipe for this Bulk IN endpoint. //
g_USBHCDCDevice.ulBulkInPipe = USBHCDPipeAllocSize(0, USBHCD_PIPE_BULK_IN_DMA, pDevice->ulAddress, pEndpointDescriptor->wMaxPacketSize, USBHCDCINCallback);
// // Configure the USB pipe as a Bulk IN endpoint. // USBHCDPipeConfig(g_USBHCDCDevice.ulBulkInPipe, pEndpointDescriptor->wMaxPacketSize, 64, (pEndpointDescriptor->bEndpointAddress & USB_EP_DESC_NUM_M));
Callback looks like this:
unsigned char SchedulePipeInBuffer[64];void USBHCDCINCallback(unsigned long ulPipe, unsigned long ulEvent){ //unsigned long ulSize; // // Handles a request to schedule a new request on the interrupt IN // pipe. // if(ulEvent == USB_EVENT_SCHEDULER) { USBHCDPipeSchedule(ulPipe, SchedulePipeInBuffer, 64); } // // Called when new data is available on the interrupt IN pipe. // if(ulEvent == USB_EVENT_RX_AVAILABLE) { // // If the callback exists then call it. // if(g_USBHCDCDevice.pfnCallback != 0) {
//Handle received data
g_USBHCDCDevice.pfnCallback((unsigned long)&g_USBHCDCDevice, CDC_EVENT_RX_AVAILABLE, (void*)SchedulePipeInBuffer); memset(SchedulePipeInBuffer,0,64);
//schedule another read
USBHCDPipeSchedule(ulPipe, SchedulePipeInBuffer, 64); } }}
I don't know if DMA is the best solution for receiving data, as I'm getting all 64 bytes after DMA finishes reading.
So I don't know where my data ends in received buffer.
DMA is probably the best solution for Mass Storage Device, but for my functionality where received size is not known.
I will probably have to implement something else.
Any suggestions?
I have now disabled DMA on Pipe In.
// // Allocate the USB Pipe for this Bulk IN endpoint. // g_USBHCDCDevice.ulBulkInPipe = USBHCDPipeAllocSize(0, USBHCD_PIPE_BULK_IN,/*USBHCD_PIPE_BULK_IN_DMA,*/ pDevice->ulAddress, pEndpointDescriptor->wMaxPacketSize, USBHCDCINCallback);
And changed callback function when RX_AVAILABLE. When I receive
USB_EVENT_RX_AVAILABLE I read out from pipe and schedule another read.
// // Called when new data is available on the interrupt IN pipe. // if(ulEvent == USB_EVENT_RX_AVAILABLE) { // // If the callback exists then call it. // if(g_USBHCDCDevice.pfnCallback != 0) { // // Read the Data out. // ulSize = USBHCDPipeReadNonBlocking(g_USBHCDCDevice.ulBulkInPipe, SchedulePipeInBuffer, 64); USBHCDPipeSchedule(ulPipe, SchedulePipeInBuffer, 64); } }
I get the correct size now when not using DMA.
If anyone has a better approach please let me know.
Charlie,
I have prepared an example of CDC host driver for the use with FTDI chip.
5488.Stellaris USB CDC Host Example.zip
I hope I'm not violating any copyright law.
This example application demonstrates using aUSB Communications Device Class for hosting a FTDI FT232R device. I'm using FTDIs UB232R development module:http://apple.clickandbuild.com/cnb/shop/ftdichip?productID=66&search=UB232R&op=catalogue-product_info-nullWhich has this FTDI chip: http://www.ftdichip.com/Products/ICs/FT232R.htm It has USB_CLASS_VEND_SPECIFIC (0xff) Interface Class.Other CDC drivers could also be added to this example in the future (ACM, Prolific,...).We will use it for connecting GSM modem (over FTDI) to our custom Stellaris board with OTG support.
Copy files to StellarisWare folder Add usb_host_cdc project to workspace Add usbhcdc.c and usbhcdcftdi.c to usblib project. Recompile usblib. Upload to target. After device is enumerated it sends FTDI baudrate control transfer. Baudrate is set to 115200. When FTDI is connected to USB OTG it will send out "usb_host_cdc echo example" string. When device is ready everything FTDI receives on RX is send to TX (echo).
Hi Peter! Great job you have done! I´m a newbie with USB, and I was able to almost make your software work.
Almost because I´m trying to connect a Prolific device in my LM3S9B96. I can see the following:
USB reset.Connection 0 - getting device descriptorConnection 0 - setting address 1Connection 0 - getting config descriptorConnection 0 - setting configuration.
I know that I have to include the Prolific driver, but I couldn´t find where... Debugging the software, I see the status HCD_DEV_CONFIGURED in g_sUSBHCD.eDeviceState[0], but the g_eState is always STATE_UNKNOWN_DEVICE.
Where is the FTDI device info in your software? I have read a lot of times the files and I didn´t find it. I´m sure that if I find it I will be able to make it work.
Thank you!
Hello Luciano,
I had the same problem when debugging and learning how USB library works.In this example I'm using USB_CLASS_VEND_SPECIFIC interface class, maybe your device has different class interface.And when usb library is searching for driver (USBHCDOpenDriver()) for your device, it cannot match ulInterfaceClass.
I have used USBlyzer demo (2.0 build 25, which can be used as demo all the time if you change system clock) on my PC to lookup my device info:
USBView is also great and is free:http://www.ftdichip.com/Support/Utilities.htm
BTW: In the meantime, I have implemented ACM driver for Stellaris using this example code:https://github.com/felis/USB_Host_Shield_2.0And as I can see, it has prolific example also. Maybe it helps.Best regards
Looks like image is not displayed, So I'm attaching a smaller one and txt:
Connection Status Device connected Current Configuration 1 Speed Full (12 Mbit/s) Device Address 1 Number Of Open Pipes 2
Device Descriptor MCTEST COffset Field Size Value Description 0 bLength 1 12h 1 bDescriptorType 1 01h Device 2 bcdUSB 2 0200h USB Spec 2.0 4 bDeviceClass 1 00h Class info in Ifc Descriptors 5 bDeviceSubClass 1 00h 6 bDeviceProtocol 1 00h 7 bMaxPacketSize0 1 08h 8 bytes 8 idVendor 2 0403h Future Technology Devices International, Ltd 10 idProduct 2 6001h 12 bcdDevice 2 0600h 6.00 14 iManufacturer 1 01h "FTDI" 15 iProduct 1 02h "MCTEST C" 16 iSerialNumber 1 03h "FTPBG74H" 17 bNumConfigurations 1 01h
Configuration Descriptor 1 Bus Powered, 90 mAOffset Field Size Value Description 0 bLength 1 09h 1 bDescriptorType 1 02h Configuration 2 wTotalLength 2 0020h 4 bNumInterfaces 1 01h 5 bConfigurationValue 1 01h 6 iConfiguration 1 00h 7 bmAttributes 1 A0h Bus Powered, Remote Wakeup 4..0: Reserved ...00000 5: Remote Wakeup ..1..... Yes 6: Self Powered .0...... No, Bus Powered 7: Reserved (set to one)(bus-powered for 1.0) 1....... 8 bMaxPower 1 2Dh 90 mA
Interface Descriptor 0/0 Vendor-Specific, 2 EndpointsOffset Field Size Value Description 0 bLength 1 09h 1 bDescriptorType 1 04h Interface 2 bInterfaceNumber 1 00h 3 bAlternateSetting 1 00h 4 bNumEndpoints 1 02h 5 bInterfaceClass 1 FFh Vendor-Specific 6 bInterfaceSubClass 1 FFh 7 bInterfaceProtocol 1 FFh 8 iInterface 1 02h "MCTEST C"
Endpoint Descriptor 81 1 In, Bulk, 64 bytesOffset Field Size Value Description 0 bLength 1 07h 1 bDescriptorType 1 05h Endpoint 2 bEndpointAddress 1 81h 1 In 3 bmAttributes 1 02h Bulk 1..0: Transfer Type ......10 Bulk 7..2: Reserved 000000.. 4 wMaxPacketSize 2 0040h 64 bytes 6 bInterval 1 00h
Endpoint Descriptor 02 2 Out, Bulk, 64 bytesOffset Field Size Value Description 0 bLength 1 07h 1 bDescriptorType 1 05h Endpoint 2 bEndpointAddress 1 02h 2 Out 3 bmAttributes 1 02h Bulk 1..0: Transfer Type ......10 Bulk 7..2: Reserved 000000.. 4 wMaxPacketSize 2 0040h 64 bytes 6 bInterval 1 00h
Peter,First of all, FTDI chip isn't a CDC device. It's a vendor-specific.Just those devices, which expose 0x02 at interfaceClass field of its interface descriptor, is called as CDC.Your implementation seems almost fine, but a couple of refinement is required.1) In USBHCDCOpen() (usbhcdc.c), check VID/PID on the device descriptor, first, so that this routine succeeds just for the target FTDI chip.2) The first two bytes of every bulk IN packet hold status bytes from the chip. The rest of the packet, if any, is the RX data.As of the contents of the status bytes, refer to the source code of libFTDIhttp://www.intra2net.com/en/developer/libftdi/ ftdi.c/** Poll modem status information This function allows the retrieve the two status bytes of the device. The device sends these bytes also as a header for each read access where they are discarded by ftdi_read_data(). The chip generates the two stripped status bytes in the absence of data every 40 ms. Layout of the first byte: - B0..B3 - must be 0 - B4 Clear to send (CTS) 0 = inactive 1 = active - B5 Data set ready (DTS) 0 = inactive 1 = active - B6 Ring indicator (RI) 0 = inactive 1 = active - B7 Receive line signal detect (RLSD) 0 = inactive 1 = active Layout of the second byte: - B0 Data ready (DR) - B1 Overrun error (OE) - B2 Parity error (PE) - B3 Framing error (FE) - B4 Break interrupt (BI) - B5 Transmitter holding register (THRE) - B6 Transmitter empty (TEMT) - B7 Error in RCVR FIFOTsuneo
Hi Peter and Charlie,
Prolific PL2303 is also a vendor-specific.The differences from FTDI are,
1) PL2303 has an extra interrupt IN endpoint, which returns status bytes. FTDI returns the status bytes over the first two bytes of every bulk IN packet.2) The command over vendor requests (control transfer) are different from those FTDI's at all.As of the baud rate setting, refer to pl2303_set_termios() on this Linux driver source.Linux/drivers/usb/serial/pl2303.chttp://lxr.free-electrons.com/source/drivers/usb/serial/pl2303.c#L250I believe it isn't so much work, to apply Peter's FTDI implementation to Prolific.Tsuneo
Tsuneo,
Most thanks for all the comments.
I will implement those changes and also add ACM code to the example project maybe it would be useful to someone.
Now we have a ACM GPRS Benq M23 modem for our research project like this one:http://www.circuitsathome.com/mcu/interfacing-arduino-to-usb-gprs-modem/comment-page-1#comments
I can now communicate with Benq M23.I’m having problem detecting when socket is closed.
We are used to detect this using DCD pin on other serial communication modems.I have noticed that CDC ACM has this capability with interrupt endpoint.When I first open a socket I receive data on interrupt endpoint:A1 20 00 00 00 00 02 00 83 00
By USB Class Definition for Comminication Devices pdf, this is a Class-Specific Notification 0xA1 with “Serial State” notification 0×20, indicating that DCD signal is high.
But if the socket is closed I stop receiving endpoint interrupts.
I receive DCD high notification only once when socket is opened.The second time when socket is closed DCD low is not present, which would be useful for detecting if other side has disconnected. Now, I have implemented a NO CARRIER detection. But interrupt would be more elegant.
Thanks for all the information.
Best Regards
Hi Peter and Tsuneo! Thank you all guys for the help!
I will follow your recommendations.
Luciano
Hi Luciano,Auu sorry,Prolific implementation request was yours.Prolific protocol likes CDC-ACM's more than FTDI's.(CDC-ACM: Communication Device Class - Abstract Control Model, class triad = (0x02, 0x02, 0x01))1) DescriptorsProlific descriptors are simplified one of CDC-ACM;- Single interface with three endpoints (interrupt IN, bulk IN/OUT)- No extra class-specific descriptor2) Bulk IN/OUT endpointsProlific exchanges just data (without status) over bulk IN/OUT, like CDC-ACM3) Modem StatusProlific carries status byte over the interrupt IN pipe, like CDC-ACMThe status byte locates on the ninth byte of "Notification" bytes, like CDC-ACMIts bitmap is same as those of CDC-ACM, just with CTS extension.Prolific status byte bitmaphttp://lxr.free-electrons.com/source/drivers/usb/serial/pl2303.c#L134134 #define UART_DCD 0x01135 #define UART_DSR 0x02136 #define UART_BREAK_ERROR 0x04137 #define UART_RING 0x08138 #define UART_FRAME_ERROR 0x10139 #define UART_PARITY_ERROR 0x20140 #define UART_OVERRUN_ERROR 0x40141 #define UART_CTS 0x80CDC-ACM: UART State Bitmap of SERIAL_STATE notificationD0 bRxCarrier - DCDD1 bTxCarrier - DSRD2 bBreak - breakD3 bRingSignal - RingD4 bFraming - framing errorD5 bParity - parity errorD6 bOverRun - overrun errorD15..D7 - reservedIn these reasons, Peter's CDC-ACM implementation will give you better starting point for Prolific.Hi Peter,Maybe you've already touched to them, here is a little mods for your first code.usbhcdc.cstatic void *USBHCDCOpen(tUSBHostDevice *pDevice){ ... // // Loop through the endpoints of the device. //// for(iIdx = 0; iIdx < 3; iIdx++) for(iIdx = 0; iIdx < pInterface->bNumEndpoints; iIdx++) { ... // // See if this is a bulk endpoint. //// if((pEndpointDescriptor->bmAttributes & USB_EP_ATTR_BULK) ==// USB_EP_ATTR_BULK) if((pEndpointDescriptor->bmAttributes & USB_EP_ATTR_TYPE_M) == USB_EP_ATTR_BULKTsuneo
Peter Šamperl:But if the socket is closed I stop receiving endpoint interrupts.