Table of Contents
UIC
The UIC is the gamepad's auxiliary microcontroller. It is connected to the CPU over the SPI bus.
Given the characteristics, the UIC could be a STM8L151R8. It has 4KB of RAM, 2KB of EEPROM and 64KB of FLASH.
Pinout
Pin | Name | Function |
---|---|---|
1 | PA0 | SWIM pin |
2 | PA1/NRST | Reset |
3 | PA2 | DPAD right |
4 | PA3 | DPAD left |
5 | PA4 | DPAD down |
6 | PA5 | Left joystick Y |
7 | PA6 | Left joystick X |
8 | PA7 | Right joystick button |
9 | GNDA/Vref- | Analog ground and ADC negative reference |
10 | GND1 | Ground |
11 | Vcc1 | Supply voltage |
12 | VccA | Analog supply voltage |
13 | Vref+ | ADC positive reference |
14 | PG0 | DPAD up |
15 | PG1 | xx |
16 | PG2 | xx |
17 | PG3 | xx |
18 | (res.) | xx |
19 | PE0 | xx |
20 | PE1 | xx |
21 | PE2 | Red LED |
22 | PE3 | Button ZL |
23 | PE4 | Button L |
24 | PE5 | Sync button |
25 | PD0 | Button ZR |
26 | PD1 | Button R |
27 | PD2 | xx |
28 | PD3 | xx |
29 | Vcc3 | Supply voltage |
30 | GND3 | Ground |
31 | PB0 | xx |
32 | PB1 | xx |
33 | PB2 | Amber LED |
34 | PB3 | xx |
35 | PB4 | SPI - UIC chipselect |
36 | PB5 | SPI - clock |
37 | PB6 | SPI - MOSI |
38 | PB7 | SPI - MISO |
39 | PF0 | xx |
40 | PF1 | xx |
41 | PF4 | xx |
42 | PF5 | xx |
43 | PF6 | Button A |
44 | PF7 | Button B |
45 | PD4 | Button X |
46 | PD5 | Button Y |
47 | PD6 | Right joystick X |
48 | PD7 | Right joystick Y |
49 | PG4 | xx |
50 | PG5 | xx |
51 | PG6 | xx |
52 | PG7 | xx |
53 | PC0 | UIC I2C - SDA |
54 | PC1 | UIC I2C - SCL |
55 | Vcc2 | Supply voltage |
56 | GND2 | Ground |
57 | PC2 | Button + |
58 | PC3 | Button - |
59 | PC4 | HOME button |
60 | PC5 | TV button |
61 | PC6 | Left joystick button |
62 | PC7 | xx |
63 | PE6 | Blue LED (?) |
64 | PE7 | Power button (active low) |
Pins 1 and 2 are connected to test points TP233 and TP234 respectively. Pin 1 doesn't seem to be connected to anything else. Pin 2 is connected to a simple reset circuit.
Pin 1 would be the SWIM debug pin, but as far as I've seen, SWIM seems to be entirely disabled on the UIC.
Bootloader command list
Bootloader commands must be sent in two bytes, where the second byte is the first byte negated. Additionally, the read/write commands have basic integrity checks on the input data.
The only exception is command 0x7F.
Bootloader commands only apply when the UIC is in firmware upload mode (ie when no firmware is installed). In this mode, it is required to send command 0x7F before the other commands become available.
Command | Parameters | Response bytes | Description |
---|---|---|---|
0x00 0xFF | 0 | 1 | Get version and supported commands |
0x11 0xEE | 5+1 | 1+1+N+1 | Read memory |
0x21 0xDE | 0 | 1 | Finalize firmware upload |
0x31 0xCE | 5+1+N | 1+1+1 | Write memory |
0x7F | 0 | 1 | Get firmware type |
The command set is based on the official STM8 bootloader command set, with a few differences:
- The data returned by command 00 FF is wrong
- Command 21 DE does not take an address
- Command 11 EE is limited to 128 bytes
- There is no memory erase command
Command 00 FF
Get bootloader version and supported commands.
Response is 8 bytes: 0x79, 0x05, 0x10, 0x00, 0x11, 0x21, 0x31, 0x43.
The first byte is the bootloader's standard 'OK' code. The latter 7 bytes are hardcoded.
The second byte is the number of command bytes. The third byte is the bootloader version. The subsequent bytes theoretically list the supported commands. In practice, the list advertises command 0x43, but it isn't supported.
This command doesn't seem to do much beyond returning a fixed response, so it probably just serves to ensure the UIC is ready for a firmware upload. On the gamepad, the host ignores the response bytes.
Command 11 EE
Read memory.
First set of parameters: 5 bytes, AA BB CC DD EE
- AA = address bit 24-31
- BB = address bit 16-23
- CC = address bit 8-15
- DD = address bit 0-7
- EE = AA^BB^CC^DD
A response is sent after the first set of parameters: 0x79 = OK, 0x1F = error (incorrect parameters).
Second parameter: one byte, length of data to read. Maximum length allowed is 128.
A second response is sent after this second parameter byte, with same values as the first response.
If the second response is 0x79, it is followed by the requested data.
Command 21 DE
Finalize firmware upload.
Response is one byte: 0x51.
This command writes the bytes 0xA5 0x5A at address 0x1010, to indicate that a firmware is installed. Then the UIC is reset.
Command 31 CE
Write memory.
First set of parameters: 5 bytes, AA BB CC DD EE
- AA = address bit 24-31
- BB = address bit 16-23
- CC = address bit 8-15
- DD = address bit 0-7
- EE = AA^BB^CC^DD
A response is sent after the first set of parameters: 0x79 = OK, 0x1F = error (incorrect parameters).
Second parameter: one byte, length of data to write. Maximum length allowed is 128.
A second response is sent after this second parameter byte, with same values as the first response.
Then the data to be written is sent, followed by one checksum byte. The checksum is the data length XORed to each data byte.
A third response byte is sent: if the integrity check passes and the data is successfully written, the response is 0x79, otherwise it is 0x1F.
This command is used to upload firmware data to the UIC's FLASH memory.
Command 7F
In firmware upload mode, command 0x7F returns 0x79.
Command list
Command | Parameters | Response bytes | Description |
---|---|---|---|
0x01 | 1 | 0 | set UIC state |
0x02 | 3+N | 0 | write UIC memory |
0x03 | 3 | N | read UIC memory |
0x04 | 0 | 0 | EEPROM write disable |
0x05 | 0 | 1 | query UIC state |
0x06 | 0 | 0 | EEPROM write enable |
0x07 | 0 | 128 | query input data |
0x08 | 2 | 0 | ? |
0x09 | 1 | 0 | begin firmware update |
0x0A | 0 | 6 | ? |
0x0B | 0 | 4 | get UIC firmware version |
0x0C | 102 | 0 | ? |
0x0D | 1 | 0 | ? |
0x0E | 1 | 0 | ? |
0x0F | 0 | 2 | ? |
0x10 | 0 | 1 | ? |
0x11 | 1 | 0 | ? |
0x12 | 1 | 0 | toggle backlight |
0x13 | 0 | 1 | ? |
0x14 | 0 | 0 | ? |
0x15 | 0 | 0 | reboot |
0x16 | ? | ? | ? |
0x17 | 1 | 0 | ? |
0x18 | 0 | 1 | ? |
0x19 | 255 | 0 | ? |
0x1A | 0 | 255 | ? |
0x1B | 4 | 0 | ? |
0x1C | 0 | 4 | ? |
0x7F | 0 | 1 | get UIC firmware ID/type |
Command 01
Set UIC state.
Parameter: one byte, the UIC state to switch to.
There are restrictions on which state you can switch to based on the current state, see UIC states to see which transitions are possible.
Command 02
Write UIC memory. Used to write to the EEPROM.
Parameters: AA BB CC
- AA = address bit8-15
- BB = address bit0-7
- CC = length
Followed by CC bytes of data.
After sending the parameter bytes, the host should wait atleast 60 microseconds before sending the data. Sending the data too early can cause the UIC-side DMA to malfunction.
Address must be within range 0x1100..0x17FF.
Before using this command, the EEPROM must be unlocked for writing via command 0x06. After all data is written, command 0x04 must be used to commit the changes to EEPROM. Command 0x02 may be invoked multiple times in a row.
Internally, this command redirects the provided address to RAM at 0x01B7. Command 0x04 does write back RAM data to EEPROM.
Command 03
Read UIC memory. Used to read the EEPROM.
Parameters: AA BB CC
- AA = address bit8-15
- BB = address bit0-7
- CC = length
Response is CC bytes of data.
Address must be within range 0x1100..0x17FF.
Internally, this command redirects the provided address to RAM at 0x01B7, where a copy of the EEPROM data is kept.
Command 04
EEPROM write disable. Commits EEPROM writes. Should be invoked after writing to EEPROM.
After invoking this command, the host should wait atleast 140 milliseconds before sending further UIC commands.
Command 05
Query the current UIC state.
Response is one byte: the current UIC state.
The UIC starts in state 11.
Command 06
EEPROM write enable. Should be invoked before writing to EEPROM.
Command 07
Query input data.
Response:
Offset | Length | Desc. |
---|---|---|
0x00 | 2 | Sequence ID? |
0x02 | 2 | Button bitmask |
0x04 | 1 | Power status |
0x05 | 1 | Battery charge |
0x06 | 2 | Left stick X |
0x08 | 2 | Left stick Y |
0x0A | 2 | Right stick X |
0x0C | 2 | Right stick Y |
0x0E | 1 | Audio volume |
0x0F | 2 | Accelerometer X (signed) |
0x11 | 2 | Accelerometer Y (signed) |
0x13 | 2 | Accelerometer Z (signed) |
0x15 | 3 | Gyroscope roll (signed) |
0x18 | 3 | Gyroscope yaw (signed) |
0x1B | 3 | Gyroscope pitch (signed) |
0x1E | 6 | Magnet data (unknown) |
0x24 | 40 | Touchscreen data (10 samples) |
0x4C | 4 | ??? |
0x50 | 1 | Extra button bitmask |
0x51 | 46 | ??? |
0x7F | 1 | Firmware version negated |
Button bitmask:
Bit | Desc. |
---|---|
0 | Down |
1 | Up |
2 | Right |
3 | Left |
4 | Y |
5 | X |
6 | B |
7 | A |
8 | Sync |
9 | Home |
10 | Minus |
11 | Plus |
12 | R |
13 | L |
14 | ZR |
15 | ZL |
Power status:
Bit | Desc. |
---|---|
0 | AC plugged in |
1 | Power button pressed |
6 | Charging |
7 | “POWER_USB” - presumably, expansion device present |
Extra button bitmask:
Bit | Desc. |
---|---|
5 | TV |
6 | R3 |
7 | L3 |
Touchscreen data:
Each sample is 4 bytes long: 2 bytes for the X coordinate, 2 bytes for the Y coordinate. The X and Y coordinates take up 12 bits.
The remaining bits are used to store a touchscreen pressure reading. See the libdrc page on input data for more information.
Command 09
Begin firmware update. After this command is sent, command 0x7F will return 0x79, and the UIC will be ready to accept a firmware upload.
WARNING: the UIC remembers the 'waiting for firmware update' state even after a full power-off.
Parameter: unknown, set to zero.
Command 12
Toggle backlight.
Parameter: 0x00=off, 0x01=on.
Command 13
Returns some status bit.
This commands reads the value at 0x0006 in RAM, and returns bit 1 of that value. Not sure what the value means, but it seems tied to the blue power LED, so it is likely related to the power management system.
The stock gamepad firmware waits for the return value from this command to become 1 before doing wifi initialization, so this is likely related to wifi power too. Not waiting for it to become 1 before doing wifi init will cause the wifi hardware to stop functioning when it becomes 1.
Response: one byte, 0 or 1.
Command 15
Reboot the gamepad.
Command 7F
Query firmware ID/version.
Response: 0x2F or 0x3F when a firmware is installed. 0x79 when a firmware needs to be uploaded.
Firmware upload
WARNING: the following is theoretical and has not yet been successfully replicated so far. A firmware upload gone wrong can and will brick the UIC.
The process to upload a new UIC firmware is as follows:
- Send command 0x7F to identify the currently installed firmware
- If command 0x7F returned 0x2F or 0x3F: send command 0x09 to switch to firmware update mode. Check with command 0x7F until it is effective.
- Send bytes 0x00, 0xFF. Receive 0x79. (1)
- Receive 7 bytes.
Then you are ready to upload the firmware data, in chunks of 128 bytes maximum. For each chunk:
- Send bytes 0x31, 0xCE. Receive 0x79.
- Send bytes AA, BB, CC, DD, EE (where AA=address bits 24-31, BB=address bits 16-23, CC=address bits 8-15, DD=address bits 0-7, EE=AA^BB^CC^DD). Receive 0x79. (2)
- Send byte AA (where AA=length of this chunk). Receive 0x79.
- Send each data byte, then a trailing byte AA (where AA=length of this chunk XORed to each data byte). Receive 0x79.
When all chunks are uploaded, send a final command:
- Send bytes 0x21, 0xDE. Receive 0x51. (3)
- Your new UIC firmware is now up and running!
(1): Each “send, receive” line is understood as one single SPI transaction. “Receive 0x79” means to keep receiving bytes until receiving a nonzero value. A value of 0x79 indicates success. In the stock firmware code, under some circumstances, another value will prompt retry attempts, while under other circumstances it will be an outright failure case.
(2): The address is in UIC memory space. The UIC firmware upload starts at address 0x9000.
(3): “Receive 0x51” means to keep receiving bytes until receiving a value that isn't 0x79. A value of 0x51 indicates success.
UIC states
The UIC has 15 possible states. The state determines what it will do, for example, input polling is only done in certain states.
State | Internal name | Description |
---|---|---|
0 | active | Default active state |
1 | wiiactive | vWii mode state |
2 | background | ? |
3 | Sleep mode | |
4 | Alternate sleep mode (used if EEPROM data is invalid) | |
5 | pairing | Pairing to WiiU |
6 | fwupdate | Related to firmware update |
7 | Debug – causes bootloader to load diagnostics firmware | |
8 | ? | |
9 | ? | |
10 | ? | |
11 | wowlsetting | Idle state the gamepad is booted in |
12 | dksetting | ? |
13 | ? | |
14 | subactive | ? |
The current UIC state can be retrieved with command 0x05, and changed with command 0x01. The following table shows which state transitions are allowed:
New state → | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
↓ Current state | |||||||||||||||
0 | X | X | X | X | X | X | X | X | X | X | |||||
1 | X | X | X | X | X | X | X | ||||||||
2 | X | X | X | X | X | X | X | X | X | X | |||||
3 | X | X | X | X | X | X | X | X | |||||||
4 | X | X | X | X | X | X | X | ||||||||
5 | X | X | X | X | X | X | X | ||||||||
6 | X | X | X | X | X | X | X | ||||||||
7 | X | X | X | X | |||||||||||
8 | X | X | |||||||||||||
9 | X | X | X | X | X | X | X | X | X | X | |||||
10 | X | ||||||||||||||
11 | X | X | X | X | X | ||||||||||
12 | X | X | X | X | X | X | X | X | X | X | X | X | X | ||
13 | |||||||||||||||
14 | X | X | X | X | X | X | X | X | X | X |
An X denotes an allowed state transition. For example, if the UIC is in state 0, you may switch to state 1, but not to state 2.
When powering on the gamepad, the UIC starts in state 11, which is an idle state (where, among other things, no input polling is done). Switching to states 3 or 4 puts the gamepad in sleep mode. Pressing the power button turns the gamepad on again, but this time the UIC is in state 0 and ready to go.
TODO: work out and document what the various states do. Also, maybe different EEPROM parameters start the UIC in a different state?
States 3 and 4 may not work correctly under certain conditions, like if the backlight is on.
Expansion port
The gamepad's expansion port is connected to the UIC's I2C BUS. It hasn't been used by any retail device, however it is used by Nintendo for diagnostics purposes.
The diagnostics firmware contains a test named “CHECK USB JIG PULLED OUT”, which implies that Nintendo's device is a USB adapter of sorts.
To further prove this, the “POWER_USB” bit in the power status bitmask (in the command 0x07 input data structure) is set or cleared after attempting to probe device 0x48 on the I2C bus.
It isn't clear whether the USB jig serves to transfer data to/from the gamepad somehow, or whether its sole purpose is to activate the diagnostics mode. The retail UIC firmware doesn't appear to contain any functions for interacting with an expansion device beyond the aforementioned probing.