Important changes to forums and questions
All forums and questions are now archived. To start a new conversation or read the latest updates go to forums.mbed.com.
11 years, 8 months ago.
How can I send and receive USB Host Serial messages from my code ?
I want to be able to use my MBED to control, and log data & commands etc. using USB Host,
I need to connect to some equipment, which has an FTDI driver inside it.
I have attempted to connect a USB <-> Serial cable, from FTDI,
but the code does not recognize it :(
I have (just once) managed to get TWO MBED's connected, one sending out a repeated string (device)
and revived buy USB Host, but I cannot work out how to get the communications link up and running.
Any help would be appreciated.
cheers
Lex.
Question relating to:
4 Answers
11 years, 8 months ago.
Hi,
FTDI chips does not enumerate as serial devices... If you want to use a FTDI chip, you need to filter the usb device by vid/pid instead of usb class.
A good starting point is to take a look at USBHostSerial.cpp:
/*virtual*/ void USBHostSerial::setVidPid(uint16_t vid, uint16_t pid) { // we don't check VID/PID for Serial driver } /*virtual*/ bool USBHostSerial::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed { if ((serial_intf == -1) && (intf_class == SERIAL_CLASS) && (intf_subclass == 0x00) && (intf_protocol == 0x00)) { serial_intf = intf_nb; return true; } return false; } /*virtual*/ bool USBHostSerial::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used { if (intf_nb == serial_intf) { if (type == BULK_ENDPOINT) { serial_device_found = true; return true; } } return false; }
These three methods are automatically called when a usb device is connected. You can use the setVidPid method to find a ftdi chip. Then you don't have to check that "intf_class == SERIAL_CLASS" as it is not the case for these chips...
Cheers, Sam
Samuel,
What do you mean when you say "FTDI chips does not enumerate as serial devices"?
I am considering purchasing an mbed LPC1768 board. My plan is to solder a USB female receptacle to the appropriate D+ and D- pins, add two 15k resistors, and program the board as USB host as indicated in http://mbed.org/handbook/USBHostSerial. Then, I would plug a second board to the USB female receptable. This second board is a USB device and has the FTDI chip shown in http://www.ftdichip.com/Products/ICs/FT232B.htm. Would I have any USB recognition problem with this set up?
posted by 18 Sep 201411 years, 8 months ago.
I have attempted to get this to work, but my USB knowlage is not vast,
can we have an example please.
Bizzarly though, the MCP2200 does work,
But I would also realy want to be able to controll some equipment with FTDI chips inside,
Thanks
Ceri
10 years, 2 months ago.
Samuel,
What do you mean when you say "FTDI chips does not enumerate as serial devices"?
I am considering purchasing an mbed LPC1768 board. My plan is to solder a USB female receptacle to the appropriate D+ and D- pins, add two 15k resistors, and program the board as USB host as indicated in http://mbed.org/handbook/USBHostSerial. Then, I would plug a second board to the USB female receptable. This second board is a USB device and has the FTDI chip shown in http://www.ftdichip.com/Products/ICs/FT232B.htm. Would I have any USB recognition problem with this set up?
10 years, 2 months ago.
Samuel says it quite clearly. USB devices send descriptors to the host, the device descriptors contains a "class". Classes can be for instance mass storage device, human interface device or serial device. Classes allow that a generic class driver is used for products from different manufacturers. Although the FTDI chip is a serial device, FTDI has decided not to enumerate it as a serial device. Therefore its class is not serial device but manufacturer defined. In such a case you should call a manufacturer driver. In such case the driver is defined by the vid/pid combination and possibly other parameters. So instead of testing for the device class you test for the vid/pid combination of your FTDI device. AFAIK the chip itself is a normal serial device so you won't need to change much else. Beware of the correct endpoint numbers though.
Thank you very much for this useful explanation. Do you know if the FTDI driver is already installed in the LPC1768 board? According to the FTDI website, I only see D2XX drivers for ARM processors (see http://www.ftdichip.com/Drivers/D2XX.htm).
I could not find the documentation for the USBHostSerial::setVidPid(uint16_t vid, uint16_t pid), so I don't know what it is supposed to do. Would it be something like:
void USBHostSerial::setVidPid(uint16_t vid, uint16_t pid) { if (vid and pid are the corresponding values of my FTDI chip) call some method; }
?
Thank you for any clue you might provide. Do you think it would be wise to contact FTDI directly?
posted by 23 Sep 2014No I don't think you can use the FTDI supplied drivers. I had a look at the USBHost library (which is now quite different from the one I used some years ago). As Samuel said, the trick is in the three methods from abstract class IUSBEnumerator. The important one is parseInterface, this one must return true for your FTDI serial device and preferably false for any other device. The code in the USBHostSerial implementation that I found in the library differs a bit from the code in Samuels' post.
#define CHECK_INTERFACE(cls,subcls,proto) \ (((cls == 0xFF) && (subcls == 0xFF) && (proto == 0xFF)) /* QUALCOM CDC */ || \ ((cls == SERIAL_CLASS) && (subcls == 0x00) && (proto == 0x00)) /* STANDARD CDC */ ) /*virtual*/ void USBHostSerial::setVidPid(uint16_t vid, uint16_t pid) { // we don't check VID/PID for MSD driver } /*virtual*/ bool USBHostSerial::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed { if (!ports_found && CHECK_INTERFACE(intf_class, intf_subclass, intf_protocol)) { port_intf = intf_nb; ports_found = true; return true; } return false; } /*virtual*/ bool USBHostSerial::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used { if (ports_found && (intf_nb == port_intf)) { if (type == BULK_ENDPOINT) return true; } return false; }
This code does not test for VID/PID but accepts FF,FF,FF as the class,subclass,proto tuple. Please check these values for FTDI devices. If they are also FF,FF,FF it should already work. If it is different you can either modify the library or write your own by simply inheriting everything from USBHostSerial and overriding the first two virtual functions.
class USBHostFTDISerial: public USBHostSerial { uint16_t _vid, _pid; public: virtual void setVidPid(uint16_t vid, uint16_t pid) { _vid=vid;_pid=pid;} virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) { /* test anything you like and return true on success eg. test _vid/_pid instead of class,subclass,proto but keep the other tests and settings */ } };
OK I'm looking at the values for two USB-Serial leads, one a "Prolific" and the other "Aten". According to windows the Prolific has VID 067b PID 2302 and the Aten has 0557,2008.
Both appear to have FF,00,00 as the C,S,P Tuple
I'm wondering about a "hack" to just recognise FF,00,00 and ignore the VID,PID temporarily
Also do I have to fetch and hack the library, or can I just derive a new class and override the detection method, which seems "nicer".
With the test for Class=0xff kludged in it is recognising the two cables, but there is one peculiarity: It is transferring data one byte behind. Characters aren't being missed but the first character sent doesn't come through until a second is sent.
CORRECTION: IT IS NOT THE FAULT OF USBHOSTSERIAL!!
I replaced that "printf" statement with pc.putc and the write-behind stopped.
posted by 28 Jun 2017