SD card initialization in SD mode

Discussion around product based on ARM Cortex M4 core.

Moderators: nferre, ncollot

Owais
Posts: 57
Joined: Wed Jul 23, 2014 3:25 pm

SD card initialization in SD mode

Thu Sep 04, 2014 12:58 pm

Hello,

I am trying to initialize an SD card in SD mode. Has anyone here done this before? If so, any help would be appreciated.Thanks.

Regards,
Owais.
Owais
Posts: 57
Joined: Wed Jul 23, 2014 3:25 pm

Re: SD card initialization in SD mode

Thu Sep 04, 2014 4:18 pm

Hello,

To be more clear about my situation, I have initialized the HSMCI interface of SAM4S. The clock is set at 400kHz and bus width at 1-bit for initialization of SD card. Secondly the SD card command CMD0, CMD8, CMD55, ACMD41, CMD2, CMD3 are executed successfully and the Relative Card Address is received as 45928. I am using a 4GB Micro SD HC card. After this, CMD9, CMD7, ACMD51 fail to execute and the card cannot be set into High Speed mode. I have tried this whole process in AS Example Unit Test and there it works without any of these issues. I am simple initializing the HSMCI interface and then the SD card. Though AS example does some other stuff that I am not following. Any help would be appreciated.

Regards,
Owais
jharley
Posts: 238
Joined: Thu Dec 06, 2012 6:40 am

Re: SD card initialization in SD mode

Thu Sep 04, 2014 6:15 pm

Hello,
Owais wrote:Though AS example does some other stuff that I am not following.
How did you determine that the "other stuff" is not needed?
Owais wrote:After this, CMD9, CMD7, ACMD51 fail to execute and the card cannot be set into High Speed mode.
Any application command "ACMDxx" should be preceded by CMD55.

From the specification
All the ACMDs shall be preceded with APP_CMD command (CMD55)
In case you haven't seen it, here is a link to the SD card specification.
https://www.sdcard.org/downloads/pls/si ... t1_410.pdf

Hopefully this helps you.

Kind Regards
Owais
Posts: 57
Joined: Wed Jul 23, 2014 3:25 pm

Re: SD card initialization in SD mode

Fri Sep 05, 2014 9:52 am

Thanks jharley for your response. First of all the additional stuff that AS does is related to setting up clock for the card detection pin and then it proceeds to initialization of HSMCI and SD card. I have taken the part of the code that initializes HSMCI and SD card and used it in my own project. As long as the commands are concerned I have checked it and all ACMD commands are followed by CMD55 I haven't changed a bit in the part of the code that I took from AS example. The problem is that this code is running properly in AS and when I use it in my project the above mentioned problems occur. Hope this presents the problem more clearly. Moreover if you know any critical part that I am missing between initialization of HSMCI and SD card please  do let me know. I have added the HSMCI initialization code and SD initialization code as follows. Thanks.

Regards,
Owais

Code: Select all

uint32_t hsmci_init(void)
{
	//enable MCI's clock
	PMC->PMC_PCER0 = PMC_PCER0_PID18;
	//configure PIOs to be controlled by MCI
	PIOA->PIO_PDR = PINS_MCI;
	PIOA->PIO_IDR = PINS_MCI;
	PIOA->PIO_ABCDSR[0] &= ~PINS_MCI; // 0 - Peripheral C
	PIOA->PIO_ABCDSR[1] |=  PINS_MCI; // 1 - Peripheral C
	//PIOA->PIO_PUER = PINS_MCI; //Pullup enable
	// configure card detect pin
	PMC->PMC_PCER0 = PMC_PCER0_PID11;
	PIOA->PIO_PER = PIN_CDMCI;
	PIOA->PIO_IDR = PIN_CDMCI;
	PIOA->PIO_ODR = PIN_CDMCI;
	//PIOA->PIO_PUER = PIN_CDMCI;

	//configure MCI regs
	//perform software reset
	HSMCI->HSMCI_CR = HSMCI_CR_SWRST;
	// Set the Data Timeout Register to 2 Mega Cycles
	HSMCI->HSMCI_DTOR = HSMCI_DTOR_DTOMUL_1048576 | HSMCI_DTOR_DTOCYC(2);
	// Set Completion Signal Timeout to 2 Mega Cycles
	HSMCI->HSMCI_CSTOR = HSMCI_CSTOR_CSTOMUL_1048576 | HSMCI_CSTOR_CSTOCYC(2);
	// Set Configuration Register
	HSMCI->HSMCI_CFG = HSMCI_CFG_FIFOMODE | HSMCI_CFG_FERRCTRL;
	// Set power saving to maximum value
	HSMCI->HSMCI_MR = HSMCI_MR_PWSDIV_Msk;
	// Enable the HSMCI and the Power Saving
	HSMCI->HSMCI_CR = HSMCI_CR_MCIEN | HSMCI_CR_PWSEN;
	
	const uint8_t CLKDIV = 0x95;	// slowest possible clock divider
	const uint32_t MCI_CLKDIV_MASK = (uint32_t)CLKDIV;	//120MHz/(2x(CLKDIV+1)) = 400kHz
	const uint32_t MCI_BLKLEN_MASK = (uint32_t)(512 << 16);
	
	//set MCI Mode Register
#if HSMCI_MR_PDCMODE // In case of DMA enable force byte transfer
	HSMCI->HSMCI_MR = MCI_BLKLEN_MASK | MCI_CLKDIV_MASK | HSMCI_MR_FBYTE| HSMCI_MR_RDPROOF | HSMCI_MR_WRPROOF;
#else
	HSMCI->HSMCI_MR = MCI_BLKLEN_MASK | MCI_CLKDIV_MASK | HSMCI_MR_RDPROOF | HSMCI_MR_WRPROOF;
#endif

	//configure SDCR register select slot A and set 4 bit bus width
	HSMCI->HSMCI_SDCR = HSMCI_SDCR_SDCSEL_SLOTA | HSMCI_SDCR_SDCBU[code]
S_1;
return ( OK );
}
[/code]

Code: Select all

uint32_t sd_init(void)
{
	//Index of current slot configured
	static uint8_t sd_mmc_slot_sel = 0;
	sd_mmc_card->type = CARD_TYPE_SD;
	sd_mmc_card->version = CARD_VER_UNKNOWN;
	sd_mmc_card->rca = 0;
	uint8_t v2 = 0;
	
	// Card need of 74 cycles clock minimum to start
	hsmci_send_clock();
	// CMD0 - Reset all cards to idle state.
	if (!hsmci_send_cmd(SDMMC_MCI_CMD0_GO_IDLE_STATE, 0))
	{
		//return FAIL;
		printf("CMD0 failed\n\r");
	}
	if (!sd_cmd8(&v2))
	{
		//return FAIL;
		printf("CMD8 failed\n\r");
	}
	// Try to get the SD card's operating condition
	if (!sd_mci_op_cond(v2))
	{
		//It is not a SD card
		//return FAIL;
		printf("Not a valid SD card\n\r");
	}
	// SD MEMORY, Put the Card in Identify Mode
	// Note: The CID is not used in this stack
	if (!hsmci_send_cmd(SDMMC_CMD2_ALL_SEND_CID, 0))
	{
		//return FAIL;
		printf("CMD2 failed\n\r");
	}
	// Ask the card to publish a new relative address (RCA).
	if (!hsmci_send_cmd(SD_CMD3_SEND_RELATIVE_ADDR, 0))
	{
		//return FAIL;
		printf("CMD3 failed\n\r");
	}
	sd_mmc_card->rca = (hsmci_get_response() >> 16) & 0xFFFF;
	printf("Card relative address is : %d\n\r", sd_mmc_card->rca);
	// SD MEMORY, Get the Card-Specific Data
	if (!hsmci_send_cmd(SDMMC_MCI_CMD9_SEND_CSD, sd_mmc_card->rca << 16))
	{
		//return FAIL;
		printf("CMD9 failed\n\r");
	}
	hsmci_get_response_128(sd_mmc_card->csd);
	sd_decode_csd();
		
	// Select the SD card and put it into Transfer Mode
	if (!hsmci_send_cmd(SDMMC_CMD7_SELECT_CARD_CMD, sd_mmc_card->rca << 16))
	{
		//return FAIL;
		printf("Failed to execute CMD7\n\r");
	}
	
	// SD MEMORY, Read the SCR to get card version
	if (!sd_acmd51())
	{
		//return FAIL;
		printf("ACMD51 failed\n\r");
	}
	if ((4 <= hsmci_get_bus_width(sd_mmc_slot_sel)))
	{
		// TRY to enable 4-bit mode
		if (!sd_acmd6())
		{
			//return FAIL;
			printf("ACMD6 failed\n\r");
		}
		// Switch to selected bus mode
		sd_mmc_configure_slot();
	}
	if (hsmci_is_high_speed_capable())
	{
		// TRY to enable High-Speed Mode		
		if (!sd_cm6_set_high_speed())
		{
			//return FAIL;
			printf("High Speed not set\n\r");
		}
		// Valid new configuration
		sd_mmc_configure_slot();
	}
	// SD MEMORY, Set default block size
	if (!hsmci_send_cmd(SDMMC_CMD16_SET_BLOCKLEN, SD_MMC_BLOCK_SIZE))
	{
		//return FAIL;
		printf("CMD16 failed\n\r");
	}
	return OK;
}

uint32_t sd_acmd51(void)
{
	uint8_t scr[SD_SCR_REG_BSIZE];

	// CMD55 - Indicate to the card that the next command is an
	// application specific command rather than a standard command.
	if (!hsmci_send_cmd(SDMMC_CMD55_APP_CMD, (uint32_t)sd_mmc_card->rca << 16))
	{
		return FAIL;
	}
	if (!hsmci_adtc_start(SD_ACMD51_SEND_SCR, 0, SD_SCR_REG_BSIZE, 1, OK))
	{
		return FAIL;
	}
	if (!hsmci_start_read_blocks(scr, 1))
	{
		return FAIL;
	}
	if (!hsmci_wait_end_of_read_blocks())
	{
		return FAIL;
	}
	// Get SD Memory Card - Spec. Version
	switch (SD_SCR_SD_SPEC(scr))
	{
		case SD_SCR_SD_SPEC_1_0_01:
		sd_mmc_card->version = CARD_VER_SD_1_0;
		break;

		case SD_SCR_SD_SPEC_1_10:
		sd_mmc_card->version = CARD_VER_SD_1_10;
		break;
case SD_SCR_SD_SPEC_2_00:
		if (SD_SCR_SD_SPEC3(scr) == SD[code]
_SCR_SD_SPEC_3_00)
{
sd_mmc_card->version = CARD_VER_SD_3_0;
}
else
{
sd_mmc_card->version = CARD_VER_SD_2_0;
}
break;

default:
sd_mmc_card->version = CARD_VER_SD_1_0;
break;
}
return OK;
}

uint32_t sd_acmd6(void)
{
// CMD55 - Indicate to the card that the next command is an
// application specific command rather than a standard command.
if (!hsmci_send_cmd(SDMMC_CMD55_APP_CMD, (uint32_t)sd_mmc_card->rca << 16))
{
return FAIL;
}
// 10b = 4 bits bus
if (!hsmci_send_cmd(SD_ACMD6_SET_BUS_WIDTH, 0x2))
{
return FAIL;
}
sd_mmc_card->bus_width = 4;
printf("%d-bit bus width enabled.\n\r", (int)sd_mmc_card->bus_width);
return OK;
}
[/code]
jharley
Posts: 238
Joined: Thu Dec 06, 2012 6:40 am

Re: SD card initialization in SD mode

Sun Sep 07, 2014 3:19 am

You might try turning on the HSMCI_DEBUG flag and see if you can get more information on the failure.

As far as other troubleshooting steps, I would probably get out my mixed signal analyzer and look at the difference in the data stream between the code that works and the code that doesn't work.
Owais
Posts: 57
Joined: Wed Jul 23, 2014 3:25 pm

Re: SD card initialization in SD mode

Sun Sep 07, 2014 1:58 pm

Thanks again jharley for your response. I will start the debugging now but as far as the initialization is concerned I am not missing any step am I. If there is something critical that I have missed in the above steps do share.

Regards,
Owais
Owais
Posts: 57
Joined: Wed Jul 23, 2014 3:25 pm

Re: SD card initialization in SD mode

Tue Sep 09, 2014 4:26 pm

Hello,
I have managed to initialize the HSMCI and SD card in SD mode. It seems that it was related to power save enable of HSMCI interface, once I cleared the PWSEN field in the HSMCI_CR it started to run properly. I can now check the relative card address and have enabled the full speed and 4bit bus width for the interface. Is there anyone who has worked with SD cards and could help me with testing the read and write operation for some RAW data perhaps some simple operation to write some data and read it back would be very helpful. Thanks in advance.

Regards,
Owais

P.S. I am already trying to go through AS example but it is too bulky for me.
Owais
Posts: 57
Joined: Wed Jul 23, 2014 3:25 pm

Re: SD card initialization in SD mode

Thu Sep 11, 2014 8:45 am

Guys any help would be appreciated in this regard. I have the card in ready state and just want to know how to start reading and writing to it. To be exact I need to know what are the parameters that I should pass to the following functions in order to read and write on the card.
Regards

Code: Select all

uint32_t hsmci_start_read_blocks(void *dest, uint16_t nb_block)
{
	uint32_t nb_data;

	nb_data = nb_block * hsmci_block_size;
	//Assert(nb_data <= (((uint32_t)hsmci_block_size * hsmci_nb_block) - hsmci_transfert_pos));
	//Assert(nb_data <= (PERIPH_RCR_RXCTR_Msk >> PERIPH_RCR_RXCTR_Pos));

	// Handle unaligned memory address
	if (((uint32_t)dest & 0x3) || (hsmci_block_size & 0x3))
	{
		HSMCI->HSMCI_MR |= HSMCI_MR_FBYTE;
	}
	else
	{
		HSMCI->HSMCI_MR &= ~HSMCI_MR_FBYTE;
	}

	// Configure PDC transfer
	HSMCI->HSMCI_RPR = (uint32_t)dest;
	HSMCI->HSMCI_RCR = (HSMCI->HSMCI_MR & HSMCI_MR_FBYTE) ?	nb_data : nb_data / 4;
	HSMCI->HSMCI_RNCR = 0;
	// Start transfer
	HSMCI->HSMCI_PTCR = HSMCI_PTCR_RXTEN;
	hsmci_transfert_pos += nb_data;
	return OK;
}

uint32_t hsmci_wait_end_of_read_blocks(void)
{
	uint32_t sr;
	// Wait end of transfer
	// Note: no need of timeout, because it is include in HSMCI, see DTOE bit.
	do
	{
		sr = HSMCI->HSMCI_SR;
		if (sr & (HSMCI_SR_UNRE | HSMCI_SR_OVRE | HSMCI_SR_DTOE | HSMCI_SR_DCRCE))
		{
			HSMCI->HSMCI_PTCR = HSMCI_PTCR_RXTDIS | HSMCI_PTCR_TXTDIS;
			hsmci_reset();
			return FAIL;
		}

	} while (!(sr & HSMCI_SR_RXBUFF));

	if (hsmci_transfert_pos < ((uint32_t)hsmci_block_size * hsmci_nb_block))
	{
		return OK;
	}
	// It is the last transfer, then wait command completed
	// Note: no need of timeout, because it is include in HSMCI, see DTOE bit.
	do
	{
		sr = HSMCI->HSMCI_SR;
		if (sr & (HSMCI_SR_UNRE | HSMCI_SR_OVRE | HSMCI_SR_DTOE | HSMCI_SR_DCRCE))
		{
			hsmci_reset();
			return FAIL;
		}
	} while (!(sr & HSMCI_SR_XFRDONE));
	return OK;
}

uint32_t hsmci_start_write_blocks(const void *src, uint16_t nb_block)
{
	uint32_t nb_data;

	nb_data = nb_block * hsmci_block_size;
	//Assert(nb_data <= (((uint32_t)hsmci_block_size * hsmci_nb_block) - hsmci_transfert_pos));
	//Assert(nb_data <= (PERIPH_TCR_TXCTR_Msk >> PERIPH_TCR_TXCTR_Pos));

	// Handle unaligned memory address
	if (((uint32_t)src & 0x3) || (hsmci_block_size & 0x3))
	{
		HSMCI->HSMCI_MR |= HSMCI_MR_FBYTE;
	}
	else
	{
		HSMCI->HSMCI_MR &= ~HSMCI_MR_FBYTE;
	}

	// Configure PDC transfer
	HSMCI->HSMCI_TPR = (uint32_t)src;
	HSMCI->HSMCI_TCR = (HSMCI->HSMCI_MR & HSMCI_MR_FBYTE) ? nb_data : nb_data / 4;
	HSMCI->HSMCI_TNCR = 0;
	// Start transfer
	HSMCI->HSMCI_PTCR = HSMCI_PTCR_TXTEN;
	hsmci_transfert_pos += nb_data;
	return OK;
}

uint32_t hsmci_wait_end_of_write_blocks(void)
{
	uint32_t sr;

	// Wait end of transfer
	// Note: no need of timeout, because it is include in HSMCI, see DTOE bit.
	do
	{
		sr = HSMCI->HSMCI_SR;
		if (sr & (HSMCI_SR_UNRE | HSMCI_SR_OVRE | HSMCI_SR_DTOE | HSMCI_SR_DCRCE))
		{
			hsmci_reset();
			HSMCI->HSMCI_PTCR = HSMCI_PTCR_RXTDIS | HSMCI_PTCR_TXTDIS;
			return FAIL;
		}
	} while (!(sr & HSMCI_SR_TXBUFE));

	if (hsmci_transfert_pos < ((uint32_t)hsmci_block_size * hsmci_nb_block))
	{
		return OK;
	}
	// It is the last transfer, then wait command completed
	// Note: no need of timeout, because it is include in HSMCI, see DTOE bit.
	do
	{
		sr = HSMCI->HSMCI_SR;
		if (sr & (HSMCI_SR_UNRE | HSMCI_SR_OVRE | HSMCI_SR_DTOE | HSMCI_SR_DCRCE))
		{
			hsmci_reset();
			return FAIL;
		}
	} while (!(sr & HSMCI_SR_NOTBUSY));
	//Assert(HSMCI->HSMCI_SR & HSMCI_SR_FIFOEMPTY);
	return OK;
}
Owais
Posts: 57
Joined: Wed Jul 23, 2014 3:25 pm

Re: SD card initialization in SD mode

Thu Sep 11, 2014 3:33 pm

Hello,
I am hoping that there is someone out there who has done this stuff before and could help me in proceeding further. I am in dire need of help at this point it is very hopeless since I can't even write or read a byte on or from the SD. Please help.
Regards,
Owais
Sam++
Posts: 16
Joined: Tue Jul 01, 2014 9:05 pm

Re: SD card initialization in SD mode

Fri Sep 12, 2014 3:46 pm

Hi,

I have this implementation working for reading :

Code: Select all

	HSMCI->HSMCI_MR |= HSMCI_MR_PDCMODE;
	HSMCI->HSMCI_BLKR = HSMCI_BLKR_BLKLEN(512);
	HSMCI->HSMCI_RPR = (uint32_t)pAddress;
	HSMCI->HSMCI_RCR = ((512) / 4);
	HSMCI->HSMCI_PTCR = HSMCI_PTCR_RXTEN;
	if(m_bIsHCXC)	//	Byte address or Block Address ?
		HSMCI->HSMCI_ARGR = sector;
	else
		HSMCI->HSMCI_ARGR = sector * 512;
	
	HSMCI->HSMCI_CMDR	=	HSMCI_CMDR_CMDNB(17)
						|	HSMCI_CMDR_MAXLAT_64
						|	HSMCI_CMDR_RSPTYP_48_BIT
						|	HSMCI_CMDR_TRTYP_BYTE
						|	HSMCI_CMDR_TRDIR_READ
						|	HSMCI_CMDR_TRCMD_START_DATA;
	
	while(HSMCI_SR_ENDRX != (HSMCI->HSMCI_SR  & HSMCI_SR_ENDRX));
Hope this helps,

Paul
Owais
Posts: 57
Joined: Wed Jul 23, 2014 3:25 pm

Re: SD card initialization in SD mode

Fri Sep 12, 2014 3:54 pm

Thank for your response. Can you please explain what exactly are you reading here I mean is it a byte or block? Is the card HC or SC? Are you also able to write to the SD card and read that back?

Regards,
Owais.
Sam++
Posts: 16
Joined: Tue Jul 01, 2014 9:05 pm

Re: SD card initialization in SD mode

Fri Sep 12, 2014 11:21 pm

Well, this code sequence reads one sector of data into a buffer.

The sectror number is in 'sector', the destination address is in pAddress.

m_bIsHCXC is a boolean indicating if the card uses byte or block addresses. (assuming one block is 512 bytes long)

Cheers,

Paul

EDIT: no writing implemented at the moment...
Owais
Posts: 57
Joined: Wed Jul 23, 2014 3:25 pm

Re: SD card initialization in SD mode

Sat Sep 13, 2014 7:36 pm

Hello, Thanks for your reply Paul. I understand, can you please elaborate on the sector what exactly does that mean? Is one sector equal to one block? Moreover, How is the addressing done in this case how would I know which sector to write to assuming sector is indeed equal to a block in that case how should I know the next available sector? I am confused with how to keep track of the addresses and for instance if we want to read a sector previously written how would we know which sector to read from? These may seem very basic questions but for me these are the very obvious ones at the moment. Thank you for you help.

Regards,
Owais
blue_z
Location: USA
Posts: 1957
Joined: Thu Apr 19, 2007 10:15 pm

Re: SD card initialization in SD mode

Sun Sep 14, 2014 1:19 am

Owais wrote:please elaborate on the sector what exactly does that mean?
"Sector" is terminology from disk drives. It's a fundamental unit (i.e. the smallest amount of data) of recording on the magnetic platter and for data transfer. A more complete description is here
"Block" can be synonymous with sector, but "block" can be used in more contexts (e.g. not device specific).
A "block" device implies a device that performs its data transfers in largish fixed-sized chunks, as opposed to a "character" device that allows variable-sized transfers.
Owais wrote:Is one sector equal to one block?
The SDcard can perform transfers for a block size of 512 bytes (i.e. the common HDD sector size), but other (smaller) block sizes can be programmed if desired.
If you want the SDcard to be readable by other systems, especially a PC, then the SDcard must conform to expected media layout and use a supported filesystem.
That is, for maximum compatibility, the block size should be 512 bytes, the first block/sector should contain a (PC-DOS) MBR (Master Boot Record), and the rest of the SDcard should be partitioned and each partition should have a filesystem.
In other words, it should resemble a HDD for a PC.
Owais wrote: Moreover, How is the addressing done in this case
You need to learn how to apply layers of abstraction.
The bottom layer would handle the fundamental I/O operations. This is what is commonly the physical device driver.
The layer above would be a logical block address to physical block address handler. A relative block number within a partition has to be translated to an absolute device block/sector address(es) for I/O operations by the driver.
The layer above that would be a filesystem that manages free and used blocks/sectors and provides the concept of directories and files to the application layer.
Owais wrote:how would I know which sector to write to assuming sector is indeed equal to a block
That is a resource management issue usually handled by a filesystem.
If you forgo using a filesystem, then you have a raw block device.
Owais wrote:in that case how should I know the next available sector?
See previous remark.
Owais wrote: I am confused with how to keep track of the addresses and for instance if we want to read a sector previously written how would we know which sector to read from?
See previous remark.

Regards
Owais
Posts: 57
Joined: Wed Jul 23, 2014 3:25 pm

Re: SD card initialization in SD mode

Sun Sep 14, 2014 12:40 pm

Hello and thanks for your detailed response blue_z, I am indeed a beginner in working with storage devices in particular SD cards. I understand I have much to learn in this regard. My main goal at this point was to just write a raw data into an already formatted SD card and then read that data back just to be familiar with the working and then I am planning to use a file system to take care of the addressing. As i have mentioned earlier I have got the physical drivers from AS examples and they conform to the read write operation given in the datasheet, its just that if I give a data lets say a byte and try to write it randomly anywhere in the SD card would this work? If so, can I read it back just to display on a PC terminal to be sure it is working. Also the SD card publishes a RCA(Relative Card Address) what is the purpose of that is it somehow used in writing or reading the very first data to the SD card?

Regards.

Return to “SAM4 Cortex-M4 MCU”

Who is online

Users browsing this forum: No registered users and 3 guests