Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SD Card does not enter high voltage mode #58

Open
kudruu opened this issue Aug 23, 2018 · 0 comments
Open

SD Card does not enter high voltage mode #58

kudruu opened this issue Aug 23, 2018 · 0 comments

Comments

@kudruu
Copy link

kudruu commented Aug 23, 2018

Using information from here and here I am having difficulty setting my UHS-1, Type 2 cards into high voltage mode.

Presumably, this step should be accomplished when sending 0x40000000 during ACMD41, but that does not seem to be the case. In fact, according to the SD protocol, the upper 8 bits are ignored when the lower 24 bits are 0. So does this command even have any effect here? What should the value be instead?

Secondly, it asserts that some cards already require CRC. So I updated the CRC portion of cardCommand() to be:

// send CRC
uint8_t crc = 0XFF;
if (cmd == CMD0) crc = 0X95;  // correct crc for CMD0 with arg 0
if (cmd == CMD8) crc = 0X87;  // correct crc for CMD8 with arg 0X1AA
if (cmd == CMD1) crc = 0xF9;
//if (cmd == ACMD41) crc = 0x77; //correct crc for ACMD41 with arg 0x40000000
if (cmd == ACMD41) crc = 0x17; //correct crc for ACMD41 with arg 0x50000000
if (cmd == CMD58) crc = 0xFD;
spiSend(crc);

Lastly, it recommends sending a dummy byte before CMD0 (aside from the 74 clock pulses), therefore I begin the function:

uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) {
  // end read if in partialBlockRead mode
  readEnd();

  // select card
  chipSelectLow();

  // wait up to 300 ms if busy
  waitNotBusy(300);

  //send dummy byte before idle
  if (cmd == CMD0) spiSend(0xFF);

  // send command
  spiSend(cmd | 0x40);

...

But for some reason, my cards always remain in low voltage (1.8V) mode, despite being purportedly capable of 2.7-3.3V operation (as evidenced in the OCR).

My full ::init() function looks like this:

uint8_t Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) {
  errorCode_ = inBlock_ = partialBlockRead_ = type_ = 0;
  chipSelectPin_ = chipSelectPin;
  // 16-bit init start time allows over a minute
  unsigned int t0 = millis();
  uint32_t arg;

  // set pin modes
  pinMode(chipSelectPin_, OUTPUT);
  digitalWrite(chipSelectPin_, HIGH);

  /* Drive the MISO pin high */
  pinMode(SPI_MISO_PIN, OUTPUT);
  digitalWrite(SPI_MISO_PIN, HIGH);

#ifndef USE_SPI_LIB
  pinMode(SPI_MISO_PIN, INPUT);
  pinMode(SPI_MOSI_PIN, OUTPUT);
  pinMode(SPI_SCK_PIN, OUTPUT);
#endif

#ifndef SOFTWARE_SPI
#ifndef USE_SPI_LIB
  // SS must be in output mode even it is not chip select
  pinMode(SS_PIN, OUTPUT);
  digitalWrite(SS_PIN, HIGH); // disable any SPI device using hardware SS pin
  // Enable SPI, Master, clock rate f_osc/128
  SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0);
  // clear double speed
  SPSR &= ~(1 << SPI2X);
#else // USE_SPI_LIB
  SDCARD_SPI.begin();
  settings = SPISettings(350000, MSBFIRST, SPI_MODE0);
#endif // USE_SPI_LIB
#endif // SOFTWARE_SPI

  // must supply min of 74 clock cycles with CS high.
#ifdef USE_SPI_LIB
  SDCARD_SPI.beginTransaction(settings);
#endif
  for (uint8_t i = 0; i < 10; i++) spiSend(0XFF);
#ifdef USE_SPI_LIB
  SDCARD_SPI.endTransaction();
#endif

  chipSelectLow();
  //Send CMD0
  // command to go idle in SPI mode
  while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) {
    unsigned int d = millis() - t0;
    if (d > SD_INIT_TIMEOUT) {
      error(SD_CARD_ERROR_CMD0);
      goto fail;
    }
  }
  //Send CMD8
  // check SD version
  if ((cardCommand(CMD8, 0x1AA) & R1_ILLEGAL_COMMAND)) {
    type(SD_CARD_TYPE_SD1);
  } else {
    // only need last byte of r7 response
    for (uint8_t i = 0; i < 4; i++) status_ = spiRec();
    if (status_ != 0XAA) {
      if(status_ != 0x01){
        error(SD_CARD_ERROR_CMD8);
        goto fail;
      }
    }
    type(SD_CARD_TYPE_SD2);
  }
  //SDHC supported, SDXC maximum performance
  arg = type() == SD_CARD_TYPE_SD2 ? 0X50000000 : 0;

  while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) {
    // check for timeout
    unsigned int d = millis() - t0;
    if (d > SD_INIT_TIMEOUT) {
      break;
    }
  }

  /*Try CMD1 before trying ACMD41 again */
  if(status_){
    while ((status_ = cardCommand(CMD1, 0)) != R1_READY_STATE) {
      unsigned int d = millis() - t0;
      if (d > SD_INIT_TIMEOUT) {
        error(SD_CARD_ERROR_CMD0);
        goto fail;
      }
    }
    while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) {
      // check for timeout
      unsigned int d = millis() - t0;
      if (d > SD_INIT_TIMEOUT) {
        error(SD_CARD_ERROR_ACMD41);
        goto fail;
      }
    }
  }

  // command to initialize in SPI mode

  // initialize card and send host supports SDHC if SD2
  // if SD2 read OCR register to check for SDHC card
  if (type() == SD_CARD_TYPE_SD2) {
    if ((status_ = cardCommand(CMD58, 0))) {
      error(SD_CARD_ERROR_CMD58);
      goto fail;
    }
    if ((spiRec() & 0XC0) == 0XC0) type(SD_CARD_TYPE_SDHC);
    // discard rest of ocr - contains allowed voltage range
    for (uint8_t i = 0; i < 3; i++) spiRec();
  }
  chipSelectHigh();

#ifndef SOFTWARE_SPI
  return setSckRate(sckRateID);
#else  // SOFTWARE_SPI
  return true;
#endif  // SOFTWARE_SPI

 fail:
  chipSelectHigh();
  return false;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant