Skip to content

SuperCard DSONE SDHC & DSTT

lifehackerhansol edited this page Nov 11, 2024 · 7 revisions

SuperCard DSONE SDHC / DSTT

This page documents a subset of extra card commands found in the DSTT, as well as the SuperCard DSONE SDHC's SD code, herein DSTT and DSONE, respectively. This page was written by lifehackerhansol, based on original research as well as BSD-3-Clause licensed code from SuperCard team and Cluny.

Commands: what are they, what do they do (or at least some of them)

Below are a list of commands found in the DSONE's FOSS driver in u64, as follows:

XXXXXXXX XXXXXXXX

Each two digits, from left to right, is REG_CARD_COMMAND[0] to REG_CARD_COMMAND[7] as defined in libnds.
Lowercase x will imply that this is unused. Any others are explained.

PSRAM commands(?)

  • Seems to read from the device's PSRAM? Not confirmed.

70aaaaaa aaxxxxxx

  • aaaaaaaa = u32 address (highest bit to lowest bit)
  • The only known use case of this command is to check whether the DSONE has an SD or SDHC inserted, by passing the address 0x7fa00-0x20.
    • This will be important later: When SD, address must be <<9. When SDHC, address is verbatim.
  • This command seems to always return 1 on the DSTT, according to Taiju Yamada. // likely because there is no PSRAM to be found here
    • Instead, DSTT's bootloader writes 1/0 to 0x027FFC24 in main RAM. Very reliable, thank you DSTT team.

SDIO

This cart uses SDIO. The following commands are SDIO-specific.

Note that reading data from the SD card is handled separately: consider Read-specific commands section down this page.

Some more commands are necessary for writing data to the SD card; consider Write-specific commands section down this page.

51aaaaaa aabbccxx

  • SDIO send command
  • aaaaaaaa: argument
  • bb: SDIO CMD index
  • cc: SDIO response

50xxxxxx xxxxxxxx

  • Check if the SDIO is busy. CARD_BUSY / CARD_DATA_READY wasn't enough, it seems.
  • Returns 0 if false, non-0 if true. It is recommended to loop 0x50 until this value returns 0.

52xxxxxx xxxxxxxx

  • Reads SDIO response data from previously sent command.
  • This response is delivered in big-endian.

Read-specific commands

These commands are specifically for reading from the SD.

53aaaaaa aaxxxxxx

  • aaaaaaaa = u32 sector address (highest bit to lowest bit)
    • << 9 if non-SDHC
  • This command initiates a single-page read: that is, it reads one 0x200 byte chunk.

54aaaaaa aaxxxxxx

  • aaaaaaaa = u32 sector address (highest bit to lowest bit)
    • << 9 if non-SDHC
  • This command initiates a sequential read: that is, it will read several 0x200 chunks with less delay than 0x53.

80xxxxxx xxxxxxxx

  • This command appears to be a wait until the SD is ready to deliver a 0x200 byte chunk.
  • This must be sent before every 0x200 chunk read.

81xxxxxx xxxxxxxx

  • This command starts the 0x200 chunk read.
  • In single-page reads, this is the last command sent.
  • In sequential reads, after this command send CMD0 (for some reason) to read the next 0x200 byte, or CMD12 to end sequential read.

Write-specific commands

56xxxxxx xxxxxxxx

  • This command ends any write. (not the same as CMD12 STOP_TRANSMISSION, it seems?)
  • If this is a sequential write, make sure the command ran before this was CMD12! Otherwise the hardware will lock up!
  • After sending this command, loop 0x50 to wait until hardware is idle.

82xxxxxx xxxxxxxx

  • This command starts the 0x200 chunk write.
  • From here a reverse cardPolledTransfer can be done; copy a u32 to REG_CARD_DATA_RD, wait for CARD_DATA_READY, loop until 0x200 complete
  • After 0x200 bytes are written, loop 0x50 to wait for card ready, then send 0x56 command (detailed usage in its own command subbullet)
  • In sequential writes, if the current 0x200 byte chunk is the last chunk, pass CMD12, then pass 0x56 command. Wait and flush both commands.

As you can see, very messy :). Let me know if this needs to be cleared up, because frankly this needs to be shown with actual code...

Existing FOSS code

Free and open-source implemenations of the DSONE SD driver can be found on Chishm's website with the names scdssdhc and scdssdhc1. They are also archived in this repository. Both are licensed under BSD-3-Clause. However, these only implement single-page R/W, and this is VERY SLOW.

A bug is present in these drivers: the driver will attempt to save the SD/SDHC check to some place in RAM (rewritable!). Do not do this, just add a global boolean within the driver instead.

A Zlib-licensed implementation, without the above bug, exists in blocksds directory of this repository, with the platform name scdssdhc and ttio. The difference between these two is that scdssdhc will read the SDHC variable written to the PSRAM by the DSONE bootloader, while ttio will perform a full SDIO init, as well as implement the necessary workarounds for model quirks (see below.)

Model quirks

  • Timebomb clones
    • For whatever reason, timebombed carts (r4i-sdhc.com, etc) cannot do both sequential read and single read. You can't do if num_sectors > 1, then do sequential. else, do single
    • Attempts to mix them have shown the cart to infinitely loop on command 0x80.
    • To make a DSTT-universal driver, it is recommended to only use sequential reads for all reads.
  • Some initial R4iTT carts, r4i-gold.com Gold RTS, PK3DS(?)
    • In all other cases, for 0x50/0x52/0x80/0x81/0x82 commands can be sent as is.
    • However! The old SuperCard and DSTT implementation was to only rewrite the first byte of the card command register. Thus, if a user sent 51 ca fe ba be 00 00 00, 0x50 and 0x52 commands would retain XX ca fe ba be 00 00 00.
    • These carts (unconfirmed list) unfortunately rely on the behaviour of the old drivers; this means 50 00 00 00 00 00 00 00 is an invalid command.
    • To make a DSTT-universal driver, do not clear the rest of the registers, unless you are sending a brand-new command via 0x51/0x53/0x54.