Skip to content

Acekard RPG, Acekard 2, R4iDSN

lifehackerhansol edited this page Nov 11, 2024 · 5 revisions

Acekard RPG, Acekard 2, R4iDSN

This page documents a subset of extra card commands found in the Acekard RPG's SD driver. The Acekard 2 and R4iDSN are nearly identical to the RPG; the differences will be described inline. This page was written by lifehackerhansol, based on original research as well as MIT licensed code from Acekard team and GPL-3.0-or-later licensed code from Yellow Wood Goblin.

SDIO

Userspace (that is, the console) is responsible for sending SDIO commands to the cartridge, using the console's cartridge API as a passthrough.

SDIO command structure

SDIO commands are structured as follows:

aa bb 00 cc dd dd dd dd

  • aa: command ID. The R4iDSN uses AB, while all other known carts use D5.
  • bb: parameter type. Will be described further down this page.
  • cc: SDIO command
  • dddddddd: SDIO argument

Interestingly, the Acekard 2 (and R4/R4i Ultra) responds to these commands even without booting the cartridge; you may run the driver code externally (i.e. from code on the console SD card) and access the SD card present on the cartridge. It is untested whether this behaviour exists on all cartridges implementing this API.

SDIO command parameter types

Known parameter types are as follows:

  • 0: No response. Userspace does not need to poll the cartridge.
  • 1: Read response. Userspace must poll the cartridge for as many bits as needed, depending on the SDIO cmd.
  • 3: Read single block. This is to be used with SDIO CMD17. A response is not read; the data block is retrieved via another command.
  • 4: Read multiple block. This is to be used with SDIO CMD18. A response is not read; the data block is retrieved via another command.
  • 5: Write single block. This is to be used with SDIO CMD24. A response is not read; the data block is written via another command.
  • 6: Write multiple block. This is to be used with SDIO CMD25. A response is not read; the data block is written via another command.

SDIO response structure

The cartridge returns a stream of bytes; every bit in an SDIO response is transferred as a byte, with BIT(7) as the response bit in every byte. The bits are returned from MSB to LSB, 4 bytes at a time, via the REG_CARD_DATA_RD register.

It is observed on an Acekard 2.1 that the responses were either 0xF3 for 1, or 0x73 for 0; it is unknown whether this is reproducible, but it likely doesn't matter as BIT(7) of each byte is all one should care about.

The cartridge, for some reason, does not return the actual MSB; rather, it delivers all but one bit, with the trailing bit seemingly always 0. This should be worked around by userspace (for instance, by shifting the packed response >> 1).

Reading data blocks

The command to read a block, either for single or multi block, is the following:

B7 00 00 00 00 13 00 00

This is the standard cartridge block read command; it appears the 0x13 specifies to read from SD (when reading the actual onboard flash, this value is 0x10; out of scope of this document for now). The response is transferred, one u32 at a time, via the REG_CARD_DATA_RD register.

Prior to performing this command, one should check if the cartridge is ready (see "Verifying command status").

When using CMD17, it is advised to add a 5-microsecond delay to allow for the cartridge to handle CRC calculation.

When using CMD18, one can loop the 0xB7 command as many times as needed. After each block, user should verify that the SD host state is 0x7 (see "Verifying SD host state").

Writing data blocks

Userspace shall write two u32s at a time into the card command register, byte-swapped.

This should be repeated until a complete block is written.

When using CMD24, after the block is transferred, user should verify that the SD host state is 0 (see "Verifying SD host state").

When using CMD25, after each complete block, user should verify that the SD host state is 0xE (see "Verifying SD host state"). After all data is transferred and CMD12 (STOP_TRANSMISSION) is sent, user should verify that the SD host state is 0 (see "Verifying SD host state").

Verifying SD host state

The command to check the SD host state is as follows:

C0 00 00 00 00 00 00 00

The response is 4-bits; the Acekard RPG returns the bits in the low-4 bits of the least significant byte, whereas all other known carts return the bits in the high-4 bits of the least significant byte.

Currently it is unknown what each of the response types refer to.

Verifying command status

One can use the 0xB8 command (3rd Chip ID) to verify whether the cartridge is currently performing a command. When dealing with the SD card, it is notably only used when doing block reads.

The cartridge should respond with 0xFC2 when idle.

SDHC and SDIO initialization

Userspace should perform a full SDIO initialization; by specification, ACMD41 returns the HCS bit. When this bit is set, after performing the full init routine, the following command should be sent to set the cartridge into SDHC mode:

C1 01 00 00 00 00 00 00

Interestingly, Acekard has a 0.1-millisecond-delay when polling ACMD41.

Existing FOSS code

The Acekard RPG's userspace stack was released under the MIT license; an archive of this source can be found here.

Yellow Wood Goblin, a past scene developer, had open sourced their modification of the above source code (Wood RPG) under the GPL-3.0-or-later license for a short amount of time; an archive of the last open-source release can be found here.

Both of these source codes are the initial references of the Acekard RPG and the R4iDSN's SD card driver; the Acekard 2 was separately reverse-engineered by the DS-Homebrew team by cross-referencing above source codes and observing the Acekard 2's behaviour.

Since then, a permissively-licensed DLDI driver has been released; you may find it here.

Model quirks

  • r4dspro.com(?) carts, presumably more carts(?)
    • There are a few Acekard 2 derivatives out there that cannot use CMD25; doing so causes lockups. A separate driver should be created to use only CMD24 writes for this cart.