open-story-teller/software/system/sdcard.c

1597 lines
47 KiB
C

/*------------------------------------------------------------------------*/
/* STM32F100: MMCv3/SDv1/SDv2 (SPI mode) control module */
/*------------------------------------------------------------------------*/
/*
/ Copyright (C) 2018, ChaN, all right reserved.
/
/ * This software is a free software and there is NO WARRANTY.
/ * No restriction on use. You can use, modify and redistribute it for
/ personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
/ * Redistributions of source code must retain the above copyright notice.
/
/-------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------
Module Private Functions
---------------------------------------------------------------------------*/
#include "ost_hal.h"
#include "debug.h"
#include "sdcard.h"
/**
* @}
*/
/* STM32_Private_Types */
/** @defgroup STM32_Private_Defines
* @{
*/
/**
* @brief Dummy byte
*/
#define SD_DUMMY_BYTE 0xFF
/**
* @brief Number of 8-bit cycles for RUMP UP phase
*/
#define SD_NUM_TRIES_RUMPUP ((uint32_t)2500)
/**
* @brief Maximum number of tries to send a command
*/
#define SD_NUM_TRIES ((uint16_t)300)
/**
* @brief Maximum number of tries until ACMD41/CMD1 initializes SD card
* It means a time until "In Idle State" flag is set during initialization
* For information:
* ~ 11000 for Kingston 4Gb
* ~ 10000 for SanDisk 1Gb
* ~ 6000 for Samsung 8Gb
*/
#define SD_NUM_TRIES_INIT ((uint16_t)20000)
/**
* @brief Maximum number of tries to receive data transmission token
* It means a time before data transmission starts
* For information:
* ~ 300 for SanDisk 1Gb
* ~ 600 for Kingston 4Gb
* ~ 900 for SP 4Gb
* ~ 500 for Samsung 8Gb
* ~ 300 for Lexar 4Gb
*/
#define SD_NUM_TRIES_READ ((uint16_t)2000)
/**
* @brief Maximum number of tries until SD card writes data
* It means a time while BUSY flag is set, i.e. card writes the data received
* For information:
* ~ 6100 for Kingston 4Gb
* ~ 4600 for Lexar 4Gb
* ~ 80000 for SP 4Gb (9000)
* ~ 10000 for SanDisk 1Gb
* ~119000 for Samsung 8Gb
*/
#define SD_NUM_TRIES_WRITE ((uint32_t)1000000)
/**
* @brief Maximum number of tries until SD card erases data
* It means a time while BUSY flag is set, i.e. card erases sectors
* For information:
* ~ 6100 for Kingston 4Gb
* ~ 5200 for Lexar 4Gb
* ~ 10300 for SP 4Gb
* ~ N/A for SanDisk 1Gb
* ~120000 for Samsung 8Gb
*/
#define SD_NUM_TRIES_ERASE ((uint32_t)1000000)
/**
* @brief Start Data tokens:
* Tokens (necessary because at nop/idle (and CS active) only 0xff is
* on the data/command line)
*/
#define SD_DATA_BLOCK_READ_START 0xFE /*!< Data token start byte, Start Single/Multiple Block Read */
#define SD_DATA_SINGLE_BLOCK_WRITE_START 0xFE /*!< Data token start byte, Start Single Block Write */
#define SD_DATA_MULTIPLE_BLOCK_WRITE_START 0xFC /*!< Data token start byte, Start Multiple Block Write */
#define SD_DATA_MULTIPLE_BLOCK_WRITE_STOP 0xFD /*!< Data token stop byte, Stop Multiple Block Write */
static SDCardType cardType;
/**
* @brief Detect if SD card is correctly plugged in the memory slot.
* @param None
* @retval Return if SD is detected or not
*/
uint8_t SD_Detect(void)
{ /* check GPIO to detect SD */
if (ost_hal_sdcard_get_presence())
{
return SD_PRESENT;
}
return SD_NOT_PRESENT;
}
/**
* @brief Hold SPI bus for SD card
* @param None
* @retval None
*/
static void SD_Bus_Hold(void)
{ /* Select SD Card: set SD chip select pin low */
ost_hal_sdcard_cs_low();
}
static uint8_t SD_SpiWriteByte(uint8_t byte)
{
ost_hal_sdcard_spi_exchange(&byte, &byte, 1);
return byte;
}
/**
* @brief Release SPI bus used by SD card
* @param None
* @retval None
*/
static void SD_Bus_Release(void)
{ /* Deselect SD Card: set SD chip select pin high */
ost_hal_sdcard_cs_high();
SD_SpiWriteByte(0xFF); /* send dummy byte: 8 Clock pulses of delay */
}
/**
* @brief Send a command to SD card and receive R1 response
* @param Cmd: Command to send to SD card
* @param Arg: Command argument
* @param Crc: CRC
* @retval R1 response byte
*/
static SD_Error SD_SendCmd(uint8_t cmd, uint32_t arg, uint8_t crc)
{
uint8_t res;
uint16_t i = SD_NUM_TRIES;
/* send a command */
SD_SpiWriteByte((cmd & 0x3F) | 0x40); /*!< byte 1 */
SD_SpiWriteByte((uint8_t)(arg >> 24)); /*!< byte 2 */
SD_SpiWriteByte((uint8_t)(arg >> 16)); /*!< byte 3 */
SD_SpiWriteByte((uint8_t)(arg >> 8)); /*!< byte 4 */
SD_SpiWriteByte((uint8_t)arg); /*!< byte 5 */
SD_SpiWriteByte(crc | 0x01); /*!< byte 6: CRC */
/* a byte received immediately after CMD12 should be discarded... */
if (cmd == SD_CMD_STOP_TRANSMISSION)
SD_SpiWriteByte(0xFF);
/* SD Card responds within Ncr (response time),
which is 0-8 bytes for SDSC cards, 1-8 bytes for MMC cards */
do
{
res = SD_SpiWriteByte(0xFF);
/* R1 response always starts with 7th bit set to 0 */
} while ((res & SD_CHECK_BIT) != 0x00 && i-- > 0);
return (SD_Error)res;
}
/**
* @brief Some commands take longer time and respond with R1b response,
* so we have to wait until 0xFF recieved (MISO is set to HIGH)
* @retval Nonzero if required state wasn't recieved
*/
static SD_Error SD_WaitReady(void)
{
uint16_t i = SD_NUM_TRIES;
while (i-- > 0)
{
if (SD_SpiWriteByte(0xFF) == 0xFF)
{
// debug_printf( " [[ WAIT delay %d ]] ", SD_NUM_TRIES - i );
return SD_RESPONSE_NO_ERROR;
}
}
// debug_printf( " [[ WAIT delay was not enough ]] " );
return SD_RESPONSE_FAILURE;
}
/**
* @brief Get 4 bytes of R3 or R7 response
* @param pres: Pointer to uint32_t variable for result
* @retval None
*/
static void SD_GetResponse4b(uint8_t *pres)
{
pres[3] = SD_SpiWriteByte(0xFF);
pres[2] = SD_SpiWriteByte(0xFF);
pres[1] = SD_SpiWriteByte(0xFF);
pres[0] = SD_SpiWriteByte(0xFF);
}
/**
* @brief Set SD Card sector size to SD_CMD_SET_BLOCKLEN (512 bytes)
* @param New sector size
* @retval The SD Response:
* - SD_RESPONSE_FAILURE: Sequence failed
* - SD_RESPONSE_NO_ERROR: Sequence succeed
*/
static SD_Error SD_FixSectorSize(uint16_t ssize)
{
return SD_SendCmd(SD_CMD_SET_BLOCKLEN, (uint32_t)ssize, 0xFF);
}
/**
* @brief Wait until data transmission token is received
* @retval Data transmission token or 0xFF if timeout occured
*/
static uint8_t SD_WaitBytesRead(void)
{
uint16_t i = SD_NUM_TRIES_READ;
uint8_t b;
do
{
b = SD_SpiWriteByte(0xFF);
} while (b == 0xFF && i-- > 0);
// if (b != 0xFF)
// debug_printf(" [[ READ delay %d ]] ", SD_NUM_TRIES_READ - i);
// else
// debug_printf(" [[ READ delay was not enough ]] ");
return b;
}
/**
* @brief Writing data into flash takes even longer time and it responds with R1b response,
* so we have to wait until 0xFF recieved (MISO is set to HIGH)
* @retval Nonzero if required state wasn't recieved
*/
static SD_Error SD_WaitBytesWritten(void)
{
uint32_t i = SD_NUM_TRIES_WRITE;
while (i-- > 0)
{
if (SD_SpiWriteByte(0xFF) == 0xFF)
{
// debug_printf(" [[ WRITE delay %lu ]] ", SD_NUM_TRIES_WRITE - i);
return SD_RESPONSE_NO_ERROR;
}
}
// debug_printf(" [[ WRITE delay was not enough ]] ");
return SD_RESPONSE_FAILURE;
}
/**
* @brief Erasing data into flash takes some time and it responds with R1b response,
* so we have to wait until 0xFF recieved (MISO is set to HIGH)
* @retval Nonzero if required state wasn't recieved
*/
static SD_Error SD_WaitBytesErased(void)
{
uint32_t i = SD_NUM_TRIES_ERASE;
while (i-- > 0)
{
if (SD_SpiWriteByte(0xFF) == 0xFF)
{
// debug_printf(" [[ ERASE delay %lu ]] ", SD_NUM_TRIES_ERASE - i);
return SD_RESPONSE_NO_ERROR;
}
}
// debug_printf(" [[ ERASE delay was not enough ]] ");
return SD_RESPONSE_FAILURE;
}
/**
* @brief Recieve data from SD Card
* @param data: Pre-allocated data buffer
* @param len: Number of bytes to receive
* @retval The SD Response:
* - SD_RESPONSE_FAILURE: Sequence failed
* - SD_RESPONSE_NO_ERROR: Sequence succeed
*/
static SD_Error SD_ReceiveData(uint8_t *data, uint16_t len)
{
uint16_t i = 0;
uint8_t b;
/* some cards need time before transmitting the data... */
b = SD_WaitBytesRead();
if (b != 0xFF)
{ /* most cards send transmission start token, don't fail if it's not the case... */
data[i] = b;
if (data[i] == SD_DATA_BLOCK_READ_START) /* 0xFE */
data[i] = SD_SpiWriteByte(0xFF); /* just get the next byte... */
/* receive the rest of data... */
// for (i = 1; i < len; ++i)
// data[i] = SD_SpiWriteByte(0xFF);
ost_hal_sdcard_spi_read(&data[1], (len - 1));
/* get CRC bytes (not really needed by us, but required by SD) */
SD_SpiWriteByte(0xFF);
SD_SpiWriteByte(0xFF);
return SD_RESPONSE_NO_ERROR;
}
return SD_RESPONSE_FAILURE;
}
/**
* @brief Put SD in Idle state.
* @param None
* @retval The SD Response:
* - SD_RESPONSE_FAILURE: Sequence failed
* - SD_RESPONSE_NO_ERROR: Sequence succeed
*/
static SD_Error SD_GoIdleState(void)
{
uint32_t res = 0;
uint16_t i;
uint8_t state;
/* --- put SD card in SPI mode */
SD_Bus_Hold();
i = SD_NUM_TRIES; /* reset try count... */
do
{ /* loop until In Idle State Response (in R1 format) confirmation */
state = SD_SendCmd(SD_CMD_GO_IDLE_STATE, 0x00000000, 0x95); /* valid CRC is mandatory here */
} while (state != SD_IN_IDLE_STATE && i-- > 0);
/* still no Idle State Response => return response failure */
if (state != SD_IN_IDLE_STATE)
return SD_RESPONSE_FAILURE;
/* --- SD card is now in idle state and in SPI mode, activate it and get its type */
cardType = SD_Card_SDSC_v2;
state = SD_WaitReady(); /* make sure card is ready before we go further... */
/* --- try to send CMD8 to offer voltage 2.7-3.6V with check pattern 0xAA */
i = SD_NUM_TRIES; /* reset try count... */
do
{
state = SD_SendCmd(SD_CMD_SEND_IF_COND, 0x000001AA, 0x87); /* valid CRC is mandatory here */
if ((state & SD_ILLEGAL_COMMAND) != 0)
{ /* SD card doesn't accept CMD8 => it's SDSC or MMC card... */
cardType = SD_Card_SDSC_v1;
break;
}
else /* SD card accepts CMD8 => it's SDHC or SDXC card... */
{ /* get R7 response and verify pattern for sanity check... */
SD_GetResponse4b((uint8_t *)&res);
if ((res & 0x0000FFFF) == 0x000001AA)
break; /* check pattern is OK, card accepted offered voltage... */
/* else specification recommends to retry CMD8 again */
}
} while (i-- > 0);
if (i == 0)
return SD_RESPONSE_FAILURE; /* error occurred... */
state = SD_WaitReady(); /* make sure card is ready before we go further... */
/* --- activate card initialization sequence... */
/* CMD55(0) -> ACMD41(0) -> ... */
i = SD_NUM_TRIES_INIT; /* reset try count... */
do
{
state = SD_SendCmd(SD_CMD_SEND_APP, 0x00000000, 0x65);
if (state != SD_IN_IDLE_STATE)
{ /* error occurred => last chance is to try it as a legacy MMC card */
cardType = SD_Card_MMC;
break;
}
state = SD_WaitReady(); /* make sure card is ready before we go further... */
if (cardType == SD_Card_SDSC_v1) /* HCS bit (0 here) is ignored by SDSC card */
state = SD_SendCmd(SD_CMD_ACTIVATE_INIT, 0x00000000, 0xFF);
else
state = SD_SendCmd(SD_CMD_ACTIVATE_INIT, 0x40000000, 0x77);
/* loop while SD_IN_IDLE_STATE bit is set, meaning card is still performing initialization */
} while ((state & SD_IN_IDLE_STATE) != 0x00 && i-- > 0);
/* it might be legacy MMC card... */
if (cardType == SD_Card_SDSC_v1 &&
(state & SD_IN_IDLE_STATE) != 0x00)
cardType = SD_Card_MMC;
state = SD_WaitReady(); /* make sure card is ready before we go further... */
if (cardType == SD_Card_MMC) /* legacy MMC card is initialized with CMD1... */
{ /* -> CMD1(0) -> ... */
i = SD_NUM_TRIES_INIT; /* reset try count... */
do
{
state = SD_SendCmd(SD_CMD_SEND_OP_COND, 0x00000000, 0xFF);
} while ((state & SD_IN_IDLE_STATE) != 0x00 && i-- > 0);
if (i == 0)
return SD_RESPONSE_FAILURE; /* error occurred... */
}
else if (cardType == SD_Card_SDSC_v2) /* recent cards support byte-addressing, check it... */
{ /* -> CMD58(0)... */
if (i == 0) /* first check if timeout occured during its initialization... */
return SD_RESPONSE_FAILURE; /* error occurred... */
/* request OCR register (send CMD58)... */
state = SD_SendCmd(SD_CMD_READ_OCR, 0x00000000, 0xFF);
if (state == SD_RESPONSE_NO_ERROR)
{ /* get OCR register (R3 response) and check its CCS (bit 30) */
SD_GetResponse4b((uint8_t *)&res);
cardType = (res & 0x40000000) ? SD_Card_SDHC : SD_Card_SDSC_v2;
}
}
/* else cardType == SD_Card_SDSC_v1 */
state = SD_WaitReady(); /* make sure card is ready before we go further... */
/* print out detected SD card type... */
switch (cardType)
{
case SD_Card_SDSC_v1:
debug_printf("SDSC v1 (byte address)");
break;
case SD_Card_SDSC_v2:
debug_printf("SDSC v2 (byte address)");
break;
case SD_Card_SDHC:
debug_printf("SDHC (512-bytes sector address)");
break;
case SD_Card_MMC:
debug_printf("MMC (byte address)");
break;
default:
debug_printf("UNKNOWN");
break;
}
debug_printf(" card initialized successfully\r\n");
return SD_RESPONSE_NO_ERROR;
}
SD_Error sdcard_init()
{
uint32_t i = 0;
SD_Error state;
/* step 0:
* Check if SD card is present... */
if (SD_Detect() == SD_NOT_PRESENT)
{
return SD_RESPONSE_FAILURE;
}
debug_printf("\r\n [TEST] SD Card detected\r\n");
/* step 2:
* Card is now powered up (i.e. 1ms at least elapsed at 0.5V),
* Supply rump up time (set MOSI HIGH) to let voltage reach stable 2.2V at least.
* According to the specs it must be 74 SPI clock cycles minimum at 100-400Khz
* At 25Mhz it'll be 250 times more cycles => send 2500 times 0xFF byte.
* Chip Select pin should be set HIGH too. */
/* set SD chip select pin high */
ost_hal_sdcard_cs_high();
/* send dummy byte 0xFF (rise MOSI high for 2500*8 SPI bus clock cycles) */
while (i++ < SD_NUM_TRIES_RUMPUP)
{
SD_SpiWriteByte(SD_DUMMY_BYTE);
}
/* step 3:
* Put SD in SPI mode & perform soft reset */
state = SD_GoIdleState();
/* step 4:
* Force sector size to SD_BLOCK_SIZE (i.e. 512 bytes) */
if (state == SD_RESPONSE_NO_ERROR && cardType != SD_Card_SDHC)
{
state = SD_FixSectorSize((uint16_t)SD_BLOCK_SIZE);
}
/* step 5:
* Release SPI bus for other devices */
SD_Bus_Release();
return state;
}
/**
* @brief Reads a sector of SD_BLOCK_SIZE bytes from the SD card
* @param pBuffer: pointer to the buffer that receives the data read from SD.
* @param readAddr: SD's internal address to read from (sector number)
* @retval The SD Response:
* - SD_RESPONSE_FAILURE: Sequence failed
* - SD_RESPONSE_NO_ERROR: Sequence succeed
*/
SD_Error sdcard_sector_read(uint32_t readAddr, uint8_t *pBuffer)
{
SD_Error state;
// debug_printf("--> reading sector %lu ...", readAddr);
/* non High Capacity cards use byte-oriented addresses */
if (cardType != SD_Card_SDHC)
readAddr <<= 9;
SD_Bus_Hold(); /* hold SPI bus... */
state = SD_WaitReady(); /* make sure card is ready before we go further... */
/* send CMD17 (SD_CMD_READ_SINGLE_BLOCK) to read one block */
state = SD_SendCmd(SD_CMD_READ_SINGLE_BLOCK, readAddr, 0xFF);
/* receive data if command acknowledged... */
if (state == SD_RESPONSE_NO_ERROR)
state = SD_ReceiveData(pBuffer, SD_BLOCK_SIZE);
SD_Bus_Release(); /* release SPI bus... */
// if (state == SD_RESPONSE_NO_ERROR)
// debug_printf("OK\r\n");
// else
// debug_printf("KO(%d)\r\n", state);
return state;
}
/**
* @brief Reads multiple sectors of SD_BLOCK_SIZE bytes from the SD card
* @param pBuffer: pointer to the buffer that receives the data read from SD.
* @param readAddr: SD's internal address to read from.
* @param nbSectors: number of blocks to be read.
* @retval The SD Response:
* - SD_RESPONSE_FAILURE: Sequence failed
* - SD_RESPONSE_NO_ERROR: Sequence succeed
*/
SD_Error sdcard_sectors_read(uint32_t readAddr, uint8_t *pBuffer, uint32_t nbSectors)
{
SD_Error state;
// debug_printf("--> reading %lu sectors from %lu ...", nbSectors, readAddr);
/* non High Capacity cards use byte-oriented addresses */
if (cardType != SD_Card_SDHC)
readAddr <<= 9;
SD_Bus_Hold(); /* hold SPI bus... */
state = SD_WaitReady(); /* make sure card is ready before we go further... */
/* send CMD18 (SD_CMD_READ_MULT_BLOCK) to read multiple blocks */
state = SD_SendCmd(SD_CMD_READ_MULT_BLOCK, readAddr, 0xFF);
if (state == SD_RESPONSE_NO_ERROR)
{ /* receive data... */
while (nbSectors-- > 0)
{
state = SD_ReceiveData(pBuffer, SD_BLOCK_SIZE);
if (state != SD_RESPONSE_NO_ERROR)
break;
pBuffer += SD_BLOCK_SIZE;
}
/* transmission is open-ended (no block count was set) =>
* send CMD12 (SD_CMD_STOP_TRANSMISSION) to stop it... */
state = SD_SendCmd(SD_CMD_STOP_TRANSMISSION, 0x00000000, 0xFF);
}
SD_Bus_Release(); /* release SPI bus... */
// if (state == SD_RESPONSE_NO_ERROR)
// debug_printf("OK\r\n");
// else
// debug_printf("KO(%d)\r\n", state);
return state;
}
/**
* @brief Writes a sector of SD_BLOCK_SIZE bytes on the SD card
* @param pBuffer: pointer to the buffer with the data to be written on SD.
* @param writeAddr: address to write on.
* @retval The SD Response:
* - SD_RESPONSE_FAILURE: Sequence failed
* - SD_RESPONSE_NO_ERROR: Sequence succeed
*/
SD_Error sdcard_sector_write(uint32_t writeAddr, const uint8_t *pBuffer)
{
SD_Error state;
SD_DataResponse res;
uint16_t BlockSize = SD_BLOCK_SIZE;
debug_printf("--> writing sector %lu ...", writeAddr);
/* non High Capacity cards use byte-oriented addresses */
if (cardType != SD_Card_SDHC)
writeAddr <<= 9;
SD_Bus_Hold(); /* hold SPI bus... */
state = SD_WaitReady(); /* make sure card is ready before we go further... */
/* send CMD24 (SD_CMD_WRITE_SINGLE_BLOCK) to write single block */
state = SD_SendCmd(SD_CMD_WRITE_SINGLE_BLOCK, writeAddr, 0xFF);
if (state == SD_RESPONSE_NO_ERROR)
{ /* wait at least 8 clock cycles (send >=1 0xFF bytes) before transmission starts */
SD_SpiWriteByte(SD_DUMMY_BYTE);
SD_SpiWriteByte(SD_DUMMY_BYTE);
SD_SpiWriteByte(SD_DUMMY_BYTE);
/* send data token to signify the start of data transmission... */
SD_SpiWriteByte(SD_DATA_SINGLE_BLOCK_WRITE_START); /* 0xFE */
/* send data... */
while (BlockSize-- > 0)
SD_SpiWriteByte(*pBuffer++);
/* put 2 CRC bytes (not really needed by us, but required by SD) */
SD_SpiWriteByte(SD_DUMMY_BYTE);
SD_SpiWriteByte(SD_DUMMY_BYTE);
/* check data response... */
res = (SD_DataResponse)(SD_SpiWriteByte(0xFF) & SD_RESPONSE_MASK); /* mask unused bits */
if ((res & SD_RESPONSE_ACCEPTED) != 0)
{ /* card is now processing data and goes to BUSY mode, wait until it finishes... */
state = SD_WaitBytesWritten(); /* make sure card is ready before we go further... */
}
else
state = SD_RESPONSE_FAILURE;
}
SD_Bus_Release(); /* release SPI bus... */
// if (state == SD_RESPONSE_NO_ERROR)
// debug_printf("OK\r\n");
// else
// debug_printf("KO(%d)\r\n", state);
return state;
}
/**
* @brief Writes multiple sectors of SD_BLOCK_SIZE bytes on the SD card
* @param pBuffer: pointer to the buffer with the data to be written on the SD.
* @param writeAddr: address to write on.
* @param nbSectors: number of blocks to be written.
* @retval The SD Response:
* - SD_RESPONSE_FAILURE: Sequence failed
* - SD_RESPONSE_NO_ERROR: Sequence succeed
*/
SD_Error sdcard_sectors_write(uint32_t writeAddr, const uint8_t *pBuffer, uint32_t nbSectors)
{
SD_Error state;
SD_DataResponse res;
uint16_t BlockSize = SD_BLOCK_SIZE;
debug_printf("--> writing %lu sectors at %lu ...", nbSectors, writeAddr);
/* non High Capacity cards use byte-oriented addresses */
if (cardType != SD_Card_SDHC)
writeAddr <<= 9;
SD_Bus_Hold(); /* hold SPI bus... */
state = SD_WaitReady(); /* make sure card is ready before we go further... */
/* it is recommended to specify in advance the number of blocks being written
* to let SD card erase needed number of blocks, write operation should take less time then */
if (cardType != SD_Card_MMC)
{ /* notify card about the total number of blocks to be sent (send CMD23)... */
state = SD_SendCmd(SD_CMD_SET_BLOCK_COUNT, (uint32_t)nbSectors, 0xFF);
if (state != SD_RESPONSE_NO_ERROR)
{
SD_Bus_Release(); /* release SPI bus... */
return state;
}
}
/* request writing data starting from the given address (send CMD25)... */
state = SD_SendCmd(SD_CMD_WRITE_MULT_BLOCK, writeAddr, 0xFF);
if (state == SD_RESPONSE_NO_ERROR)
{
/* send some dummy bytes before transmission starts... */
SD_SpiWriteByte(0xFF);
SD_SpiWriteByte(0xFF);
SD_SpiWriteByte(0xFF);
/* transfer data... */
while (nbSectors-- > 0 && state != SD_RESPONSE_FAILURE)
{ /* --- {{ send data packet */
SD_SpiWriteByte(SD_DATA_MULTIPLE_BLOCK_WRITE_START); /* 0xFC */
/* send data... */
while (BlockSize-- > 0)
SD_SpiWriteByte(*pBuffer++);
/* put CRC bytes (not really needed by us, but required by SD) */
SD_SpiWriteByte(0xFF);
SD_SpiWriteByte(0xFF);
/* --- }} */
/* check data response... */
res = (SD_DataResponse)(SD_SpiWriteByte(0xFF) & SD_RESPONSE_MASK); /* mask unused bits */
if ((res & SD_RESPONSE_ACCEPTED) != 0)
{ /* card is now processing data and goes to BUSY mode, wait until it finishes... */
state = SD_WaitBytesWritten(); /* make sure card is ready before we go further... */
}
else
state = SD_RESPONSE_FAILURE;
}
/* notify SD card that we finished sending data to write on it */
SD_SpiWriteByte(SD_DATA_MULTIPLE_BLOCK_WRITE_STOP); /* 0xFD */
SD_SpiWriteByte(0xFF); /* read and discard 1 byte from card */
/* card is now processing data and goes to BUSY mode, wait until it finishes... */
state = SD_WaitReady(); /* make sure card is ready before we go further... */
}
SD_Bus_Release(); /* release SPI bus... */
if (state == SD_RESPONSE_NO_ERROR)
debug_printf("OK\n");
else
debug_printf("KO(%d)\n", state);
return state;
}
/**
* @brief Erase specified range of sectors on SD card
* @param eraseAddrFrom: Starting sector number
* @param eraseAddrTo: End sector number
* @retval The SD Response:
* - SD_RESPONSE_FAILURE: Sequence failed
* - SD_RESPONSE_NO_ERROR: Sequence succeed
*/
SD_Error sdcard_sectors_erase(uint32_t eraseAddrFrom, uint32_t eraseAddrTo)
{
SD_Error state;
if (cardType == SD_Card_MMC)
{
debug_printf("--> erasing sectors is not supported for MMC cards\n");
return SD_ILLEGAL_COMMAND;
}
// debug_printf("--> erasing sectors from %lu to %lu ...", eraseAddrFrom, eraseAddrTo);
/* non High Capacity cards use byte-oriented addresses */
if (cardType != SD_Card_SDHC)
{
eraseAddrFrom <<= 9;
eraseAddrTo <<= 9;
}
SD_Bus_Hold(); /* hold SPI bus... */
state = SD_WaitReady(); /* make sure card is ready before we go further... */
/* send starting block address (CMD32)... */
state = SD_SendCmd(SD_CMD_ERASE_BLOCK_START, (uint32_t)eraseAddrFrom, 0xFF);
if (state == SD_RESPONSE_NO_ERROR)
{ /* send end block address (CMD33)... */
state = SD_SendCmd(SD_CMD_ERASE_BLOCK_END, (uint32_t)eraseAddrTo, 0xFF);
if (state == SD_RESPONSE_NO_ERROR)
{ /* erase all selected blocks (CMD38)... */
state = SD_SendCmd(SD_CMD_ERASE, 0x00000000, 0xFF);
if (state == SD_RESPONSE_NO_ERROR)
{ /* wait until sectors get erased... */
state = SD_WaitBytesErased(); /* make sure card is ready before we go further... */
}
}
}
SD_Bus_Release(); /* release SPI bus... */
// if (state == SD_RESPONSE_NO_ERROR)
// debug_printf("OK\r\n");
// else
// debug_printf("KO(%d)\r\n", state);
return state;
}
/**
* @brief Read the CSD card register.
* Reading the contents of the CSD register in SPI mode is a simple
* read-block transaction.
* @param SD_csd: pointer on an SCD register structure
* @retval The SD Response:
* - SD_RESPONSE_FAILURE: Sequence failed
* - SD_RESPONSE_NO_ERROR: Sequence succeed
*/
static SD_Error SD_GetCSDRegister(SD_CSD *SD_csd)
{
SD_Error state;
uint8_t CSD_Tab[16];
state = SD_WaitReady(); /* make sure card is ready before we go further... */
if (state != SD_RESPONSE_NO_ERROR)
return SD_RESPONSE_FAILURE;
/* request CSD register (send CMD9)... */
state = SD_SendCmd(SD_CMD_SEND_CSD, 0x00000000, 0xFF);
if (state != SD_RESPONSE_NO_ERROR)
return SD_RESPONSE_FAILURE;
state = SD_ReceiveData(CSD_Tab, 16); /* receive CSD register data */
SD_csd->CSDStruct = (CSD_Tab[0] & 0xC0) >> 6; /* Byte 0 */
SD_csd->SysSpecVersion = (CSD_Tab[0] & 0x3C) >> 2;
SD_csd->Reserved1 = CSD_Tab[0] & 0x03;
SD_csd->TAAC = CSD_Tab[1]; /* Byte 1 */
SD_csd->NSAC = CSD_Tab[2]; /* Byte 2 */
SD_csd->MaxBusClkFrec = CSD_Tab[3]; /* Byte 3 */
SD_csd->CardComdClasses = CSD_Tab[4] << 4; /* Byte 4 */
SD_csd->CardComdClasses |= (CSD_Tab[5] & 0xF0) >> 4; /* Byte 5 */
SD_csd->RdBlockLen = CSD_Tab[5] & 0x0F;
SD_csd->PartBlockRead = (CSD_Tab[6] & 0x80) >> 7; /* Byte 6 */
SD_csd->WrBlockMisalign = (CSD_Tab[6] & 0x40) >> 6;
SD_csd->RdBlockMisalign = (CSD_Tab[6] & 0x20) >> 5;
SD_csd->DSRImpl = (CSD_Tab[6] & 0x10) >> 4;
SD_csd->Reserved2 = (CSD_Tab[6] & 0x0C) >> 2;
if (SD_csd->CSDStruct == 0)
{ /* v1 */
SD_csd->DeviceSize = (CSD_Tab[6] & 0x03) << 10; /* DeviceSize has 12 bits here */
SD_csd->DeviceSize |= CSD_Tab[7] << 2; /* Byte 7 */
SD_csd->DeviceSize |= (CSD_Tab[8] & 0xC0) >> 6; /* Byte 8 */
SD_csd->MaxRdCurrentVDDMin = (CSD_Tab[8] & 0x38) >> 3;
SD_csd->MaxRdCurrentVDDMax = CSD_Tab[8] & 0x07;
SD_csd->MaxWrCurrentVDDMin = (CSD_Tab[9] & 0xE0) >> 5; /* Byte 9 */
SD_csd->MaxWrCurrentVDDMax = (CSD_Tab[9] & 0x1C) >> 2;
SD_csd->DeviceSizeMul = (CSD_Tab[9] & 0x03) << 1;
SD_csd->DeviceSizeMul |= (CSD_Tab[10] & 0x80) >> 7; /* Byte 10 */
}
else
{ /* v2 */
SD_csd->Reserved5 = (CSD_Tab[6] & 0x03) << 2;
SD_csd->Reserved5 |= (CSD_Tab[7] & 0xC0) >> 6; /* Byte 7 */
SD_csd->DeviceSize = (CSD_Tab[7] & 0x3F) << 16; /* DeviceSize has 22 bits here */
SD_csd->DeviceSize |= CSD_Tab[8] << 8; /* Byte 8 */
SD_csd->DeviceSize |= CSD_Tab[9]; /* Byte 9 */
SD_csd->Reserved6 = (CSD_Tab[10] & 0x80) >> 7; /* Byte 10 */
}
SD_csd->EraseBlockEnable = (CSD_Tab[10] & 0x40) >> 6;
SD_csd->EraseSectorSize = (CSD_Tab[10] & 0x3F) << 1;
SD_csd->EraseSectorSize |= (CSD_Tab[11] & 0x80) >> 7; /* Byte 11 */
SD_csd->WrProtectGrSize = CSD_Tab[11] & 0x7F;
SD_csd->WrProtectGrEnable = (CSD_Tab[12] & 0x80) >> 7; /* Byte 12 */
SD_csd->ManDeflECC = (CSD_Tab[12] & 0x60) >> 5;
SD_csd->WrSpeedFact = (CSD_Tab[12] & 0x1C) >> 2;
SD_csd->MaxWrBlockLen = (CSD_Tab[12] & 0x03) << 2;
SD_csd->MaxWrBlockLen |= (CSD_Tab[13] & 0xC0) >> 6; /* Byte 13 */
SD_csd->WriteBlockPaPartial = (CSD_Tab[13] & 0x20) >> 5;
SD_csd->Reserved3 = CSD_Tab[13] & 0x1E;
SD_csd->ContentProtectAppli = CSD_Tab[13] & 0x01;
SD_csd->FileFormatGroup = (CSD_Tab[14] & 0x80) >> 7; /* Byte 14 */
SD_csd->CopyFlag = (CSD_Tab[14] & 0x40) >> 6;
SD_csd->PermWrProtect = (CSD_Tab[14] & 0x20) >> 5;
SD_csd->TempWrProtect = (CSD_Tab[14] & 0x10) >> 4;
SD_csd->FileFormat = (CSD_Tab[14] & 0x0C) >> 2;
SD_csd->ECC = CSD_Tab[14] & 0x03;
SD_csd->CSD_CRC = (CSD_Tab[15] & 0xFE) >> 1; /* Byte 15 */
SD_csd->Reserved4 = CSD_Tab[15] & 0x01;
return state;
}
/**
* @brief Read the CID card register.
* Reading the contents of the CID register in SPI mode is a simple
* read-block transaction.
* @param SD_cid: pointer on an CID register structure
* @retval The SD Response:
* - SD_RESPONSE_FAILURE: Sequence failed
* - SD_RESPONSE_NO_ERROR: Sequence succeed
*/
static SD_Error SD_GetCIDRegister(SD_CID *SD_cid)
{
SD_Error state;
uint8_t CID_Tab[16];
state = SD_WaitReady(); /* make sure card is ready before we go further... */
if (state != SD_RESPONSE_NO_ERROR)
return SD_RESPONSE_FAILURE;
/* request CID register (send CMD10)... */
state = SD_SendCmd(SD_CMD_SEND_CID, 0x00000000, 0xFF);
if (state != SD_RESPONSE_NO_ERROR)
return SD_RESPONSE_FAILURE;
state = SD_ReceiveData(CID_Tab, 16); /* receive CID register data */
SD_cid->ManufacturerID = CID_Tab[0]; /* Byte 0 */
SD_cid->OEM_AppliID = CID_Tab[1] << 8; /* Byte 1 */
SD_cid->OEM_AppliID |= CID_Tab[2]; /* Byte 2 */
SD_cid->ProdName1 = CID_Tab[3] << 24; /* Byte 3 */
SD_cid->ProdName1 |= CID_Tab[4] << 16; /* Byte 4 */
SD_cid->ProdName1 |= CID_Tab[5] << 8; /* Byte 5 */
SD_cid->ProdName1 |= CID_Tab[6]; /* Byte 6 */
SD_cid->ProdName2 = CID_Tab[7]; /* Byte 7 */
SD_cid->ProdRev = CID_Tab[8]; /* Byte 8 */
SD_cid->ProdSN = CID_Tab[9] << 24; /* Byte 9 */
SD_cid->ProdSN |= CID_Tab[10] << 16; /* Byte 10 */
SD_cid->ProdSN |= CID_Tab[11] << 8; /* Byte 11 */
SD_cid->ProdSN |= CID_Tab[12]; /* Byte 12 */
SD_cid->Reserved1 |= (CID_Tab[13] & 0xF0) >> 4; /* Byte 13 */
SD_cid->ManufactDate = (CID_Tab[13] & 0x0F) << 8;
SD_cid->ManufactDate |= CID_Tab[14]; /* Byte 14 */
SD_cid->CID_CRC = (CID_Tab[15] & 0xFE) >> 1; /* Byte 15 */
SD_cid->Reserved2 = 1;
return state;
}
/**
* @brief Read the SCR card register.
* Reading the contents of the SCR register in SPI mode is a simple
* read-block transaction.
* @param SD_scr: pointer on an SCR register structure
* @retval The SD Response:
* - SD_RESPONSE_FAILURE: Sequence failed
* - SD_RESPONSE_NO_ERROR: Sequence succeed
*/
static SD_Error SD_GetSCRRegister(SD_SCR *SD_scr)
{
SD_Error state;
uint8_t SCR_Tab[8];
if (cardType == SD_Card_MMC)
{
debug_printf("SCR Register is not available for MMC cards\n");
return SD_ILLEGAL_COMMAND;
}
state = SD_WaitReady(); /* make sure card is ready before we go further... */
if (state != SD_RESPONSE_NO_ERROR)
return SD_RESPONSE_FAILURE;
/* request SCR register (send ACMD51)... */
state = SD_SendCmd(SD_CMD_SEND_APP, 0x00000000, 0x65);
if (state == SD_RESPONSE_NO_ERROR)
state = SD_SendCmd(SD_CMD_SEND_SCR, 0x00000000, 0xFF);
if (state != SD_RESPONSE_NO_ERROR)
return SD_RESPONSE_FAILURE;
state = SD_ReceiveData(SCR_Tab, 8); /* receive SCR register data */
SD_scr->SCR_Version = (SCR_Tab[0] & 0xF0) >> 4; /* Byte 0 */
SD_scr->SpecVersion = SCR_Tab[0] & 0x0F;
SD_scr->StateAfterErase = (SCR_Tab[1] & 0x80) >> 7; /* Byte 1 */
SD_scr->Security = (SCR_Tab[1] & 0x70) >> 4;
SD_scr->BusWidth = SCR_Tab[1] & 0x0F;
SD_scr->SpecVersion3 = (SCR_Tab[2] & 0x80) >> 7; /* Byte 2 */
SD_scr->ExSecurity = (SCR_Tab[2] & 0x78) >> 3;
SD_scr->Reserved1 = (SCR_Tab[2] & 0x07) << 6;
SD_scr->Reserved1 |= (SCR_Tab[3] & 0xFC) >> 2; /* Byte 3 */
SD_scr->CmdSupport1 = (SCR_Tab[3] & 0x02) >> 1;
SD_scr->CmdSupport2 = SCR_Tab[3] & 0x01;
SD_scr->Reserved2 = SCR_Tab[4] << 24; /* Byte 4 */
SD_scr->Reserved2 |= SCR_Tab[5] << 16; /* Byte 5 */
SD_scr->Reserved2 |= SCR_Tab[6] << 8; /* Byte 6 */
SD_scr->Reserved2 |= SCR_Tab[7]; /* Byte 7 */
return state;
}
/**
* @brief Returns information about specific card.
* @param cardinfo: pointer to a SD_CardInfo structure that contains all SD
* card information.
* @retval The SD Response:
* - SD_RESPONSE_FAILURE: Sequence failed
* - SD_RESPONSE_NO_ERROR: Sequence succeed
*/
SD_Error sdcard_get_card_info(SD_CardInfo *cardinfo)
{
SD_Error status;
SD_Bus_Hold(); /* hold SPI bus... */
status = SD_GetCSDRegister(&(cardinfo->SD_csd));
if (status == SD_RESPONSE_NO_ERROR)
status = SD_GetCIDRegister(&(cardinfo->SD_cid));
if (status == SD_RESPONSE_NO_ERROR && cardType != SD_Card_MMC)
status = SD_GetSCRRegister(&(cardinfo->SD_scr));
SD_Bus_Release(); /* release SPI bus... */
if (status == SD_RESPONSE_NO_ERROR)
{ /* to avoid overflow, card capacity is calculated in Kbytes */
if (cardinfo->SD_csd.CSDStruct == 0)
{ // v1:
cardinfo->CardCapacity = cardinfo->SD_csd.DeviceSize + 1;
cardinfo->CardCapacity *= (1 << (cardinfo->SD_csd.DeviceSizeMul + 2));
cardinfo->CardBlockSize = 1 << cardinfo->SD_csd.RdBlockLen;
if (cardinfo->SD_csd.RdBlockLen > 10)
cardinfo->CardCapacity *= (1 << (cardinfo->SD_csd.RdBlockLen - 10));
else
cardinfo->CardCapacity /= (1 << (10 - cardinfo->SD_csd.RdBlockLen));
}
else
{ // v2:
cardinfo->CardCapacity = cardinfo->SD_csd.DeviceSize + 1;
cardinfo->CardBlockSize = 1 << cardinfo->SD_csd.RdBlockLen;
cardinfo->CardCapacity *= cardinfo->CardBlockSize;
}
}
return status;
}
/**
* @brief Prints out human-readable information about SD Card
* @param Previously retrieved card info structure
* @retval None
*/
void sdcard_dump_card_info(const SD_CardInfo *cardinfo)
{
uint8_t is_OSRv1 = (cardinfo->SD_csd.CSDStruct == 0);
debug_printf("\nDumping SD Card information:\n\n GLOBAL INFO\nSD Card type : ");
/* some cards report wrong CSDStruct field in CSR register => use detected card type instead... */
if (is_OSRv1 != 0)
debug_printf("SDSC (v1 or v2)\n");
else
debug_printf("SDHC or SDXC\n");
debug_printf("Card Capacity : %lu Kbytes\n", cardinfo->CardCapacity);
debug_printf("Card Block Size : %lu bytes\n", cardinfo->CardBlockSize);
debug_printf("\n Card identification register (CID)\n");
debug_printf("Manufacturer ID : %d\n", cardinfo->SD_cid.ManufacturerID);
debug_printf("OEM / Application ID : %c%c\n",
((char *)&(cardinfo->SD_cid.OEM_AppliID))[1],
((char *)&(cardinfo->SD_cid.OEM_AppliID))[0]);
debug_printf("Product Name : %c%c%c%c%c\n",
((char *)&(cardinfo->SD_cid.ProdName1))[3],
((char *)&(cardinfo->SD_cid.ProdName1))[2],
((char *)&(cardinfo->SD_cid.ProdName1))[1],
((char *)&(cardinfo->SD_cid.ProdName1))[0],
(char)(cardinfo->SD_cid.ProdName2));
debug_printf("Product Revision : %d.%d\n",
(cardinfo->SD_cid.ProdRev & 0xF0) >> 4,
(cardinfo->SD_cid.ProdRev & 0x0F));
debug_printf("Product Serial Number : %lu\n",
cardinfo->SD_cid.ProdSN);
debug_printf("Manufacturing Date (YYYY-MM) : %d-%d\n",
2000 + ((cardinfo->SD_cid.ManufactDate & 0x0FF0) >> 4),
cardinfo->SD_cid.ManufactDate & 0x000F);
debug_printf("CID CRC : %d\n", cardinfo->SD_cid.CID_CRC & 0x7F);
debug_printf("\n Card-specific data register (CSD)\n");
if (is_OSRv1 != 0)
{
debug_printf("Data read access-time : ");
switch ((cardinfo->SD_csd.TAAC & 0x78) >> 3)
{
case 0x0:
debug_printf("0.0");
break;
case 0x1:
debug_printf("1.0");
break;
case 0x2:
debug_printf("1.2");
break;
case 0x3:
debug_printf("1.3");
break;
case 0x4:
debug_printf("1.5");
break;
case 0x5:
debug_printf("2.0");
break;
case 0x6:
debug_printf("2.5");
break;
case 0x7:
debug_printf("3.0");
break;
case 0x8:
debug_printf("3.5");
break;
case 0x9:
debug_printf("4.0");
break;
case 0xA:
debug_printf("4.5");
break;
case 0xB:
debug_printf("5.0");
break;
case 0xC:
debug_printf("5.5");
break;
case 0xD:
debug_printf("6.0");
break;
case 0xE:
debug_printf("7.0");
break;
case 0xF:
debug_printf("8.0");
break;
default:
break;
}
debug_printf(" x 1");
switch (cardinfo->SD_csd.TAAC & 0x07)
{
case 0:
debug_printf("n");
break;
case 1:
debug_printf("0n");
break;
case 2:
debug_printf("00n");
break;
case 3:
debug_printf("u");
break;
case 4:
debug_printf("0u");
break;
case 5:
debug_printf("00u");
break;
case 6:
debug_printf("m");
break;
case 7:
debug_printf("0m");
break;
default:
break;
}
debug_printf("s\nData read access-time in CLK cycles : %d\n", cardinfo->SD_csd.NSAC);
}
debug_printf("Max. bus clock frequency : %x", cardinfo->SD_csd.MaxBusClkFrec);
switch (cardinfo->SD_csd.MaxBusClkFrec)
{
case 0x32:
debug_printf(" (25Mhz)\n");
break;
case 0x5A:
debug_printf(" (50Mhz)\n");
break;
case 0x0B:
debug_printf(" (100Mhz)\n");
break;
case 0x2B:
debug_printf(" (200Mhz)\n");
break;
default:
debug_printf("\n");
break;
}
debug_printf("\nCard command classes :");
if (cardinfo->SD_csd.CardComdClasses & (0x001))
debug_printf(" 0(basic)");
if (cardinfo->SD_csd.CardComdClasses & (1 << 1))
debug_printf(" 1");
if (cardinfo->SD_csd.CardComdClasses & (1 << 2))
debug_printf(" 2(read)");
if (cardinfo->SD_csd.CardComdClasses & (1 << 3))
debug_printf(" 3");
if (cardinfo->SD_csd.CardComdClasses & (1 << 4))
debug_printf(" 4(write)");
if (cardinfo->SD_csd.CardComdClasses & (1 << 5))
debug_printf(" 5(erase)");
if (cardinfo->SD_csd.CardComdClasses & (1 << 6))
debug_printf(" 6(protect)");
if (cardinfo->SD_csd.CardComdClasses & (1 << 7))
debug_printf(" 7(lock)");
if (cardinfo->SD_csd.CardComdClasses & (1 << 8))
debug_printf(" 8(app)");
if (cardinfo->SD_csd.CardComdClasses & (1 << 9))
debug_printf(" 9(i/o)");
if (cardinfo->SD_csd.CardComdClasses & (1 << 10))
debug_printf(" 10(switch)");
if (cardinfo->SD_csd.CardComdClasses & (1 << 11))
debug_printf(" 11");
debug_printf("\n");
if (is_OSRv1 != 0)
{
debug_printf("Max. read data block length : %d ( %d bytes )\n",
cardinfo->SD_csd.RdBlockLen,
1 << (cardinfo->SD_csd.RdBlockLen));
debug_printf("Partial blocks for read allowed : %d\n", cardinfo->SD_csd.PartBlockRead);
debug_printf("Write block misalignment : %d\n", cardinfo->SD_csd.WrBlockMisalign);
debug_printf("Read block misalignment : %d\n", cardinfo->SD_csd.RdBlockMisalign);
}
else
{
debug_printf("Max. read data block length : always 512 bytes\n");
debug_printf("Partial blocks for read are not allowed\n");
debug_printf("Read/Write block misalignment is not allowed\n");
}
debug_printf("DSR implemented : %d\n", cardinfo->SD_csd.DSRImpl);
debug_printf("Device Size (4112 <= and <= 65375): %lu\n", cardinfo->SD_csd.DeviceSize);
if (is_OSRv1 != 0)
{
debug_printf("Max. read current at VDD min : ");
switch (cardinfo->SD_csd.MaxRdCurrentVDDMin)
{
case 0:
debug_printf("0.5");
break;
case 1:
debug_printf("1");
break;
case 2:
debug_printf("5");
break;
case 3:
debug_printf("10");
break;
case 4:
debug_printf("25");
break;
case 5:
debug_printf("35");
break;
case 6:
debug_printf("60");
break;
case 7:
debug_printf("100");
break;
default:
break;
}
debug_printf("mA\nMax. read current at VDD max : ");
switch (cardinfo->SD_csd.MaxRdCurrentVDDMax)
{
case 0:
debug_printf("0.5");
break;
case 1:
debug_printf("1");
break;
case 2:
debug_printf("5");
break;
case 3:
debug_printf("10");
break;
case 4:
debug_printf("25");
break;
case 5:
debug_printf("35");
break;
case 6:
debug_printf("60");
break;
case 7:
debug_printf("100");
break;
default:
break;
}
debug_printf("mA\nMax. write current at VDD min : ");
switch (cardinfo->SD_csd.MaxWrCurrentVDDMin)
{
case 0:
debug_printf("1");
break;
case 1:
debug_printf("5");
break;
case 2:
debug_printf("10");
break;
case 3:
debug_printf("25");
break;
case 4:
debug_printf("35");
break;
case 5:
debug_printf("45");
break;
case 6:
debug_printf("80");
break;
case 7:
debug_printf("200");
break;
default:
break;
}
debug_printf("mA\nMax. write current at VDD max : ");
switch (cardinfo->SD_csd.MaxWrCurrentVDDMax)
{
case 0:
debug_printf("1");
break;
case 1:
debug_printf("5");
break;
case 2:
debug_printf("10");
break;
case 3:
debug_printf("25");
break;
case 4:
debug_printf("35");
break;
case 5:
debug_printf("45");
break;
case 6:
debug_printf("80");
break;
case 7:
debug_printf("200");
break;
default:
break;
}
debug_printf("mA\nDevice size multiplier : %d\n", cardinfo->SD_csd.DeviceSizeMul);
if (cardinfo->SD_csd.EraseBlockEnable == 0)
debug_printf("Erase size : 1 or more units of %d bytes each\n", cardinfo->SD_csd.EraseSectorSize);
else
debug_printf("Erase size : 1 or more blocks of 512 bytes each\n");
debug_printf("Write protect group size : %d\n", cardinfo->SD_csd.WrProtectGrSize);
debug_printf("Write protect group enable : %d\n", cardinfo->SD_csd.WrProtectGrEnable);
debug_printf("Write speed factor (Twrite/Tread) : %d\n", 1 << (cardinfo->SD_csd.WrSpeedFact & 0x3F));
debug_printf("Max. write data block length : %d\n", 1 << (cardinfo->SD_csd.MaxWrBlockLen & 0xF));
debug_printf("Partial blocks for write allowed : %d\n", cardinfo->SD_csd.WriteBlockPaPartial);
debug_printf("File format group : %d\n", cardinfo->SD_csd.FileFormatGroup);
}
else
{
debug_printf("Erase size : 1 or more blocks of 512 bytes each\n");
debug_printf("Write protect group disabled\n");
debug_printf("Write timeout : 250ms\n");
debug_printf("Max. write data block length : 512 bytes\n");
debug_printf("Partial blocks for write are not allowed\n");
}
debug_printf("Copy flag (OTP) : %d\n", cardinfo->SD_csd.CopyFlag);
debug_printf("Permanent write protection : %d\n", cardinfo->SD_csd.PermWrProtect);
debug_printf("Temporary write protection : %d\n", cardinfo->SD_csd.TempWrProtect);
if (is_OSRv1 != 0)
{
debug_printf("File Format : ");
switch (cardinfo->SD_csd.FileFormat)
{
case 0:
debug_printf("HDD-like file system with partition table\n");
break;
case 1:
debug_printf("DOS FAT (FDD-like) with boot sector only (no partition table)\n");
break;
case 2:
debug_printf("Universal File Format\n");
break;
case 3:
debug_printf("Others/Unknown\n");
break;
default:
break;
}
}
debug_printf("CSD CRC : %d\n", cardinfo->SD_csd.CSD_CRC);
if (cardType != SD_Card_MMC)
{
debug_printf("\n SD Card configuration register (SCR)\n");
debug_printf("SCR structure version : %d\n", cardinfo->SD_scr.SCR_Version);
debug_printf("Physical layer specification version number : ");
switch (cardinfo->SD_scr.SpecVersion)
{
case 0:
debug_printf("Version 1.0 and 1.01");
break;
case 1:
debug_printf("Version 1.10");
break;
case 2:
debug_printf("Version %s", (cardinfo->SD_scr.SpecVersion3 == 0) ? "2.00" : "3.0x");
break;
default:
debug_printf("reserved");
break;
}
debug_printf("\nState of bits after sector erase : 0x%s\n", cardinfo->SD_scr.StateAfterErase ? "FF" : "00");
debug_printf("CPRM security version : ");
switch (cardinfo->SD_scr.Security)
{
case 0:
debug_printf("no security");
break;
case 1:
debug_printf("not used");
break;
case 2:
debug_printf("SDSC security ver 1.01");
break;
case 3:
debug_printf("SDHC security ver 2.00");
break;
case 4:
debug_printf("SDXC security ver 3.xx");
break;
default:
debug_printf("reserved");
break;
}
debug_printf("\nSupported data bus width :");
if (cardinfo->SD_scr.BusWidth & 0x01)
debug_printf(" 1 bit");
if (cardinfo->SD_scr.BusWidth & 0x04)
debug_printf(" 4 bit");
debug_printf("\nExtended security is%s supported\n", (cardinfo->SD_scr.ExSecurity == 0) ? " not" : "");
debug_printf("Support of CMD23 (set block count) : %c\n", cardinfo->SD_scr.CmdSupport1 ? 'Y' : 'N');
debug_printf("Support of CMD20 (speed class control) : %c\n", cardinfo->SD_scr.CmdSupport2 ? 'Y' : 'N');
}
debug_printf("\nDONE\n");
}
/**
* @brief Prints out SD card status in human-readable form
* @param Previously retrieved SD card status structure
* @retval None
*/
void sdcard_dump_status(const SD_Status *SD_status)
{
debug_printf("\nDumping SD Card status information:\n\n");
if (cardType != SD_Card_MMC)
{
debug_printf("Bus width : ");
switch (SD_status->BusWidth)
{
case 0x00:
debug_printf("1 bit");
break;
case 0x02:
debug_printf("4 bits");
break;
default:
debug_printf("reserved");
break;
}
debug_printf("\nSD card is%s in secured mode\n", SD_status->InSecuredMode ? "" : " not");
debug_printf("Card Type : ");
switch (SD_status->CardType)
{
case 0x0000:
debug_printf("Regular SD card");
break;
case 0x0001:
debug_printf("SD ROM card");
break;
case 0x0002:
debug_printf("OTP card");
break;
default:
debug_printf("other card");
break;
}
debug_printf("\nSize of protected area : %lu\n", SD_status->SizeProtectedArea);
debug_printf("Speed class : ");
switch (SD_status->SpeedClass)
{
case 0x00:
debug_printf("Class 0");
break;
case 0x01:
debug_printf("Class 2");
break;
case 0x02:
debug_printf("Class 4");
break;
case 0x03:
debug_printf("Class 6");
break;
case 0x04:
debug_printf("Class 10");
break;
default:
debug_printf("Reserved");
break;
}
debug_printf("\nPerformance move : ");
switch (SD_status->PerformanceMove)
{
case 0x00:
debug_printf("Sequential write");
break;
case 0xFF:
debug_printf("Infinity");
break;
default:
debug_printf("%d Mb/sec", SD_status->PerformanceMove);
break;
}
debug_printf("\nAllocation Unit size : ");
switch (SD_status->AU_Size)
{
case 0x00:
debug_printf("not defined");
break;
case 0x01:
debug_printf("16 Kb");
break;
case 0x02:
debug_printf("32 Kb");
break;
case 0x03:
debug_printf("64 Kb");
break;
case 0x04:
debug_printf("128 Kb");
break;
case 0x05:
debug_printf("256 Kb");
break;
case 0x06:
debug_printf("512 Kb");
break;
case 0x07:
debug_printf("1 Mb");
break;
case 0x08:
debug_printf("2 Mb");
break;
case 0x09:
debug_printf("4 Mb");
break;
case 0x0A:
debug_printf("8 Mb");
break;
case 0x0B:
debug_printf("12 Mb");
break;
case 0x0C:
debug_printf("16 Mb");
break;
case 0x0D:
debug_printf("24 Mb");
break;
case 0x0E:
debug_printf("32 Mb");
break;
case 0x0F:
debug_printf("64 Mb");
break;
default:
break;
}
debug_printf("\nErase Size : %d AU blocks\n", SD_status->EraseSize);
debug_printf("Erase Timeout : %d seconds\n", SD_status->EraseTimeout);
debug_printf("Erase Offset : %d seconds\n", SD_status->EraseOffset);
debug_printf("Speed Grade for UHS mode : %s\n",
(SD_status->UHS_SpeedGrade == 0) ? "< 10 Mb/sec" : "> 10 Mb/sec");
debug_printf("Allocation Unit size for UHS mode : ");
switch (SD_status->UHS_AU_Size)
{
case 0x00:
debug_printf("not defined");
break;
case 0x07:
debug_printf("1 Mb");
break;
case 0x08:
debug_printf("2 Mb");
break;
case 0x09:
debug_printf("4 Mb");
break;
case 0x0A:
debug_printf("8 Mb");
break;
case 0x0B:
debug_printf("12 Mb");
break;
case 0x0C:
debug_printf("16 Mb");
break;
case 0x0D:
debug_printf("24 Mb");
break;
case 0x0E:
debug_printf("32 Mb");
break;
case 0x0F:
debug_printf("64 Mb");
break;
default:
debug_printf("not used");
break;
}
}
debug_printf("\n\nDONE\n");
}