In memory of Ben “bushing” Byer, who passed away on Monday, February 8th, 2016.

Difference between revisions of "Wiimote"

From WiiBrew
Jump to navigation Jump to search
(Removed the protocol stuff as it’s now on its own page)
m (→‎Input Features: replaced with link to separate article)
Line 312: Line 312:
 
Most of these are also mirrored across the high bits of the individual peripheral. For example, the second byte of the address is ignored in the Extension controller address, which means any address of the form 0xA4xx00 will work (as will 0xA5xx00).
 
Most of these are also mirrored across the high bits of the individual peripheral. For example, the second byte of the address is ignored in the Extension controller address, which means any address of the form 0xA4xx00 will work (as will 0xA5xx00).
  
= Input Features =
+
= Input features =
The Wii Remote has two input features that are controlled directly by the Broadcom chip: a [[#Accelerometer | Three-Axis Accelerometer]] and 11 [[#Buttons | Buttons]]. Additionally, it has an [[#IR Camera | IR Camera]] with an object tracking processor, and an expansion port that allows for external input features such as those contained in the Nunchuk and the Classic Controller (see [[#Extension Controllers | Extension Controllers]]).
+
See [[/Input features]].
 
 
== Buttons ==
 
The Wii Remote has 11 buttons on its front face, and one trigger-style button on the back. Of these, the Power button is special and is treated differently by the Wii Remote. All the other buttons are independantly accessible through a two-byte bitmask which is transmitted first in most Input Reports. A button will report a 1-bit if pressed, or a 0-bit otherwise. By default, these are sent only when the state of any button changes, in [[#0x30: Core Buttons | Data Reporting Mode 0x30]]. However, the Wii Remote may be configured to report the state of the buttons continuously; see [[#Data Reporting | Data Reporting]].
 
 
 
=== Core Buttons ===
 
The Wii Remote has 11 buttons that are used as regular input devices: A, B (trigger), a 4-directional D-Pad, +, -, Home, 1, and 2. These are reported as bits in a two-byte bitmask. These are the assignments, in big-endian order:
 
{| style="border: 1px solid #bbb; border-collapse: collapse; padding: 0.2em 0.2em 0.2em 0.2em;"
 
|- style="background-color: #ddd;"
 
| style="border: 1px solid #ccc; padding: 0.2em;" | '''Bit'''
 
| style="border: 1px solid #ccc; padding: 0.2em;" | '''Mask'''
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #ded;" | '''First Byte'''
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #dde;" | '''Second Byte'''
 
|- style="background-color: #eee;"
 
| style="border: 1px solid #ccc; padding: 0.2em;" | 0
 
| style="border: 1px solid #ccc; padding: 0.2em;" | 0x01
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #ded;" | D-Pad Left
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #dde;" | Two
 
|- style="background-color: #eee;"
 
| style="border: 1px solid #ccc; padding: 0.2em;" | 1
 
| style="border: 1px solid #ccc; padding: 0.2em;" | 0x02
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #ded;" | D-Pad Right
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #dde;" | One
 
|- style="background-color: #eee;"
 
| style="border: 1px solid #ccc; padding: 0.2em;" | 2
 
| style="border: 1px solid #ccc; padding: 0.2em;" | 0x04
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #ded;" | D-Pad Down
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #dde;" | B
 
|- style="background-color: #eee;"
 
| style="border: 1px solid #ccc; padding: 0.2em;" | 3
 
| style="border: 1px solid #ccc; padding: 0.2em;" | 0x08
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #ded;" | D-Pad Up
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #dde;" | A
 
|- style="background-color: #eee;"
 
| style="border: 1px solid #ccc; padding: 0.2em;" | 4
 
| style="border: 1px solid #ccc; padding: 0.2em;" | 0x10
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #ded;" | Plus
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #dde;" | Minus
 
|- style="background-color: #eee;"
 
| style="border: 1px solid #ccc; padding: 0.2em;" | 5
 
| style="border: 1px solid #ccc; padding: 0.2em;" | 0x20
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #ded; color: #888" | Other uses
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #dde; color: #888" | Other uses
 
|- style="background-color: #eee;"
 
| style="border: 1px solid #ccc; padding: 0.2em;" | 6
 
| style="border: 1px solid #ccc; padding: 0.2em;" | 0x40
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #ded; color: #888" | Other uses
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #dde; color: #888" | Other uses
 
|- style="background-color: #eee;"
 
| style="border: 1px solid #ccc; padding: 0.2em;" | 7
 
| style="border: 1px solid #ccc; padding: 0.2em;" | 0x80
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #ded; color: #888" | Unknown
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #dde;" | Home
 
|}
 
 
 
=== Power Button ===
 
When the Wii Remote is turned off, pressing the Power button will attempt to wake up the Wii that is synchronized to it. The mechanism for this is unknown, and it is handled entirely within the Wii's bluetooth module. When the Wii Remote is turned on and connected to a host, pressing and holding the Power button for a few seconds will turn the Wii Remote off and request disconnection from the host. The disconnection reason included with the Baseband (ACL) disconnection request indicates that the power button was pressed: REMOTE DEVICE TERMINATED CONNECTION DUE TO POWER OFF (0x15). Another possible value is REMOTE DEVICE TERMINATED CONNECTION DUE TO LOW RESOURCES (0x14), which indicates that the Wii Remote performed a controlled shut down due to a low battery condition.
 
 
 
=== Sync Button ===
 
The sync button is hidden under the battery cover. When the Sync button is pressed, the Wii remote will disconnect from whatever it is currently connected to, make itself discoverable, and accept pairing or connection requests for exactly 20 seconds (regardless of how long the button is held down for).
 
 
 
The "syncing" of a Wii Remote involves standard Bluetooth pairing. When the Sync button is pressed on the remote, it will accept pairing requests. The required PIN is the hosts's Bluetooth address, backwards (last byte first), in binary (6 bytes). Most current Bluetooth implementations don't deal with this correctly, as they usually consider the PIN to be a regular null-terminated ASCII string (no 00 bytes, etc) and most Bluetooth addresses will contain null bytes. Any further steps that need to be taken after the Wii Remote is paired have not been reverse engineered yet.
 
 
 
Once the Wii Remote is synced, when a button is pressed, it will actively seek out its paired host and try to connect to it, instead of the other way around. Establishing a connection can be done on PSM 0x11 for writing and PSM 0x13 for reading using the Bluetooth L2CAP protocol.
 
 
 
=== Button Hardware ===
 
 
 
The physical hardware of the buttons varies: there are membrane switches and microswitch click buttons. There has been some success soldering wires to the membrane switch contacts and actuating the switch through an external switch. The following table describes the physical hardware for each input.
 
 
 
{| class="wikitable" border="1"
 
|-
 
! Function
 
! Switch type
 
! Circuit board surface
 
|-
 
| A
 
| [http://en.wikipedia.org/wiki/Membrane_switch membrane]
 
| top, SW9
 
|-
 
| B
 
| membrane
 
| bottom, SW8
 
|-
 
| -
 
| [http://en.wikipedia.org/wiki/Microswitch microswitch]
 
| top, SW10
 
|-
 
| Home
 
| microswitch
 
| top, SW11
 
|-
 
| +
 
| microswitch
 
| top, SW5
 
|-
 
| 1
 
| membrane
 
| top, SW7
 
|-
 
| 2
 
| membrane
 
| top, SW6
 
|-
 
| Up
 
| membrane
 
| top, SW4
 
|-
 
| Down
 
| membrane
 
| top, SW3
 
|-
 
| Left
 
| membrane
 
| top, SW1
 
|-
 
| Right
 
| membrane
 
| top, SW2
 
|-
 
| Sync
 
|
 
| bottom, SW12
 
|-
 
| Power
 
|
 
| top, SW13
 
|}
 
 
 
== Accelerometer ==
 
[[File:Wii-Remote-Accel.jpg|right|thumb|200px|ADXL330 in a Wii remote]][[File:Wiimote_axis2.png|right|thumb|200px|Coordinate system used by Wii Remote]]
 
The Wii Remote includes a three-axis linear accelerometer located on the top suface of the circuit board, slightly left of the large A button.  The integrated circuit is the [http://www.seekic.com/icdata/%20ADXL330.html ADXL330] ([http://www.analog.com/UploadedFiles/Data_Sheets/ADXL330.pdf data sheet]), manufactured by Analog Devices.  This device is physically rated to measure accelerations over a range of at least +/- 3g with 10% sensitivity.
 
 
 
Since the accelerometer actually measures the force exerted by a set of small proof masses inside of it with respect to its enclosure, the accelerometer measures linear acceleration in a free fall frame of reference. If the Wii Remote is in free fall, it will report zero acceleration. At rest, it will report an upward acceleration (+Z, when horizontal) equal to the acceleration due to gravity, g (approximately 9.8 m/s²) but in the opposite direction. This fact can be used to derive tilt from the acceleration outputs when the Wii Remote is reasonably still.
 
 
 
=== Normal Accelerometer Reporting ===
 
In all [[#Data Reporting | Data Reporting Modes]] which include Accelerometer data except for [[#0x3e / 0x3f: Interleaved Core Buttons and Accelerometer with 36 IR bytes | mode 0x3e/0x3f]], the accelerometer data is reported as three consecutive bytes:
 
 
 
(a1) RR BB BB XX YY ZZ [...]
 
 
 
XX, YY, and ZZ are unsigned bytes representing the acceleration in each of the three axis, where zero acceleration is approximately 0x80. The coordinate system is shown in the diagram above (note that this is different from the coordinate system used by GlovePIE). Additionally, the BB BB [[#Buttons | Buttons]] bytes also include the LSBs of the acceleration values in the unused bits, according to the following table:
 
 
 
{| style="border-collapse: collapse; padding: 0.2em 0.2em 0.2em 0.2em; text-align: center;"
 
|- style="background-color: #ddd;"
 
| style="background-color: #fff;" colspan="2" |  
 
| style="border: 1px solid #ccc; padding: 0.2em; text-align: center;" colspan="8"| '''Bit'''
 
|- style="background-color: #cdc;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #ddd;" | '''Byte'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''7'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''6'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''5'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''4'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''3'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''2'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''1'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''0'''
 
|- style="background-color: #ded;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eee;" | 0
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #ddd;" |  
 
| style="border: 1px solid #ccc; padding: 0.2em;" colspan="2" | '''X'''<span style="color: #777;">&lt;<span style="color: #c00;">1:0</span>&gt;</span>
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #ddd;" colspan="5" | &nbsp;
 
|- style="background-color: #ded;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eee;" | 1
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #ddd;" | &nbsp;
 
| style="border: 1px solid #ccc; padding: 0.2em;" | '''Z'''<span style="color: #777;">&lt;<span style="color: #c00;">1</span>&gt;</span>
 
| style="border: 1px solid #ccc; padding: 0.2em;" | '''Y'''<span style="color: #777;">&lt;<span style="color: #c00;">1</span>&gt;</span>
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #ddd;" colspan="5" | &nbsp;
 
|}
 
 
 
Note that X has 10 bits of precision, while Y and Z only have 9. For consistency, they are assumed all to have a 10-bit range and the LSB is always set to zero for Y and Z.
 
 
 
=== Interleaved Accelerometer Reporting ===
 
In [[#0x3e / 0x3f: Interleaved Core Buttons and Accelerometer with 36 IR bytes | Data Reporting Mode 0x3e/0x3f]], the accelerometer data is spread over two reports:
 
 
 
(a1) 3e BB BB XX [...]
 
(a1) 3f BB BB YY [...]
 
 
 
In this mode, the LSBs are not available. Instead, X and Y acceleration is reported as a single byte, and the Z value is encoded in the unused bits of the BB BB [[#Buttons | Buttons]] data as follows:
 
 
 
{| style="border-collapse: collapse; padding: 0.2em 0.2em 0.2em 0.2em; text-align: center;"
 
|- style="background-color: #ddd;"
 
| style="background-color: #fff;" colspan="2" | &nbsp;
 
| style="border: 1px solid #ccc; padding: 0.2em; text-align: center;" colspan="8"| '''Bit'''
 
|- style="background-color: #cdc;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #ddd;" | '''Report ID'''
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #ddd;" | '''Byte'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''7'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''6'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''5'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''4'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''3'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''2'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''1'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''0'''
 
|- style="background-color: #ded;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eee;" | 0x3e
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eee;" | 0
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #ddd;" | &nbsp;
 
| style="border: 1px solid #ccc; padding: 0.2em;" colspan="2" | '''Z'''<span style="color: #777;">&lt;<span style="color: #c00;">5:4</span>&gt;</span>
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #ddd;" colspan="5" | &nbsp;
 
|- style="background-color: #ded;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eee;" | 0x3e
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eee;" | 1
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #ddd;" | &nbsp;
 
| style="border: 1px solid #ccc; padding: 0.2em;" colspan="2" | '''Z'''<span style="color: #777;">&lt;<span style="color: #c00;">7:6</span>&gt;</span>
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #ddd;" colspan="5" | &nbsp;
 
|- style="background-color: #ded;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eee;" | 0x3f
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eee;" | 0
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #ddd;" | &nbsp;
 
| style="border: 1px solid #ccc; padding: 0.2em;" colspan="2" | '''Z'''<span style="color: #777;">&lt;<span style="color: #c00;">1:0</span>&gt;</span>
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #ddd;" colspan="5" | &nbsp;
 
|- style="background-color: #ded;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eee;" | 0x3f
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eee;" | 1
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #ddd;" | &nbsp;
 
| style="border: 1px solid #ccc; padding: 0.2em;" colspan="2" | '''Z'''<span style="color: #777;">&lt;<span style="color: #c00;">3:2</span>&gt;</span>
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #ddd;" colspan="5" | &nbsp;
 
|}
 
 
 
== IR Camera ==
 
[[File:Wii-Remote-Camera.jpg|200px|thumb|right|Wii remote camera]] The Wii Remote includes a 128x96 monochrome camera with built-in image processing. The camera looks through an infrared pass filter in the remote's plastic casing. The camera's built-in image processing is capable of tracking up to 4 moving objects, and these data are the only data available to the host. Raw pixel data is not available to the host, so the camera cannot be used to take a conventional picture. The built-in processor uses 8x subpixel analysis to provide 1024x768 resolution for the tracked points. The Sensor Bar that comes with the Wii includes two IR LED clusters at each end, which are tracked by the Wii Remote to provide pointing information. The distance between the centers of the LED clusters is 20 cm (as measured on one unit).
 
 
 
The IR Camera is enabled by setting bit 2 on output reports 0x13 and 0x1a:
 
(a2) 13 04
 
(a2) 1a 04
 
 
 
The first enables a 24MHz pixel clock on pin 7 of the camera.  The second pulls pin 4 low - probably an active-low enable.
 
 
 
=== Mechanical Characteristics ===
 
 
 
The camera component is mounted on the bottom surface of the circuit board.  The camera module itself is mounted in a socket perpendicular to the circuit board; to remove just the camera module, no desoldering is required.  The process is as follows:
 
 
 
First, orient the camera so that you are looking into the lens with the PCB horizontal and below the lens..  There are four metal clips, two on each of the
 
vertical sides of the socket.  Use something tiny to slide between each metal clip and the camera module: maybe wire wrap wire?  Then look at the back of the camera module, opposite the lens.  There is a small rectangular hole in the middle of each vertical side of the socket.  Use a pin or something to pry/press the camera module out.
 
 
 
Once the camera module is free of its socket, it may be further disassembled by gently prising up the tiny PCB with gold contacts; this is gently glued to the module's structure, but will come loose without damage.  At this point you have three pieces: the camera socket, still attached to the Wiimote PCB, the camera module housing, complete with lens and dichroic filter (of unknown optical properties), and a tiny PCB with the camera chip and eight gold contacts on the bottom.
 
 
 
=== Optical Characteristics ===
 
 
 
The IR camera has an effective field of view is about 33 degrees horizontally and 23 degrees vertically (as measured on one unit). With the IR-pass filter intact, 940nm sources are detected with approximately twice the intensity of equivalent 850nm sources, but are not resolved as well at close distances. If the filter is removed, it can track any bright object.  However, the IR filter referred to here is not only the dark plastic window of the wiimote but also a teensy slab of dichroic-coated glass inside the camera module.  One may operate the wiimote having installed neither, one or the other, or both filters.
 
 
 
=== Initialization ===
 
 
 
{{BoxCenter|'''Reminder'''<br />Remember to set bit 2 (0x04) on the first byte of the Output Reports to write to registers!}}
 
 
 
The following procedure should be followed to turn on the IR Camera:
 
 
 
#Enable IR Camera (Send 0x04 to Output Report 0x13)
 
#Enable IR Camera 2 (Send 0x04 to Output Report 0x1a)
 
#Write 0x08 to register 0xb00030
 
#Write Sensitivity Block 1 to registers at 0xb00000
 
#Write Sensitivity Block 2 to registers at 0xb0001a
 
#Write Mode Number to register 0xb00033
 
#Write 0x08 to register 0xb00030 (again)
 
 
 
After these steps, the Wii Remote will be in one of 3 states: IR camera on but not taking data, IR camera on and taking data and half sensitivity, IR camera on and taking data at full sensitivity.  Which state you end up in appears to be pretty much random.  Repeat the steps until you're in the desired state. To avoid the random state put a delay of at least 50ms between every single byte transmission.
 
 
 
The Wii preforms these steps slightly different, differences in bold:
 
#Enable IR Pixel Clock (send '''0x06''' to Output Report 0x13)
 
#Enable IR Logic (send '''0x06''' to Output Report 0x1A)
 
#Write '''0x01''' to register 0xb00030
 
#Write Sensitivity Block 1 to registers at 0xb00000
 
#Write Sensitivity Block 2 to registers at 0xb0001a
 
#Write Mode Number to register 0xb00033
 
#Write 0x08 to register 0xb00030 (again)
 
 
 
Adding bit 0x02 to reports 0x13 and 0x1a is a request for acknowledgement (if set, wiimote will respond with report 0x22).
 
 
 
=== Sensitivity Settings ===
 
Sensitivity is controlled by two configuration blocks, 9 bytes and 2 bytes long. The following settings are known to work:
 
 
 
{| style="border-collapse: collapse; padding: 0.2em 0.2em 0.2em 0.2em;"
 
|- style="text-align: center;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #ded;" | '''Block 1'''
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #dde;" | '''Block 2'''
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #ddd;" | '''Notes'''
 
|- style="text-align: center;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #efe; font-family: monospace;" | 00 00 00 00 00 00 90 00 C0
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eef; font-family: monospace;" | 40 00
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eee; text-align: left;" | Suggested by [[User:Marcan | Marcan]]
 
|- style="text-align: center;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #efe; font-family: monospace;" | 00 00 00 00 00 00 FF 00 0C
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eef; font-family: monospace;" | 00 00
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eee; text-align: left;" | Suggested by Kestrel (max sensitivity)
 
|- style="text-align: center;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #efe; font-family: monospace;" | 00 00 00 00 00 00 90 00 41
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eef; font-family: monospace;" | 40 00
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eee; text-align: left;" | Suggested by inio (high sensitivity)
 
|- style="text-align: center;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #efe; font-family: monospace;" | 02 00 00 71 01 00 64 00 fe
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eef; font-family: monospace;" | fd 05
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eee; text-align: left;" | Wii level 1
 
|- style="text-align: center;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #efe; font-family: monospace;" | 02 00 00 71 01 00 96 00 b4
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eef; font-family: monospace;" | b3 04
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eee; text-align: left;" | Wii level 2
 
|- style="text-align: center;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #efe; font-family: monospace;" | 02 00 00 71 01 00 aa 00 64
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eef; font-family: monospace;" | 63 03
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eee; text-align: left;" | Wii level 3 (Suggested by Cliff)
 
|- style="text-align: center;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #efe; font-family: monospace;" | 02 00 00 71 01 00 c8 00 36
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eef; font-family: monospace;" | 35 03
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eee; text-align: left;" | Wii level 4
 
|- style="text-align: center;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #efe; font-family: monospace;" | 07 00 00 71 01 00 72 00 20
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eef; font-family: monospace;" | 1f 03
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eee; text-align: left;" | Wii level 5
 
|}
 
 
 
The last byte of Block 1 determines the intensity sensitivity, with increasing values reducing the sensitivity. Both bytes of Block 2 must be zero for the full sensitivity range to be available. Setting the sensitivity as high as possible, without unwanted light being tracked, is recommended to achieve the highest subpixel resolution. As the sensitivity is reduced, the subpixel resolution also reduces, approaching the true sensor resolution of 128x96.
 
 
 
=== Data Formats ===
 
The IR Camera can return different sets of data describing the objects it is tracking. When the IR camera identifies an object, it assigns it to the first available object slot. If an object moves out of view, its slot is marked as empty (returns 0xFF data), but other objects retain their slots. For example, if the camera is tracking two objects and the first moves out of view, the data returned will be [empty, second object, empty, empty]. With more than four objects visible, the camera is prone to rapidly switching between some of them. This could allow perception of more than four objects, at a reduced response speed and reliability.
 
 
 
{| style="border-collapse: collapse; padding: 0.2em 0.2em 0.2em 0.2em;"
 
|- style="background-color: #dde; text-align: center;"
 
| style="border: 1px solid #ccc; padding: 0.2em; text-align: center;" | '''Mode'''
 
| style="border: 1px solid #ccc; padding: 0.2em; text-align: center; background-color: #ded;" | '''Mode Number'''
 
|- style="background-color: #eef; text-align: center;"
 
| style="border: 1px solid #ccc; padding: 0.2em; text-align: center;" | [[#Basic Mode | Basic]]
 
| style="border: 1px solid #ccc; padding: 0.2em; text-align: center; background-color: #efe;" | 1
 
|- style="background-color: #eef; text-align: center;"
 
| style="border: 1px solid #ccc; padding: 0.2em; text-align: center;" | [[#Extended Mode | Extended]]
 
| style="border: 1px solid #ccc; padding: 0.2em; text-align: center; background-color: #efe;" | 3
 
|- style="background-color: #eef; text-align: center;"
 
| style="border: 1px solid #ccc; padding: 0.2em; text-align: center;" | [[#Full Mode | Full]]
 
| style="border: 1px solid #ccc; padding: 0.2em; text-align: center; background-color: #efe;" | 5
 
|}
 
 
 
The data format MUST match the number of bytes available in the [[#Data Reporting | Reporting Mode]] selected. Even choosing a mode with space for more bytes than necessary will not work, it has to be an exact match.
 
 
 
==== Basic Mode ====
 
In Basic Mode, the IR Camera returns 10 bytes of data corresponding to the X and Y locations of each of the four dots. Each location is encoded in 10 bits and has a range of 0-1023 for the X dimension, and 0-767 for the Y dimension. Each pair of dots is packed into 5 bytes, and two of these are transmitted for a total of 4 dots and 10 bytes.
 
 
 
This is the data format for a pair of objects:
 
{| style="border-collapse: collapse; padding: 0.2em 0.2em 0.2em 0.2em; text-align: center;"
 
|- style="background-color: #ddd;"
 
| style="background-color: #fff;" | &nbsp;
 
| style="border: 1px solid #ccc; padding: 0.2em; text-align: center;" colspan="8"| '''Bit'''
 
|- style="background-color: #cdc;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #ddd;" | '''Byte'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''7'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''6'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''5'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''4'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''3'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''2'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''1'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''0'''
 
|- style="background-color: #ded;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eee;" | 0
 
| style="border: 1px solid #ccc; padding: 0.2em;" colspan="8" | '''X1'''<span style="color: #777;">&lt;<span style="color: #c00;">7:0</span>&gt;</span>
 
|- style="background-color: #ded;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eee;" | 1
 
| style="border: 1px solid #ccc; padding: 0.2em;" colspan="8" | '''Y1'''<span style="color: #777;">&lt;<span style="color: #c00;">7:0</span>&gt;</span>
 
|- style="background-color: #ded;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eee;" | 2
 
| style="border: 1px solid #ccc; padding: 0.2em;" colspan="2" | '''Y1'''<span style="color: #777;">&lt;<span style="color: #c00;">9:8</span>&gt;</span>
 
| style="border: 1px solid #ccc; padding: 0.2em;" colspan="2" | '''X1'''<span style="color: #777;">&lt;<span style="color: #c00;">9:8</span>&gt;</span>
 
| style="border: 1px solid #ccc; padding: 0.2em;" colspan="2" | '''Y2'''<span style="color: #777;">&lt;<span style="color: #c00;">9:8</span>&gt;</span>
 
| style="border: 1px solid #ccc; padding: 0.2em;" colspan="2" | '''X2'''<span style="color: #777;">&lt;<span style="color: #c00;">9:8</span>&gt;</span>
 
|- style="background-color: #ded;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eee;" | 3
 
| style="border: 1px solid #ccc; padding: 0.2em;" colspan="8" | '''X2'''<span style="color: #777;">&lt;<span style="color: #c00;">7:0</span>&gt;</span>
 
|- style="background-color: #ded;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eee;" | 4
 
| style="border: 1px solid #ccc; padding: 0.2em;" colspan="8" | '''Y2'''<span style="color: #777;">&lt;<span style="color: #c00;">7:0</span>&gt;</span>
 
|}
 
 
 
==== Extended Mode ====
 
In Extended Mode, the IR Camera returns the same data as it does in Basic Mode, plus a rough size value for each object. The data is returned as 12 bytes, three bytes per object. Size has a range of 0-15.
 
 
 
This is the data format for each object:
 
{| style="border-collapse: collapse; padding: 0.2em 0.2em 0.2em 0.2em; text-align: center;"
 
|- style="background-color: #ddd;"
 
| style="background-color: #fff;" | &nbsp;
 
| style="border: 1px solid #ccc; padding: 0.2em; text-align: center;" colspan="8"| '''Bit'''
 
|- style="background-color: #cdc;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #ddd;" | '''Byte'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''7'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''6'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''5'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''4'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''3'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''2'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''1'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''0'''
 
|- style="background-color: #ded;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eee;" | 0
 
| style="border: 1px solid #ccc; padding: 0.2em;" colspan="8" | '''X'''<span style="color: #777;">&lt;<span style="color: #c00;">7:0</span>&gt;</span>
 
|- style="background-color: #ded;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eee;" | 1
 
| style="border: 1px solid #ccc; padding: 0.2em;" colspan="8" | '''Y'''<span style="color: #777;">&lt;<span style="color: #c00;">7:0</span>&gt;</span>
 
|- style="background-color: #ded;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eee;" | 2
 
| style="border: 1px solid #ccc; padding: 0.2em;" colspan="2" | '''Y'''<span style="color: #777;">&lt;<span style="color: #c00;">9:8</span>&gt;</span>
 
| style="border: 1px solid #ccc; padding: 0.2em;" colspan="2" | '''X'''<span style="color: #777;">&lt;<span style="color: #c00;">9:8</span>&gt;</span>
 
| style="border: 1px solid #ccc; padding: 0.2em;" colspan="4" | '''S'''<span style="color: #777;">&lt;<span style="color: #c00;">3:0</span>&gt;</span>
 
|}
 
 
 
==== Full Mode ====
 
In Full Mode, the IR Camera returns even more data, 9 bytes per object for a total of 36 bytes for all four. The data is split up between two input reports of 18 bytes each (see [[#0x3e / 0x3f: Interleaved Core Buttons and Accelerometer with 36 IR bytes | Data Reporting Mode 0x3e/0x3f]]). The first three bytes of each object are the same as the extended mode, and are followed by the bounding box of the pixels included in the blob along with a deeper intensity value.  The data format of each object is:
 
 
 
{| style="border-collapse: collapse; padding: 0.2em 0.2em 0.2em 0.2em; text-align: center;"
 
|- style="background-color: #ddd;"
 
| style="background-color: #fff;" | &nbsp;
 
| style="border: 1px solid #ccc; padding: 0.2em; text-align: center;" colspan="8"| '''Bit'''
 
|- style="background-color: #cdc;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #ddd;" | '''Byte'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''7'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''6'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''5'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''4'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''3'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''2'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''1'''
 
| style="border: 1px solid #ccc; padding: 0.2em; width:2em;" | '''0'''
 
|- style="background-color: #ded;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eee;" | 0
 
| style="border: 1px solid #ccc; padding: 0.2em;" colspan="8" | '''X'''<span style="color: #777;">&lt;<span style="color: #c00;">7:0</span>&gt;</span>
 
|- style="background-color: #ded;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eee;" | 1
 
| style="border: 1px solid #ccc; padding: 0.2em;" colspan="8" | '''Y'''<span style="color: #777;">&lt;<span style="color: #c00;">7:0</span>&gt;</span>
 
|- style="background-color: #ded;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eee;" | 2
 
| style="border: 1px solid #ccc; padding: 0.2em;" colspan="2" | '''Y'''<span style="color: #777;">&lt;<span style="color: #c00;">9:8</span>&gt;</span>
 
| style="border: 1px solid #ccc; padding: 0.2em;" colspan="2" | '''X'''<span style="color: #777;">&lt;<span style="color: #c00;">9:8</span>&gt;</span>
 
| style="border: 1px solid #ccc; padding: 0.2em;" colspan="4" | '''S'''<span style="color: #777;">&lt;<span style="color: #c00;">3:0</span>&gt;</span>
 
|- style="background-color: #ded;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eee;" | 3
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #ddd;" | 0
 
| style="border: 1px solid #ccc; padding: 0.2em;" colspan="7" | '''X min'''<span style="color: #777;">&lt;<span style="color: #c00;">6:0</span>&gt;</span>
 
|- style="background-color: #ded;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eee;" | 4
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #ddd;" | 0
 
| style="border: 1px solid #ccc; padding: 0.2em;" colspan="7" | '''Y min'''<span style="color: #777;">&lt;<span style="color: #c00;">6:0</span>&gt;</span>
 
|- style="background-color: #ded;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eee;" | 5
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #ddd;" | 0
 
| style="border: 1px solid #ccc; padding: 0.2em;" colspan="7" | '''X max'''<span style="color: #777;">&lt;<span style="color: #c00;">6:0</span>&gt;</span>
 
|- style="background-color: #ded;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eee;" | 6
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #ddd;" | 0
 
| style="border: 1px solid #ccc; padding: 0.2em;" colspan="7" | '''Y max'''<span style="color: #777;">&lt;<span style="color: #c00;">6:0</span>&gt;</span>
 
|- style="background-color: #ded;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eee;" | 7
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #ddd;"  colspan="8" | 0
 
|- style="background-color: #ded;"
 
| style="border: 1px solid #ccc; padding: 0.2em; background-color: #eee;" | 8
 
| style="border: 1px solid #ccc; padding: 0.2em;" colspan="8" | '''Intensity'''<span style="color: #777;">&lt;<span style="color: #c00;">7:0</span>&gt;</span>
 
|}
 
  
 
= Feedback Features =
 
= Feedback Features =

Revision as of 18:50, 2 December 2021

Wii remote circuit board, top surface
Wii remote circuit board, bottom surface
This article is a technical guide to the Wii Remote. For a high-level overview of the Wii Remote, see the Wikipedia entry.
Broadcom BCM2042 in a Wii remote

The Wii Remote (informally known as the Wiimote) is the Wii's main input device. It is a wireless device, using standard Bluetooth technology to communicate with the Wii. It is built around a Broadcom BCM2042 bluetooth System-on-a-chip, and contains multiple peripherals that provide data to it, as well as an expansion port for external add-ons. The Wii Remote uses (and, at times, abuses) the standard Bluetooth HID protocol to communicate with the host, which is directly based upon the USB HID standard. As such, it will appear as a standard input device to any Bluetooth host. However, the Wii Remote does not make use of the standard data types and HID descriptor, and only describes its report format length, leaving the actual contents undefined, which makes it useless with standard HID drivers (but some Wiimote Drivers exist). The Wii Remote actually uses a fairly complex set of operations, transmitted through HID Output reports, and returns a number of different data packets through its Input reports, which contain the data from its peripherals.

Summary

Reverse engineering and documenting all of the Wii Remote's features is a work in progress. Here are the known features and their status:

Bluetooth Communication ButtonGreen.png Connecting to the Wii Remote and listening for connections works.
Core Buttons ButtonGreen.png All working.
Accelerometer ButtonGreen.png All working.
IR Camera ButtonGreen.png All working.
Power Button ButtonGreen.png All working.
Speaker ButtonGreen.png All working.
Player LEDs ButtonGreen.png All working.
Status Information ButtonGreen.png Battery and extension info in Status Report
Extension Controllers ButtonYellow.png Official extensions are supported, however many 3rd party extensions are not understood. See Extension Controllers page
Legend ButtonGreen.png Perfect or near-perfect ButtonYellow.png Usable but not complete ButtonRed.png Unusable

Protocol

See /Protocol

EEPROM Memory

Wii Remote Flash.jpg

There is a 128kbit (= 16kB) EEPROM chip (Data Sheet / Full EEPROM dump from a sample Wii Remote) in the Wii Remote. Part of its contents include code for the built-in microcontroller, and a generic section which can be freely read and written by the host. This section is 0x1700 bytes long, and part of this memory is used to store the Mii Data. It can be accessed by reading from/writing to addresses 0x0000-0x16FF in the Wii Remote's virtual memory space; in the actual EEPROM chip, the data is located at 0x0070-0x176F.

The firmware stored in the Wiimote has been disassembled.

The BCM2042 microcontroller built into the Wii Remote includes a large 108kb on-chip ROM section for storing firmware. If the EEPROM chip really contains code for the BCM2042 then this was probably done to make firmware updates possible, so there might be a way of accessing the other parts of the EEPROM via Bluetooth as well. From the BCM2042 Product Brief: "ROM-based design eliminates external flash memories; Flash option offered to support feature development".

On a virgin Wii Remote, acquired separately (not bundled with a Wii), that has never communicated with any device (except the PC used to dump the memory contents), most of the memory is blank (0x00). However, the first few bytes contain some information:

0000:  A1 AA 8B 99 AE 9E 78 30 A7 74 D3 A1 AA 8B 99 AE
0010:  9E 78 30 A7 74 D3 82 82 82 15 9C 9C 9E 38 40 3E
0020:  82 82 82 15 9C 9C 9E 38 40 3E 00 00 00 00 00 00
0030:  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

This can be better visualized as two sequences, each one repeated twice:

0000:  A1 AA 8B 99 AE 9E 78 30 A7 74 D3
000B:  A1 AA 8B 99 AE 9E 78 30 A7 74 D3
0016:  82 82 82 15 9C 9C 9E 38 40 3E
0020:  82 82 82 15 9C 9C 9E 38 40 3E

These are two blocks of calibration data (for redundancy), where the last byte of each is a checksum (all prior bytes plus 0x55). Nintendo's libraries will only use a calibration block if its checksum is correct, falling back to the second one if the first one is incorrect, and falling back to default values otherwise.

The first block contains calibration data related to the IR camera: the position of 4 reference values. Nintendo's code uses this to compute a center offset, scale, and possibly an angle offset. It also looks like the values could appear in any order; code exists to check for values in each quadrant (below and above x=512 and y=384).

  Bit
Byte 7 6 5 4 3 2 1 0
0x00 0x0B X 1<7:0>
0x01 0x0C Y 1<7:0>
0x02 0x0D Y 1<9:8> X 1<9:8> Y 2<9:8> X 2<9:8>
0x03 0x0E X 2<7:0>
0x04 0x0F Y 2<7:0>
0x05 0x10 X 3<7:0>
0x06 0x11 Y 3<7:0>
0x07 0x12 Y 3<9:8> X 3<9:8> Y 4<9:8> X 4<9:8>
0x08 0x13 X 4<7:0>
0x09 0x14 Y 4<7:0>
0x0A 0x15 Checksum

The data given above decodes to (0A1, 2AA), (399, 28B), (39E, 078), (0A7, 030).

Additional examples
  • b4 b8 b8 a0 ad b6 66 30 a5 61 18: (3B4, 2B8), (0A0, 2B8), (3B6, 066), (0A5, 030)
  • 70 5e 03 7b 50 83 9b b8 7a a5 e6: (070, 05E), (37B, 003), (383, 29B), (07A, 2B8)
  • 83 9b 80 7e 50 8a 4c 3b 8d 98 f7: (083, 29B), (07E, 080), (38A, 04C), (38D, 23B)
  • 6f a9 8b 7d ae 78 5d 03 83 67 e5: (06F, 2A9), (37D, 28B), (078, 05D), (383, 003)

The four bytes starting at 0x0016 and 0x0020 store the calibrated zero offsets for the accelerometer (high 8 bits of X,Y,Z in the first three bytes, low 2 bits packed in the fourth byte as --XXYYZZ). The four bytes at 0x001A and 0x24 store the force of gravity on those axes. The byte at 0x1e and 0x28 seems to be unused, but apparently used to contain flags related to the speaker volume and the rumble motor (Nintendo games will print a debug message related to it but do not seem to use the value elsewhere). On all checked remotes, that byte has been 0x40.

  Bit
Byte 7 6 5 4 3 2 1 0
0x16 0x20 0G X Acceleration<9:2>
0x17 0x21 0G Y Acceleration<9:2>
0x18 0x22 0G Z Acceleration<9:2>
0x19 0x23 0 0G X Acc<1:0> 0G Y Acc<1:0> 0G Z Acc<1:0>
0x1A 0x24 1G X Acceleration<9:2>
0x1B 0x25 1G Y Acceleration<9:2>
0x1C 0x26 1G Z Acceleration<9:2>
0x1D 0x27 0 1G X Acc<1:0> 1G Y Acc<1:0> 1G Z Acc<1:0>
0x1E 0x28 Motor Volume
0x1F 0x29 Checksum

At 0x16D0, there is some more unknown data:

16D0:  00 00 00 FF 11 EE 00 00 33 CC 44 BB 00 00 66 99
16E0:  77 88 00 00 2B 01 E8 13 00 00 00 00 00 00 00 00
16F0:  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

In contrast to the data at 0x0000, this data seems to differ in only a few bytes between different Wii Remotes.

The "User Data" section appears to start with a 0x38-byte header, repeated twice (so 0x70 bytes total). The header starts with an 8-byte timestamp (from TBL and TBU; 1/60750000ths of a second since January 1 2000). That is followed by a 34-byte (17 characters, or 16 excluding the null terminator) Unicode name (which does not necessarily match the game's name), followed by the 4-byte game ID, then the application type (the value at 0x80003184). Then there is a checksum (at 0x2f), which is the sum of bytes 0 through 0x2e plus 0x55. Bytes 0x30 through 0x37 do not seem to be used and were all 0.

Known memory ranges are listed below.

Start End Length Initial Value Use
0x0000 0x0029 0x002A See above Calibration values / pre-set data
0x002A 0x0FC9 0x0FA0 Zeroed User data / Unknown uses
0x0FCA 0x12B9 0x02f0 Zeroed Mii Data block 1
0x12BA 0x15A9 0x02f0 Zeroed Mii Data block 2
0x15AA 0x16CF 0x0126 Zeroed Unknown / Unused
0x16D0 0x16FF 0x0030 See above Unknown data

The top byte of the address is unused, which means memory is mirrored every 0x10000 bytes. Reading from unused addresses where the low 16 bits are >= 0x1700 will result in error returns.

Control Registers

The Wii Remote has several memory mapped register spaces corresponding to different peripherals in it. These include the Speaker, Extension Controllers, and the IR Camera.

Reminder
Remember to set bit 2 (0x04) on the first byte of the Output Report, otherwise you'll overwrite EEPROM memory!

The peripheral to access is selected by the first byte of the address, and the lower 16 bits specify the register to access within that peripheral. The lowest bit of the high byte is ignored, which means every peripheral is mirrored at its address + 0x10000. Known peripherals are listed below:

Start End Use
0xA20000 0xA20009 Speaker settings
0xA40000 0xA400FF Extension Controller settings and data
0xA60000 0xA600FF Wii Motion Plus settings and data
0xB00000 0xB00033 IR Camera settings

Most of these are also mirrored across the high bits of the individual peripheral. For example, the second byte of the address is ignored in the Extension controller address, which means any address of the form 0xA4xx00 will work (as will 0xA5xx00).

Input features

See /Input features.

Feedback Features

The Wii Remote sports three feedback features: Player LEDs, Rumble, and the Speaker.

Player LEDs

Wii remote player LEDs

There are four blue LEDs on the front face of the Wii Remote. During discovery and before initialization, these LEDs blink at a fixed rate. The number of blinking LEDs is proportional to the battery voltage, indicating battery charge (all four are lit for newly charged batteries, and only the first is lit if the batteries are low and should be replaced).

During gameplay with the Wii, one LED is lit to indicate the player number assigned to the Wii Remote. However, the LEDs are independently controllable by the host, and can be set to display any pattern. They can also be modulated at a moderately high speed, enabling some brightness control at the cost of a lot of Bluetooth bandwidth. Sigma-delta modulation works reasonably well for this.

The LEDs can be controlled by sending a report with ID 0x11:

(a2) 11 LL

The high nybble of LL controls the four LEDs. Bit 4 of LL controls the first LED, and bit 7 controls the last:

Bit Mask LEDs
4 0x10
·
··
···
····
5 0x20
·
··
···
····
6 0x40
·
··
···
····
7 0x80
·
··
···
····

Turning off all LEDs for an extended period of time is discouraged, as it might lead the user to believe the Wii Remote is turned off and disconnected, when in fact it is active.

The LEDs are surface mount parts, driven at 2.66 VDC.

Rumble

Wii remote rumble motor

The Wii Remote includes a rumble feature, which is implemented as a small motor attached to an off-center weight. It will cause the controller to vibrate when activated.

The rumble motor is primarilly controlled via the report with ID 0x10:

(a2) 10 RR

Setting RR to 1 enables rumble, and setting it to 0 disables rumble. However, note that the rumble motor can be turned on or off through any of the Output Reports, not just 0x10. Setting the LSB (bit 0) of the first byte of any output report will activate the rumble motor, and unsetting it will deactivate it. For example, the following report will turn the rumble motor on:

(a2) 11 01

However, this will also have the side-effect of turning off all LEDs. The rumble bit needs to be set properly with every single report sent, to avoid inadvertently turning the rumble motor off.

Different photos of the rumble motor hardware show different markings. One example is SEM 8728DA. The Wii Remote drives it at 3.3 VDC and it draws 35 mA. It would be reasonable to think that the rumble motor could be removed and the motor replaced with another device with equal voltage and equal or less current draw.

Speaker

The Wii Remote has a small low-quality 21mm piezo-electric speaker, used for short sound effects during gameplay. The sound is streamed directly from the host, and the speaker has some adjustable parameters.

The speaker is controlled by using three output reports, together with a section of the register address space of the Wii Remote.

Report 0x14 is used to enable or disable the speaker. Setting bit 2 will enable the speaker, and clearing it will disable it. For example, to enable the speaker, send:

(a2) 14 04

Report 0x19 is used to mute or unmute the speaker, and works identically to report 0x14. 0x04 will mute the speaker, and 0x00 will unmute it.

Report 0x18 is used to send speaker data. 1-20 bytes may be sent at once:

(a2) 18 LL DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD

LL specifies the data length, shifted left by three bits. The DD bytes are the speaker data. To fullfill the report length requirements, the data must be padded if it is less than 20 bytes long. Sound data must be sent at the proper rate.

Initialization Sequence

Reminder
Remember to set bit 2 (0x04) on the first byte of the Output Reports to write to registers!

The following sequence will initialize the speaker:

  1. Enable speaker (Send 0x04 to Output Report 0x14)
  2. Mute speaker (Send 0x04 to Output Report 0x19)
  3. Write 0x01 to register 0xa20009
  4. Write 0x08 to register 0xa20001
  5. Write 7-byte configuration to registers 0xa20001-0xa20008
  6. Write 0x01 to register 0xa20008
  7. Unmute speaker (Send 0x00 to Output Report 0x19)

Speaker Configuration

7 bytes control the speaker settings, including volume. The full purpose of these bytes is not known, but the following values seem to produce some sound:

00 FF RR RR VV 00 00

RR RR specify the sample rate (little-endian format), using the following formulae:

pcm_sample_rate = 12000000 / rate_value adpcm_sample_rate = 6000000 / rate_value

The standard value is 0x7d0, for 3000Hz 4-bit PCM

FF configures the data format. Setting it to 0x40 configures the speaker to use signed 8-bit PCM, while setting it to 0x00 configures it to use 4-bit Yamaha ADPCM. VV specifies the volume, which has a range of 0x00-0xFF for 8-bit mode, and 0x00-0x40 for 4-bit mode.

This configuration can be used to play 4-bit ADPCM sound at 3000Hz:

00 00 D0 07 40 00 00

This configuration can be used to play 8-bit PCM sound at 1500Hz sample rate:

00 40 40 1f 40 00 00

It looks like the best compromise between sample rate and slow bluetooth chipsets / drivers is playing 8-bit PCM at 2000Hz, so a new 20-byte chunk of audio data is sent every 10 milliseconds.

00 40 70 17 60 00 00

Sound Data Format

The Wii Remote can use multiple sound formats at multiple sampling rates. PC drivers currently seem unable to keep up with the higher rates.

The 4-bit ADPCM is Yamaha ADPCM (for example, as implemented in ffmpeg).

8-bit signed PCM mode works, but when in 8-bit mode the sampling frequency must be made so low that the audio quality is pretty bad.

Extension Controllers

Wiimote/Extension Controllers

Notes

See Also

Acknowledgements

Some of the information here is based on the documentation at Wiili