SD Card fails to initialize

Go To Last Post
7 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello everyone,

 

I am doing a personal project to learn more about programming a microcontroller and designing a PCB. Although I am using an Arduino Mega I created the topic here because I am programming it as an AVR, but if that’s not correct please move it to the right section.

 

My tools are the Arduino Mega 2560 r3, avrdude v6.3, avr-gcc v5.4.0 and MPLAB v5.20.

 

My goal right now is to write to SD Card, a module that I bought from eBay,

 

https://tinyurl.com/y3t4caal

 

Firstly, I tested with the Arduino SD Card library and I could read the card and write to it without problems, so it works.

 

Next, I read the following websites,

 

http://elm-chan.org/docs/mmc/mmc_e.html

http://bikealive.nl/sd-v2-initialization.html

https://www.engineersgarage.com/embedded/avr-microcontroller-projects/sd-card-interfacing-project

 

to understand the protocol.

 

At last, I downloaded a simple example,

 

https://www.engineersgarage.com/embedded/avr-microcontroller-projects/sd-card-interfacing-project

 

and started modifying it.

 

PROBLEM

 

I am not being able to initialize the sd card I can’t figure out why. The command that fails is the APP_CMD, I would expect to receive something different from 0xFF but that’s all I receive.

The code is,

 

#define F_CPU 16000000UL

#define GO_IDLE_STATE            0

#define SEND_OP_COND             1

#define SEND_IF_COND             8

#define SD_SEND_OP_COND          41  

#define APP_CMD                  55

void sdsc_init(void) {

    int x;
    unsigned char tmp;
    char buffer[10];

    // Initialize SPI
    DDRB = 0x87; // 1000 0111
    SPCR = 0x53; // 0101 0011
    SPSR = 0x00; // 0000 0000
    _delay_ms(100);
    // Initialize SPI

    PORTB |= 0x01;            // Chip select high
    for (x = 0; x < 12; x++)  //dummies clock
        sdsc -> spi_rx();

    PORTB &=~0x01;        // Chip select low

    while (0x01 != sdsc_command(GO_IDLE_STATE, 0));
    while (0x01 != sdsc_command(SEND_IF_COND, 0x000001AA));
    while ( sdsc_command ( APP_CMD, 0 ) && sdsc_command ( SD_SEND_OP_COND, 0x40000000 ) ); //v2

    //while (sdsc_command(APP_CMD, 0) && sdsc_command(SD_SEND_OP_COND, 0x00000000));   // v1
    //while (sdsc_command(SEND_OP_COND, 0x00000000)); // mmc

    while (0x00 != sdsc_command(READ_OCR, 0));
    PORTB |= 0x01;          // Chip select high

}

 

 

 

unsigned char sdsc_command(unsigned char cmd, unsigned long arg) {

    unsigned char r1;

    sdsc -> spi_tx(cmd | 0x40);
    sdsc -> spi_tx(arg >> 24);
    sdsc -> spi_tx(arg >> 16);
    sdsc -> spi_tx(arg >> 8);
    sdsc -> spi_tx(arg);

    if (cmd == SEND_IF_COND)
        sdsc -> spi_tx(0x87);
    else
        sdsc -> spi_tx(0x95);

    while ((r1 = sdsc -> spi_rx()) == 0xff); // wait response

    return r1;
}

void spi_tx(unsigned char data) {

    SPDR = data;
    while (!(SPSR & (1 << SPIF)));
}

unsigned char spi_rx(void) {

    SPDR = 0xff;
    while (!(SPSR & (1 << SPIF)));

    return SPDR;

}

 

Unfortunately, I can’t test the SPI communication with another module to check if the functions are correctly working because I don’t have another module with SPI.

 

Most of the code is equal to the original, I just changed the ports and added code to work with other versions of sd card.

 

I added delays between the sdsc_command but nothing happened. I don't know how to solve this problem, any help is welcome.

 

I attach the code.

 

Thank you

 

Attachment(s): 

Last Edited: Fri. Jul 19, 2019 - 01:00 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Doing while ( sdsc_command ( APP_CMD, 0 ) && sdsc_command ( SD_SEND_OP_COND, 0x40000000 ) ); //v2 is not a good idea, because you cannot be certain which one of those two sdsc_command() will be performed first.
( the SD_SEND_OP_COND operation should preceed the APP_CMD )

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I suggest you just have a search on "FatFS"  then you do not have to worry about the low level stuff.

It also is the SD/MMC interface package most of us here use and thus will be familiar with, in addition there will be a lot of threads about it here on the forum.

that should get you going in no time. It will take quit some reading at first as there are a lot of threads questions here, but then you should be good to go in no time.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

meslomp wrote:
I suggest you just have a search on "FatFS"
His links above suggest he already did.

 

I would suggest it is possibly the "best" implementation of SD/MMC + FAT for embedded micros so I would also suggest using it. In the MMC support code the disk_initialize looks like:

 

DSTATUS mmc_disk_initialize (void)
{
	BYTE n, cmd, ty, ocr[4];


	power_off();						/* Turn off the socket power to reset the card */
	for (Timer1 = 10; Timer1; ) ;		/* Wait for 100ms */
	if (Stat & STA_NODISK) return Stat;	/* No card in the socket? */

	power_on();							/* Turn on the socket power */
	FCLK_SLOW();
	for (n = 10; n; n--) xchg_spi(0xFF);	/* 80 dummy clocks */

	ty = 0;
	if (send_cmd(CMD0, 0) == 1) {			/* Put the card SPI mode */
		Timer1 = 100;						/* Initialization timeout of 1000 msec */
		if (send_cmd(CMD8, 0x1AA) == 1) {	/* Is the card SDv2? */
			for (n = 0; n < 4; n++) ocr[n] = xchg_spi(0xFF);	/* Get trailing return value of R7 resp */
			if (ocr[2] == 0x01 && ocr[3] == 0xAA) {				/* The card can work at vdd range of 2.7-3.6V */
				while (Timer1 && send_cmd(ACMD41, 1UL << 30));	/* Wait for leaving idle state (ACMD41 with HCS bit) */
				if (Timer1 && send_cmd(CMD58, 0) == 0) {		/* Check CCS bit in the OCR */
					for (n = 0; n < 4; n++) ocr[n] = xchg_spi(0xFF);
					ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2;	/* Check if the card is SDv2 */
				}
			}
		} else {							/* SDv1 or MMCv3 */
			if (send_cmd(ACMD41, 0) <= 1) 	{
				ty = CT_SD1; cmd = ACMD41;	/* SDv1 */
			} else {
				ty = CT_MMC; cmd = CMD1;	/* MMCv3 */
			}
			while (Timer1 && send_cmd(cmd, 0));			/* Wait for leaving idle state */
			if (!Timer1 || send_cmd(CMD16, 512) != 0)	/* Set R/W block length to 512 */
				ty = 0;
		}
	}
	CardType = ty;
	deselect();

	if (ty) {			/* Initialization succeded */
		Stat &= ~STA_NOINIT;		/* Clear STA_NOINIT */
		FCLK_FAST();
	} else {			/* Initialization failed */
		power_off();
	}

	return Stat;
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mikech wrote:

Doing while ( sdsc_command ( APP_CMD, 0 ) && sdsc_command ( SD_SEND_OP_COND, 0x40000000 ) ); //v2 is not a good idea, because you cannot be certain which one of those two sdsc_command() will be performed first.
( the SD_SEND_OP_COND operation should preceed the APP_CMD )

 

The && operator guarantees that the left-hand expression is evaluated first.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I stand corrected..
Sometime in the dim past I 'read' that expressions might not be evaluated in the order that one expected, and hence I've used brackets () and simple expressions everywhere.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you everyone. The implementation of FatFS it's too complicated for me. I wanted simple code just to write to SD Card. I tried again to use the FatFS but it's too overwhelming. I didn't want to use code that I cannot understand in my project. And wanted to keep it simple.

 

Eventually I found this one,

 

https://exploreembedded.com/wiki...

 

that works perfectly fine and it's simple to read. I am already using it, I will adapt to my needs.

 

Unfortunately i couldn't find out the problem with the code that I posted so i cannot offer a solution.