• AVR Freaks

SDHC Initialization doesn't respond to ACMD41 (Returns 0x01)

Author
esoren
New Member
  • Total Posts : 7
  • Reward points : 0
  • Joined: 2011/04/14 21:00:06
  • Location: 0
  • Status: offline
2011/04/14 21:16:10 (permalink)
0

SDHC Initialization doesn't respond to ACMD41 (Returns 0x01)

I normally try not to post problems online until I am REALLY stuck -- I really don't know what I am doing wrong and I am hoping one of you will see a silly mistake I've made. 

I am trying to initialize an SDHC card using a PIC18f44J50. I got the code working with a normal SD card to do extended reading/writing but I will need larger capacities than 2GB for my project. 

So far I have everything working up to ACMD41. 

CMD0 response is R1(0x01)
CMD8 responds with R7 and supports the working voltage (mirrors my check pattern and the VHS)
CMD58 gives me the expected R3 response 
CMD55 response is R1(0x01)
ACMD41 response is always 0x01 so the card never comes out of idle. 

I've done a lot of web searching and I've read the Specifications more times than I care to admit. I have written out each command and response bit-by-bit to verify they make sense. I have tried various things with the CS line (deasserting between commands, leaving asserted the whole time, etc) and nothing seems to make a difference. 

Does anyone have any idea where I've gone wrong? (note: this always returns 4 after a 2-3s delay) 


   
unsigned char SD_Init() {
    unsigned int i, n = 0;
    unsigned char status;
    unsigned char status1, status2, status3, status4, status5;

    Delay10KTCYx(10); //wait for the SD card to initialize


    SSP1CON1 = 0b00100010; //SPI clk = Fosc/64, SSPEN=1, CKP = 0
    SSP1CON1bits.CKP = 1; //clock idle state high level
    SSP1STATbits.CKE = 0;
    SSP1STATbits.SMP = 0;


    CS1_PIN = 1;  // Turn off SD Card
    for(i=0; i < 20; i++) {
        while(SPIWrite(0xFF)); // give SD Card about a hundred clock cycles to boot up
    }
    CS1_PIN = 0;

    //SEND CMD0 
    i = 0; 
    do {

        if(i++ > 250) {
            Nop();
            return 1; //timeout 1
        }

        CS1_PIN = 1; 
        SPIWrite(0xFF);
        CS1_PIN = 0; 
        SPIWrite(0xFF); 

        //cmd0 = 0x40 00 00 00 00 95
        SPIWrite(0x40);
        SPIWrite(0x00);
        SPIWrite(0x00);
        SPIWrite(0x00);
        SPIWrite(0x00);
        SPIWrite(0x95);

        n = 0;
        do{
             if(n++ > 250) {
                  break; 
             }
             status = SPIRead();
        } while (status == 0xFF); //wait for a response  


    } while(status != 0x01); //wait for R1 response

    SPIWrite(0xFF);  //dummy clocks
    SPIWrite(0xFF); 

    //SEND CMD8
    i = 0;
    do {

        if(i++ > 50) {
            return 2; //timeout 2
        }

        CS1_PIN = 1; 
        SPIWrite(0xFF);
        CS1_PIN = 0; 
 


        SPIWrite(0xFF);
        SPIWrite(0x48); //cmd8 = 0x48 00 00 01 AA 87 
        SPIWrite(0x00); 
        SPIWrite(0x00);  
        SPIWrite(0x01);  
        SPIWrite(0xAA);  
        SPIWrite(0x87);  

        n = 0; 
        do{ 
            if(n++ > 100) { 
                break;  
            } 
            status = SPIRead(); 
            if(status == 0x01) { 
                SPIRead(); //0x00  
                SPIRead(); //0x00 
                SPIRead(); //0x01 (or 0x00); 
                status = SPIRead(); //0xAA  
                break; 
            } 
        } while (1==1);  
    } while(status != 0xAA); //wait for the echo response at the end of R7

    SPIWrite(0xFF); 
    SPIWrite(0xFF); 

    //SEND CMD58

    i = 0;
    do {

        if(i++ > 50) { 
            return 3; //timeout 3 
        } 

        CS1_PIN = 1;  
        SPIWrite(0xFF); 
        CS1_PIN = 0;  


        SPIWrite(0xFF);  
        SPIWrite(0x7A); //cmd58 = 0x7A 00 00 00 00 FF 
        SPIWrite(0x00); 
        SPIWrite(0x00);  
        SPIWrite(0x00);  
        SPIWrite(0x00);  
        SPIWrite(0xFF);  

        n = 0; 
        do{ 
            if(n++ > 100) { 
                break;  
            } 
            status = SPIRead(); 
            if(status == 0x01) { 
                status1 = SPIRead(); //0x00 
                status2 = SPIRead(); //0xFF 
                status3 = SPIRead(); //0x80 
                status4 = SPIRead(); //0x00  
                status = 0x01;  
                break; 
            } 
        } while (1==1);  
    } while(status != 0x01); //wait for the echo response at the end of R7

    SPIWrite(0xFF); 
    SPIWrite(0xFF); 



    //SEND ACMD41
    i = 0;
    do {
        if(i++ > 5000) { 
            return 4; //timeout 4 
        } 

        CS1_PIN = 1;  
        SPIWrite(0xFF);  
        CS1_PIN = 0;  
        
        SPIWrite(0xFF);  
        SPIWrite(0x77); //CMD55 = 0x77 00 00 00 00 FF 
        SPIWrite(0x00);  
        SPIWrite(0x00);  
        SPIWrite(0x00);  
        SPIWrite(0x00);  
        SPIWrite(0xFF); 

        status1 = SPIRead();  
        status2 = SPIRead(); //0x01: R1 Response: Idle 

        CS1_PIN = 1;  
        SPIWrite(0xFF); 
        CS1_PIN = 0; 

        SPIWrite(0xFF);  
        SPIWrite(0x69); //acmd41 = 0x69 40 00 00 00 FF (HCS = 1)  
        SPIWrite(0x40);  
        SPIWrite(0x00);  
        SPIWrite(0x00);  
        SPIWrite(0x00);  
        SPIWrite(0xFF);  

        n = 0; 
        do{ 
            if(n++ > 10) { 
                break;  
            } 
            status = SPIRead(); 
        } while(status != 0x00);  


        CS1_PIN = 1;  
        for(n = 0; n < 10; n++) {
            SPIWrite(0xFF);  
        }


    } while(status != 0x00); //wait until out of idle state


    CS1_PIN = 1; //unselect SD card
    SSP1CON1 &= 0b11110000; //set SSP clock speed to FOSC/4 (10Mhz)

    return 0;
}



post edited by esoren - 2011/04/15 11:07:54
#1

7 Replies Related Threads

    esoren
    New Member
    • Total Posts : 7
    • Reward points : 0
    • Joined: 2011/04/14 21:00:06
    • Location: 0
    • Status: offline
    Re:SDHC Initialization doesn't respond to ACMD41 (Returns 0x01) 2011/04/15 15:03:46 (permalink)
    0
    Double Post - new information: 

    I've been working with the code quite a bit. I made it so that the PIC repeatedly issues CMD55 until it gets an R1 response before it issues ACMD41. If CMD55 doesn't ever receive an R1 response (after 500 tries) it breaks out of the loop and issues ACMD41 anyway. 

    Apparently this a good idea. As I've been using the debugger on the code I am seeing some strange behavior.

    On the first 55/41 attempt I get: 

    CMD55 - response 0x01
    ACMD41 - response 0x01

    On every try thereafter I get NO response from CMD55 (only 0xFF). If I comment out ACMD41 entirely then I always get an 0x01 response from CMD55. 

    So something about issuing ACMD41 is causing the card to lock up and not respond to CMD55 at all. 

    Any ideas? I am attaching the relevant section of code: 

      
    //SEND ACMD41
    i = 0;
    do {
        if(i++ > 1000) {
            return 4; //timeout 4  (the CMD55/ACMD41 command has failed 1000 times)
        }

        //Send CMD55 until R1 response 
        u = 0; 
        do { 
            if(u++ > 500) {
                break; //timeout 6 (no R1 response from CMD55 after 500 tries -- go straight to ACMD41)
            }

            CS1_PIN = 1; 
            SPIWrite(0xFF);
            CS1_PIN = 0; 
            SPIWrite(0xFF);  

            if(SPIWait()) { //this function sends 0xFF until it receives 0xFF in response 
                return 5; //timeout 5
            }


            SPIWrite(0x77); //CMD55 = 0x77 00 00 00 00 01 
            SPIWrite(0x00); 
            SPIWrite(0x00); 
            SPIWrite(0x00); 
            SPIWrite(0x00); 
            SPIWrite(0x01);

            k = 0; 
            do {
                if(k++ > 10) {
                    break; 
                }
                status = SPIRead();
            } while(status & 0x80); 

        } while(status != 0x01); 


        CS1_PIN = 1; 
        SPIWrite(0xFF);
        CS1_PIN = 0; 
        SPIWrite(0xFF); 
        if(SPIWait()) { //this function sends 0xFF until it receives 0xFF in response 
            return 5; //timeout 5
        }

        SPIWrite(0x69); //acmd41 = 0x69 40 00 00 00 01 (HCS = 1) 
        SPIWrite(0x40); 
        SPIWrite(0x00); 
        SPIWrite(0x00); 
        SPIWrite(0x00); 
        SPIWrite(0x01); 

        n = 0;
        do{
            if(n++ > 10) {              break;           }          status = SPIRead(); 
        } while(status & 0x80); 

    } while(status != 0x00); //wait until out of idle state 


    post edited by esoren - 2011/04/15 15:10:46
    #2
    pfg
    New Member
    • Total Posts : 25
    • Reward points : 0
    • Joined: 2010/07/24 14:50:48
    • Location: 0
    • Status: offline
    Re:SDHC Initialization doesn't respond to ACMD41 (Returns 0x01) 2011/04/23 17:14:58 (permalink)
    0
    You may want to look at the flowchart on card init here and compare to what your doing.

    http://elm-chan.org/fsw/ff/00index_e.html

    I would be interested in hearing how it worked out for getting HC to communicate :)
    post edited by pfg - 2011/04/23 17:17:54
    #3
    frostmeister
    Super Member
    • Total Posts : 769
    • Reward points : 0
    • Joined: 2006/12/03 10:20:52
    • Location: UK
    • Status: offline
    Re:SDHC Initialization doesn't respond to ACMD41 (Returns 0x01) 2011/04/24 03:21:39 (permalink)
    0
    In my init routines, CMD55 + ACMD41 are paired, waiting for a 0x00 response from ACMD41. I don't think you issue 55 repeatedly, or the card would think you're sending ACMD55, which isn't a valid command.

    I've seen anything in the range of 5 ~ 1000 attempts when a loop counter is used to track attempts. Spec says allow up to 100mS I believe.
    #4
    matonga
    New Member
    • Total Posts : 1
    • Reward points : 0
    • Joined: 2011/05/22 21:09:00
    • Location: 0
    • Status: offline
    Re:SDHC Initialization doesn't respond to ACMD41 (Returns 0x01) 2011/05/22 21:27:50 (permalink)
    0
    If of any help, I'm doing this with a Kingston microSD 2.0 GByte card, it is not SDXC/SDHC but it speaks SD Version 2 so I suppose it'll be useful to you anyway:

    I'll omit the SPI reads and put just SPI writes and comment the results I'm getting to make it easier to read.

    First I ensure CS line is deasserted and power up the card (have a 3.3V CTR allowing to power-cycle the card) and wait for 1 msec.

    Then send least 74 clocks. I let the SPI peripheral do it for me (I don't let it drive the CS line, I drive it myself), by sending this:

    int i;
    for (i=0; i<10; i++) WriteSDByte (0xFF);

    10 bytes means 80 clocks, more than the required 74.

    WriteSDByte is a convenience function, uses Microchip C30 libs to write to SPI and wait for completion.

    Then I assert CS line and send CMD0 once:

    WriteSDCmd (0x40, 0, 0x95);

    Again another convenience function (actually sends 0x40, 0x00, 0x00, 0x00, 0x00, 0x95).

    And get this for response:

    0x1F 0x01 0xFF 0xFF 0xFF ...

    After reading response I deassert CS line. In effect, I reassert CS line before sending a command and deassert it after reading responses.

    About the first 0x1F... the card seems to have problems to pull up the MISO line... maybe I should clock it with 250 kbps instead of 4 mbps first.

    Then I follow pretty much @pfg's suggestion (this flowchart: http://elm-chan.org/docs/mmc/sdinit.png).

    WriteSDCmd (0x48, 0x1AA, 0x87);

    And get:

    0xFF 0x01 0x00 0x00 0x01 0xAA 0xFF 0xFF 0xFF 0xFF ...

    Then ACMD41:

    WriteSDCmd (0x77, 0, 0);  // I get 0xFF 0x01 in MISO pin after doing this
    WriteSDCmd (0x69, 0x40000000, 0);    // I get 0xFF 0x01

    I have to issue this command repeatedly, until the second line returns 0xFF 0x00 instead.

    Then I send CMD58:


    WriteSDCmd (0x7A, 0, 0);  // I get 0xFF 0x00 0x80 0xFF 0x80 0x00 0xFF 0xFF 0xFF...

    The response received is really R1 (1 byte; 0x00) + OCR (4 bytes; 0x80FF8000)

    By checking bit 30 now we know the card uses byte addressing. @esoren will probably receive something like 0xC0FF8000 instead, indicating he must use block addressing instead.

    I store bit 30 into some var, for example <int sd_ccs_bit>.

    After that, I set block size to 512 bytes using CMD16:

    WriteSDCmd (0x50, 0x200, 0);    // returns 0xFF 0x00 0xFF 0xFF 0xFF...

    Each time I read/write a block I use this:

    int read_SD_block (unsigned long address, char *out_buffer) {
        if (!sd_ccs_bit) address <<= 9;
        ...
    }

    So if SDSD card then I multiply by 512 (shift by 9), else for SDXC/SDHC cards do nothing.

    I hope this helps other people, I had real trouble too speaking to SD card.
    #5
    esoren
    New Member
    • Total Posts : 7
    • Reward points : 0
    • Joined: 2011/04/14 21:00:06
    • Location: 0
    • Status: offline
    Re:SDHC Initialization doesn't respond to ACMD41 (Returns 0x01) 2011/06/07 22:21:51 (permalink)
    0
    Thank you all for your help. Believe it or not, I am still facing this problem! I actually had a PCB fab'd for this project and I am seeing exactly the same problem as before -- so I am pretty confident its not a hardware problem. ;) 

    I will spend a couple of days trying to implement your suggestions -- although I am pretty sure I am already doing what you're suggesting. According to the flowchart, I am following the left-most branch to eventually reach "Unknown card". 

    frostmeister: Thank you for your input. I agree that CMD55 and ACMD41 should always be paired. That is how I normally have it setup. What I noticed which seems abnormal is that after issuing the first CMD55+ACMD41 I get no further response from the card. The first time I issue CMD55 I get an 0x01 R1 response. After I send ACMD41 I get no response at all from any subsequent CMD55. I am under the impression from the specifications that the card should always give some kind of response so I thinks its strange that from that point forward I get nothing but 0xFF's. 

    I'll keep you guys updated -- hopefully this is just a silly mistake somewhere in my code. 
    post edited by esoren - 2011/06/07 22:23:03
    #6
    esoren
    New Member
    • Total Posts : 7
    • Reward points : 0
    • Joined: 2011/04/14 21:00:06
    • Location: 0
    • Status: offline
    Re:SDHC Initialization doesn't respond to ACMD41 (Returns 0x01) 2011/06/09 14:11:07 (permalink)
    0
    UPDATE: IT WORKS!

    I really appreciate all of your help! It turns out the problem was likely a hardware problem. The error I was receiving on the new PCB was in fact different from the error I received on the breadboard. When I fixed that error everything worked flawlessly first try. 

    In case someone runs across this thread, here are the things that I have changed -- I don't know what made the difference, though :(

    1.) I am using the MSSP2 module instead of MSSP1
    2.) On the new design I included pullup resistors on pins 8 and 9 
    3.) Changed all of the pullup resistors from 10k to 47k
    4.) Increased the operating frequency of the pic. (replaced 10Mhz crystal with 16Mhz)

     
    #7
    stirwl
    New Member
    • Total Posts : 1
    • Reward points : 0
    • Joined: 2012/10/17 20:38:58
    • Location: 0
    • Status: offline
    Re:SDHC Initialization doesn't respond to ACMD41 (Returns 0x01) 2012/10/17 20:42:55 (permalink)
    0
    see "SD Physical Layer Specification Version 2.00" page 19
    "If HCS is set to 0, High Capacity SD Memory Card never return ready statue (keep busy bit to 0). "
    Perhaps there is a problem with your acmd41 argument(expect 0x40000000)
    #8
    Jump to:
    © 2019 APG vNext Commercial Version 4.5