NXP_SDHC.cpp TODO - High Speed Mode

Status
Not open for further replies.
I use the high speed mode on a 3.6 with o trouble but my code is in Forth. It is quite straightforward though.
 
So far I haven't had any luck getting anything but SDHC_RESULT_ERROR from CMD6. Some of the flags are just guesses based on the other commands, but I've tried all the variations I can think of.

EDIT: I can get a OK response if I call this earlier in SDHC_CardInit() before changing to 4 bit data bus and 25MHz clock

Code:
static int SDHC_CMD6_SwitchFunction(uint32_t modes)
{
  uint32_t xfertyp;
  uint32_t status[16];
  int result;

 Serial.println("SDHC_CMD6_SwitchFunction");
 
//   SDHC_IRQSTAT = 0xffff;
#if defined(__IMXRT1062__)
  SDHC_MIX_CTRL |= SDHC_MIX_CTRL_DTDSEL;
#endif

  SDHC_CMDARG = modes;
//   SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(1) | SDHC_BLKATTR_BLKSIZE(64);

  xfertyp = (SDHC_XFERTYP_CMDINX(SDHC_CMD6) | SDHC_XFERTYP_CICEN |
             SDHC_XFERTYP_CCCEN | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48) |
             SDHC_XFERTYP_DTDSEL | SDHC_XFERTYP_DPSEL);
             
  result = SDHC_CMD_Do(xfertyp);
  
 Serial.print("SDHC_CMD_Do result was: ");
 Serial.println(result, HEX);
 
  if(result != SDHC_RESULT_OK) return result;

  // receive status
  while (!(SDHC_IRQSTAT & SDHC_IRQSTAT_TC)) { }  // wait for transfer to complete
  SDHC_IRQSTAT = (SDHC_IRQSTAT_TC | SDHC_IRQSTAT_BRR | SDHC_IRQSTAT_AC12E);

  result = SDHC_Read(status, 16);
  if (result == SDHC_RESULT_OK) {
    //(void)SDHC_CMDRSP0;
    sdCardDesc.accessMode = (status[3] >> 0) & 0xFF;
    sdCardDesc.cmdSystem = (status[2] >> 16) & 0xFF;
    sdCardDesc.drvStrength = (status[2] >> 0) & 0xFF;
    sdCardDesc.current = (status[1] >> 16) & 0xFF;
    
    Serial.println("SDIO Access Mode: " + sdCardDesc.accessMode);
    Serial.println("SDIO Command System: " + sdCardDesc.cmdSystem);
    Serial.println("SDIO Driver Strength: " + sdCardDesc.drvStrength);
    Serial.println("SDIO Current: " + sdCardDesc.current);
    
    for (int i = 0; i < 16; i++) {
    Serial.println(status[i], HEX);
    }
  }
  return result;
}
 
Last edited:
It has been some time since I wrote this so my memory has faded a bit. Looking at the code, DSADDR is set to point to a buffer, BLKATTR is set (count=1 and size=64), and the XFERTYP flags are 0x3a0011. (I use DMA)

I do see another difference in that I wait on the command complete flag in IRQSTAT and not transfer complete. I have no idea how the library you are using handles that data transfer but I suspect that waiting for transfer to complete before reading the data could cause trouble.. You should probably look at how a sector read is done.
 
Thanks for the responses!

This version does appear to be giving plausible results as long as it's called prior to switching to 4bit transfers. I would not be at all surprised if some of the flags are still wrong. You were correct that the sector read had the wait after the data read.

Code:
static int SDHC_CMD6_SwitchFunction(uint32_t modes)
{
  uint32_t xfertyp;
  uint32_t status[16];
  int result;

 Serial.println("SDHC_CMD6_SwitchFunction");
 
//   SDHC_IRQSTAT = 0xffff;
#if defined(__IMXRT1062__)
  SDHC_MIX_CTRL |= SDHC_MIX_CTRL_DTDSEL;
#endif

  SDHC_CMDARG = modes;
  SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(1) | SDHC_BLKATTR_BLKSIZE(64);

  xfertyp = (SDHC_XFERTYP_CMDINX(SDHC_CMD6) | SDHC_XFERTYP_CICEN |
             SDHC_XFERTYP_CCCEN | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48) |
             SDHC_XFERTYP_DTDSEL | SDHC_XFERTYP_DPSEL);
             
  result = SDHC_CMD_Do(xfertyp);
  
 Serial.print("SDHC_CMD_Do result was: ");
 Serial.println(result, HEX);
 
  if(result != SDHC_RESULT_OK) return result;

  result = SDHC_Read(status, 16);
  Serial.print("SDHC_Read result was: ");
  Serial.println(result, HEX);

  // receive status
  while (!(SDHC_IRQSTAT & SDHC_IRQSTAT_TC)) { }  // wait for transfer to complete
  SDHC_IRQSTAT = (SDHC_IRQSTAT_TC | SDHC_IRQSTAT_BRR | SDHC_IRQSTAT_AC12E);

  if (result == SDHC_RESULT_OK) {
    //(void)SDHC_CMDRSP0;
    uint8_t* statusBytes = (uint8_t*) status;
    sdCardDesc.accessMode = statusBytes[13];
    sdCardDesc.cmdSystem = statusBytes[11];
    sdCardDesc.drvStrength = statusBytes[9];
    sdCardDesc.current = statusBytes[7];

  Serial.print("SDIO Access Mode: ");
  Serial.println(sdCardDesc.accessMode, HEX);
  Serial.print("SDIO Command System: ");
  Serial.println(sdCardDesc.cmdSystem, HEX);
  Serial.print("SDIO Driver Strength: ");
  Serial.println(sdCardDesc.drvStrength, HEX);
  Serial.print("SDIO Current: ");
  Serial.println(sdCardDesc.current, HEX);
  }
  return result;
}
 
I think you should wait for command complete after calling SDHC_Read(). The transfer should be complete when it returns.

I switch to 4 bit mode before checking for 50MHz capability.
 
I looked at what the SD specification has to say about CMD6 again. Very confusing.

When asking about capabilities (mode=0) it says to select a function. This seemed useless but further reading shows that the data returned reflects that change. This can be used to verify that the card will not demand too much current in the new mode.

So the sequence is, more or less:

Verify card supports switch function command. (Some old SD cards will not. Probably not a big problem.)

Send CMD6 with argument 0x0ffffff1. This selects high speed mode and leaves everything else alone. Examine data to verify that high speed mode is available. A check of the current field might be in order as well. Hard to tell if that will be a problem unless you also know the input voltage to the regulator.

Send CMD6 with argument 0x8ffffff1 to switch to high speed mode. Check data to verify the switch happened before altering the local clock speed
 
Status
Not open for further replies.
Back
Top