This is the third part of a series of articles written to describe development of interface between Arduino and popular game controllers using USB Host Shield. Previous parts:
Revision 0.4 – 13th January 2010
Part 3. Develop the Bluetooth USB and HCI interface used in the support of the Wiimote and PS3 game controller, and also some utilities needed to analyse and configure these devices.
1. USB Interface
As before, we first look at the descriptors for the USB dongle using the USB_Desc sketch. The result is:
Start Device descriptor: Descriptor Length: 12 Descriptor type: 01 USB version: 0110 Device class: E0 Device Subclass: 01 Device Protocol: 01 Max.packet size: 10 Vendor ID: 0A12 Product ID: 0001 Revision ID: 0134 Mfg.string index: 00 Prod.string index: 00 Serial number index: 00 Number of conf.: 01 Configuration descriptor: Total length: 006C Num.intf: 02 Conf.value: 01 Conf.string: 00 Attr.: 80 Max.pwr: 32 Interface descriptor: Intf.number: 00 Alt.: 00 Endpoints: 03 Intf. Class: E0 Intf. Subclass: 01 Intf. Protocol: 01 Intf.string: 00 Endpoint descriptor: Endpoint address: 81 Attr.: 03 Max.pkt size: 0010 Polling interval: 01 Endpoint descriptor: Endpoint address: 82 Attr.: 02 Max.pkt size: 0040 Polling interval: 00 Endpoint descriptor: Endpoint address: 02 Attr.: 02 Max.pkt size: 0040 Polling interval: 00 Interface descriptor: Intf.number: 01 Alt.: 00 Endpoints: 02 Intf. Class: E0 Intf. Subclass: 01 Intf. Protocol: 01 Intf.string: 00 Endpoint descriptor: Endpoint address: 83 Attr.: 01 Max.pkt size: 0000 Polling interval: 01 Endpoint descriptor: Endpoint address: 03 Attr.: 01 Max.pkt size: 0000 Polling interval: 01 Interface descriptor: Intf.number: 01 Alt.: 01 Endpoints: 02 Intf. Class: E0 Intf. Subclass: 01 Intf. Protocol: 01 Intf.string: 00 Endpoint descriptor: Endpoint address: 83 Attr.: 01 Max.pkt size: 0009 Polling interval: 01 Endpoint descriptor: Endpoint address: 03 Attr.: 01 Max.pkt size: 0009 Polling interval: 01 Interface descriptor: Intf.number: 01 Alt.: 02 Endpoints: 02 Intf. Class: E0 Intf. Subclass: 01 Intf. Protocol: 01 Intf.string: 00 Endpoint descriptor: Endpoint address: 83 Attr.: 01 Max.pkt size: 0011 Polling interval: 01 Endpoint descriptor: Endpoint address: 03 Attr.: 01 Max.pkt size: 0011 Polling interval: 01
The device descriptor is straight forward, but the configuration descriptor shows two interfaces and the second interface has alternate settings. The usage of the different endpoints is described here: Bluetooth Endpoint Usage
The second interface (interface one) is used for isochronous bandwidth related to carrying voice channels and we do not use this for Bluetooth HID, so they will be ignored.
We have four endpoints to consider:
The control endpoint (endpoint 0): This is used to send control messages and HCI commands.
The interrupt endpoint (endpoint 0×81): Where HCI events are received from the USB dongle.
The input endpoint (endpoint 0x 82): The bulk endpoint where ACL reports are received from the connected Bluetooth device.
The output endpoint (endpoint 0×02): The bulk endpoint where ACL reports are sent to the connected Bluetooth device.
These four endpoints discovered are registered as pipes to the USB Host library.
/* Initialize data structures for endpoints of device 1*/ ep_record[ CONTROL_PIPE ] = *( Usb.getDevTableEntry( 0,0 )); //copy endpoint 0 parameters ep_record[ EVENT_PIPE ].epAddr = 0x01; // Bluetooth event endpoint ep_record[ EVENT_PIPE ].Attr = EP_INTERRUPT; ep_record[ EVENT_PIPE ].MaxPktSize = INT_MAXPKTSIZE; ep_record[ EVENT_PIPE ].Interval = EP_POLL; ep_record[ EVENT_PIPE ].sndToggle = bmSNDTOG0; ep_record[ EVENT_PIPE ].rcvToggle = bmRCVTOG0; ep_record[ DATAIN_PIPE ].epAddr = 0x02; // Bluetooth data endpoint ep_record[ DATAIN_PIPE ].Attr = EP_BULK; ep_record[ DATAIN_PIPE ].MaxPktSize = BULK_MAXPKTSIZE; ep_record[ DATAIN_PIPE ].Interval = 0; ep_record[ DATAIN_PIPE ].sndToggle = bmSNDTOG0; ep_record[ DATAIN_PIPE ].rcvToggle = bmRCVTOG0; ep_record[ DATAOUT_PIPE ].epAddr = 0x02; // Bluetooth data endpoint ep_record[ DATAOUT_PIPE ].Attr = EP_BULK; ep_record[ DATAOUT_PIPE ].MaxPktSize = BULK_MAXPKTSIZE; ep_record[ DATAOUT_PIPE ].Interval = 0; ep_record[ DATAOUT_PIPE ].sndToggle = bmSNDTOG0; ep_record[ DATAOUT_PIPE ].rcvToggle = bmRCVTOG0; Usb.setDevTableEntry( BT_ADDR, ep_record );
The VID and the PID of the Bluetooth dongle should be checked to ensure compatibility. The CSR is the only dongle currently supported, but others have been found compatible and may be added later.
The device is configured and the interface 0 then set. At this stage we have communication with the Bluetooth dongle and can now start to communicate over Bluetooth.
2. Listen while we talk
We are now in a position to send HCI commands to the Bluetooth dongle over the control pipe, but first need to set up a process to read the interrupt pipe regularly. The events received on the interrupt pipe may not be directly related to the commands sent, so they must be processed as they arrive. As the USB host, we control the data transfers; we do not have to buffer large amounts of data, we only pull over the pipe what we can handle at any time. Also in the spirit of our “reduced host” for both USB and Bluetooth, we do no have to process all of the 36 possible events in the Bluetooth specification; we process only the ones we need for each application and ignore the rest. Significant events are communicated to the higher level routines through a set of flags.
We also commence reading the ACL input endpoint in case ACL events are ready there too. These are ignored until connection is made, but are read in case they block HCI events.
At this stage we handle only these HCI events:
#define EV_COMMAND_COMPLETE 0x0e #define EV_COMMAND_STATUS 0x0f #define EV_CONNECT_COMPLETE 0x03 #define EV_DISCONNECT_COMPLETE 0x05 #define EV_NUM_COMPLETE_PKT 0x13 #define EV_INQUIRY_COMPLETE 0x01 #define EV_INQUIRY_RESULT 0x02 #define EV_REMOTE_NAME_COMPLETE 0x07 #define EV_INCOMING_CONNECT 0x04 #define EV_ROLE_CHANGED 0x12
And we use these flags:
/* HCI event flags*/ #define HCI_FLAG_CMD_COMPLETE 0x01 #define HCI_FLAG_CMD_STATUS 0x02 #define HCI_FLAG_CONN_COMPLETE 0x04 #define HCI_FLAG_DISCONN_COMPLETE 0x08 #define HCI_FLAG_CONNECT_OK 0x10 #define HCI_FLAG_INQUIRY_COMPLETE 0x20 #define HCI_FLAG_REMOTE_NAME_COMPLETE 0x40 #define HCI_FLAG_INCOMING_REQUEST 0x80 //Macros for event flag tests #define hci_cmd_complete (hci_event_flag & HCI_FLAG_CMD_COMPLETE) #define hci_cmd_status (hci_event_flag & HCI_FLAG_CMD_STATUS) #define hci_connect_complete (hci_event_flag & HCI_FLAG_CONN_COMPLETE) #define hci_disconnect_complete (hci_event_flag & HCI_FLAG_DISCONN_COMPLETE) #define hci_connect_ok (hci_event_flag & HCI_FLAG_CONNECT_OK) #define hci_inquiry_complete (hci_event_flag & HCI_FLAG_INQUIRY_COMPLETE) #define hci_remote_name_complete (hci_event_flag & HCI_FLAG_REMOTE_NAME_COMPLETE) #define hci_incoming_connect_request (hci_event_flag & HCI_FLAG_INCOMING_REQUEST)
3. Sending HCI Commands
To send HCI commands such as HCI reset we send a class specific output via the control pipe
// used in control endpoint header for HCI Commands #define bmREQ_HCI_OUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE #define HCI_COMMAND_REQ 0 void hci_reset(void) { hci_event_flag = 0; // clear all the flags buf[0] = 0x03; buf[1] = 0x0c; buf[2] = 0x00; HCI_Command(3 , buf); return; } //perform HCI Command byte HCI_Command( unsigned int nbytes, char* dataptr ) { hci_command_packets--; hci_event_flag &= ~HCI_FLAG_CMD_COMPLETE; return( Usb.ctrlReq( BT_ADDR, ep_record[ CONTROL_PIPE ].epAddr, bmREQ_HCI_OUT, HCI_COMMAND_REQ, 0x00, 0x00 ,0, nbytes, dataptr )); }
4. Bluetooth HCI Utility
Our first sketch to access the Bluetooth dongle will be a utility to gather data from the Bluetooth dongle itself and also to make Bluetooth inquires and connections. The sketch is structured as a state machine to maintain non blocking behavior and so enable the event task to run regularly. The blueutils sketch is loaded into the Arduino, and a CSR bluetooth dongle connected to the USB shield. Running the sketch returns the following over the serial port:
freeMemory() reports: 1513 CSR Initialized HCI Reset complete ACL Data Packet Length: 672 SCO Data Packet Length: 48 Total ACL Data Packets: 4 Total SCO Data Packets: 1 HCI Version: 3 HCI Revision: 3164 LMP Version: 3 Manufacturer Id: 10 LMP Subversion: 3164 Local Name: Local Bluetooth Address: 00158316C075 Search for devices Search complete Devices Found : 0 Wait for Incoming Connect Request
This confirms we are talking to the dongle and gives useful information especially the bluetooth address hardcoded into the dongle.
5. Connecting Wiimote Game Controller
The connection process is different for the Wiimote and the PS3, so we will look at these in turn.
The wiimote has two methods of connection know as soft connect and hard connect. We look at the soft connect mode here. In soft connect mode a connection is made from the Arduino to the Wiimote, and to enable this the Bluetooth address of the wiimote must be discovered.
The blueutils sketch is run again, and when the message comes on the serial port of “Search for devices”, the “1″ and “2″ buttons on the Wiimote are pressed simultaneously. The search will take about 10 seconds and at the end return something similar to:
freeMemory() reports: 1513 CSR Initialized HCI Reset complete ACL Data Packet Length: 672 SCO Data Packet Length: 48 Total ACL Data Packets: 4 Total SCO Data Packets: 1 HCI Version: 3 HCI Revision: 3164 LMP Version: 3 Manufacturer Id: 10 LMP Subversion: 3164 Local Name: Local Bluetooth Address: 00158316C075 Search for devices Search complete Devices Found : 1 Found BDADDR: 0022AA8A06A3 Class: 042500 Mode: 1 Offset: 69C9 Remote Name: 0 Nintendo RVL-CNT-01 Connected to device
Here the Arduino has found the Wiimote and used the discovered Bluetooth Address to make a connection to it.
6. Connecting PS3 Game Controller
The PS3 Game Controller connection process is the other way round. The PS3 controller make the connection to the Arduino. The PS3 controller does not respond to requests for inquiry or connection.
To initate the connection the PS3 controller needs to know the Bluetooth Address of the Arduino. MotioninJoy can be used to set a USB dongle address into the PS3 contoller or alternatively sixpair.c under linux. These read the USB dongle bluetooth address and set this into the PS3 controller.
Since we know the Arduino Bluetooth address from the utility above “Local Bluetooth Address: 00158316C075″ and we have ability using PS3LCD or the PS3 library to set the host Bluetooth Address, we can also use that method.
When the PS3 is programmed with the correct USB dongle Bluetooth address, the following is dsplayed when the “PS” buuton on the PS3 Game Controler is pressed at the “Wait for Incoming Connect Request” prompt.
freeMemory() reports: 1513 CSR Initialized HCI Reset complete ACL Data Packet Length: 672 SCO Data Packet Length: 48 Total ACL Data Packets: 4 Total SCO Data Packets: 1 HCI Version: 3 HCI Revision: 3164 LMP Version: 3 Manufacturer Id: 10 LMP Subversion: 3164 Local Name: Local Bluetooth Address: 00158316C075 Search for devices Search complete Devices Found : 0 Wait for Incoming Connect Request Connected to device
Related posts:
- PS3 and Wiimote Game Controllers on the Arduino Host Shield: Part 2
- PS3 and Wiimote Game Controllers on the Arduino Host Shield: Part 1
- Hook up PS3 controller to USB Host shield
- Arduino USB Host – Peripherals.
- Arduino USB Host Shield build log. Part 4.
- Arduino USB Host Shield build log. Part 3.
- Arduino USB Host Shield build log. Part 2.
- Arduino USB Host Shield build log. Part 1.
- USB Host Shield for Arduino – first prototype.
- Arduino USB Host – USB Descriptors.


Absolutely fantastic articles! When will parts 4 and 5 be avaiable? Great work! :)
Hi. I’m in my school’s robotics club and we’re following these guides to try and sync up a PS3 controller to an arduino board to control our robot. We have got the PS3LCD sketch to compile (finally) and now have absolutely no idea where to connect the pins? Is there a clear picture of how to connect it all up? We really need to know just what pins to plug into where from where and all that.
Any help would be incredibly appreciated. :)
Thanks so much and keep up the good work.
Sam.