Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 7 of 7

Thread: NXP_SDHC.cpp TODO - High Speed Mode

  1. #1
    Senior Member
    Join Date
    Sep 2015
    Posts
    108

    NXP_SDHC.cpp TODO - High Speed Mode

    Is there a technical reason other than too few hours in the day that high speed mode hasn't been implemented in NXP_SDHC per this TODO note? I might try it, but if there's a known issue I won't bother.

    https://github.com/PaulStoffregen/SD..._SDHC.cpp#L565

  2. #2
    I use the high speed mode on a 3.6 with o trouble but my code is in Forth. It is quite straightforward though.

  3. #3
    Senior Member
    Join Date
    Sep 2015
    Posts
    108
    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 by ecurtz; 08-24-2020 at 10:13 PM.

  4. #4
    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.

  5. #5
    Senior Member
    Join Date
    Sep 2015
    Posts
    108
    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;
    }

  6. #6
    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.

  7. #7
    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

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •