|Yes||I2C1_DATA||0x10161000||1||I2C bus 1 devices|
|Yes||I2C1_CNT||0x10161001||1||I2C bus 1 devices|
|Yes||I2C1_CNTEX||0x10161002||2||I2C bus 1 devices|
|Yes||I2C1_SCL||0x10161004||2||I2C bus 1 devices|
|Yes||I2C2_DATA||0x10144000||1||I2C bus 2 devices|
|Yes||I2C2_CNT||0x10144001||1||I2C bus 2 devices|
|Yes||I2C2_CNTEX||0x10144002||2||I2C bus 2 devices|
|Yes||I2C2_SCL||0x10144004||2||I2C bus 2 devices|
|Yes||I2C3_DATA||0x10148000||1||I2C bus 3 devices|
|Yes||I2C3_CNT||0x10148001||1||I2C bus 3 devices|
|Yes||I2C3_CNTEX||0x10148002||2||I2C bus 3 devices|
|Yes||I2C3_SCL||0x10148004||2||I2C bus 3 devices|
|0||Stop (0=No, 1=Stop/last byte)|
|1||Start (0=No, 1=Start/first byte)|
|2||Pause (0=Transfer Data, 1=Pause after Error, used with/after Stop)|
|4||Ack Flag (0=Error, 1=Okay) (For DataRead: W, for DataWrite: R)|
|5||Data Direction (0=Write, 1=Read)|
|6||Interrupt Enable (0=Disable, 1=Enable)|
|7||Start/busy (0=Ready, 1=Start/busy)|
|Device id||Device bus id||Device Write Address||Accessible via I2C service||Device description|
|0||1||0x4a||"i2c::MCU"||Power management?(same device addr as the DSi power-management)|
|1||1||0x7a||"i2c::CAM"||Camera0?(same dev-addr as DSi cam0)|
|2||1||0x78||"i2c::CAM"||Camera1?(same dev-addr as DSi cam1)|
|9||3||0xa6||"i2c::HID"||Unknown. The device table in I2C-module had the device address changed from 0xA6 to 0xD6 with 8.0.0-18.|
|17||3||0x54||"i2c::IR"||Used by IR-module starting with 8.0.0-18, for New3DS-only HID via "ir:rst". This deviceid doesn't seem to be supported by i2c module on 8.0.0-18(actual support was later added in New3DS i2c module).|
Notice: These device addresses are used for writing to the respective device, for reading bit0 must be set (see I2C protocol). Thus, the actual device address is >> 1.
|0x05||0x4003?||Danger zone - MCU firmware is uploaded here|
|0x08||1||3D slider position 0x9..0xFB|
|0x09||1||Sound volume: 0x0..0x3F.|
|0xB||1||Battery level: 0x0..0x40.|
|0xF||1||Flags: bit7-5 are read via mcu::GPU. The rest of these are read via mcu::RTC: bit4 = BatteryChargeState. bit3 = AdapterState. bit1 = ShellState.|
|0x10||1||Special HID status flags: bit0 = power button pressed, bit1 = power button pressed long, bit2 = home button pressed, bit3 = home button released, bit4 = wifi slider enabled, bit5 = shell got closed, bit6 = shell got opened. If nothing has changed this register is 0.|
|0x12||1||0x40 if volume slider position changed|
|0x20||8||System power control - bit0 = power off, bit1 = reboot (unused?). bit2 = reboot (used by mcu-module and LgyBg). bit3 = used by LgyBg to power off, causes hangs in 3DS-mode. bit4 = doesn't seem to do anything, but an mcu::RTC command uses this. Other bits are unused, and seem to do nothing.|
|0x22||8||Used to set LCD states. bit0 = don't push to LCDs, bit1 = push to LCDs, bit2 = bottom screen backlight off, bit3 = bottom screen backlight on, bit4 = top screen backlight off, bit5 = top screen backlight on|
|0x24||8||Watchdog timer. This must be set *before* the timer is triggered, otherwise the old value is used. Value zero disables the watchdog.|
|0x28||8||Brightness of the WiFi/Power LED|
|0x2A||8||Setting bits 0-7 enables the WiFi LED|
|0x2B||8||Camera LED, setting bit 0 makes the LED blink, setting bit 1 makes the LED stay on|
|0x2C||8||Setting bits 0-7 turns on the 3D LED on the original 3ds|
|0x2D||0x64||This is used for controlling the notification LED(see MCURTC:SetInfoLEDPatternHeader as well), when this register is written.|
|0x2E||1||This returns the notification LED status when read.|
|0x30||8||RTC time (system clock). 7 bytes are read from this. The upper nibble of each byte encodes 10s (BCD), so each byte is post-processed with (byte & 0xF) + (10 * (byte >> 4)). Byte 0 encodes seconds, byte 1 minutes, byte 2 hours, byte *4* days, byte 5 months and byte 6 years (byte 3 is unused?)|
|0x60||8||Offset in u8 array accessed via address 0x61 (written before any read/write below)|
|0x61||0x100||Reads/writes to an MCU u8 array, repeats after 0x100 bytes? The first byte is used to store flags for managing FIRM/NS state - bit0 = "WirelessDisabled", bit1 = "SoftwareClosed", bit2 = "PowerOffInitiated", bit4 = "LegacyJumpProhibited". This register survives power-off, but does not seem to be saved to non-volatile storage (does not survive battery pulls). This register doesn't seem to actually control MCU behaviour by itself, it just seems to be used for storing arbitrary data.|
Device 5 & 6
LCD controllers for main/sub displays, most likely.
|0x40||8||CMD_IN/CMD_RESULT1||Write to trigger a command? Seen commands: 0xFF=Reset?, 0x62=IsFinished?. Result is stored in CMD_RESULT1:CMD_RESULT0.|
See the datasheet linked to on the Hardware page for reference.
This is the DebugPad device, see here.
|Raw I2C register address||Internal register address||Width||Description|
|0x0||0x0||0x40||RHR / THR (data receive/send FIFO)|
See the datasheet linked to on the Hardware page for reference. From that datasheet, for the structure of the I2C register address u8: "Bit 0 is not used, bits 2:1 select the channel, bits 6:3 select one of the UART internal registers. Bit 7 is not used with the I2C-bus interface, but it is used by the SPI interface to indicate a read or a write operation."
Used by Cfg-sysmodule via the i2c::EEP service. This is presumably EEPROM going by the service name.
The Cfg-module code which loads the CCAL file from NAND will load it from I2C instead, if a certain state flag is non-zero. HMAC/hash verification is skipped when the CCAL was loaded from I2C.
Since the *Raw commands are used with this, this device has no I2C registers. Instead, raw data is transfered after the I2C device is selected. Hence, WriteDeviceRaw is used for sending commands to the controller, while ReadDeviceRaw is for receiving responses from the controller. Certain commands may return multiple command responses.
Command request / response structure:
|0x1||0x1||Command source / destination.|
Following the above header is the payload data(when payload size is non-zero), with the size specified in the header. The command response payload is usually at least 1-byte, where that byte appears to be normally 0x0. For command requests the payload data is the command parameters.
For command requests sent to the NFC tag itself, Cmd=0x0 and CmdID=0x0. The command request payload data here is the actual command request data for the NFC tag, starting with the CmdID u8 at payload+0.
During NFC module startup, a certain command is sent to the controller which eventually(after various cmd-reply headers etc) returns the following the payload after the first byte in the payload:
000000: 44 65 63 20 32 32 20 32 30 31 32 31 34 3a 35 33 Dec 22 201214:53 000010: 3a 35 30 01 05 0d 46 05 1b 79 20 07 32 30 37 39 :50...F..y .2079 000020: 31 42 35 1B5
Or that is: "Dec 22 201214:53:50<binary>20791B5". Therefore, this appears to return the part-number of the NFC controller(other command request(s) / response(s) use this part-number value too).
NFC controller commands
|CmdRequest||CmdID||Payload data for parameters||Description|
|0x2E||0x2F||Firmware image for this chunk, size varies.||This is used during NFC module startup to upload the firmware image to the NFC controller. This is used repeatedly to upload multiple chunks of the image.|