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].
0x0002.... SetLcdPowerState. This writes the upper LCD bits of MCU register 0x22.
0x0003000 GetGpuLcdInterfaceState. This writes the value of I2C-MCU register 0xf bit7 to u8 cmdreply[2].
0x0004.... 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
0x000D.... GetMcuGpuEvent
0x000E.... ?

MCU HID service "mcu::HID"

Command Header Description
0x00010000 ?
0x0002.... ?
0x0003.... ?
0x0004.... ?
0x0005.... ?
0x0006.... ?
0x0007.... Get3dSliderState
0x0008.... ?
0x00090000 ?
0x000A0000 ?
0x000B.... ?
0x000C.... GetMcuHidEvent
0x000D0000 ?
0x000E0000 GetSoundVolume

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.... GetMcuRtcEvent
0x0025.... ?
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)
0x004E.... PublishHidNotifications
0x004F.... Sets some flag (otherwise set when uploading MCU firmware)
0x0050.... Returns the above flag
0x0051.... SetLegacyPoweroff
0x00520000 IsLegacyPoweroff
0x0053.... ?
0x0054.... ?
0x0055.... ?
0x0056.... ?
0x0057.... ?
0x0058.... ?
0x0059.... SetLegacyJumpProhibitedFlag
0x005A.... 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). For the bitmasks controlling these LEDs, bit clear = LED enable, bit set = LED disable? These notification LEDs(red LED, green LED, blue LED, ...) can only be enabled/disabled, nothing more.

MCU sound service "mcu::SND"

Command Header Description
0x0001.... GetSoundVolume
0x0002.... ?
0x0003.... ?

MCU wifi service "mcu::NWM"

Command Header Description
0x0001.... SetWiFiLedState
0x0002.... GetWiFiLedState
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.... Sets a FIRM WiFi-state-related flag?
0x0008.... Gets the above flag

MCU service "mcu::HWC"

Command Header Description
0x0001.... GetMcuRegister? Seems to read an arbitrary register (by parameter)
0x0002.... SetMcuRegister?
0x0003.... ?
0x0004.... ?
0x0005.... GetBatteryLevel
0x0006.... ?
0x0007.... ?
0x0008.... ?
0x0009.... Set3dLedState
0x000A0640 This is the same as MCURTC:SetInfoLEDPattern.
0x000B.... GetSoundVolume
0x000C.... ?
0x000D.... ?
0x000E.... ?
0x000F.... GetRtcTime
0x0010.... GetMcuFwVerHigh
0x0011.... GetMcuFwVerLow

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?)

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.

Title version Firmware
New3DS v8192/safe v9217 (latest) 19.56
Old3DS v6145 to v8192 (latest) 18.37
Old3DS v5122 18.35
Old3DS v4102 18.30
Old3DS v2048 17.52
Old3DS safe v0 17.20
Old3DS factory 17.07