Only one session can be open per service at a time. If a session is already open for a service, MCU module will wait for the thread handling the session to terminate(triggered by the session being closed by the user process), then it accepts the new session. The commands for each service are handled by separate threads.
MCU camera service "mcu::CAM"
Command Header
|
Description
|
0x0001....
|
?
|
0x0002....
|
?
|
MCU GPU service "mcu::GPU"
Command Header
|
Description
|
0x00010000
|
GetLcdPowerState. This writes the value of I2C-MCU register 0xf bit6 to u8 cmdreply[2], and the value of bit5 from that register to u8 cmdreply[3].
|
0x00020080
|
SetLcdPowerState. This writes the upper LCD bits of MCU register 0x22.
|
0x00030000
|
GetGpuLcdInterfaceState. This writes the value of I2C-MCU register 0xf bit7 to u8 cmdreply[2].
|
0x00040040
|
SetGpuLcdInterfaceState. This writes the lower two bits of MCU register 0x22.
|
0x0005....
|
?
|
0x0006....
|
?
|
0x0007....
|
?
|
0x0008....
|
?
|
0x00090000
|
GetMcuFwVerHigh. Called by GSP module
|
0x000A0000
|
GetMcuFwVerLow. Called by GSP module
|
0x000B....
|
Set3dLedState
|
0x000C....
|
Get3dLedState
|
0x000D0000
|
GetMcuGpuEventHandle. Event handle written to TLS+0x8c. MCU notifications 24 to 29 signal this.
|
0x000E0000
|
GetMcuGpuEventReason. Writes some value to TLS+0x88. Called by GSP module
|
MCU HID service "mcu::HID"
Command Header
|
Description
|
0x00010000
|
? (observed command header 0x00010040)
|
0x0002....
|
?
|
0x0003....
|
?
|
0x0004....
|
?
|
0x0005....
|
?
|
0x0006....
|
?
|
0x00070000
|
Get3dSliderState
|
0x0008....
|
?
|
0x00090000
|
?
|
0x000A0000
|
?
|
0x000B....
|
?
|
0x000C0000
|
GetMcuHidEventHandle. MCU notifications 11 and 12 signal this.
|
0x000D0000
|
GetMcuHidEventReason
|
0x000E0000
|
GetSoundVolume
|
0x000F0040
|
SetAccelerometerState(int enable). 1 = enable, 0 = disable accelerometer
|
MCU service "mcu::RTC"
Command Header
|
Description
|
0x0001....
|
SetSystemClock (RTC)
|
0x0002....
|
GetSystemClock (RTC)
|
0x0003....
|
?
|
0x0004....
|
?
|
0x0005....
|
?
|
0x0006....
|
?
|
0x0007....
|
?
|
0x0008....
|
?
|
0x0009....
|
?
|
0x000A....
|
?
|
0x000B....
|
?
|
0x000C....
|
?
|
0x000D....
|
?
|
0x000E....
|
?
|
0x000F....
|
?
|
0x0010....
|
?
|
0x0011....
|
?
|
0x0012....
|
?
|
0x0013....
|
?
|
0x0014....
|
?
|
0x0015....
|
?
|
0x0016....
|
?
|
0x0017....
|
?
|
0x0018....
|
?
|
0x0019....
|
?
|
0x001A....
|
?
|
0x001B....
|
?
|
0x001C....
|
?
|
0x001D....
|
?
|
0x001E....
|
?
|
0x001F0040
|
SetPedometerRecordingMode
|
0x00200000
|
GetPedometerState
|
0x0021....
|
?
|
0x0022....
|
?
|
0x0023....
|
?
|
0x0024....
|
GetMcuRtcEventHandle. MCU notifications 1, 8, 9, 10, 13, 14 and 15 signal this.
|
0x0025....
|
GetMcuRtcEventReason
|
0x0026....
|
?
|
0x0027....
|
?
|
0x0028....
|
?
|
0x0029....
|
?
|
0x002A0000
|
GetShellState. This writes the value of I2C-MCU register 0xf bit1 to u8 cmdreply[2].
|
0x002B0000
|
GetAdapterState. This writes the value of I2C-MCU register 0xf bit3 to u8 cmdreply[2].
|
0x002C0000
|
GetBatteryChargeState. This writes the value of I2C-MCU register 0xf bit4 to u8 cmdreply[2].
|
0x002D0000
|
GetBatteryLevel
|
0x002E....
|
?
|
0x002F....
|
?
|
0x0030....
|
?
|
0x0031....
|
?
|
0x0032....
|
PowerOff (writes 0x1 to i2c MCU device, reg 0x20)
|
0x0033....
|
HardwareReboot (writes 0x4 to i2c MCU device, reg 0x20)
|
0x0034....
|
?
|
0x0035....
|
Writes 0x10 to i2c MCU device, reg 0x20
|
0x0036....
|
SetWatchdogTimer
|
0x0037....
|
GetWatchdogTimer
|
0x0038....
|
?
|
0x0039....
|
?
|
0x003A....
|
?
|
0x003B0640
|
SetInfoLEDPattern
|
0x003C0040
|
SetInfoLEDPatternHeader
|
0x003D0000
|
GetInfoLEDStatus
|
0x003E....
|
?
|
0x003F....
|
?
|
0x0040....
|
?
|
0x0041....
|
?
|
0x00420040
|
SetBatteryEmptyLEDPattern
|
0x0043....
|
?
|
0x0044....
|
?
|
0x0045....
|
?
|
0x0046....
|
?
|
0x0047....
|
?
|
0x0048....
|
?
|
0x0049....
|
?
|
0x004A....
|
?
|
0x004B....
|
?
|
0x004C....
|
?
|
0x004D....
|
ReadHidFlagRegister (reads i2c MCU device, reg 0x10)
|
0x004E0040
|
PublishNotifications
|
0x004F....
|
Sets some flag (otherwise set when uploading MCU firmware)
|
0x0050....
|
Returns the above flag
|
0x00510040
|
SetSoftwareClosedFlag
|
0x00520000
|
GetSoftwareClosedFlag
|
0x0053....
|
?
|
0x0054....
|
?
|
0x0055....
|
?
|
0x0056....
|
?
|
0x0057....
|
?
|
0x0058....
|
?
|
0x00590040
|
SetLegacyJumpProhibitedFlag
|
0x005A0000
|
GetLegacyJumpProhibitedFlag
|
Note that using invalid input with these InfoLED/SetBatteryEmptyLEDPattern commands(especially SetInfoLEDPattern) can cause the system to be bricked(however the boot failure may not begin immediately after using the invalid parameters).
MCU sound service "mcu::SND"
Command Header
|
Description
|
0x0001....
|
GetSoundVolume
|
0x0002....
|
?
|
0x0003....
|
?
|
MCU wifi service "mcu::NWM"
Command Header
|
Description
|
0x0001....
|
SetWirelessLedState
|
0x0002....
|
GetWirelessLedState
|
0x0003....
|
Sets GPIO 0x20 high/low?
|
0x0004....
|
Gets GPIO 0x20 high/low?
|
0x0005....
|
Sets GPIO 0x40000 high/low?
|
0x0006....
|
Gets GPIO 0x40000 high/low?
|
0x0007....
|
SetWirelessDisabledFlag
|
0x0008....
|
GetWirelessDisabledFlag
|
MCU service "mcu::HWC"MCU service "mcu::PLS"
RTC-related? Each of these seems to retrieve a second counter from a different RTC register.
Command Header
|
Description
|
0x0001....
|
?
|
0x0002....
|
?
|
0x0003....
|
?
|
0x0004....
|
?
|
0x0005....
|
?
|
0x0006....
|
?
|
0x0007....
|
?
|
0x0008....
|
?
|
0x0009....
|
?
|
MCU codec service "mcu::CDC"
Command Header
|
Description
|
0x00010000
|
?
|
New3DS
The Old3DS/New3DS MCU sysmodules are identical except that the MCU firmware binary written via I2C is different. The size of that binary is the same. The only different words in .text are for the version of that MCU fw binary.
MCU firmware versions
These reside in mcu-module .rodata, are uploaded to MCU register 0x05 and are usually size 0x4003 bytes. (0x4000 bytes with 3 byte magic "jhl"?)
There exists an alternate code path where uploading is done using register 0x3B (decided by making some nonsense conclusions about registers 0x0F and 0x10). This may be a "hack" around early versions of MCU? Register 0x3B is RTC-related on recent versions of MCU, and the "nonsense" condition is not met even on factory MCU firmware.
On dev-units, the user-facing representation of this firmware version is displayed by first subtracting 0x10 from the major field (raw register 0x00). It is these user-facing versions that are displayed in the table below. It is unknown what bit4 (0x10) actually represents, but it is seemingly always set.
Title version
|
Firmware
|
New3DS v8192/safe v9217 (latest)
|
3.56
|
Old3DS v6145 to v8192 (latest)
|
2.37
|
Old3DS v5122
|
2.35
|
Old3DS v4102
|
2.30
|
Old3DS v3072
|
2.16
|
Old3DS v2048
|
1.52
|
Old3DS v1026
|
1.51
|
Old3DS v0/safe v0
|
1.20
|
Old3DS factory
|
1.07
|