Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ typedef volatile int64_t vs64;
#define SDIO_D1 6
#define SDIO_D2 7
#define SDIO_D3 8
#define SDIO_PIN_MASK ((1u << SDIO_D3) | (1u << SDIO_D2) | (1u << SDIO_D1) | (1u << SDIO_D0) | \
(1u << SDIO_CMD) | (1u << SDIO_CLK))

#define PIN_RST 9
#define PIN_CEB 10
Expand All @@ -43,11 +45,16 @@ typedef volatile int64_t vs64;
#define PIN_D7 19
#define PIN_IRQ 20
#define PIN_CS2 21
#define NTRC_PIN_MASK ((1u << PIN_CS2) | (1u << PIN_IRQ) | (1u << PIN_D7) | (1u << PIN_D6) | \
(1u << PIN_D5) | (1u << PIN_D4) | (1u << PIN_D3) | (1u << PIN_D2) | \
(1u << PIN_D1) | (1u << PIN_D0) | (1u << PIN_WREB) | (1u << PIN_CEB) | \
(1u << PIN_RST))

#define PIN_USB_VBUS 24

#define PIN_DEV_TX0 0
#define PIN_DEV_RX0 1
#define DEV_UART_PIN_MASK ((1u << PIN_DEV_RX0) | (1u << PIN_DEV_TX0))

#define PIN_INPUT_MASK 0x2FFE00

Expand Down
138 changes: 103 additions & 35 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,9 @@ static void initSd(void)
{
memset(&sFatFs, 0, sizeof(sFatFs));

//try mounting 16 times
//try mounting 3 times
bool ok = false;
for (int i = 0; i < 16; i++)
for (int i = 0; i < 3; i++)
{
FRESULT mountResult = f_mount(&sFatFs, "0:", 1);
if (mountResult == FR_OK)
Expand Down Expand Up @@ -159,6 +159,106 @@ static void tryRebootToBootsel(void)
}
}

static inline void earlyGpioInit(void)
{
// Set all GPIOs to inputs.
// Note that we rely on hardware reset having enabled pull-downs.
gpio_init_mask(0xFFFFFFFFu);

// Set NTRCARD IRQ pin low.
// This needs to happen immediately.
gpio_put(PIN_IRQ, false);
gpio_set_dir(PIN_IRQ, GPIO_OUT);
gpio_disable_pulls(PIN_IRQ);

// Set SDIO and NTRCARD pin drive strengths.
// 4 mA is the default after reset. 2 mA is enough.
gpio_set_drive_strength(SDIO_CLK, GPIO_DRIVE_STRENGTH_2MA);
gpio_set_drive_strength(SDIO_CMD, GPIO_DRIVE_STRENGTH_2MA);
gpio_set_drive_strength(SDIO_D0, GPIO_DRIVE_STRENGTH_2MA);
gpio_set_drive_strength(SDIO_D1, GPIO_DRIVE_STRENGTH_2MA);
gpio_set_drive_strength(SDIO_D2, GPIO_DRIVE_STRENGTH_2MA);
gpio_set_drive_strength(SDIO_D3, GPIO_DRIVE_STRENGTH_2MA);

gpio_set_drive_strength(PIN_D0, GPIO_DRIVE_STRENGTH_2MA);
gpio_set_drive_strength(PIN_D1, GPIO_DRIVE_STRENGTH_2MA);
gpio_set_drive_strength(PIN_D2, GPIO_DRIVE_STRENGTH_2MA);
gpio_set_drive_strength(PIN_D3, GPIO_DRIVE_STRENGTH_2MA);
gpio_set_drive_strength(PIN_D4, GPIO_DRIVE_STRENGTH_2MA);
gpio_set_drive_strength(PIN_D5, GPIO_DRIVE_STRENGTH_2MA);
gpio_set_drive_strength(PIN_D6, GPIO_DRIVE_STRENGTH_2MA);
gpio_set_drive_strength(PIN_D7, GPIO_DRIVE_STRENGTH_2MA);

// Setup SDIO and NTRCARD pin pulls.
// SDIO CMD/DAT required when there are no external pull-ups.
gpio_disable_pulls(SDIO_CLK);
#if 0
// We have no external pull-ups.
gpio_pull_up(SDIO_CMD);
gpio_pull_up(SDIO_D0);
gpio_pull_up(SDIO_D1);
gpio_pull_up(SDIO_D2);
gpio_pull_up(SDIO_D3);
#else
// We have external pull-ups.
gpio_disable_pulls(SDIO_CMD);
gpio_disable_pulls(SDIO_D0);
gpio_disable_pulls(SDIO_D1);
gpio_disable_pulls(SDIO_D2);
gpio_disable_pulls(SDIO_D3);
#endif

gpio_disable_pulls(PIN_RST);
gpio_disable_pulls(PIN_CEB);
gpio_disable_pulls(PIN_WREB);
gpio_disable_pulls(PIN_D0);
gpio_disable_pulls(PIN_D1);
gpio_disable_pulls(PIN_D2);
gpio_disable_pulls(PIN_D3);
gpio_disable_pulls(PIN_D4);
gpio_disable_pulls(PIN_D5);
gpio_disable_pulls(PIN_D6);
gpio_disable_pulls(PIN_D7);
gpio_disable_pulls(PIN_CS2);

// Set SDIO and NTRCARD DAT pin slew rate.
// Default slew rate after reset is slow. Good enough for 25 MHz.
#if 0
gpio_set_slew_rate(SDIO_CLK, GPIO_SLEW_RATE_FAST);
gpio_set_slew_rate(SDIO_CMD, GPIO_SLEW_RATE_FAST);
gpio_set_slew_rate(SDIO_D0, GPIO_SLEW_RATE_FAST);
gpio_set_slew_rate(SDIO_D1, GPIO_SLEW_RATE_FAST);
gpio_set_slew_rate(SDIO_D2, GPIO_SLEW_RATE_FAST);
gpio_set_slew_rate(SDIO_D3, GPIO_SLEW_RATE_FAST);

gpio_set_slew_rate(PIN_D0, GPIO_SLEW_RATE_FAST);
gpio_set_slew_rate(PIN_D1, GPIO_SLEW_RATE_FAST);
gpio_set_slew_rate(PIN_D2, GPIO_SLEW_RATE_FAST);
gpio_set_slew_rate(PIN_D3, GPIO_SLEW_RATE_FAST);
gpio_set_slew_rate(PIN_D4, GPIO_SLEW_RATE_FAST);
gpio_set_slew_rate(PIN_D5, GPIO_SLEW_RATE_FAST);
gpio_set_slew_rate(PIN_D6, GPIO_SLEW_RATE_FAST);
gpio_set_slew_rate(PIN_D7, GPIO_SLEW_RATE_FAST);
#endif

// SDIO CLK pin needs to be low before init.
gpio_put(SDIO_CLK, false);
gpio_set_dir(SDIO_CLK, true);

// Disable all unused GPIO inputs. Saves a little power.
#if 1
uint32_t usedPins = NTRC_PIN_MASK | SDIO_PIN_MASK | DEV_UART_PIN_MASK;
for(uint32_t i = 0; i < NUM_BANK0_GPIOS; i++)
{
if(!(usedPins & 1u))
{
gpio_set_input_enabled(i, false);
}
usedPins >>= 1;
}
#endif
}

int __time_critical_func(main)()
{
bi_decl(bi_program_description("Ntr card emulator"));
Expand Down Expand Up @@ -196,39 +296,7 @@ int __time_critical_func(main)()

multicore_launch_core1(core1_entry);

gpio_init_mask(PIN_INPUT_MASK);
gpio_set_dir_in_masked(PIN_INPUT_MASK);
gpio_init(PIN_IRQ);
gpio_put(PIN_IRQ, 0);
gpio_set_dir(PIN_IRQ, GPIO_OUT);
gpio_disable_pulls(PIN_D0);
gpio_disable_pulls(PIN_D1);
gpio_disable_pulls(PIN_D2);
gpio_disable_pulls(PIN_D3);
gpio_disable_pulls(PIN_D4);
gpio_disable_pulls(PIN_D5);
gpio_disable_pulls(PIN_D6);
gpio_disable_pulls(PIN_D7);
gpio_set_slew_rate(PIN_D0, GPIO_SLEW_RATE_FAST);
gpio_set_slew_rate(PIN_D1, GPIO_SLEW_RATE_FAST);
gpio_set_slew_rate(PIN_D2, GPIO_SLEW_RATE_FAST);
gpio_set_slew_rate(PIN_D3, GPIO_SLEW_RATE_FAST);
gpio_set_slew_rate(PIN_D4, GPIO_SLEW_RATE_FAST);
gpio_set_slew_rate(PIN_D5, GPIO_SLEW_RATE_FAST);
gpio_set_slew_rate(PIN_D6, GPIO_SLEW_RATE_FAST);
gpio_set_slew_rate(PIN_D7, GPIO_SLEW_RATE_FAST);
gpio_pull_up(PIN_CEB);
gpio_pull_up(PIN_WREB);
gpio_pull_down(PIN_RST);
gpio_pull_up(PIN_CS2);
gpio_set_drive_strength(PIN_D0, GPIO_DRIVE_STRENGTH_2MA);
gpio_set_drive_strength(PIN_D1, GPIO_DRIVE_STRENGTH_2MA);
gpio_set_drive_strength(PIN_D2, GPIO_DRIVE_STRENGTH_2MA);
gpio_set_drive_strength(PIN_D3, GPIO_DRIVE_STRENGTH_2MA);
gpio_set_drive_strength(PIN_D4, GPIO_DRIVE_STRENGTH_2MA);
gpio_set_drive_strength(PIN_D5, GPIO_DRIVE_STRENGTH_2MA);
gpio_set_drive_strength(PIN_D6, GPIO_DRIVE_STRENGTH_2MA);
gpio_set_drive_strength(PIN_D7, GPIO_DRIVE_STRENGTH_2MA);
earlyGpioInit();

#ifdef DETECT_CONSOLE_TYPE
setRomToDsiRom();
Expand Down
78 changes: 52 additions & 26 deletions src/sd/SdCard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,40 +97,51 @@ sdio_status_t SdCard::ACmd41SdSendOpCond(u32 argument, u32& response) const
return rp2040_sdio_command_R3(ACMD41, argument, &response); // SD_SEND_OP_COND
}

sdio_status_t SdCard::ACmd42SetClrCardDetect(u32 argument) const
{
u32 response;
return rp2040_sdio_command_R1(ACMD42, argument, &response); // SET_CLR_CARD_DETECT
}

bool SdCard::TryInitialize()
{
u32 reply;
sdio_status_t status;

// Initialize at 1 MHz clock speed
rp2040_sdio_init(25);

// Establish initial connection with the card
for (int retries = 0; retries < 5; retries++)
{
// sleep_us(1000);
reply = 0;
Cmd0GoIdleState();
status = Cmd8SendIfCond(0x1AA, reply);
// Initialize at ~403.225 kHz.
rp2040_sdio_init(62);

if (status == SDIO_OK && reply == 0x1AA)
// Send a minimum of 74 clock cycles before the first command.
// This delay assumes a clock rate of 403.225 kHz.
// The CMD/CLK state machine must continuously clock the card for this to work.
sleep_us(183);

// Go into idle state.
Cmd0GoIdleState();

// Send interface/voltage support. Only SDv2 and up will respond.
// Voltage supplied (VHS) 2.7-3.6V plus check pattern.
status = Cmd8SendIfCond(0x1AA, reply);
if(status == SDIO_OK)
{
if(reply != 0x1AA)
{
break;
return false;
}
}

if (reply != 0x1AA || status != SDIO_OK)
else if(status != SDIO_ERR_RESPONSE_TIMEOUT)
{
return false;
}

// Send ACMD41 to begin card initialization and wait for it to complete
// Send ACMD41 to begin card initialization and wait for it to complete.
// 3.2-3.3V, XPC = Maximum Performance, HCS set if SEND_IF_COND didn't time out.
const u32 opCondArg = SD_ACMD41_XPC | SD_OCR_3_2_3_3V | (status == SDIO_OK ? SD_ACMD41_HCS : 0u);
u32 start = millis();
do
{
if (Cmd55AppCmd(0) != SDIO_OK ||
ACmd41SdSendOpCond(0xD0040000, _sdioOcr) != SDIO_OK) // 3.0V voltage
// !checkReturnOk(rp2040_sdio_command_R1(ACMD41, 0xC0100000, &g_sdio_ocr)))
ACmd41SdSendOpCond(opCondArg, _sdioOcr) != SDIO_OK)
{
return false;
}
Expand All @@ -139,41 +150,56 @@ bool SdCard::TryInitialize()
{
return false;
}
} while (!(_sdioOcr & (1 << 31)));
} while (!(_sdioOcr & SD_OCR_READY));

// Get CID
// Check if the voltage is supported.
if(!(_sdioOcr & SD_OCR_3_2_3_3V)) // 3.2-3.3V.
{
return false;
}

// Get CID.
if (Cmd2AllSendCid(_sdioCid) != SDIO_OK)
{
return false;
}

// Get relative card address
// Get relative card address.
if (Cmd3SendRelativeAddr(_sdioRca) != SDIO_OK)
{
return false;
}

// Get CSD
// Increase to 25 MHz clock rate.
// SD spec note:
// We can increase the clock after end of identification state.
rp2040_sdio_init(1);

// Get CSD.
if (Cmd9SendCsd(_sdioRca, _sdioCsd) != SDIO_OK)
{
return false;
}

// Select card
// Select card.
if (Cmd7SelectCard(_sdioRca) != SDIO_OK)
{
return false;
}

// Set 4-bit bus mode
// Disable DAT3 pull-up.
if (Cmd55AppCmd(_sdioRca) != SDIO_OK ||
ACmd6SetBusWidth(2) != SDIO_OK)
ACmd42SetClrCardDetect(0) != SDIO_OK)
{
return false;
}

// Increase to 25 MHz clock rate
rp2040_sdio_init(1);
// Set 4-bit bus mode.
if (Cmd55AppCmd(_sdioRca) != SDIO_OK ||
ACmd6SetBusWidth(2) != SDIO_OK)
{
return false;
}

_lastSdSector = CalculateSdCapacity() - 1;

Expand Down
1 change: 1 addition & 0 deletions src/sd/SdCard.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ class SdCard
sdio_status_t ACmd6SetBusWidth(u32 argument) const;
sdio_status_t ACmd23SetWrBlkEraseCount(u32 count) const;
sdio_status_t ACmd41SdSendOpCond(u32 argument, u32& response) const;
sdio_status_t ACmd42SetClrCardDetect(u32 argument) const;

bool IsSdhcCard() const { return (_sdioOcr & (1 << 30)) != 0; }
bool IsCardBusy() const { return (sio_hw->gpio_in & (1 << SDIO_D0)) == 0; }
Expand Down
26 changes: 26 additions & 0 deletions src/sd/SdCardInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,9 @@ const uint8_t ACMD23 = 0X17;
/** SD_SEND_OP_COMD - Sends host capacity support information and
activates the card's initialization process */
const uint8_t ACMD41 = 0X29;
/** SET_CLR_CARD_DETECT - Connect[1]/Disconnect[0] the 50 KOhm pull-up resistor
on CD/DAT3 (pin 1) of the card. */
const uint8_t ACMD42 = 0X2A;
//==============================================================================
// CARD_STATUS
/** The command's argument was out of the allowed range for this card. */
Expand Down Expand Up @@ -252,6 +255,29 @@ const uint8_t DATA_RES_MASK = 0X1F;
/** write data accepted token */
const uint8_t DATA_RES_ACCEPTED = 0X05;
//==============================================================================
// 5.1 Operation Conditions Register (OCR).
#define SD_OCR_2_7_2_8V (1UL << 15) // 2.7-2.8V.
#define SD_OCR_2_8_2_9V (1UL << 16) // 2.8-2.9V.
#define SD_OCR_2_9_3_0V (1UL << 17) // 2.9-3.0V.
#define SD_OCR_3_0_3_1V (1UL << 18) // 3.0-3.1V.
#define SD_OCR_3_1_3_2V (1UL << 19) // 3.1-3.2V.
#define SD_OCR_3_2_3_3V (1UL << 20) // 3.2-3.3V.
#define SD_OCR_3_3_3_4V (1UL << 21) // 3.3-3.4V.
#define SD_OCR_3_4_3_5V (1UL << 22) // 3.4-3.5V.
#define SD_OCR_3_5_3_6V (1UL << 23) // 3.5-3.6V.
#define SD_OCR_S18A (1UL << 24) // S18A: Switching to 1.8V Accepted. 0b: Continues current voltage signaling, 1b: Ready for switching signal voltage.
#define SD_OCR_CO2T (1UL << 27) // Over 2TB Card. CCS must also be 1 if this is 1.
#define SD_OCR_UHS_II (1UL << 29) // UHS-II Card Status. 0b: Non UHS-II Card, 1b: UHS-II Card.
#define SD_OCR_CCS (1UL << 30) // Card Capacity Status. 0b: SDSC, 1b: SDHC or SDXC.
#define SD_OCR_READY (1UL << 31) // Busy Status. 0b: On Initialization, 1b: Initialization Complete.
//==============================================================================
// Argument bits for SEND_OP_COND (ACMD41).
// For voltage bits see OCR register above.
#define SD_ACMD41_S18R (1UL << 24) // S18R: Switching to 1.8V Request. 0b: Use current signal voltage, 1b: Switch to 1.8V signal voltage.
#define SD_ACMD41_HO2T (1UL << 27) // Over 2TB Supported Host. HCS must also be 1 if this is 1.
#define SD_ACMD41_XPC (1UL << 28) // SDXC Power Control. 0b: Power Saving, 1b: Maximum Performance.
#define SD_ACMD41_HCS (1UL << 30) // Host Capacity Support. 0b: SDSC Only Host, 1b: SDHC or SDXC Supported.
//==============================================================================
/**
* \class CID
* \brief Card IDentification (CID) register.
Expand Down
Loading