Difference between revisions of "I2C Registers"
(Merge MCUHWC:ReadRegister to this) |
(→Device 3: added missing registers and their properties as placeholders and fixed mistakes) |
||
Line 242: | Line 242: | ||
| ro | | ro | ||
| Version low | | Version low | ||
+ | |- | ||
+ | | 0x02 | ||
+ | | s | ||
+ | | ro | ||
+ | | ? | ||
+ | |- | ||
+ | | 0x03 | ||
+ | | s | ||
+ | | rw | ||
+ | | Top screen flicker | ||
|- | |- | ||
| 0x04 | | 0x04 | ||
| s | | s | ||
| rw | | rw | ||
− | | | + | | Bottom screen flicker |
|- | |- | ||
| 0x05 | | 0x05 | ||
| s / 0x4003? | | s / 0x4003? | ||
| rw / ? | | rw / ? | ||
− | | | + | | Danger zone - [[MCU_Services#MCU_firmware_versions|MCU firmware]] is uploaded here (???) |
+ | |- | ||
+ | | 0x06 | ||
+ | | s | ||
+ | | rw | ||
+ | | ? | ||
+ | |- | ||
+ | | 0x07 | ||
+ | | s | ||
+ | | rw | ||
+ | | ? | ||
|- | |- | ||
| 0x08 | | 0x08 | ||
Line 263: | Line 283: | ||
| Volume slider state (0x00 - 0x3F) | | Volume slider state (0x00 - 0x3F) | ||
This is the same value returned by [[MCUHWC:GetSoundVolume|MCUHWC:GetSoundVolume]] | This is the same value returned by [[MCUHWC:GetSoundVolume|MCUHWC:GetSoundVolume]] | ||
+ | |- | ||
+ | | 0x0A | ||
+ | | s | ||
+ | | ro | ||
+ | | ? (seems to be power management related?) | ||
|- | |- | ||
| 0x0B | | 0x0B | ||
Line 268: | Line 293: | ||
| ro | | ro | ||
| Battery percentage | | Battery percentage | ||
+ | |- | ||
+ | | 0x0C | ||
+ | | s | ||
+ | | ro | ||
+ | | ? (changes to 0 for a second when the charger is plugged in then it resets to its previous value) | ||
|- | |- | ||
| 0x0D | | 0x0D | ||
Line 273: | Line 303: | ||
| ro | | ro | ||
| System voltage | | System voltage | ||
+ | |- | ||
+ | | 0x0E | ||
+ | | s | ||
+ | | ro | ||
+ | | ? | ||
|- | |- | ||
| 0x0F | | 0x0F | ||
Line 283: | Line 318: | ||
| ro | | ro | ||
| 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. | | 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. | ||
+ | Needs confirmation (or some flags to enable). | ||
+ | |- | ||
+ | | 0x11 | ||
+ | | s | ||
+ | | ro | ||
+ | | ? | ||
|- | |- | ||
| 0x12 | | 0x12 | ||
Line 288: | Line 329: | ||
| ro | | ro | ||
| 0x40 if volume slider position changed | | 0x40 if volume slider position changed | ||
+ | Needs confirmation (or some flags to enable). | ||
+ | |- | ||
+ | | 0x13 | ||
+ | | s | ||
+ | | ro | ||
+ | | ? | ||
+ | |- | ||
+ | | 0x14 | ||
+ | | s | ||
+ | | ro | ||
+ | | ? | ||
+ | |- | ||
+ | | 0x15 | ||
+ | | s | ||
+ | | rw | ||
+ | | ? | ||
+ | |- | ||
+ | | 0x16 | ||
+ | | s | ||
+ | | rw | ||
+ | | ? | ||
+ | |- | ||
+ | | 0x17 | ||
+ | | s | ||
+ | | rw | ||
+ | | ? | ||
+ | |- | ||
+ | | 0x18 | ||
+ | | s | ||
+ | | rw | ||
+ | | ? | ||
+ | |- | ||
+ | | 0x19 | ||
+ | | s | ||
+ | | rw | ||
+ | | ? | ||
+ | |- | ||
+ | | 0x1A | ||
+ | | s | ||
+ | | rw | ||
+ | | ? | ||
+ | |- | ||
+ | | 0x1B | ||
+ | | s | ||
+ | | rw | ||
+ | | ? | ||
+ | |- | ||
+ | | 0x1C | ||
+ | | s | ||
+ | | rw | ||
+ | | ? | ||
+ | |- | ||
+ | | 0x1D | ||
+ | | s | ||
+ | | rw | ||
+ | | ? | ||
+ | |- | ||
+ | | 0x1E | ||
+ | | s | ||
+ | | rw | ||
+ | | ? | ||
+ | |- | ||
+ | | 0x1F | ||
+ | | s | ||
+ | | rw | ||
+ | | ? | ||
|- | |- | ||
| 0x20 | | 0x20 | ||
| s | | s | ||
− | | wo | + | | wo |
| 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. | | 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. | ||
+ | |- | ||
+ | | 0x21 | ||
+ | | s | ||
+ | | ro(?) | ||
+ | | ? | ||
|- | |- | ||
| 0x22 | | 0x22 | ||
| s | | s | ||
− | | | + | | wo |
| 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 | | 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 | ||
+ | |- | ||
+ | | 0x23 | ||
+ | | s | ||
+ | | ro(?) | ||
+ | | ? | ||
|- | |- | ||
| 0x24 | | 0x24 | ||
Line 303: | Line 420: | ||
| ?? | | ?? | ||
| Watchdog timer. This must be set *before* the timer is triggered, otherwise the old value is used. Value zero disables the watchdog. | | Watchdog timer. This must be set *before* the timer is triggered, otherwise the old value is used. Value zero disables the watchdog. | ||
+ | |- | ||
+ | | 0x25 | ||
+ | | s | ||
+ | | rw | ||
+ | | ? | ||
+ | |- | ||
+ | | 0x26 | ||
+ | | s | ||
+ | | rw | ||
+ | | ? | ||
|- | |- | ||
| 0x27 | | 0x27 | ||
| s | | s | ||
− | | ro | + | | ro (rw?) |
| Raw volume slider state | | Raw volume slider state | ||
|- | |- | ||
Line 315: | Line 442: | ||
|- | |- | ||
| 0x29 | | 0x29 | ||
− | | dynamic | + | | dynamic / s |
− | | rw | + | | ro / rw |
− | | Repeat register, any byte written | + | | Repeat register, any byte written in the first byte gets repeated indefinitely(?, needs confirmation past 0xFF). The rest of the bytes are read-only. Setting the shared byte of this register (via overflow glitches) will also work, confirming that this is a semi-dynamic register as the first byte is stored in the shared register pool, but the rest of the bytes are fake. |
|- | |- | ||
| 0x2A | | 0x2A | ||
Line 342: | Line 469: | ||
| s | | s | ||
| ro | | ro | ||
− | | This [[MCURTC:GetInfoLEDStatus|returns]] the notification LED status when read | + | | This [[MCURTC:GetInfoLEDStatus|returns]] the notification LED status when read (1 means new cycle started) |
+ | |- | ||
+ | | 0x2F | ||
+ | | s | ||
+ | | ro(?) | ||
+ | | ? | ||
|- | |- | ||
| 0x30 | | 0x30 | ||
Line 349: | Line 481: | ||
| rw | | rw | ||
| 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?) | | 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?) | ||
+ | |- | ||
+ | | 0x38 | ||
+ | | s | ||
+ | | rw | ||
+ | | ? | ||
+ | |- | ||
+ | | 0x39 | ||
+ | | s | ||
+ | | rw | ||
+ | | ? | ||
+ | |- | ||
+ | | 0x3A | ||
+ | | s | ||
+ | | rw | ||
+ | | ? | ||
+ | |- | ||
+ | | 0x3B | ||
+ | | s | ||
+ | | rw | ||
+ | | ? | ||
+ | |- | ||
+ | | 0x3C | ||
+ | | s | ||
+ | | rw | ||
+ | | ? | ||
|- | |- | ||
| 0x3D | | 0x3D | ||
+ | 0x3E | ||
| s (2) | | s (2) | ||
| ro | | ro | ||
| RTC tick counter (resets to 0 when the seconds increase) | | RTC tick counter (resets to 0 when the seconds increase) | ||
− | |||
|- | |- | ||
| 0x3F | | 0x3F | ||
| s | | s | ||
− | | | + | | wo |
| Peripheral power related? bit0 seems to depower everything, pressing the power key afterwards instantly turns the whole 3DS off | | Peripheral power related? bit0 seems to depower everything, pressing the power key afterwards instantly turns the whole 3DS off | ||
+ | |- | ||
+ | | 0x40 | ||
+ | | s | ||
+ | | rw | ||
+ | | ? | ||
+ | |- | ||
+ | | 0x41 | ||
+ | | s | ||
+ | | rw | ||
+ | | ? | ||
+ | |- | ||
+ | | 0x42 | ||
+ | | s | ||
+ | | rw | ||
+ | | ? | ||
+ | |- | ||
+ | | 0x43 | ||
+ | | s | ||
+ | | rw | ||
+ | | ? | ||
+ | |- | ||
+ | | 0x44 | ||
+ | | s | ||
+ | | rw | ||
+ | | ? (setting this seems to freeze the system for a second) | ||
+ | |- | ||
+ | | 0x45 | ||
+ | | s | ||
+ | | rw | ||
+ | | ? | ||
|- | |- | ||
| 0x46 | | 0x46 | ||
Line 375: | Line 562: | ||
| ro | | ro | ||
| Gyro X(?) axis rotation (0x00 = 3DS base facing upwards, 0x40 = face-down flat, 0xBE = standing(?) flat) | | Gyro X(?) axis rotation (0x00 = 3DS base facing upwards, 0x40 = face-down flat, 0xBE = standing(?) flat) | ||
+ | |- | ||
+ | | 0x4B | ||
+ | | s | ||
+ | | rw | ||
+ | | ? (setting this to 0xFF seems to freeze the system when trying to transition to Home Menu if some other registers are set accordingly) | ||
+ | |- | ||
+ | | 0x4C | ||
+ | | s | ||
+ | | rw | ||
+ | | ? | ||
+ | |- | ||
+ | | 0x4D | ||
+ | | s | ||
+ | | rw | ||
+ | | ? | ||
+ | |- | ||
+ | | 0x4E | ||
+ | | s | ||
+ | | rw | ||
+ | | ? | ||
|- | |- | ||
| 0x4F | | 0x4F | ||
Line 380: | Line 587: | ||
| ro | | ro | ||
| Unkonwn. Reading past the 6th byte is FF-filled, so register size of 6 is assumed. | | Unkonwn. Reading past the 6th byte is FF-filled, so register size of 6 is assumed. | ||
+ | |- | ||
+ | | 0x50 | ||
+ | - 0x57 | ||
+ | | s | ||
+ | | rw | ||
+ | | ? | ||
+ | |- | ||
+ | | 0x58 | ||
+ | | s | ||
+ | | rw | ||
+ | | DSP volume slider 0% volume offset (setting this to 0xFF will esentially mute the DSP as it's the volume slider's maximum raw value) | ||
+ | |- | ||
+ | | 0x59 | ||
+ | | s | ||
+ | | rw | ||
+ | | DSP volume slider 100% volume offset (setting both this and the above to 0 will disable the volume slider with 100% volume, setting this to a lower value than the above will make the volume slider have only 2 states; on and off) | ||
+ | |- | ||
+ | | 0x5A | ||
+ | | s | ||
+ | | rw | ||
+ | | ? | ||
+ | |- | ||
+ | | 0x5B | ||
+ | - 0x5F | ||
+ | | s | ||
+ | | ro(?) | ||
+ | | ? (these seem to be invalid regsiters) | ||
|- | |- | ||
| 0x60 | | 0x60 | ||
− | | 0x100 | + | | 0x100 |
− | | ro | + | | ro |
first byte is wo | first byte is wo | ||
| Looping queue register | | Looping queue register | ||
Line 390: | Line 624: | ||
|- | |- | ||
| 0x61 | | 0x61 | ||
− | | 0x100 | + | | 0x100 |
| rw | | rw | ||
| Writing to this register pushes values on top of register 0x60's stack. Reading from this register doesn't advance the stack. | | Writing to this register pushes values on top of register 0x60's stack. Reading from this register doesn't advance the stack. | ||
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. | 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. | ||
+ | |- | ||
+ | | 0x62 - 0x7E | ||
+ | | s | ||
+ | | invalid (ro) | ||
+ | | These registers don't exist at all, thus reading them will yield 0xFF | ||
|- | |- | ||
| 0x7F | | 0x7F | ||
Line 406: | Line 645: | ||
byte 17: WiFi LED brightness | byte 17: WiFi LED brightness | ||
byte 18: raw button states? | byte 18: raw button states? | ||
− | bit0: unset while power button is held | + | bit0: unset while power button is held |
− | bit1: unset while home button is held | + | bit1: unset while home button is held |
− | bit2: unset while Wifi slider is held | + | bit2: unset while Wifi slider is held |
− | + | bit5: unset while the charging LED is active | |
− | bit6: unset | + | bit6: unset while charger is plugged in |
this byte is reset to 0 before an svcBreak takes effect | this byte is reset to 0 before an svcBreak takes effect |
Revision as of 05:11, 24 April 2017
Registers
Old3DS | Name | Address | Width | Used by |
---|---|---|---|---|
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 |
I2C_CNT
BIT | DESCRIPTION |
---|---|
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) |
I2C Devices
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) |
3 | 2 | 0x4a | "i2c::MCU" | MCU |
4 | 2 | 0x78 | "i2c::CAM" | ? |
5 | 2 | 0x2c | "i2c::LCD" | ? |
6 | 2 | 0x2e | "i2c::LCD" | ? |
7 | 2 | 0x40 | "i2c::DEB" | ? |
8 | 2 | 0x44 | "i2c::DEB" | ? |
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. |
10 | 3 | 0xd0 | "i2c::HID" | Gyroscope |
11 | 3 | 0xd2 | "i2c::HID" | ? |
12 | 3 | 0xa4 | "i2c::HID" | DebugPad |
13 | 3 | 0x9a | "i2c::IR" | IR |
14 | 3 | 0xa0 | "i2c::EEP" | eeprom? |
15 | 2 | 0xee | "i2c::NFC" | New3DS-only NFC |
16 | 1 | 0x40 | "i2c::QTM" | New3DS-only QTM |
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.
Device 3
REGISTER | WIDTH | INFO | DESCRIPTION |
---|---|---|---|
0x00 | s | ro | Version high |
0x01 | s | ro | Version low |
0x02 | s | ro | ? |
0x03 | s | rw | Top screen flicker |
0x04 | s | rw | Bottom screen flicker |
0x05 | s / 0x4003? | rw / ? | Danger zone - MCU firmware is uploaded here (???) |
0x06 | s | rw | ? |
0x07 | s | rw | ? |
0x08 | s | ro | Raw 3D slider position |
0x09 | s | ro | Volume slider state (0x00 - 0x3F)
This is the same value returned by MCUHWC:GetSoundVolume |
0x0A | s | ro | ? (seems to be power management related?) |
0x0B | s | ro | Battery percentage |
0x0C | s | ro | ? (changes to 0 for a second when the charger is plugged in then it resets to its previous value) |
0x0D | s | ro | System voltage |
0x0E | s | ro | ? |
0x0F | s | ro | Flags: bit7-5 are read via mcu::GPU. The rest of these are read via mcu::RTC: bit4 = BatteryChargeState. bit3 = AdapterState. bit1 = ShellState. |
0x10 | s | ro | 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.
Needs confirmation (or some flags to enable). |
0x11 | s | ro | ? |
0x12 | s | ro | 0x40 if volume slider position changed
Needs confirmation (or some flags to enable). |
0x13 | s | ro | ? |
0x14 | s | ro | ? |
0x15 | s | rw | ? |
0x16 | s | rw | ? |
0x17 | s | rw | ? |
0x18 | s | rw | ? |
0x19 | s | rw | ? |
0x1A | s | rw | ? |
0x1B | s | rw | ? |
0x1C | s | rw | ? |
0x1D | s | rw | ? |
0x1E | s | rw | ? |
0x1F | s | rw | ? |
0x20 | s | wo | 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. |
0x21 | s | ro(?) | ? |
0x22 | s | wo | 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 |
0x23 | s | ro(?) | ? |
0x24 | s | ?? | Watchdog timer. This must be set *before* the timer is triggered, otherwise the old value is used. Value zero disables the watchdog. |
0x25 | s | rw | ? |
0x26 | s | rw | ? |
0x27 | s | ro (rw?) | Raw volume slider state |
0x28 | s | rw | Brightness of the WiFi/Power LED |
0x29 | dynamic / s | ro / rw | Repeat register, any byte written in the first byte gets repeated indefinitely(?, needs confirmation past 0xFF). The rest of the bytes are read-only. Setting the shared byte of this register (via overflow glitches) will also work, confirming that this is a semi-dynamic register as the first byte is stored in the shared register pool, but the rest of the bytes are fake. |
0x2A | s | rw | WiFi LED state, non-0 value turns on the WiFi LED, capped at 0x0F |
0x2B | s | rw | Camera LED state, 0, 3, 6-0xF = off, 1 = slowly blinking, 2 = constantly on, 4 = flash once, 5 = delay before changing to 2 |
0x2C | s | rw | 3D LED state, capped at 0x0F |
0x2D | 0x64 | wo | This is used for controlling the notification LED (see MCURTC:SetInfoLEDPatternHeader as well), when this register is written. It's possible to write data here with size less than 0x64, and only that portion of the pattern data will get overwritten. Reading from this register only returns zeroes, so it's considered write-only. |
0x2E | s | ro | This returns the notification LED status when read (1 means new cycle started) |
0x2F | s | ro(?) | ? |
0x30
- 0x37 |
s | rw | 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?) |
0x38 | s | rw | ? |
0x39 | s | rw | ? |
0x3A | s | rw | ? |
0x3B | s | rw | ? |
0x3C | s | rw | ? |
0x3D
0x3E |
s (2) | ro | RTC tick counter (resets to 0 when the seconds increase) |
0x3F | s | wo | Peripheral power related? bit0 seems to depower everything, pressing the power key afterwards instantly turns the whole 3DS off |
0x40 | s | rw | ? |
0x41 | s | rw | ? |
0x42 | s | rw | ? |
0x43 | s | rw | ? |
0x44 | s | rw | ? (setting this seems to freeze the system for a second) |
0x45 | s | rw | ? |
0x46 | s | ro | Gyro Y(?) axis rotation (0x00 = flat, 0x40 = 3DS standing on right side, 0xBE = 3DS standing on left side) |
0x48 | s | ro | Gyro Z(?) axis rotation (0x00 = flat, 0x40 = 3DS standing horizontally, 0xBE = 3DS base is horizontally upside-down) |
0x4A | s | ro | Gyro X(?) axis rotation (0x00 = 3DS base facing upwards, 0x40 = face-down flat, 0xBE = standing(?) flat) |
0x4B | s | rw | ? (setting this to 0xFF seems to freeze the system when trying to transition to Home Menu if some other registers are set accordingly) |
0x4C | s | rw | ? |
0x4D | s | rw | ? |
0x4E | s | rw | ? |
0x4F | 6(?) | ro | Unkonwn. Reading past the 6th byte is FF-filled, so register size of 6 is assumed. |
0x50
- 0x57 |
s | rw | ? |
0x58 | s | rw | DSP volume slider 0% volume offset (setting this to 0xFF will esentially mute the DSP as it's the volume slider's maximum raw value) |
0x59 | s | rw | DSP volume slider 100% volume offset (setting both this and the above to 0 will disable the volume slider with 100% volume, setting this to a lower value than the above will make the volume slider have only 2 states; on and off) |
0x5A | s | rw | ? |
0x5B
- 0x5F |
s | ro(?) | ? (these seem to be invalid regsiters) |
0x60 | 0x100 | ro
first byte is wo |
Looping queue register
Writing to first byte resets the queue position to the nth element Reading from this register causes the values to shift up by `readsize-1`(needs confirmation) bytes after returning `readsize-1` bytes from the top of the stack (first byte is read-only, so is always zero) |
0x61 | 0x100 | rw | Writing to this register pushes values on top of register 0x60's stack. Reading from this register doesn't advance the stack.
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. |
0x62 - 0x7E | s | invalid (ro) | These registers don't exist at all, thus reading them will yield 0xFF |
0x7F | 19(?) | ro | Unknown.
byte 06: battery related? (seems to decrease while charging and increase while discharging) byte 10: power LED related? 0 is off, 1 is red byte 13: RGB LED red factor byte 14: RGB LED green factor byte 15: RGB LED blue factor byte 17: WiFi LED brightness byte 18: raw button states? bit0: unset while power button is held bit1: unset while home button is held bit2: unset while Wifi slider is held bit5: unset while the charging LED is active bit6: unset while charger is plugged in this byte is reset to 0 before an svcBreak takes effect |
0x80
- 0xFF |
s | invalid (ro) | These registers don't exist at all, thus reading them will yield 0xFF |
Note: the letter "s" in the size field means that the given register is in a "shared register pool", meaning if you read/write with size more than 1 you can read the next `readamount-1` of shared registers. It's possible to corrupt the shared value of a "non-shared" register by writing into a shared register with a size bigger than one. Writing more than 0x100 bytes into a shared register will corrupt all writable registers, including the shared portion of "non-shared" registers.
Non-shared register: it's a register separate from the shared register pool. Messing with these registers will not affect the shared register pool at all.
Device 5 & 6
LCD controllers for main/sub displays, most likely.
Register | Width | Name | Description |
---|---|---|---|
0x1 | 8 | ? | |
0x11 | 8 | ? | |
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. |
0x41 | 8 | CMD_RESULT0 | Read result |
0x50 | 8 | ? | |
0x60 | 8 | ? | |
0xFE | 8 | ? |
Device 10
See the datasheet linked to on the Hardware page for reference.
Device 12
REGISTER | WIDTH | DESCRIPTION |
---|---|---|
0x0 | 21 | DebugPad state. |
This is the DebugPad device, see here.
Device 13
Raw I2C register address | Internal register address | Width | Description |
---|---|---|---|
0x0 | 0x0 | 0x40 | RHR / THR (data receive/send FIFO) |
0x8 | 0x1 | 0x1 | IER |
0x10 | 0x2 | 0x1 | FCR/IIR |
0x18 | 0x3 | 0x1 | LCR |
0x20 | 0x4 | 0x1 | MCR |
0x28 | 0x5 | 0x1 | LSR |
0x30 | 0x6 | 0x1 | MSR/TCR |
0x38 | 0x7 | 0x1 | SPR/TLR |
0x40 | 0x8 | 0x1 | TXLVL |
0x48 | 0x9 | 0x1 | RXLVL |
0x50 | 0xA | 0x1 | IODir |
0x58 | 0xB | 0x1 | IOState |
0x60 | 0xC | 0x1 | IoIntEna |
0x68 | 0xD | 0x1 | reserved |
0x70 | 0xE | 0x1 | IOControl |
0x78 | 0xF | 0x1 | EFCR |
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."
Device 14
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(nandro:/sys/{HWCAL0.dat/HWCAL1.dat}) file from NAND will load it from I2C instead, if a certain state flag is non-zero. Likewise for the function which writes CCAL to NAND. HMAC/hash verification after loading is skipped when the CCAL was loaded from I2C.
Device 15
This the New3DS NFC controller "I2C" interface. This device is accessed via the WriteDeviceRaw/ReadDeviceRaw I2C service commands.
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:
Offset | Size | Description |
---|---|---|
0x0 | 0x1 | Normally 0x10? |
0x1 | 0x1 | Command source / destination. |
0x2 | 0x1 | CmdID |
0x3 | 0x1 | Payload size. |
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[1]=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[1] | 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. |