Debugging an Arduino Due Hosting a PS3 Controller

Hi folks,

I'm trying to port support for the PS3 Controller to the Arduinio Due using it's hosting feature. My code is inspired from the work of the folks over at circuits-at-home. Here's the inspirational source code that I started from.

Currently, I can read the device descriptors, but I'm getting a STALL message when I try to set the configuration 200ms afterwards.

I've chopped up a USB cable to probe the lines with a logic analyzer. Here's the raw information being sent for the setConf function:

Time [s], Analyzer Name, Decoded Protocol Result                                
1.540221,USB LS and FS,SYNC                                                     
1.540222,USB LS and FS,PID SETUP                                                
1.540223,USB LS and FS,Address=0x00 Endpoint=0x00                               
1.540224,USB LS and FS,CRC OK 0x02                                              
1.540224,USB LS and FS,EOP                                                      
1.540225,USB LS and FS,SYNC                                                     
1.540225,USB LS and FS,PID DATA0                                                
1.540226,USB LS and FS,bmRequestType=0x00 Data direction=No data, Type=Standard, Recipient=Device
1.540227,USB LS and FS,bRequest=0x09 SET_CONFIGURATION                          
1.540227,USB LS and FS,wValue=0x0001                                            
1.540229,USB LS and FS,wIndex=0x0000                                            
1.540230,USB LS and FS,wLength=0x0000                                           
1.540231,USB LS and FS,CRC OK 0x2527                                            
1.540233,USB LS and FS,EOP                                                      
1.540233,USB LS and FS,SYNC                                                     
1.540234,USB LS and FS,PID ACK                                                  
1.540234,USB LS and FS,EOP

and then a few micros later...

1.540398,USB LS and FS,SYNC                                                     
1.540399,USB LS and FS,PID NAK                                                  
1.540399,USB LS and FS,EOP                                                      
1.540400,USB LS and FS,SYNC                                                     
1.540401,USB LS and FS,PID IN                                                   
1.540402,USB LS and FS,Address=0x00 Endpoint=0x00                               
1.540403,USB LS and FS,CRC OK 0x02                                              
1.540403,USB LS and FS,EOP                                                      
1.540404,USB LS and FS,SYNC                                                     
1.540404,USB LS and FS,PID STALL                                                
1.540405,USB LS and FS,EOP

I'm guessing I'm making some wrong assumptions about how USB works, so here are my questions:

  • Does anyone see anything egregiously wrong with this setup?
  • I omitted changing the USB device address, which the first example does do. Is that necessary?
  • Does the Arduino Due need any additional hardware besides a cable for USB Hosting? Currently, it's just plugged in via a usb cable and powered externally from a 9V wall wart.

Here's a truncated version of the code, for reference. Thanks for taking a look!

#define PS3_ADDR 0
USBHost my_usb_host;

void loop() {
    my_usb_host.Task();
    if( my_usb_host.getUsbTaskState() == USB_STATE_CONFIGURING ) {  //wait for addressing state
        Serial.println("Initializing controller.");
        PS3_init();
        process_report();
        my_usb_host.setUsbTaskState( USB_STATE_RUNNING );
    }
    if( my_usb_host.getUsbTaskState() == USB_STATE_RUNNING ) {  //poll the PS3 Controller 
        PS3_poll();
    }
    delay(100);
}

void PS3_init( void )
{
 byte rcode = 0;  //return code
 byte i;
 USB_DEVICE_DESCRIPTOR* device_descriptor;

 /* Initialize data structures for endpoints of device */
    ep_record[ CONTROL_PIPE ].epAddr = 0x00;
    ep_record[ OUTPUT_PIPE ].epAddr = 0x02;    // PS3 output endpoint
    ep_record[ OUTPUT_PIPE ].Attr  = EP_INTERRUPT;
    ep_record[ OUTPUT_PIPE ].MaxPktSize = EP_MAXPKTSIZE;
    ep_record[ OUTPUT_PIPE ].Interval  = EP_POLL;
    //ep_record[ OUTPUT_PIPE ].sndToggle = bmSNDTOG0;
    //ep_record[ OUTPUT_PIPE ].rcvToggle = bmRCVTOG0;
    ep_record[ INPUT_PIPE ].epAddr = 0x01;    // PS3 report endpoint
    ep_record[ INPUT_PIPE ].Attr  = EP_INTERRUPT;
    ep_record[ INPUT_PIPE ].MaxPktSize = EP_MAXPKTSIZE;
    ep_record[ INPUT_PIPE ].Interval  = EP_POLL;
    //ep_record[ INPUT_PIPE ].sndToggle = bmSNDTOG0;
    //ep_record[ INPUT_PIPE ].rcvToggle = bmRCVTOG0;
    
    //my_usb_host.setDevTableEntry( PS3_ADDR, ep_record );
    
    /* read the device descriptor and check VID and PID*/
    rcode = my_usb_host.getDevDescr( PS3_ADDR, ep_record[ CONTROL_PIPE ].epAddr, DEV_DESCR_LEN , (uint8_t*)buf );
    if( rcode ) {
        Serial.print("Error attempting read device descriptor. Return code :");
        Serial.println( rcode, HEX );
        while(1);  //stop
    }
    device_descriptor = (USB_DEVICE_DESCRIPTOR *) &buf;
    delay(200);
    if(
    (device_descriptor->idVendor != PS3_VID) ||(device_descriptor->idProduct != PS3_PID)  ) {
        Serial.println("Unsupported USB Device");
          while(1);  //stop   
    }
    delay(200);
    
    /* Configure device */

    Serial.println("Configuring device...");
    rcode = my_usb_host.setConf( PS3_ADDR, ep_record[ CONTROL_PIPE ].epAddr, PS3_CONFIGURATION );                    
    if( rcode ) {
        Serial.print("Error attempting to configure PS3 controller. Return code :");
        Serial.println( rcode, HEX );
        while(1);  //stop
    } 
    delay(200);

Some thoughts from what I have understood of the UOTGHS controller (full compliant USB 2.0):

Before a USB Host sets a USB Device configuration, the Host retrieves all necessary Descriptors from the Device (enumeration stage), then selects parameters amongst those provided by the Device thru its Descriptors to set (in fact propose) a configuration to the Device (Negociation stage between Host and Device), then the Device answers with the same configuration or another one (End of Negociation stage).

AFAIK, you only need a USB cable between the Native USB port ( a micro AB plug, can also receive a micro A plug) and the USB Device.

A guess: maybe you haven't extracted the correct parameters from the Device Descriptors to set a correct configuration resulting in a STALL from the Device.

There is a tutorial to retrieve a video stream from a web camera here. Sections 6 and 7 are about Descriptors and setting a Device configuration, and the Device address is changed before setting a new Device configuration but IMO changing the address is not absolutely necesssary when there is only 1 Device (no hub).

Hi, I'm currently porting the library from the Host USB to the arduino DUE to use the native USB port.

So far I've managed to read the device descriptor, but then fails at the setConf(bAddress,epInfo... line of the PS3USB.cpp library.

The rcode returned is a FF meaning timeout.

Have you had any luck since last post?

Many thanks.

An example to connect a joystick as a USB Device to a DUE as a USB Host:

https://forum.arduino.cc/index.php?topic=621442.0