Go Down

Topic: Debugging an Arduino Due Hosting a PS3 Controller (Read 184 times) previous topic - next topic


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:
Code: [Select]

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...
Code: [Select]

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!
Code: [Select]

#define PS3_ADDR 0
USBHost my_usb_host;

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

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;
    (device_descriptor->idVendor != PS3_VID) ||(device_descriptor->idProduct != PS3_PID)  ) {
        Serial.println("Unsupported USB Device");
          while(1);  //stop   
    /* 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


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).

Go Up