/*------------------------------------------------------------------------*/ /* 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(); } /** * @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(); ost_hal_sdcard_spi_transfer(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 */ ost_hal_sdcard_spi_transfer((cmd & 0x3F) | 0x40); /*!< byte 1 */ ost_hal_sdcard_spi_transfer((uint8_t)(arg >> 24)); /*!< byte 2 */ ost_hal_sdcard_spi_transfer((uint8_t)(arg >> 16)); /*!< byte 3 */ ost_hal_sdcard_spi_transfer((uint8_t)(arg >> 8)); /*!< byte 4 */ ost_hal_sdcard_spi_transfer((uint8_t)arg); /*!< byte 5 */ ost_hal_sdcard_spi_transfer(crc | 0x01); /*!< byte 6: CRC */ /* a byte received immediately after CMD12 should be discarded... */ // if (cmd == SD_CMD_STOP_TRANSMISSION) // ost_hal_sdcard_spi_transfer(); /* SD Card responds within Ncr (response time), which is 0-8 bytes for SDSC cards, 1-8 bytes for MMC cards */ do { res = ost_hal_sdcard_spi_transfer(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 (ost_hal_sdcard_spi_transfer(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] = ost_hal_sdcard_spi_transfer(0xFF); pres[2] = ost_hal_sdcard_spi_transfer(0xFF); pres[1] = ost_hal_sdcard_spi_transfer(0xFF); pres[0] = ost_hal_sdcard_spi_transfer(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 = ost_hal_sdcard_spi_transfer(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 (ost_hal_sdcard_spi_transfer(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 (ost_hal_sdcard_spi_transfer(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] = ost_hal_sdcard_spi_transfer(0xFF); /* just get the next byte... */ /* receive the rest of data... */ for (i = 1; i < len; ++i) data[i] = ost_hal_sdcard_spi_transfer(0xFF); /* get CRC bytes (not really needed by us, but required by SD) */ ost_hal_sdcard_spi_transfer(0xFF); ost_hal_sdcard_spi_transfer(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\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) { ost_hal_sdcard_spi_transfer(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\n"); else debug_printf("KO(%d)\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\n"); else debug_printf("KO(%d)\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 */ ost_hal_sdcard_spi_transfer(SD_DUMMY_BYTE); ost_hal_sdcard_spi_transfer(SD_DUMMY_BYTE); ost_hal_sdcard_spi_transfer(SD_DUMMY_BYTE); /* send data token to signify the start of data transmission... */ ost_hal_sdcard_spi_transfer(SD_DATA_SINGLE_BLOCK_WRITE_START); /* 0xFE */ /* send data... */ while (BlockSize-- > 0) ost_hal_sdcard_spi_transfer(*pBuffer++); /* put 2 CRC bytes (not really needed by us, but required by SD) */ ost_hal_sdcard_spi_transfer(SD_DUMMY_BYTE); ost_hal_sdcard_spi_transfer(SD_DUMMY_BYTE); /* check data response... */ res = (SD_DataResponse)(ost_hal_sdcard_spi_transfer(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\n"); else debug_printf("KO(%d)\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... */ ost_hal_sdcard_spi_transfer(0xFF); ost_hal_sdcard_spi_transfer(0xFF); ost_hal_sdcard_spi_transfer(0xFF); /* transfer data... */ while (nbSectors-- > 0 && state != SD_RESPONSE_FAILURE) { /* --- {{ send data packet */ ost_hal_sdcard_spi_transfer(SD_DATA_MULTIPLE_BLOCK_WRITE_START); /* 0xFC */ /* send data... */ while (BlockSize-- > 0) ost_hal_sdcard_spi_transfer(*pBuffer++); /* put CRC bytes (not really needed by us, but required by SD) */ ost_hal_sdcard_spi_transfer(0xFF); ost_hal_sdcard_spi_transfer(0xFF); /* --- }} */ /* check data response... */ res = (SD_DataResponse)(ost_hal_sdcard_spi_transfer(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 */ ost_hal_sdcard_spi_transfer(SD_DATA_MULTIPLE_BLOCK_WRITE_STOP); /* 0xFD */ ost_hal_sdcard_spi_transfer(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\n"); else debug_printf("KO(%d)\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"); }