owaisfazal wrote on Thursday, September 11, 2014:
Hello everyone,
I am a beginner in using SD cards. I am working with SAM4SD32C in Atmel Studio. So far I have managed to initialize the HSMCI interface and SD card is also initialized by sending the corresponding commands given in SD simplified specifications. Now i would like to test read and write operation for the SD card to make sure everything is working properly. After this my intention is to use the SD card as a storage device in FreeRTOS+FATSL. I have gone through the examples given in Atmel Studio and I have the following functions which are used to write and read to and from the SD card. I am stuck at this point as I am not sure what to give in the parameters of these functions to initiate a write or read operation. The functions are as follows, The read block and write block function calls the adtc command and the read block init and write block init send CMD13 to check the data ready status from the card. Please also suggest how I could integrate these function into FreeRTOS+FATSL to be able to use the SD card as a storage device with FreeRTOS.
Regards,
Owais
uint32_t sd_mmc_init_read_blocks(uint8_t slot, uint32_t start,
uint16_t nb_block)
{
uint32_t cmd, arg, resp;
// Wait for data ready status
if (!sd_mmc_cmd13())
{
printf("CMD13 data ready error\n\r");
return FAIL;
}
if (nb_block > 1)
{
cmd = SDMMC_CMD18_READ_MULTIPLE_BLOCK;
}
else
{
cmd = SDMMC_CMD17_READ_SINGLE_BLOCK;
}
/*
* SDSC Card (CCS=0) uses byte unit address,
* SDHC and SDXCCards(CCS=1)use blockunitaddress(512Bytes unit).
*/
arg = start;
if (!hsmci_adtc_start(cmd, arg, SD_MMC_BLOCK_SIZE, nb_block,1))
{
printf("adtc start error\n\r");
return FAIL;
}
// Check response
resp = hsmci_get_response();
if (resp & CARD_STATUS_ERR_RD_WR)
{
return FAIL;
}
sd_mmc_nb_block_remaining = nb_block;
sd_mmc_nb_block_to_tranfer = nb_block;
printf("Read blocks initialization done\n\r");
return OK;
}
uint32_t sd_mmc_start_read_blocks(void *dest, uint16_t
nb_block)
{
if (!(sd_mmc_nb_block_remaining >= nb_block))
{
printf("No. of blocks remaining is >= start read
block\n\r");
return FAIL;
}
if (!hsmci_start_read_blocks(dest, nb_block))
{
printf("Start read blocks failed\n\r");
sd_mmc_nb_block_remaining = 0;
return FAIL;
}
sd_mmc_nb_block_remaining -= nb_block;
return OK;
}
uint32_t sd_mmc_wait_end_of_read_blocks(int abort)
{
if (!hsmci_wait_end_of_read_blocks())
{
printf("HSMCI wait end of read blocks failed\n\r");
return FAIL;
}
if (abort)
{
sd_mmc_nb_block_remaining = 0;
}
else if (sd_mmc_nb_block_remaining)
{
return OK;
}
// All blocks are transfered then stop read operation
if (sd_mmc_nb_block_to_tranfer == 1)
{
// Single block transfer, then nothing to do
printf("All blocks transferred\n\r");
return OK;
}
if (!hsmci_adtc_stop(SDMMC_CMD12_STOP_TRANSMISSION, 0))
{
hsmci_adtc_stop(SDMMC_CMD12_STOP_TRANSMISSION, 0);
}
return OK;
}
uint32_t sd_mmc_init_write_blocks(uint8_t slot, uint32_t start,
uint16_t nb_block)
{
uint32_t cmd, arg, resp;
if (nb_block > 1)
{
cmd = SDMMC_CMD25_WRITE_MULTIPLE_BLOCK;
}
else
{
cmd = SDMMC_CMD24_WRITE_BLOCK;
}
/*
* SDSC Card (CCS=0) uses byte unit address,
* SDHC and SDXCCards(CCS=1)useblockunitaddress(512Bytes unit).
*/
arg = start;
if (!hsmci_adtc_start(cmd, arg, SD_MMC_BLOCK_SIZE, nb_block,1))
{
printf("adtc start error\n\r");
return FAIL;
}
// Check response
resp = hsmci_get_response();
if (resp & CARD_STATUS_ERR_RD_WR)
{
return FAIL;
}
sd_mmc_nb_block_remaining = nb_block;
sd_mmc_nb_block_to_tranfer = nb_block;
printf("Write blocks initialization done\n\r");
return OK;
}
uint32_t sd_mmc_start_write_blocks(const void *src, uint16_t
nb_block)
{
if(!(sd_mmc_nb_block_remaining >= nb_block))
{
printf("No. of blocks remaining is >= to start write
block\n\r");
return FAIL;
}
if (!hsmci_start_write_blocks(src, nb_block))
{
printf("Start write blocks failed\n\r");
sd_mmc_nb_block_remaining = 0;
return FAIL;
}
sd_mmc_nb_block_remaining -= nb_block;
return OK;
}
uint32_t sd_mmc_wait_end_of_write_blocks(int abort)
{
if (!hsmci_wait_end_of_write_blocks())
{
printf("HSMCI wait end of write blocks failed\n\r");
return FAIL;
}
if (abort)
{
sd_mmc_nb_block_remaining = 0;
}
else if (sd_mmc_nb_block_remaining)
{
return OK;
}
// All blocks are transfered then stop write operation
if (sd_mmc_nb_block_to_tranfer == 1)
{
// Single block transfer, then nothing to do
printf("All blocks written\n\r");
return OK;
}
// Note: SPI multiblock writes terminate using a special
// token, not a STOP_TRANSMISSION request.
if (!hsmci_adtc_stop(SDMMC_CMD12_STOP_TRANSMISSION, 0))
{
return FAIL;
}
else
{
printf("adtc stop command executed\n\r");
}
return OK;
}
uint32_t hsmci_adtc_start(uint32_t cmd, uint32_t arg, uint16_t
block_size, uint16_t nb_block, uint32_t access_block)
{
uint32_t cmdr;
#ifdef HSMCI_MR_PDCMODE
if (access_block)
{
// Enable PDC for HSMCI
HSMCI->HSMCI_MR |= HSMCI_MR_PDCMODE;
}
else
{
// Disable PDC for HSMCI
HSMCI->HSMCI_MR &= ~HSMCI_MR_PDCMODE;
}
#endif
// Enabling Read/Write Proof allows to stop the HSMCI Clock
// during read/write access if the internal FIFO is full.
// This will guarantee data integrity, not bandwidth.
HSMCI->HSMCI_MR |= HSMCI_MR_WRPROOF | HSMCI_MR_RDPROOF;
// Force byte transfer if needed
if (block_size & 0x3)
{
HSMCI->HSMCI_MR |= HSMCI_MR_FBYTE;
}
else
{
HSMCI->HSMCI_MR &= ~HSMCI_MR_FBYTE;
}
if (cmd & SDMMC_CMD_WRITE)
{
cmdr = HSMCI_CMDR_TRCMD_START_DATA | HSMCI_CMDR_TRDIR_WRITE;
}
else
{
cmdr = HSMCI_CMDR_TRCMD_START_DATA | HSMCI_CMDR_TRDIR_READ;
}
if (cmd & SDMMC_CMD_SDIO_BYTE)
{
cmdr |= HSMCI_CMDR_TRTYP_BYTE;
// Value 0 corresponds to a 512-byte transfer
HSMCI->HSMCI_BLKR = ((block_size % 512) <<HSMCI_BLKR_BCNT_Pos);
}
else
{
HSMCI->HSMCI_BLKR = (block_size << HSMCI_BLKR_BLKLEN_Pos) |
(nb_block << HSMCI_BLKR_BCNT_Pos);
if (cmd & SDMMC_CMD_SDIO_BLOCK)
{
cmdr |= HSMCI_CMDR_TRTYP_BLOCK;
}
else if (cmd & SDMMC_CMD_STREAM)
{
cmdr |= HSMCI_CMDR_TRTYP_STREAM;
}
else if (cmd & SDMMC_CMD_SINGLE_BLOCK)
{
cmdr |= HSMCI_CMDR_TRTYP_SINGLE;
}
else if (cmd & SDMMC_CMD_MULTI_BLOCK)
{
cmdr |= HSMCI_CMDR_TRTYP_MULTIPLE;
}
else
{
//Assert(FAIL); // Incorrect flags
printf("Incorrect flags in adtc command\n\r");
}
}
hsmci_transfert_pos = 0;
hsmci_block_size = block_size;
hsmci_nb_block = nb_block;
return hsmci_send_cmd_execute(cmdr, cmd, arg);
}
uint32_t hsmci_adtc_stop(uint32_t cmd, uint32_t arg)
{
return hsmci_send_cmd_execute(HSMCI_CMDR_TRCMD_STOP_DATA, cmd,
arg);
}
uint32_t sd_mmc_cmd13(void)
{
uint32_t nec_timeout;
/* Wait for data ready status.
* Nec timing: 0 to unlimited
* However a timeout is used.
* 200 000 * 8 cycles
*/
nec_timeout = 200000;
do
{
if (!hsmci_send_cmd(SDMMC_MCI_CMD13_SEND_STATUS, rca << 16))
{
return FAIL;
}
// Check busy flag
if (hsmci_get_response() & CARD_STATUS_READY_FOR_DATA)
{
break;
}
if (nec_timeout-- == 0)
{
printf("%s: CMD13 Busy timeout\n\r", __func__);
return FAIL;
}
} while (1);
return OK;
}