I finished porting USB transfers from PIC C to Arduino C++. There is now a USB class in the repository. Two main types of USB transfers – control and bulk, are implemented. If you want to know more about USB transfer mechanics, take a look at this article. The code was written to work on Microchip PIC, however, the Arduino code is almost identical.
Since we now have tools to talk to USB device, let’s start using them by looking at USB descriptors. In order for sketches from this article to work you need to copy current repository contents ( *.cpp and *.h files ) to a sub directory in your Arduino hardware libraries directory. In addition, don’t forget to supply 5V to Vbus and connect a USB device, such as flash drive or mouse to USB connector of a breakout board.
First sketch demonstrates access to device descriptor. Device descriptor is the first descriptor that the host retrieves from the device during enumeration. The information which host needs is device endpoint zero maximum packet size. In this example, maximum packet size is already set by a function in USB class, called “Task”. In addition to maximum packet size device descriptor contains other information, used during device configuration.
/* MAX3421E USB Host controller get device descriptor */ #include <spi.h> #include <max3421e.h> #include <usb.h> void setup(); void loop(); MAX3421E Max; USB Usb; void setup() { byte tmpdata = 0; Serial.begin( 9600 ); Serial.println("Start"); Max.powerOn(); delay( 200 ); } void loop() { byte rcode; Max.Task(); Usb.Task(); if( Usb.getUsbTaskState() >= 0x80 ) { //state configuring or higher rcode = getdevdescr( 1 ); //hardcoded device address if( rcode ) { Serial.print("\r\nRequest error. Error code:\t"); print_hex( rcode, 8 ); } while( 1 ); //stop } } byte getdevdescr( byte addr ) { USB_DEVICE_DESCRIPTOR buf; byte rcode; rcode = Usb.getDevDescr( addr, 0, 0x12, ( char *)&buf ); if( rcode ) { return( rcode ); } Serial.println("Device descriptor: "); Serial.print("Descriptor Length:\t"); print_hex( buf.bLength, 8 ); Serial.print("\r\nDescriptor type:\t"); print_hex( buf.bDescriptorType, 8 ); Serial.print("\r\nUSB version:\t"); print_hex( buf.bcdUSB, 16 ); Serial.print("\r\nDevice class:\t"); print_hex( buf.bDeviceClass, 8 ); Serial.print("\r\nDevice Subclass:\t"); print_hex( buf.bDeviceSubClass, 8 ); Serial.print("\r\nDevice Protocol:\t"); print_hex( buf.bDeviceProtocol, 8 ); Serial.print("\r\nMax.packet size:\t"); print_hex( buf.bMaxPacketSize0, 8 ); Serial.print("\r\nVendor ID:\t"); print_hex( buf.idVendor, 16 ); Serial.print("\r\nProduct ID:\t"); print_hex( buf.idProduct, 16 ); Serial.print("\r\nRevision ID:\t"); print_hex( buf.bcdDevice, 16 ); Serial.print("\r\nMfg.string index:\t"); print_hex( buf.iManufacturer, 8 ); Serial.print("\r\nProd.string index:\t"); print_hex( buf.iProduct, 8 ); Serial.print("\r\nSerial number index:\t"); print_hex( buf.iSerialNumber, 8 ); Serial.print("\r\nNumber of conf.:\t"); print_hex( buf.bNumConfigurations, 8 ); return( 0 ); } /* prints hex numbers with leading zeroes */ // copyright, Peter H Anderson, Baltimore, MD, Nov, '07 // source: http://www.phanderson.com/arduino/arduino_display.html void print_hex(int v, int num_places) { int mask=0, n, num_nibbles, digit; for (n=1; n<=num_places; n++) { mask = (mask << 1) | 0x0001; } v = v & mask; // truncate v to specified number of places num_nibbles = num_places / 4; if ((num_places % 4) != 0) { ++num_nibbles; } do { digit = ((v >> (num_nibbles-1) * 4)) & 0x0f; Serial.print(digit, HEX); } while(--num_nibbles); } |
Load the sketch, compile, and run. Don’t forget to connect a device, otherwise program will print “Start” and pause waiting for the device to be connected. If everything is OK, you will see output similar to one below.
Start Device descriptor: Descriptor Length: 12 Descriptor type: 01 USB version: 0100 Device class: 00 Device Subclass: 00 Device Protocol: 00 Max.packet size: 40 Vendor ID: 0CF2 Product ID: 6220 Revision ID: 0100 Mfg.string index: 01 Prod.string index: 02 Serial number index: 04 Number of conf.: 01
Let’s take a look. The first line shows descriptor size – 18 bytes ( 12 Hex ). Next line shows descriptor type (01 – device descriptor). USB version shows 0100, that’s version 1.0, the very first one. Even though USB version 3.0 is here, many low speed devices are still manufactured. I have seen web cameras compliant to USB version 1.1 and low-speed mice and keyboards. Device used in this example is pretty new flash drive, by the way.
Device class, subclass, and protocol are set to zero. This usually means that device is supported as a class and class properties are defined on interface level. Maximum packet size is 64 bytes ( 40 hex ). Vendor ID and Product ID form unique device identifier.
Strings are human-readable descriptors. Device descriptor contains index values to some of the strings. If index of a string is zero, the corresponding string is not implemented. Also, since string descriptors are optional and, with very few exceptions, are not used during normal operation, many manufacturers implement strings incorrectly.
Last byte shows number of configurations supported by the device.
Next sketch shows how to get string descriptor. Unlike device descriptor, string descriptor length is variable. In addition, strings can be coded in several languages. Therefore, the sequence of actions to get a string is more complicated than one used to get device descriptor. First, we find out length of string descriptor with index zero, which contains Language IDs. Then, we ask for the same descriptor again, this time using the correct length. Next step is to extract first Language ID. After that we find out the length of the descriptor that we want, and finally get the whole descriptor and print it. Take a look at the code:
/* MAX3421E USB Host controller get string descriptor */ #include <spi.h> #include <max3421e.h> #include <usb.h> #define LOBYTE(x) ((char*)(&(x)))[0] #define HIBYTE(x) ((char*)(&(x)))[1] void setup(); void loop(); MAX3421E Max; USB Usb; void setup() { byte tmpdata = 0; Serial.begin( 9600 ); Serial.println("Start"); Max.powerOn(); delay( 200 ); } void loop() { byte rcode; Max.Task(); Usb.Task(); if( Usb.getUsbTaskState() >= 0x80 ) { //state configuring or higher rcode = getstrdescr( 1, 1 ); //get string descriptor if( rcode ) { Serial.println( rcode, HEX ); } while( 1 ); //stop } } byte getstrdescr( byte addr, byte idx ) { char buf[ 66 ]; byte rcode; byte length; byte i; unsigned int langid; rcode = Usb.getStrDescr( addr, 0, 1, 0, 0, buf ); //get language table length if( rcode ) { Serial.println("Error retrieving LangID table length"); return( rcode ); } length = buf[ 0 ]; //length is the first byte rcode = Usb.getStrDescr( addr, 0, length, 0, 0, buf ); //get language table if( rcode ) { Serial.println("Error retrieving LangID table"); return( rcode ); } HIBYTE( langid ) = buf[ 3 ]; //get first langid LOBYTE( langid ) = buf[ 2 ]; rcode = Usb.getStrDescr( addr, 0, 1, idx, langid, buf ); if( rcode ) { Serial.println("Error retrieving string length"); return( rcode ); } length = buf[ 0 ]; rcode = Usb.getStrDescr( addr, 0, length, idx, langid, buf ); if( rcode ) { Serial.println("Error retrieving string"); return( rcode ); } for( i = 2; i < length; i+=2 ) { Serial.print( buf[ i ] ); } return( rcode ); } |
The “getstrdescr” function takes string index as a second argument. It is set to 1 in the code, because almost any USB device has this string defined. However, if you want to see other strings of your device, just change the index number in “getstrdescr” call from the loop(), re-complile the sketch and run it.
The last sketch in this article demonstrates getting configuration descriptor. Configuration descriptor contains a wealth of information about the peripheral configuration, such as interfaces, their power consumption, endpoints and their maximum packet sizes, polling intervals, etc. The structure of configuration descriptor is even more complicated. Quoting USB 2.0 specification, “When the host requests the configuration descriptor, all related interface and endpoint descriptors are returned”. It means that not only length of the descriptor is variable, but data structure needs to be analyzed during retrieval since we don’t know in advance which descriptors would follow configuration.
In order to operate an USB device, configuration descriptor and subsequent descriptors has to be parsed. We need configuration value to switch USB device to the running state (called “configured” in USB spec), endpoint addresses, directions, and maximum packet sizes, as well as values from class-specific descriptors, if any. The sketch determines configuration length, retrieves it, an then goes through the buffer, printing configuration, interface, endpoint, or unknown descriptors as it encounters them.
/* MAX3421E USB Host controller get configuration descriptor */ #include <spi.h> #include <max3421e.h> #include <usb.h> #define LOBYTE(x) ((char*)(&(x)))[0] #define HIBYTE(x) ((char*)(&(x)))[1] #define BUFSIZE 256 //buffer size void setup(); void loop(); MAX3421E Max; USB Usb; void setup() { byte tmpdata = 0; Serial.begin( 9600 ); Serial.println("Start"); Max.powerOn(); delay( 200 ); } void loop() { byte rcode; Max.Task(); Usb.Task(); if( Usb.getUsbTaskState() >= 0x80 ) { //state configuring or higher rcode = getconfdescr( 1, 0 ); //get configuration descriptor if( rcode ) { Serial.println( rcode, HEX ); } while( 1 ); //stop } } byte getconfdescr( byte addr, byte conf ) { char buf[ BUFSIZE ]; char* buf_ptr = buf; byte rcode; byte descr_length; byte descr_type; unsigned int total_length; rcode = Usb.getConfDescr( addr, 0, 4, conf, buf ); //get total length LOBYTE( total_length ) = buf[ 2 ]; HIBYTE( total_length ) = buf[ 3 ]; if( total_length > 256 ) { //check if total length is larger than buffer Serial.println("Total length truncated to 256 bytes"); total_length = 256; } rcode = Usb.getConfDescr( addr, 0, total_length, conf, buf ); //get the whole descriptor while( buf_ptr < buf + total_length ) { //parsing descriptors descr_length = *( buf_ptr ); descr_type = *( buf_ptr + 1 ); switch( descr_type ) { case( USB_DESCRIPTOR_CONFIGURATION ): printconfdescr( buf_ptr ); break; case( USB_DESCRIPTOR_INTERFACE ): printintfdescr( buf_ptr ); break; case( USB_DESCRIPTOR_ENDPOINT ): printepdescr( buf_ptr ); break; default: printunkdescr( buf_ptr ); break; }//switch( descr_type buf_ptr = ( buf_ptr + descr_length ); //advance buffer pointer }//while( buf_ptr <=... return( 0 ); } /* prints hex numbers with leading zeroes */ // copyright, Peter H Anderson, Baltimore, MD, Nov, '07 // source: http://www.phanderson.com/arduino/arduino_display.html void print_hex(int v, int num_places) { int mask=0, n, num_nibbles, digit; for (n=1; n<=num_places; n++) { mask = (mask << 1) | 0x0001; } v = v & mask; // truncate v to specified number of places num_nibbles = num_places / 4; if ((num_places % 4) != 0) { ++num_nibbles; } do { digit = ((v >> (num_nibbles-1) * 4)) & 0x0f; Serial.print(digit, HEX); } while(--num_nibbles); } /* function to print configuration descriptor */ void printconfdescr( char* descr_ptr ) { USB_CONFIGURATION_DESCRIPTOR* conf_ptr = ( USB_CONFIGURATION_DESCRIPTOR* )descr_ptr; Serial.println("Configuration descriptor:"); Serial.print("Total length:\t"); print_hex( conf_ptr->wTotalLength, 16 ); Serial.print("\r\nNum.intf:\t\t"); print_hex( conf_ptr->bNumInterfaces, 8 ); Serial.print("\r\nConf.value:\t"); print_hex( conf_ptr->bConfigurationValue, 8 ); Serial.print("\r\nConf.string:\t"); print_hex( conf_ptr->iConfiguration, 8 ); Serial.print("\r\nAttr.:\t\t"); print_hex( conf_ptr->bmAttributes, 8 ); Serial.print("\r\nMax.pwr:\t\t"); print_hex( conf_ptr->bMaxPower, 8 ); return; } /* function to print interface descriptor */ void printintfdescr( char* descr_ptr ) { USB_INTERFACE_DESCRIPTOR* intf_ptr = ( USB_INTERFACE_DESCRIPTOR* )descr_ptr; Serial.println("\r\nInterface descriptor:"); Serial.print("Intf.number:\t"); print_hex( intf_ptr->bInterfaceNumber, 8 ); Serial.print("\r\nAlt.:\t\t"); print_hex( intf_ptr->bAlternateSetting, 8 ); Serial.print("\r\nEndpoints:\t\t"); print_hex( intf_ptr->bNumEndpoints, 8 ); Serial.print("\r\nClass:\t\t"); print_hex( intf_ptr->bInterfaceClass, 8 ); Serial.print("\r\nSubclass:\t\t"); print_hex( intf_ptr->bInterfaceSubClass, 8 ); Serial.print("\r\nProtocol:\t\t"); print_hex( intf_ptr->bInterfaceProtocol, 8 ); Serial.print("\r\nIntf.string:\t"); print_hex( intf_ptr->iInterface, 8 ); return; } /* function to print endpoint descriptor */ void printepdescr( char* descr_ptr ) { USB_ENDPOINT_DESCRIPTOR* ep_ptr = ( USB_ENDPOINT_DESCRIPTOR* )descr_ptr; Serial.println("\r\nEndpoint descriptor:"); Serial.print("Endpoint address:\t"); print_hex( ep_ptr->bEndpointAddress, 8 ); Serial.print("\r\nAttr.:\t\t"); print_hex( ep_ptr->bmAttributes, 8 ); Serial.print("\r\nMax.pkt size:\t"); print_hex( ep_ptr->wMaxPacketSize, 16 ); Serial.print("\r\nPolling interval:\t"); print_hex( ep_ptr->bInterval, 8 ); return; } /*function to print unknown descriptor */ void printunkdescr( char* descr_ptr ) { byte length = *descr_ptr; byte i; Serial.println("\r\nUnknown descriptor:"); Serial. print("Length:\t\t"); print_hex( *descr_ptr, 8 ); Serial.print("\r\nType:\t\t"); print_hex( *(descr_ptr + 1 ), 8 ); Serial.print("\r\nContents:\t"); descr_ptr += 2; for( i = 0; i < length; i++ ) { print_hex( *descr_ptr, 8 ); descr_ptr++; } } |
Let’s look at the output. First example shows configuration of USB flash drive. The configuration is very simple – one interface, two bulk endpoints (in addition to endpoint zero). We can see that total length of the configuration is 32 bytes (20 hex ), has one interface, the configuration value to use in “Set configuration” request to activate this configuration is “1”, string is not defined, all attributes are zero (by spec, MSB of attributes field is always one and is not an attribute ), and power consumption is 100mA.
Start Configuration descriptor: Total length: 0020 Num.intf: 01 Conf.value: 01 Conf.string: 00 Attr.: 80 Max.pwr: 32 Interface descriptor: Intf.number: 00 Alt.: 00 Endpoints: 02 Class: 08 Subclass: 06 Protocol: 50 Intf.string: 00 Endpoint descriptor: Endpoint address: 81 Attr.: 02 Max.pkt size: 0040 Polling interval: 00 Endpoint descriptor: Endpoint address: 01 Attr.: 02 Max.pkt size: 0040 Polling interval: 00
Interface descriptor shows interface number and two endpoints. Class, subclass, and protocol combination states that this device supports so-called “Mass-storage bulk-only transport” protocol – the most popular way to communicate with USB flash drives. Endpoints show address (which is called number in USB spec ) and direction (81 means “number 01, direction IN”), attributes (02 means “bulk”), maximum packet size 64 bytes, and polling interval zero, which, by the way, doesn’t make sense for bulk endpoints anyway.
Next example shows configuration of USB keyboard. This is a ptetty modern keyboard with extra buttons for web browsing and media player control. We can see two interfaces and two unknown descriptors. They are HID descriptors – per spec, any class-specific descriptors must follow interface descriptor. The first interface shows class 03 (HID), subclass 01 (keyboard), and protocol 01 (boot protocol). Boot protocol is a simplified protocol, which allows using USB keyboards during PC boot.
Second interface is just a plain HID interface. To use it, application needs to retrieve and parse HID reports for the interface.
Start Configuration descriptor: Total length: 003B Num.intf: 02 Conf.value: 01 Conf.string: 03 Attr.: A0 Max.pwr: 32 Interface descriptor: Intf.number: 00 Alt.: 00 Endpoints: 01 Class: 03 Subclass: 01 Protocol: 01 Intf.string: 00 Unknown descriptor: Length: 09 Type: 21 Contents: 10010001223E000705 Endpoint descriptor: Endpoint address: 81 Attr.: 03 Max.pkt size: 0008 Polling interval: 0A Interface descriptor: Intf.number: 01 Alt.: 00 Endpoints: 01 Class: 03 Subclass: 00 Protocol: 00 Intf.string: 00 Unknown descriptor: Length: 09 Type: 21 Contents: 1001000122AB000705 Endpoint descriptor: Endpoint address: 82 Attr.: 03 Max.pkt size: 0008 Polling interval: 0A
The last example is taken from my favorite no-name USB Bluetooth device. I like it for the implementation – it is phenomenally buggy. Strings are messy, descriptors don’t make sense (look at max.power, for example, or the last interface with no endpoints), plus, the configuration is quite long. It goes without explanation, just take a look to get an idea of how complex USB devices can really be.
Start Configuration descriptor: Total length: 00BA Num.intf: 03 Conf.value: 01 Conf.string: 00 Attr.: C0 Max.pwr: 00 Interface descriptor: Intf.number: 00 Alt.: 00 Endpoints: 03 Class: E0 Subclass: 01 Protocol: 01 Intf.string: 00 Endpoint descriptor: Endpoint address: 81 Attr.: 03 Max.pkt size: 0010 Polling interval: 01 Endpoint descriptor: Endpoint address: 02 Attr.: 02 Max.pkt size: 0040 Polling interval: 01 Endpoint descriptor: Endpoint address: 82 Attr.: 02 Max.pkt size: 0040 Polling interval: 01 Interface descriptor: Intf.number: 01 Alt.: 00 Endpoints: 02 Class: E0 Subclass: 01 Protocol: 01 Intf.string: 00 Endpoint descriptor: Endpoint address: 03 Attr.: 01 Max.pkt size: 0000 Polling interval: 01 Endpoint descriptor: Endpoint address: 83 Attr.: 01 Max.pkt size: 0000 Polling interval: 01 Interface descriptor: Intf.number: 01 Alt.: 01 Endpoints: 02 Class: E0 Subclass: 01 Protocol: 01 Intf.string: 00 Endpoint descriptor: Endpoint address: 03 Attr.: 01 Max.pkt size: 0009 Polling interval: 01 Endpoint descriptor: Endpoint address: 83 Attr.: 01 Max.pkt size: 0009 Polling interval: 01 Interface descriptor: Intf.number: 01 Alt.: 02 Endpoints: 02 Class: E0 Subclass: 01 Protocol: 01 Intf.string: 00 Endpoint descriptor: Endpoint address: 03 Attr.: 01 Max.pkt size: 0011 Polling interval: 01 Endpoint descriptor: Endpoint address: 83 Attr.: 01 Max.pkt size: 0011 Polling interval: 01 Interface descriptor: Intf.number: 01 Alt.: 03 Endpoints: 02 Class: E0 Subclass: 01 Protocol: 01 Intf.string: 00 Endpoint descriptor: Endpoint address: 03 Attr.: 01 Max.pkt size: 0019 Polling interval: 01 Endpoint descriptor: Endpoint address: 83 Attr.: 01 Max.pkt size: 0019 Polling interval: 01 Interface descriptor: Intf.number: 01 Alt.: 04 Endpoints: 02 Class: E0 Subclass: 01 Protocol: 01 Intf.string: 00 Endpoint descriptor: Endpoint address: 03 Attr.: 01 Max.pkt size: 0021 Polling interval: 01 Endpoint descriptor: Endpoint address: 83 Attr.: 01 Max.pkt size: 0021 Polling interval: 01 Interface descriptor: Intf.number: 01 Alt.: 05 Endpoints: 02 Class: E0 Subclass: 01 Protocol: 01 Intf.string: 00 Endpoint descriptor: Endpoint address: 03 Attr.: 01 Max.pkt size: 0031 Polling interval: 01 Endpoint descriptor: Endpoint address: 83 Attr.: 01 Max.pkt size: 0031 Polling interval: 01 Interface descriptor: Intf.number: 02 Alt.: 00 Endpoints: 00 Class: FE Subclass: 01 Protocol: 00 Intf.string: 00
In the next article, I will show how to use “Set” requests, as well as how to actually use USB device for something more interesting than looking at its descriptors. Stay tuned!
Oleg.
Hi Oleg,
I’ve built an arduino project that uses a GPRS shield to send SMS’s. I now need to make a dozen similar modules and am trying to save money. Each GPRS shield costs about $100 or more, but I can get a USB GPRS dongle for less than $10. I’d like to use a arduino USB host shield to connect the arduino straight to the dongle. Before I invest too much time and energy into this, can you give me some idea if what I’m trying to is feasable, and if so how difficult would it be? The USB GPRS dongle I’m using is a HUAWEI E1750, I only need very basic functionality, just enough to send SMS’s only.
Thanks for your help
Mike
Hi Mike,
From what I learned so far, GPRS is not that difficult to implement. The biggest issue would be getting programming documentation for your module or reverse engineer control commands if unable to get docs.
I have USB GPRS code on my todo list also, don’t know when I’ll be able to start, though.
Good luck with your project!
Regards,
Oleg.
Hey Mike,
Unfortunately, I can’t help much with your question as I have a similar one. I am using a HUAWEI E160 with Oleg’s USB Host shield. I’ve had success communicating with the modem (sending/receiving SMS) via a python script when attached to my computer via USB, but getting the arduino talking to the modem via AT Commands has proved difficult so far (though I’m completely new to this technology so that doesn’t mean much).
Let me know if you have any success looking into feasibility and I will do the same.
Cheers,
Jeremy
Hi Oleg,
just received your shield this morning but I have some small problems:
I plugged an Apple keyboard.
Your getdevdescr( 1 ) code runs fine (the first one on this page).
But the 3rd example – getconfdescr( 1, 0 ) – doesn’t display nothing besides “Start”. So I tried the conf_descr_dump.pde example, but then the arduino reboots continuously after getconfdescr() is called.
So I tried the keyboard polling example, which returns
Error attempting to configure boot protocol. Return code :5
Is there anything obvious I should check?
Thanks,
p
An Apple keyboard most likely has a hub in it so keyboard sketch won’t work with it. I’m working on the code with hub support, hoping to release it in a couple months. Post your device descriptor output here – I’ll take a look why config descriptor is not showing.
Thanks for your answer. You’re right about the hub!
Here is the device descriptor of Apple’s belgian kb without numeric keypad (well, of its hub):
Device descriptor:
Descriptor Length: 12
Descriptor type: 01
USB version: 0200
Device class: 09
Device Subclass: 00
Device Protocol: 00
Max.packet size: 40
Vendor ID: 05AC
Product ID: 1005
Revision ID: 9615
Mfg.string index: 01
Prod.string index: 02
Serial number index: 03
Number of conf.: 01
The keybard with numeric keypad has the same descriptor, but with a product ID of 1006.
Using Apple’s System Profiler, those are the descriptors of the keyboards plugged to their hubs:
with numeric keypad:
Product ID: 0x0221
Vendor ID: 0x05ac (Apple Inc.)
Version: 0.69
Speed: Up to 1.5 Mb/sec
Manufacturer: Apple, Inc
Location ID: 0xfd132000
Current Available (mA): 100
Current Required (mA): 20
Without numeric keypad:
Product ID: 0x021e
Vendor ID: 0x05ac (Apple Inc.)
Version: 0.70
Speed: Up to 1.5 Mb/sec
Manufacturer: Apple Inc.
Location ID: 0xfd131200
Current Available (mA): 100
Current Required (mA): 20
Best,
p
Hello Oleg
I am doing a project on max3421e with PIC that i think you’ve already worked on.I searched internet for help on this particular combination but unable to find any good
resources can you pls help me in selection of initial hardware requirement.
Any one good link will be very helpful.
Thanks in Advance.
Mohit
Hello Mr. Oleg,
Given that Arduino Due’s sam3x has usb host behavior, I thought I could use it to write/read simple text (ASCII) to/from an USB memory stick. So far, I have solved the writing part through porting a mass storage class implementation contained in an example of Atmel Studio 6, but not for the reading. I know that Atmel ported the usb host stack v2 from you (circuits@home) for Arduino. Could you tell me where I can obtain the mentioned stack? Thank you very much,
Palliser
I’m not aware of Atmel doing anything with my code. Besides, the mass storage implementation hasn’t been released yet. Current USB Host stack is here -> https://github.com/felis/USB_Host_Shield_2.0 , it won’t work on DUE.
Hello! I hope I’m in the right place to ask this: I’ve an Arduino MEGA ADK board and it has an onboard USB host, I need to make a program that will read the Hardware ID of the devices I connect. Whether the device is a USB Flash, or any other USB Device, the program has to read the Hardware ID of the device, and, the program will have a list of specific Hardware IDs to which it would turn on an LED, and if the Hardware ID of the connected device is not on the list, another LED would turn on, indicating the error, or so… this should be possible, but I don’t know how to write code for such a thing. Please help. Thank you in advance!
What is Hardware ID?
I think you mean is that you want to read the vendor id (VID) and product id (PID). Here is an example of how it is done: https://github.com/felis/USB_Host_Shield_2.0/blob/65ba9c1366a8846e5a4eda7c9da65834f0bbee44/PS3USB.cpp#L92-L101.
Hi Oleg,
my USB host shield is working flawlessy with my USB device, but the only problem I have is that when I use a similar device (same endpoints values, same interface, same config. value, and so on, the only difference is “product id”), it doensn’t work. I’m almost sure it’s beacuse of the usb address.
Indeed I “hardcoded” address 0 to my sketch. How can I set the sketch to automatically recognize the address of the device connected?
You can’t use address 0.
Device addressing is handled by the class – you can’t use it directly and it is also not necessary. If you need several devices create an instance of the class for each device.
Nothing bad can happen “because of the USB address”. As long as addresses are unique (and different from 0) they don’t affect anything.
so what should I use when I call methods like getDevDescr or inTransfer?
If I use 0 it works perfectly on one of my device, while it doesn’t work on another one identical (except for the product ID)
you don’t use those methods directly. The device driver uses them with address stored in bAddress data member. At the same time, the driver provides methods to send/receive data. If you can’t use one of the existing drivers and want to develop your own just do it the same way other drivers do it – get the address, store it in bAddress, then set the device with this address.
thank you, yes indeed I wrote my own drivers for my device. but it only works with address = 0 when I use those methods. I can’t find bAddress inside the USB class, how can I get the address then?
Here’s one -> https://github.com/felis/USB_Host_Shield_2.0/blob/master/usbhub.h#L171 .
thanks, now I assign the address to the device with success and now I can read the descriptors of both devices (same kind of device, same endpoints value, only difference is the product ID).
but the problem is that, while I can get data from the first device, if I connect the second device I can’t get any data, using the same sketch. This is really weird since the devices are almost the same. (and both devices works flawlessy with other sketches).
what could be the problem?
Which devices are you using?
Midi devices (class 01, subclass 03). Both device are from the same Manufacturer. Both devices outputs the same data packets (simply 4 bytes of data) on the same endpoints, but I can only read one device, not the other.
Have you tried this code yet -> https://www.circuitsathome.com/mcu/midi-support-for-usb-host-2-0-library
yes I tried it, it works with both devices. Before trying this code, I wrote my own driver. Now I searched for differences in the code between mine and this Midi library, and the only one is the call to RegisterDeviceClass() method, and the fact that I wrote all the driver in the sketch and I didn’t make a class for it. Could be this the reason why my code is not working with both devices?
Will the above codes work on Arduino due?
No, sorry. Due is not supported yet.
So can you please help me..
I have Arduino Due Board on that one USB Device is connected to Native port of Due and programmer port of Due is connected to pc…i want to read Vendor ID and Product Id of Connected USB Device..How can i start…?
Start here => http://arduino.cc/en/Reference/USBHost
Oleg I am realy stucked…..I am not able to creat library to get the USB Descriptor data as mentioned in above tutorials for Arduino Due..
Can you please provide me the library as above code work on Arduino due…?
Hi oleg, I want to read my usb device’s name, some like Logic USB Keyboard shown in control pannel, what should I do? Thanks a lot!
You need to use “Get String Descriptor” request -> https://github.com/felis/USB_Host_Shield_2.0/blob/master/Usb.cpp#L791 Device descriptor contains 3 indexes toward the end, say, 1,2,3 . If you pass one of those to Get String Descriptor you’ll get the contents of the string in Unicode. Sometimes the interface descriptor contains strings too.
Yes, that’s great, it works. Thanks a lot~~~ But some strange chars show up. I discard them that are not in ASCII table.
Hi oleg,
Please tell me if you feel up to it.
Do you plan to support the keyboard to be connected via an internal USB hub?
When do you support?
I’m very troubled, in this matter.
Thank you
Hubs are already supported.
Hi oleg,
Did you use the host sheild to communicate with a Dance pad that just like this(http://detail.tmall.com/item.htmspm=a230r.1.14.1.B3UePb&id=14484075366&ad_id=&am_id=&cm_id=140105335569ed55e27b&pm_id=&abbucket=9),can you give me some advice.
Thank you.
I don’t know what this is. Post descriptors when you get it.
i’m already get it,I hnow it’s a gampad,but i’m don’t hnow how to send message to it in your code.
*********USBHID_desc.ino*****************
Opening port
Port open
Start
0000: 05 01 09 04 A1 01 A1 02 75 08 95 05 15 00 26 FF
0010: 00 35 00 46 FF 00 09 30 09 30 09 30 09 30 09 31
0020: 81 02 75 04 95 01 25 07 46 3B 01 65 14 09 00 81
0030: 42 65 00 75 01 95 0A 25 01 45 01 05 09 19 01 29
0040: 0A 81 02 06 00 FF 75 01 95 0A 25 01 45 01 09 01
0050: 81 02 C0 A1 02 75 08 95 04 46 FF 00 26 FF 00 09
0060: 02 91 02 C0 C0
Usage Page Gen Desktop Ctrls(01)
Usage Game Pad
Collection Application
Collection Logical
Report Size(08)
Report Count(05)
Logical Min(00)
Logical Max(FF00)
Physical Min(00)
Physical Max(FF00)
Usage X
Usage X
Usage X
Usage X
Usage Y
Input(00000010)
Report Size(04)
Report Count(01)
Logical Max(07)
Physical Max(3B01)
Unit(14)
Usage Undef
Input(01000010)
Unit(00)
Report Size(01)
Report Count(0A)
Logical Max(01)
Physical Max(01)
Usage Page Button(09)
Usage Min(01)
Usage Max(0A)
Input(00000010)
Usage Page Undef(00)
Report Size(01)
Report Count(0A)
Logical Max(01)
Physical Max(01)
Usage
Input(00000010)
End Collection
Collection Logical
Report Size(08)
Report Count(04)
Physical Max(FF00)
Logical Max(FF00)
Usage
Output(00000010)
End Collection
End Collection Game Pad X X X X Y(01)(7F)(7F)(7F)(7F)
Undef(0F)
Btn0001
(01) Btn0002
(00) Btn0003
(00) Btn0004
(00) Btn0005
(00) Btn0006
(00) Btn0007
(00) Btn0008
(00) Btn0009
(01) Btn000A
(01)
(01)(01)(01)(01)(01)(00)(00)(00)(01)(01)
***********USB_dec.ino******
Opening port
Port open
Start
01
—
Device descriptor:
Descriptor Length: 12
Descriptor type: 01
USB version: 0100
Device class: 00
Device Subclass: 00
Device Protocol: 00
Max.packet size: 08
Vendor ID: 0079
Product ID: 0011
Revision ID: 0106
Mfg.string index: 00
Prod.string index: 02
Serial number index: 00
Number of conf.: 01
Configuration descriptor:
Total length: 0022
Num.intf: 01
Conf.value: 01
Conf.string: 00
Attr.: 80
Max.pwr: 32
Interface descriptor:
Intf.number: 00
Alt.: 00
Endpoints: 01
Intf. Class: 03
Intf. Subclass: 00
Intf. Protocol: 00
Intf.string: 00
Unknown descriptor:
Length: 09
Type: 21
Contents: 100121012265000705
Endpoint descriptor:
Endpoint address: 81
Attr.: 03
Max.pkt size: 0008
Polling interval: 0A
Addr:1(0.0.1)
Good afternoon good sir, loved your work, but i am new to the arduino usb host concept. Would this library suffice the communication between a usb sound card with the arduino due? I work with speech recognition in my university, been doing my research with MATLAB since day 1, and now for my final project i want to apply my algorithm on a embedded system. Could share a light over this subject? Thanks in advance and sorry for my bad english 🙂
Hello I have a trouble regarding USB Bus transfer (Bulk transfer).My device send 2048 bytes after request in less than of a millesecond.I need to send this data thru serial port using max speed 115200 bps.How i can resolve the critical time ? (no lossing data received). MAX3241 have inside two buffer of 64 bytes , of course the data tranfer is 32 consecutive data sending reffered to buffer size.
Can you help me ?
I have a USB shield 2.0 this shield support standard USB 2.0
(my bulk trasnfer work with speed USB 2.0 max 480 Mbit/s)
Thank’s in advance
Pietro
If you are getting more data from USB than you can send out via serial your buffers will always be overflowing, adding extra memory will only add time before it happens.
Hello
i just bought a arduino leonardo and a usb host shield from arduino.cc . I was wondering if i can use the last version of the library in order to get the ID Product.