Connect with us

Raspberry Pi + SD Card = FAIL

Discussion in 'Microcontrollers, Programming and IoT' started by Raven Luni, Sep 3, 2013.

Scroll to continue with content
  1. Raven Luni

    Raven Luni

    798
    8
    Oct 15, 2011
    Greetings,

    Hopefully this is simple enough to explain without any pictures...

    I'm trying to access an SD card using the SPI interface from my raspberry pi. I guess you could think of this the same as any controller - its just a set of pins and logic IO. According to the spec, the logic is [email protected] - the same voltage range as an SD card.

    I have 5 pins assigned as follows:
    - [OUT] VCC
    - [OUT] CS
    - [OUT] CLK
    - [OUT] DI
    - [IN] DO

    After powering up the card (setting VCC pin to 1), I wait between 250 and 500ms before sending 80 clock cycles (with CS high) and then a CMD0 (with CS low)

    The problem is the card doesnt ever respond in any way. With no external components I get floating bus behaviour, as if the card isnt there at all or not even powered up. I've tried bypass capacitors on the power pins, pull up and pull down resistors on all pins (both external 10Ks and setting the internal 50Ks on the pi). I also put 220pF capacitors from all pins to ground. All these measures do is stablise the reading - which is whatever way the pin is pulled. I even tried using the 3.3V rail from my ATX supply in case it was a current issue. Not a saussage :(

    And the card works perfectly when its in a reader. Its a Sandisk 2GB SDSC. I havent got any others to try just at the moment (apart from the one thats in the pi but obviously cant use that).


    Why the F*** is this card pretending not to exist???
     
    Last edited: Sep 3, 2013
  2. Raven Luni

    Raven Luni

    798
    8
    Oct 15, 2011
    The last reasonable course of action I suppose would be to assume that the raw signals just cant be trusted (even though they drive LEDs and stuff no problem) and to try a fully buffered solution with a separate power supply. I'm loath to waste the effort if it doesnt work though. Wish me luck - this better f****** work!
     
  3. Solidus

    Solidus

    349
    4
    Jun 19, 2011
    Looking at the protocol specification - it says you are supposed to assert CMD8. This will determine the version number of the SD card (which version of the protocol it implements).

    Then it directs to assert ACMD41 w/ ARG = 0 after asserting CMD8. The response from this card will be a busy bit (i.e. if no response, ready to proceed).

    Have you tried this?

    (P.S. I'm assuming this project is for fun, otherwise you'd be using the inbuilt SD mechanism :p I do many such things, however, so best of luck!)
     
  4. Raven Luni

    Raven Luni

    798
    8
    Oct 15, 2011
    I was sending the 8 to begin with but focusing on the first steps after no results.
    The 8 is the same - it should at least return the check pattern but absolutely not a thing. I'm pretty sure the card isnt even operational (yet it works in a normal reader)

    And yes this is even after I've taken the buffering steps mentioned above. Its now powered from the ATX supply with transistor switches on all pins - same as before - only difference it makes is a stable reading (of absolutely f***ing nothing!!).
     
    Last edited: Sep 4, 2013
  5. Solidus

    Solidus

    349
    4
    Jun 19, 2011
    That's strange. This is a 'make sure' kind of question, but you did make sure to employ the transistor buffer stages as bidirectional, right?

    When you say you've tried it in a reader; have you tried it in the RPi reader? Those reader interfaces usually use the SD protocol as opposed to SPI - but that doesn't explain much, as if the SPI interface was shoddy you'd expect the card to be as a whole.

    Not that it's too necessary, but do you think you can work up a schematic of the buffering scheme and RPi interface? That'll tell us both if there might be an obvious mixup of something.
     
  6. Raven Luni

    Raven Luni

    798
    8
    Oct 15, 2011
    I've been digging up the web trying to find anyone else with problems and all I found was one guy talking about problems with the clock and the duty cycle having to be just right. It looks more like his clock line was just noisy though (plus isnt it supposed to be a synchronous protocol?). I've been using 1ms delays between any line transitions (which equates to a clock speed of less than 500Hz once you factor in instruction times, multitasking etc).

    Anyway, now that I've recovered some sleep, I'll start draing some pretty pictures and post some code.

    Really appreciating the help by the way :)
     
  7. Solidus

    Solidus

    349
    4
    Jun 19, 2011
    No problem :) I'm dealing with FPGAs at the moment, so when I work on implementing protocols, the timing gets to be a hassle, and there's always a big fuss on the timing. It has to be perfect in most cases :/

    Yes, both SD and SPI modes are generally synchronous, clocked to the SCK/CLK line. Now, I find it interesting of course that even transmitting the dummy frames with chip select asserted, the thing won't work.

    Do you have your hands on any routine MCUs like Arduinos? If we can't debug this thing on the RPi next thing would probably be is to SPI the thing on one of those and/or bit-bang.
     
  8. Raven Luni

    Raven Luni

    798
    8
    Oct 15, 2011
    (stupid browser)
     
    Last edited: Sep 4, 2013
  9. Raven Luni

    Raven Luni

    798
    8
    Oct 15, 2011
    OK here is the current setup. I'm using the wiringpi library for the pin control and the assignments are according to its numbering convention (all tested with LEDs so everythings correct there). Also note that the HIGHs and LOWs are properly reversed to account for the transistor inversion (except for the power).

    sd1.jpg


    And here is the code for my test program in its current state.

    sd_spi.h:
    Code:
    //=================================
    // SD Card SPI Interface Routines
    // Peter Hanratty - 01/09/2013
    //=================================
    
    #ifndef SD_SPI_H
    #define SD_SPI_H
    
    //---------------------------------
    
    #include <string.h>
    #include <wiringPi.h>
    #include "crc.h"
    
    #define COMMANDLEN	48
    #define RESPONSELEN_R1	8
    #define RESPONSELEN_R2	16
    #define RESPONSELEN_R3	40
    #define RESPONSELEN_R7	40
    
    #define R1_IDLE		0x01
    #define R1_ERES		0x02
    #define R1_CMD		0x04
    #define R1_CRC		0x08
    #define R1_ESEQ		0x10
    #define R1_ADDR		0x10
    #define R1_PARAM	0x40
    
    #define R2_LOCK		0x0001
    #define R2_WPEL		0x0002
    #define R2_ERROR	0x0004
    #define R2_CC		0x0008
    #define R2_ECC		0x0010
    #define R2_WP		0x0020
    #define R2_EPARAM	0x0040
    #define R2_RANCSD	0x0080
    #define R2_IDLE		0x0100
    #define R2_ERES		0x0200
    #define R2_CMD		0x0400
    #define R2_CRC		0x0800
    #define R2_ESEQ		0x1000
    #define R2_ADDR		0x2000
    #define R2_PARAM	0x4000
    
    #define	PIN_POWER	0
    #define	PIN_CLOCK	1
    #define	PIN_DATAIN	2
    #define	PIN_DATAOUT	3
    #define	PIN_SELECT	4
    
    #define CHECKVAL	0x4C
    #define IDLEWAIT	100
    
    //---------------------------------
    
    static char command [6];
    static char response [6];
    
    //---------------------------------
    
    void sdClear ();
    void sdInit ();
    void sdPrepCommand (char aCommand, unsigned long aParams);
    void sdSendCommand ();
    void sdGetResponse (int aResponseLen, int waitforidle);
    
    void sdCMD0 ();
    void sdCMD8 ();
    
    
    //=================================
    
    void sdClear ()
    {
    	pinMode (PIN_POWER, OUTPUT);
    	pinMode (PIN_CLOCK, OUTPUT);
    	pinMode (PIN_DATAIN, OUTPUT);
    	pinMode (PIN_DATAOUT, OUTPUT);
    	pinMode (PIN_SELECT, OUTPUT);
    	digitalWrite (PIN_POWER, LOW);
    	digitalWrite (PIN_CLOCK, HIGH);
    	digitalWrite (PIN_DATAIN, HIGH);
    	digitalWrite (PIN_DATAOUT, LOW);
    	digitalWrite (PIN_SELECT, HIGH);
    }
    
    //---------------------------------
    
    void sdInit ()
    {
    	int i;
    
    	wiringPiSetup ();
    	sdClear ();
    	delay (250);
    	pinMode (PIN_DATAOUT, INPUT);
    	digitalWrite (PIN_SELECT, LOW);
    	digitalWrite (PIN_POWER, HIGH);
    	delay (500);
    	for (i = 0; i < 80; i++)
    	{
    		digitalWrite (PIN_CLOCK, LOW);
    		delay (1);
    		digitalWrite (PIN_CLOCK, HIGH);
    		delay (1);
    	}
    	digitalWrite (PIN_SELECT, HIGH);
    	delay (1);
    }
    
    //---------------------------------
    
    void sdPrepCommand (char aCommand, unsigned long aParams)
    {
    	memset (command, 0, 6);
    	memset (response, 0, 6);
    	command [0] = aCommand & 0x3F;
    	command [0] |= 0x40;
    	command [4] = aParams & 0xFF;
    	command [3] = (aParams >> 8) & 0xFF;
    	command [2] = (aParams >> 16) & 0xFF;
    	command [1] = (aParams >> 24) & 0xFF;
    	command [5] = crc7 ((char *) command, 40) << 1;
    	command [5] |= 1;
    }
    
    //---------------------------------
    
    void sdSendCommand ()
    {
    	char *cpos = command;
    	int bitcount = 0;
    	char cbyte = *cpos;
    	
    	while (bitcount < COMMANDLEN)
    	{
    		if (cbyte & 0x80)
    			digitalWrite (PIN_DATAIN, LOW);
    		else
    			digitalWrite (PIN_DATAIN, HIGH);
    		digitalWrite (PIN_CLOCK, LOW);
    		delay (1);
    		digitalWrite (PIN_CLOCK, HIGH);
    		delay (1);
    		cbyte <<= 1;
    		bitcount++;
    		if (!(bitcount & 0x07))
    		{
    			cpos++;				
    			if (bitcount < COMMANDLEN)
    				cbyte = *cpos;
    			else
    				cbyte = 0;
    		}
    	}
    	digitalWrite (PIN_DATAIN, HIGH);
    	delay (1);
    }
    
    //---------------------------------
    
    void sdGetResponse (int aResponseLen, int waitforidle)
    {
    	char *rpos;
    	int bitcount = 0;
    	int pinstate;
    	char rbyte = 0;
    	int retry;
    
    	digitalWrite (PIN_DATAIN, HIGH);
    	if (waitforidle)
    		retry = IDLEWAIT;
    	else
    		retry = 1;
    
    	do {
    		bitcount = 0;
    		rpos = response;
    		while (bitcount < aResponseLen)
    		{
    			digitalWrite (PIN_CLOCK, LOW);
    			delay (1);
    			pinstate = digitalRead (PIN_DATAOUT);
    			digitalWrite (PIN_CLOCK, HIGH);
    			delay (1);
    			rbyte <<= 1;
    			if (!pinstate)
    				rbyte |= 1;
    			bitcount++;
    			if (!(bitcount & 0x07))
    			{
    				*rpos = rbyte;
    				rbyte = 0;
    				rpos++;				
    			}
    		}
    		retry--;
    	} while (retry && !response [0]);
    	
    	// Extra 8 clocks after response
    	for (retry = 0; retry < 8; retry++)
    	{
    		digitalWrite (PIN_CLOCK, LOW);
    		delay (1);
    		digitalWrite (PIN_CLOCK, HIGH);
    		delay (1);
    	}
    }
    
    //---------------------------------
    
    void sdCMD0 ()
    {
    	sdPrepCommand (0, 0);
    	sdSendCommand ();
    	sdGetResponse (RESPONSELEN_R1, 1);
    }
    
    //---------------------------------
    
    void sdCMD8 ()
    {
    	sdPrepCommand (8, 0x100 | CHECKVAL);
    	sdSendCommand ();
    	sdGetResponse (RESPONSELEN_R7, 0);
    }
    
    //=================================
    
    #endif
    

    sdtest3.c:
    Code:
    #include <stdio.h>
    #include <wiringPi.h>
    #include "sd_spi.h"
    
    void main ()
    {
    	printf ("\n\nInitialising card....\n");
    	sdInit ();
    	delay (250);
    	printf ("Sending CMD0...");
    	sdCMD0 ();
    	printf ("Response: [R1:%2X]\n", response [0]);
    	printf ("Sending CMD8...");
    	sdCMD8 ();
    	printf ("Response: [R1:%2X]  [IF_COND:%2X%2X%2X%2X]\n", response [0], response [1], response [2], response [3], response [4]);
    	delay (500);
    	printf ("Powering down card...\n\n");
    	sdClear ();
    }
    

    Responses with ATX power off and on respectively
    Initialising card....
    Sending CMD0...Response: [R1:FF]
    Sending CMD8...Response: [R1:FF] [IF_COND:FFFFFFFF]
    Powering down card...


    Initialising card....
    Sending CMD0...Response: [R1: 0]
    Sending CMD8...Response: [R1: 0] [IF_COND: 0 0 0 0]
    Powering down card...
     
    Last edited: Sep 4, 2013
  10. Solidus

    Solidus

    349
    4
    Jun 19, 2011
    Hmm...I can't see anything that looks too obvious to me in the code that would do something strange, but as I'm headed somewhere for the day I don't have a large amount of time to sit down and work on things.

    When I get back later I'll review the code and try to come up with a script for my ATMega to bang the protocol to a card.

    This is where we'll both be wishing the forums could do syntax highlighting.
     
    Last edited: Sep 4, 2013
  11. Raven Luni

    Raven Luni

    798
    8
    Oct 15, 2011
    I'm getting something now. Apparently both the CS and DI need to be high for at least 74 clocks on startup (I only had CS).
    The responses are nonsenseical though (always 3F for CMD0) - probably some things out of alignment - but at least its not doing nothing now :p
     
  12. Raven Luni

    Raven Luni

    798
    8
    Oct 15, 2011
    Right - just about got it figured out I think:

    You have to keep reading bytes (up to 8 apparently) with DI held high until there is a valid R1 response, then get the rest of the response if applicable. These preceding bytes will usually be 0xFF - handy for a generic check except for the strange case of CMD0. This always reads 0x3F before the 0x01 the first time, and for all subsequent calls it is 0xBF (maybe its just this card but still - wtf?). Also, an additional 8 clocks (1 byte worth) with DI high after the end of the response is definitely required.

    The stuff they dont tell you in the documentation........

    Anyway, I've successfully tested CMD0, CMD8 and CMD58 so far. It would be interesting to see if the above behaviour is repeatable on other platforms.
     
  13. Solidus

    Solidus

    349
    4
    Jun 19, 2011
    Hmm...I'm very tempted to try this out now! I'll probably use FET buffers so we can see what works better.
     
    Last edited: Sep 5, 2013
Ask a Question
Want to reply to this thread or ask your own question?
You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.
Electronics Point Logo
Continue to site
Quote of the day

-