Sample capture of SPI lines when the Joy-Con battery is connected, and attached to the console.
Upon connection the microcontroller initializes a software reset of the MEMS chip, then set up the accelerometer and gyroscope as follows:
Accelerometer | Gyroscope |
---|---|
ODR 1.66KHz, full-scale ±8g | ODR 208Hz, full-scale 2000dps |
The accelerometer also has AA filter at 100Hz bandwidth, low-pass filter enabled, slope filter enabled with cut-off frequency at 416Hz.
The Joy-Con then polls LSM6DS3 every 1.35ms(740Hz) for both accelerometer and gyroscope data in all axises, totaling 12 bytes(6 axises, each axis 2 bytes).
Since the Joy-Con polls MEMS data every 1.35ms but only send out controller update every 15ms, there might be some internal averaging to smooth out the data, needs to go through the numbers to find out.
Not documented yet. SPI sample will have all the data, and addresses that the Joy-Con is reading from flash memory so take a look at it for that information.
When the Joy-Con is attached to the, Joy-Con switches to a physical connection to talk to the Switch instead of Bluetooth. There is 10 pins on the connector.
In the picture above the rumble motor has been removed, and a whole made through the back cover, and wires routed through that.
Capture of Left Joy-Con docking with the Switch.
Logic analyzer channel | Joy-Con Connector Pin | Function | Remark |
---|---|---|---|
- | 1 | GND | - |
- | 2 | GND | - |
0 | 3 | BT status? | Only high when connected to console via bluetooth, low when unpaired, sleeping, or attached to the console directly |
1 | 4 | 5V | Joy-Con power and charging |
2 | 5 | Serial data, console to Joy-Con | Inverted level (idle at GND) |
3 | 6 | Attach status? | GND only when directly attached to console and not sleeping, 1.8V. |
- | 7 | GND | - |
4 | 8 | Serial data, Joy-Con to console | Standard level (idle at 1.8V) |
5 | 9 | ? | Always at GND |
6 | 10 | Flow control | Looks like RTS line, Joy-Con will only send data when this line is high. |
When first connected the baud rate is at 1000000bps(!), after the initial handshake the speed is then switched to 3125000bps(!!). The handshake probably exchanges information about the side of the Joy-Con, the color, and bluetooth address etc.
Console to Joy-Con | GRAY Joy-Con response | RED Joy-Con response | Different? | Remarks |
---|---|---|---|---|
A1 A2 A3 A4 19 01 03 07 00 A5 02 01 7E 00 00 00 | 19 81 03 07 00 A5 02 02 7D 00 00 64 | 19 81 03 07 00 A5 02 02 7D 00 00 64 | Same | Handshake start; 1000000bps |
19 01 03 07 00 91 01 00 00 00 00 24 | 19 81 03 0F 00 94 01 08 00 00 FA E8 01 31 67 9C 8A BB 7C 00 | 19 81 03 0F 00 94 01 08 00 00 8F 87 01 E6 4C 5F B9 E6 98 00 | Different | Joy-Con info; possibly color; side; battery level; BT info; etc |
19 01 03 0F 00 91 20 08 00 00 BD B1 C0 C6 2D 00 00 00 00 00 | 19 81 03 07 00 94 20 00 00 00 00 A8 | 19 81 03 07 00 94 20 00 00 00 00 A8 | Same | Command to switch to 3125000bps |
19 01 03 07 00 91 11 00 00 00 00 0E | 19 81 03 07 00 94 11 00 00 0F 00 33 | 19 81 03 07 00 94 11 00 00 0F 00 33 | Same | ?; 3125000 bps from now on |
19 01 03 07 00 91 10 00 00 00 00 3D | 19 81 03 07 00 94 10 00 00 00 00 D6 | 19 81 03 07 00 94 10 00 00 00 00 D6 | Same | ? |
19 01 03 0B 00 91 12 04 00 00 12 A6 0F 00 00 00 | 19 81 03 07 00 94 12 00 00 00 00 B0 | 19 81 03 07 00 94 12 00 00 00 00 B0 | Same | ? |
19 01 03 08 00 92 00 01 00 00 69 2D 1F | 61B Controller status | 61B Controller status | Different | Handshake done. Console sends this controller status request command every 15ms from now on. |
The first 4 bytes are a header, with the 4th byte being the length of the remaining packet (not counting the checksum). The next 7 bytes are a type of data, with the 8th byte being the CRC of that data. The CRC used is CRC-8 with a polynomial of 0x8D, and a initial value of 0x00.
Here's some example code for calculating the CRC using a lookup table.
Below is a example of some commands that will be sent from the Joy-Con.
19 01 03 07 00 91 10 00 00 00 00 3D 19 01 03 07 00 91 01 00 00 00 00 24 19 01 03 07 00 91 11 00 00 00 00 0E 19 81 03 07 00 94 10 00 00 00 00 D6 19 81 03 07 00 94 11 00 00 0F 00 33
In normal use the switch will ask the Joy-Con to update every 15ms (66.6fps), the command sent for requesting is below.
19 01 03 08 00 92 00 01 00 00 69 2d 1f
4ms later the Joy-Con will respond with a 61 byte answer, an example is provided.
19 81 03 38 00 92 00 31 00 00 e9 2e 30 7f 40 00 00 00 65 f7 81 00 00 00 c0 23 01 e2 ff 3e 10 0a 00 d6 ff d0 ff 23 01 e1 ff 37 10 0a 00 d6 ff cf ff 29 01 dd ff 34 10 0a 00 d7 ff ce ff
Byte # | Sample Value | Remarks |
---|---|---|
0 to 8 | 19 81 03 38 00 92 00 31 | Header, fixed |
16 to 17 | 00 02 | Button status, see section below |
19 | f7 | Joystick X value, reversed nibble? |
20 | 81 | Joystick Y value |
31 and 32 | 4e 05 | Gyroscope X value |
33 and 34 | cc fb | Gyroscope Y value |
35 and 36 | eb ff | Gyroscope Z value |
37 and 38 | 41 00 | Accelerometer X Value |
39 and 40 | 1b 03 | Accelerometer Y Value |
41 and 42 | 82 f0 | Accelerometer Z Value |
Each accelerometer and gyroscope axis data is 2 bytes long and forms a int16_t, last byte is the higher byte.
The 16th and 17th byte (on line 5, before 65 f7) are the button status, when a button is pressed the corresponding bit is set to 1.
Byte | 16th Byte | |||||||
---|---|---|---|---|---|---|---|---|
Bit Position | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Button | ? | ? | CAPTURE | STICK BUTTON | ? | ? | ? | MINUS |
Byte | 17th Byte | |||||||
---|---|---|---|---|---|---|---|---|
Bit Position | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Button | ZL | L | ? | ? | LEFT | RIGHT | UP | DOWN |
Are the joystick values, most likely being raw 8-bit ADC data. Weirdly, the X value is reversed as in (f7 = 7f). It's 127 at neutral position. The Y value wasn't reversed thought (0x81 is 129).