Posts

Google Open Accessory Interface for USB Host Shield Library 2.0 released

ADK code

ADK code


Google Open Accessory Interface is now included in USB Host Shield Library 2.0 package. It follows standard structure of rev2.0 device driver (wherever possible) and because of this is slightly different from original Arduino code developed by Google. The interface itself is pretty simple and there are many articles on the net describing it in details; in this article I will give brief overview of new code and explain the differences.

To test the code I made a little “shield” resembling Google’s one. Since the only thing I cared about while testing was data transfer in both directions, I implemented just one LED and one button. The demokit_20.pde Arduino sketch works with DemoKit.apk Android application, however, only “B1” button and “LED 1 Red” are functional. To run the sketch, you will need an Arduino board, USB Host Shield, as well as USB Host Shield 2.0 library.

The ADK class contains all necessary functionality to communicate to Android phone via ADK interface. In order for USB subsystem to initialize the device when it is connected, the instantiation should look like the following code fragment. First, the USB class is instantiated, then ADK is instantiated taking address of USB instance as the first parameter. The rest of the parameters are ID strings for the phone – they are identical to the original code.

The initialization of Android device and switching it to accessory mode is performed automatically by USB subsystem. The ADK::Init() member function is called each time a new device is detected on a bus. It first tries to determine if a device is in accessory mode already by reading its VID, PID, and if yes, configures it and reports success to the system. If device fails accessory check, the standard probing and accessory switching method is performed. If successful, device resets and appears on USB bus as an “accessory mode-capable” unit. In certain cases, Init() may be executed two times.

USB Usb;
ADK adk(&Usb,"Google, Inc.",
            "DemoKit",
            "DemoKit Arduino Board",
            "1.0",
            "http://www.android.com",
            "0000000012345678");

Since all initialization is done automatically, all we need to know is whether the phone is ready and how to exchange data with it. The ADK::isReady() returns true when phone is connected in accessory mode ready to send and receive data.The ADK::SndData() is used to send data to the phone. It takes 2 parameters, first parameter is data length and second is a pointer to a buffer holding the data (see example below).

     rcode = adk.SndData( 3, msg );

The ADK::RcvData() is used to receive data and also takes two parameters. First parameter is the address of the variable containing data length. When IN transfer is performed, a USB host may receive anything from zero bytes to a number equal to endpoint’s max.packet size. After the transfer the variable will contain number of bytes which were actually received. The second parameter is, again, pointer to the receive buffer. The following code snippet shows the example:

   uint16_t len = sizeof(msg);
 
   rcode = adk.RcvData(&len, msg);
   if( rcode ) {
     USBTRACE2("Data rcv. :", rcode );
   }

Both SndData() and RcvData() return result code of the transfer, zero if success and some other code if things went wrong during a transfer. The result code may indicate fatal error (such is 0x0d, which means device has disappeared from the bus) or simply that data is not ready (result code 0x0d AKA NAK).

Rev.2.0 library handles NAK limits on endpoint basis in epInfo data structure, consequently, data transfer functions lack nak_limit parameter. Here is how NAK limits are set up in ADK class constructor:

  // initialize endpoint data structures
	for(uint8_t i=0; i<ADK_MAX_ENDPOINTS; i++) {
		epInfo[i].epAddr		= 0;
		epInfo[i].maxPktSize	= (i) ? 0 : 8;
		epInfo[i].epAttribs		= ( 0xfc & ( USB_NAK_MAX_POWER<<2 ));
  }//for(uint8_t i=0; i<ADK_MAX_ENDPOINTS; i++...
 
  //set bulk-IN EP naklimit to 1 
  epInfo[epDataInIndex].epAttribs = ( 0xfc & ( USB_NAK_NOWAIT<<2 ));

As can be seen, for bulk-IN endpoint NAK limit is set to 1 so that application won’t spend time polling the endpoint when there is no data – RcvData() will return immediately after the first NAK. Here is another way of handling result codes of RcvData() – in this example, NAK will be excluded from reported result codes:

rcode = adk.RcvData(&len, msg);
   if( rcode && rcode != hrNAK ) {
     USBTRACE2("Data rcv. :", rcode );
   }

Finally, I want to point out to another interesting couple of lines in demokit_20.pde sketch:

USBHub hub0(&Usb);
USBHub hub1(&Usb);

These lines add support for two USB hubs. We all know that Android phones draw substantial current from VBUS while charging. The power capabilities of standard Arduino board are pushed to the limit, as a result, VBUS voltage sags to ~4.8V or even lower and the phone stops detecting VBUS. There are several ways to overcome it. One is to simply let the phone charge – as soon as battery level reaches 95%, the current consumption drops, the voltage raises and the phone starts behaving normally. Another way is to disconnect VBUS from 5V provided by Arduino and connect external supply. With library rev.2.0 there is yet another way – connect self-powered hub to the shield and connect phone to the hub. Two hubs are created in the sketch because modern hubs are rarely a single device; if your hub has more than 4 ports, most likely it consists of 2 daisy-chained hubs and both of them need to be initialized. The hub code takes about 2K of program space and can be commented out if memory size is an issue.

The code has been extensively tested with both Nexus S and Nexus One Android phones – they work fine both directly connected to the shield as well as through the hub and even two phones at the same time ( to do this, you will need to create a second instance of ADK class and add code to talk to the second unit). However, there may still be bugs – if you tried the code and saw any odd behavior, please let me know.

Oleg.

39 comments to Google Open Accessory Interface for USB Host Shield Library 2.0 released

  • When I try to run the demokit_20.pde, the following line fails

    rcode = adk.RcvData(&len, msg);

    and the value I get in rcode is DB

    Any idea why receiving data is failing for me?

  • I am using Samsung Nexus S, with USB Host shield and v2.0 of the library.

    In the phone, I am running the Demokit application from Google’s ADK.

    • which Android version is loaded into this phone?

      • Android Version: 2.3.4 (It is the OTA update that I got recently)

        Kernel Version: 2.6.35.7

        • And you’re using USB Host Shield 2.0, correct?

          Uncomment lines 185-197 in adk.cpp, recompile, run and send me terminal output.

          • Yes I am using v2.0 of the USB Host shield. http://www.circuitsathome.com/products-page/arduino-shields/usb-host-shield-2-0-for-arduino/

            I am getting this as the terminal output, after uncommenting the lines. https://gist.github.com/1087353

          • The output is correct. I too have Nexus S – I double checked it with current code and it works. The ‘DB’ error code is not even relevant to the device, this error is generated when there is no endpoint data structure for the endpoint to which a transfer has been attempted and has more to do with how initialization code is written. Make sure you use unaltered code from gitHub.

            Another problem could be power – a phone consumes a lot from Arduino when not charged to 100% – by the time sketch . Also, older Arduinos tend to be more robust – I rarely have an issue connecting my phone to Duemilanove or Mega.

            Try to run the sketch paying attention to power; if you still can’t make it work, come back and I’ll help you troubleshoot.

  • I double checked the USB Host Shield 2.0 library code, but I am still not able to run it. I also tried by connecting an external power source, but I was still getting the same “DB” error code.

    I tried the patch to 1.0 version of your USB Host Shield library by “romfort” http://romfont.com/2011/05/12/google%E2%80%99s-open-accessory-development-kit-on-standard-arduino-hardware/ and I was able to run the demo sketch successfully, both with external power and without external power source.

    But when I try with 2.0 of your USB Host Shield library I get the “DB” error code. I would be really thankful if you could help me trouble shoot it. I am using following things.

    USB Host Shield 2.0
    Arduino UNO
    Nexus S with 2.3.4 (OTA Update) Kernel Version: 2.6.35.7

  • Yuuichi

    Me too.

    My debug code is following result. (in Usb.cpp getEpInfoEntry())

    USB::getEpInfoEntry() addr: 1, ep: 5, p->epcount: 1
    USB::getEpInfoEntry() i:0, (pep)->epAddr: 0
    Data rcv. :DB

    Why p->epcount is ‘1’ ?
    Hmm bNumEP is ‘5’. Five endpoints found.

    ADK::EndpointXtract() conf: 1
    ADK::EndpointXtract() iface: 0
    ADK::EndpointXtract() alt: 0
    ADK::EndpointXtract() pep: 21A4
    ADK::EndpointXtract() bNumEP: 1
    ADK::EndpointXtract() index: 1
    ADK::EndpointXtract() epInfo[index].epAddr: 3
    ADK::EndpointXtract() epInfo[index].maxPktSize: 40

    ADK::EndpointXtract() conf: 1
    ADK::EndpointXtract() iface: 0
    ADK::EndpointXtract() alt: 0
    ADK::EndpointXtract() pep: 21A4
    ADK::EndpointXtract() bNumEP: 2
    ADK::EndpointXtract() index: 2
    ADK::EndpointXtract() epInfo[index].epAddr: 3
    ADK::EndpointXtract() epInfo[index].maxPktSize: 40

    ADK::EndpointXtract() conf: 1
    ADK::EndpointXtract() iface: 1
    ADK::EndpointXtract() alt: 0
    ADK::EndpointXtract() pep: 21A4
    ADK::EndpointXtract() bNumEP: 3
    ADK::EndpointXtract() index: 1
    ADK::EndpointXtract() epInfo[index].epAddr: 5
    ADK::EndpointXtract() epInfo[index].maxPktSize: 40

    ADK::EndpointXtract() conf: 1
    ADK::EndpointXtract() iface: 1
    ADK::EndpointXtract() alt: 0
    ADK::EndpointXtract() pep: 21A4
    ADK::EndpointXtract() bNumEP: 4
    ADK::EndpointXtract() index: 2
    ADK::EndpointXtract() epInfo[index].epAddr: 5
    ADK::EndpointXtract() epInfo[index].maxPktSize: 40

    I am patch to adk.cpp in line 280.
    It’s work.

    279 //ErrorMessage(PSTR(“Alt.Set”), alt);
    280 if( bNumEP == 3 ) return;
    281 bConfNum = conf;

    [My test environment]
    Arduino Pro mini + USB Host Shield for Arduino Pro Mini
    Arduino Mega 2560 + Sparkfun USB Host Shiled
    Nexus One with 2.3.4
    XOOM with 3.1

  • Yuuichi

    Oh, it is temporary measure.
    Correct fix is the fill in first two endpoints into structure.
    It is the same way, but it’s more smart.
    The patch is post via email.

    And endpoint problem is resolved.
    If the Android device enables USB debugging, it has five endpoints.
    otherwise it has three endpoints.

    • I guess, now I know the reason why it was not working for me earlier. I had enabled Usb debugging in my mobile, where as I think Oleg had it disabled when he tested it.

  • James Burgess

    Hi,
    seems like there are a lot of inexpensive usb wifi adapters intended for laptops that could be made to work with the host usb shield. Has anyone attempt to get one of these to work, I’m guess the challenge will be porting one of the open source drivers to avr but I like a challenge if it hasn’t already been done. If anyone knows of any existing project, opinions on how to go about this or just this.wont.work.because type comments I’d be interested in hearing them.

    Cheers,
    – James

  • sknight

    I have a persistant problem with a bunch of this stuff on my Arduino Mega ADK board. Seems if I use either V1 or V2 of your USB Host Shield library I cant communicate (sends 0x55 error via SPI) and I get “OSCOKIRQ failed to assert”.

    If I use the Android USB Library from Google I can communicate with the ADK but still get “OSCOKIRQ failed to assert”.

    Anyone know why both host shield libraries wont work on my Mega ADK? Also what “OSCOKIRQ failed to assert” means?

    Thanks everyone!
    SKNight

  • abhi

    hello Oleg,
    First of all thank you for such a great work done by u.
    I’m using Samsung Galaxy S mobile. I ported 2.3.4 android also managed to put the usb.accessory jar files required for the accessory mode(as i suppose). But when i run the code, it returns getprop result as ffff.
    Does it mean that Mobile is not supported or something is wrong from Android side(means any reqd files are missing).
    Thanks
    Abhi

    • I think the issue is with hardware support. You can bypass detection in Arduino code but it still won’t reply to ADK requests and won’t pass traffic over bulk endpoints.

  • Jeff

    Why does RcvData take a pointer to length? That precludes uses such as ret = read(buf, MAX_LEN); Is there any possibility of a partial transfer? If so, how is that represented in the return code?

  • bob1810

    I always get the following error:

    “ADK demo start
    OSCOKIRQ failed to assert”

    I am using a Mega ADK board,is this library somehow not compatible with this board?

  • robertofc

    My experience with arduino mega adk isla the same. A lot of atemps anda allways the same answer “oscokirq failed to assert”

  • Kai Yung

    I managed to get Mega ADK to work with a varient of the USB Host Shield Library 1.0. I used MicroBridge ADB, with this modification:

    Just initialize the SS,INT,GPS and RESET pins in max3421e_init() as :

    pinMode(PIN_MAX_SS, OUTPUT);
    DDRE &= ~ 0×40; // MAX_INT as input
    DDRJ &= ~ 0×08; //MAX_GPX as input
    DDRJ |= 0×04; //MAX_RESET as output

    apart from using the following defines in max3421e.h file

    #ifdef ADK_REF_BOARD

    #define PIN_MAX_SS 53

    #define MAX_SS(x) digitalWrite(SS, x)
    #define MAX_INT() ((PORTE & 0×40) >> 6)
    #define MAX_GPX() ((PORTJ & 0×08) >> 3)
    #define MAX_RESET(x) { if (x) PORTJ |= 0×04; else PORTJ &= ~0×04; }

    #endif

    I am now trying to use these pin assigments to see if I can modify the USB Host Shield 2.0 library, but so far no luck. Anyone has successfully mate the 2.0 library with Mega ADK?

    Kai

  • robertofc

    I found the response. The problem is to use the right version of arduino software. There is a beta version downloadable from here: http://code.google.com/p/arduino/wiki/Arduino1 you can read all about here http://labs.arduino.cc/ADK/Index

  • Manish

    I am using arduino mega adk with samsung galaxy s2 usb to serial is max chip but when i connect it with arduino i get buffer read error :5 unable to resolve device protocol version.

    Please help.

  • […] The Arduino firmware is a simple program receiving a toggle LED command from the connected Android device. Some parts are taken from the USB Host Shield 2.0 library. […]

  • Thuan

    Dear Mr. Oleg and all;

    I am trying to port the firmware from Arduino to my evaluation board (use EHCI Host Controller 2.0 inside) and use Xoom (Android 3.2) as the Android device.

    I can start the Demokit application on Xoom and can enter the operating screen (I can see the button, led, joystick…). It means that I started accessory mode successfully. However, after that, the USB port in the host is disabled.

    I think after the host sends identifying string (command 52) and start up accessory command (command 53) to the Xoom, the Xoom is reset to put in accessory mode. With this reset action, the electronic characteristic (voltage, current…) on the usb bus is changed. It makes the host change the port status (from enable to disable).

    Once the USB port is disabled, usb host can not send any packet anymore. So, I can not read device descriptor again to check vendor id, product id.

    I have to reset the usb port to enable this port again. However, after I reset and enable the port again, the Demokit application on Xoom is back to “Waiting for connecting device”. It seems that the accessory mode is closed.

    This is my problem.
    Could you please share some ideas to solve it.
    Thank you so much.

    Thuan

    • The device will answer in accessory mode after reset if power is still present on VBUS. It is likely that your host firmware toggles power or diconnects pulldown resistors during reset. You’d have to verify it though – a cheap DSO will show it right away.

      • Thuan

        Dear Mr. Oleg;

        Thank you for your reply.
        As your feedback, it looks like my host has problem about hardware.

        If the software has bug, I can fix but if the host has problem, what should I do now? 🙁

        I wonder is there any solution to make the Xoom enter accessory mode without reset?

        I think if the Xoom does not reset, the port will still be enabled and it will be good.

        Thank you!
        Thuan

  • Thuan

    Dear Mr. Oleg and all;

    Finally, we fixed this issue.

    The root cause is: EHCI manual suggests that we should keep the port reset assert at least 50ms, then clear the rest. However, we keep it too long (around 2s). So, the tablet closed accessory mode and back to normal mode.

    Hope it be helpful for everyone who meet this issue like us.

    Regards,
    Thuan

  • Vinod

    Hi

    adk.SndData returns 4… and i m not getting data on android phone. Can anyone plz tell me how to do it?

    void loop(){
    uint16_t value = 0;
    uint8_t data[1];

    Usb.Task();
    if(adk.isReady()) {
    if(value>100)
    {
    value = 0;
    }
    data[0] = value++;
    uint8_t ret = adk.SndData(1, data);
    |

  • Henry

    Do i always need to reset the arduino when i disconect the USB cable and Connect again?

    In my case when i disconnect from the arduino and connect again it don’t work. It works when i reset the arduino physically. Using the Accessory Development Kit i don’t have this problem.