11 years, 7 months ago.

SD card doesn't initialize *only* the first time?

Hi, I have a project MbedConsole. Basically uses a bunch of hacks to cobble together a working VGA framebuffer and PS/2 keyboard. Now I'm trying to add the final piece to my working single-board "computer": SD card access for storage.

Quick overview for context:

  • Mbed is overclocked to 100MHz
  • I'm using the fastlib library to prioritize certain interrupts

Now, despite overclocking and such, things still seem pretty stable.

I recently added SD card support with the official library, but I'm having problems with it.

I have the SD card hooked up as so:

**NEW** SparkFun SD Breakout Board
MicroSD Breakout    mbed
   D3  o-------------o 20    (DigitalOut cs)
   CMD  o-------------o 11    (SPI mosi)
   VCC o-------------o VOUT
   CLK o-------------o 13    (SPI sclk)
   GND o-------------o GND  
   D0  o-------------o 12    (SPI miso)
   CD  o
   D1  o
   D2  o

This seems to be a fairly accurate "translation" from the new sparkfun SD breakout board to the old pin out.

So, this seems to work /sometimes/. Namely, it never works the first time I try it. It'll segfault somewhere. My only clue is "Didn't get a response from the disk"

However, I traced it down and it's seems really weird. It *did* receive a response from the disk it appears. _cmdx inside SDFileSystem is where this weird behavior originates.

At

int SDFileSystem::_cmdx(int cmd, int arg) {
    _cs = 0;
    
    // send a command
    _spi.write(0x40 | cmd);
    _spi.write(arg >> 24);
    _spi.write(arg >> 16);
    _spi.write(arg >> 8);
    _spi.write(arg >> 0);
    _spi.write(0x95);
    
    // wait for the repsonse (response[7] == 0)
    for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) {
        int response = _spi.write(0xFF);
        if (!(response & 0x80)) {
            debug("response: %x", response); //this returns 0x7F !?
            return response;
        }
    }
    _cs = 1;
    _spi.write(0xFF);
    return -1; // timeout
}

So, as you can see, it returns 0x7F from the SD card. The top bit isn't set (the idle bit?) so _cmdx appears to think "ok, it's done" and returns that response.

However, it returns it to this:

    // CMD9, Response R2 (R1 byte + 16-byte block read)
    if (_cmdx(9, 0) != 0) {
        debug("Didn't get a response from the disk\n");
        return 0;
    }

And hence, it returns 0x7F, not 0 as appears to be expected. I've tried changing this check to exclusively check for `== -1` (the timeout), but that doesn't fix anything and just makes it break later on. So, I'm sure this is some error code covered somewhere in the spec, but I can't find it.

Anyway, could anyone give me any clues as to why my SD card doesn't work the first time, but does the second time?

Btw, by "first time", I mean if I unplug the mbed from power, plug it in, and run this program, it will crash. If I push the reset button, and run it again, it will work flawlessly

2 Answers

11 years, 7 months ago.

I have no idea why it's broken, but I put in a stupidly simple fix. The core problem is that initialise_card fails. at the CMD0 bit. I don't understand why. i tried adding extra time and tried eliminating any noise issues, but still wasn't working.

So, I added a `int tried_again;` to SDFileSystem and then changed initialise_card to this:

int SDFileSystem::initialise_card() {
    // Set to 100kHz for initialisation, and clock card with cs = 1
    _spi.frequency(100000);
    _cs = 1;
    for (int i = 0; i < 16; i++) {
        _spi.write(0xFF);
    }
    
    // send CMD0, should return with all zeros except IDLE STATE set (bit 0)
    if (_cmd(0, 0) != R1_IDLE_STATE) {
        if(!tried_again) //change here
        {
            tried_again=1;
            return initialise_card(); //for good luck, try it again? 
        }
        debug("No disk, or could not put SD card in to SPI idle state\n");
        return SDCARD_FAIL;
    }
    
    // send CMD8 to determine whther it is ver 2.x
    int r = _cmd8();
    if (r == R1_IDLE_STATE) {
        return initialise_card_v2();
    } else if (r == (R1_IDLE_STATE | R1_ILLEGAL_COMMAND)) {
        return initialise_card_v1();
    } else {
        debug("Not in idle state after sending CMD8 (not an SD card?)\n");
        return SDCARD_FAIL;
    }
}

I forked and published this new code at http://mbed.org/users/earlz/code/SDFileSystem_tryagain/

I'm really curious to know why this try again functionality is even needed though. I've found that it does this same thing with my setup even with the SDFileSystem sample program, but of course, only the first time.

Accepted Answer
11 years, 7 months ago.

I get the same error on many of my MBED projects,
going back quite some time.and lofts of different programs.
So far, the only 'fix' I have found is to read a file from SD and ignore the error. :-(

Ceri

I ended up basically taking your "solution" and narrowing it down to only retry the first set of commands

posted by Jordan Earls 17 Apr 2013