From f681026ec29bd462c1d6433611d89d57b9730d3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?King=20K=C3=A9vin?= Date: Sun, 2 Jul 2017 12:11:39 +0200 Subject: [PATCH] flash_sdcard: add function to retrieve erase block size --- lib/flash_sdcard.c | 98 +++++++++++++++++++++++++++++++++++++++++++--- lib/flash_sdcard.h | 8 +++- 2 files changed, 99 insertions(+), 7 deletions(-) diff --git a/lib/flash_sdcard.c b/lib/flash_sdcard.c index 6c55a3b..7ab8c60 100644 --- a/lib/flash_sdcard.c +++ b/lib/flash_sdcard.c @@ -19,7 +19,7 @@ * @note peripherals used: SPI @ref flash_sdcard_spi * @warning all calls are blocking * @implements SD Specifications, Part 1, Physical Layer, Simplified Specification, Version 6.00, 10 April 10 2017 - * @todo use SPI unidirectional mode and DMA + * @todo use SPI unidirectional mode, use DMA, force/wait going to idle state when initializing */ /* standard libraries */ @@ -54,6 +54,8 @@ static uint32_t n_ac = 8; static bool sdsc = false; /** size of card in bytes */ static uint64_t sdcard_size = 0; +/** size of an erase block bytes */ +static uint32_t erase_size = 0; /** table for CRC-7 calculation for the command messages (see section 4.5) * @note faster than calculating the CRC and doesn't cost a lot of space @@ -130,7 +132,7 @@ static void flash_sdcard_send_command(uint8_t index, uint32_t argument) * @param[in] argument command argument * @param[out] response response data to read (if no error occurred) * @param[in] size size of response to read - * @return response token R1 of 0xff if error occurred or card is not present + * @return response token R1 or 0xff if error occurred or card is not present */ static uint8_t flash_sdcard_command_response(uint8_t index, uint32_t argument, uint8_t* response, size_t size) { @@ -158,12 +160,81 @@ static uint8_t flash_sdcard_command_response(uint8_t index, uint32_t argument, u return r1; } +/** get card status + * @param[out] status SD status (512 bits) + * @return response token R2 or 0xffff if error occurred or card is not present + */ +static uint8_t flash_sdcard_status(uint8_t* status) +{ + // send CMD55 (APP_CMD) to issue following application command (see table 7-4) + uint8_t r1 = flash_sdcard_command_response(55, 0, NULL, 0); // (see table 7-3) + if ((r1&0xfe)) { // error occurred, not in idle state + return false; + } + + // send ACMD13 command + gpio_clear(SPI_NSS_PORT(FLASH_SDCARD_SPI), SPI_NSS_PIN(FLASH_SDCARD_SPI)); // set CS low to select slave and start SPI mode (see section 7.2) + flash_sdcard_spi_wait(); // wait for N_CS (min. 0, but it works better with 8 clock cycles) before writing command (see section 7.5.2.1) + flash_sdcard_send_command(13, 0); // send ACMD13 (SD_STATUS) (see table 7-4) + + // get response token R2 + uint16_t r2 = 0xffff; // response token R2 (see section 7.3.2.3) + for (uint8_t i=0; i<8 && r2&0x8000; i++) { // wait for N_CR (1 to 8 8 clock cycles) before reading response (see section 7.5.1.1) + r2 = (flash_sdcard_spi_read()<<8); // get first byte of response (see section 7.3.2.1) + } + if (0==(r2&0x8000)) { // got the first byte + r2 += flash_sdcard_spi_read(); // read second byte (see 7.3.2.3) + } + if (0==r2) { // no error + uint8_t sbt = 0; // to save the start block token (see section 7.3.3.2) + for (uint32_t i=0; i>8); // save byte + status[i*2+1] = (word>>0); // save byte + } + flash_sdcard_spi_read(); // read CRC (the CRC after the data block should clear the computed CRC) + if (SPI_CRC_RXR(FLASH_SDCARD_SPI)) { // CRC is wrong + r2 |= (1<<11); // set communication CRC error + } + // switch back to 8-bit SPI frames + while (!(SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_TXE)); // wait until the end of any transmission + while (SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_BSY); // wait until not busy before disabling + spi_disable(SPI(FLASH_SDCARD_SPI)); // disable SPI to change format + spi_disable_crc(SPI(FLASH_SDCARD_SPI)); // disable CRC since we don't use it anymore (and this allows us to clear the CRC next time we use it) + spi_set_dff_8bit(SPI(FLASH_SDCARD_SPI)); // set SPI frame to 8 bits + spi_enable(SPI(FLASH_SDCARD_SPI)); // enable SPI back + } else { // start block token not received + r2 |= (1<<11); // set communication CRC error + } + } + + // end communication + while (SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_BSY); // wait until not busy (= transmission completed) + // wait for N_EC (min. 0) before closing communication (see section 7.5.1.1) + gpio_set(SPI_NSS_PORT(FLASH_SDCARD_SPI), SPI_NSS_PIN(FLASH_SDCARD_SPI)); // set CS high to unselect card + // wait for N_DS (min. 0) before allowing any further communication (see section 7.5.1.1) + return r2; +} + /** transmit command token, receive response token and data block * @param[in] index command index * @param[in] argument command argument * @param[out] data data block to read (if no error occurred) * @param[in] size size of response to read (a multiple of 2) - * @return response token R1 of 0xff if error occurred or card is not present + * @return response token R1 or 0xff if error occurred or card is not present */ static uint8_t flash_sdcard_data_read(uint8_t index, uint32_t argument, uint8_t* data, size_t size) { @@ -180,7 +251,7 @@ static uint8_t flash_sdcard_data_read(uint8_t index, uint32_t argument, uint8_t* uint8_t r1 = 0xff; // response token R1 (see section 7.3.2.1) for (uint8_t i=0; i<8 && r1&0x80; i++) { // wait for N_CR (1 to 8 8 clock cycles) before reading response (see section 7.5.1.1) r1 = flash_sdcard_spi_read(); // get response (see section 7.3.2.1) - } + } if (0x00==r1 && 0!=size && NULL!=data) { // we have to read a response uint8_t sbt = 0; // to save the start block token (see section 7.3.3.2) for (uint32_t i=0; i>6); uint8_t c_size_mutl = ((csd[9]&0x03)<<1)+((csd[10]&0x80)>>7); @@ -346,6 +418,17 @@ bool flash_sdcard_setup(void) uint32_t c_size = ((uint32_t)(csd[7]&0x3f)<<16)+((uint16_t)csd[8]<<8)+csd[9]; sdcard_size = (c_size+1)*(512<<10); } + // calculate erase size + if (sdsc) { // see section 5.3.2 + erase_size = (((csd[10]&0x3f)<<1)+((csd[11]&0x80)>>7)+1)<<(((csd[12]&0x03)<<2)+(csd[13]>>6)); + } else { + uint8_t status[64] = {0}; // SD status (see section 4.10.2) + uint16_t r2 = flash_sdcard_status(status); // get status (see table 7-4) + if (r2) { // error occurred + return false; + } + erase_size = (8192UL<<(status[10]>>4)); // calculate erase size (see table 4-44, section 4.10.2.4) + } // ensure block length is 512 bytes for SDSC (should be per default) to we match SDHC/SDXC block size if (sdsc) { @@ -393,3 +476,8 @@ uint64_t flash_sdcard_size(void) { return sdcard_size; } + +uint32_t flash_sdcard_erase_size(void) +{ + return erase_size; +} diff --git a/lib/flash_sdcard.h b/lib/flash_sdcard.h index fce114f..8a07f4c 100644 --- a/lib/flash_sdcard.h +++ b/lib/flash_sdcard.h @@ -25,7 +25,11 @@ * @return if card has been initialized correctly */ bool flash_sdcard_setup(void); -/** return size of SD card flash memory - * @return size of SD card flash memory in bytes +/** get size of SD card flash memory + * @return size of SD card flash memory (in bytes) */ uint64_t flash_sdcard_size(void); +/** get size of a erase block + * @return size of a erase block (in bytes) + */ +uint32_t flash_sdcard_erase_size(void);