From 0909297bc20b2d9d3a198f4a53c59e5c94484a78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?King=20K=C3=A9vin?= Date: Wed, 28 Jun 2017 15:41:53 +0200 Subject: [PATCH] add card speed switching --- lib/flash_sdcard.c | 86 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 75 insertions(+), 11 deletions(-) diff --git a/lib/flash_sdcard.c b/lib/flash_sdcard.c index 8095903..877e789 100644 --- a/lib/flash_sdcard.c +++ b/lib/flash_sdcard.c @@ -34,6 +34,8 @@ #include "global.h" // global utilities #include "flash_sdcard.h" // SD card header and definitions +#include "print.h" + /** @defgroup flash_sdcard_spi SPI used to communication with SD card * @{ */ @@ -43,7 +45,12 @@ /** maximum N_AC value (time between the response token R1 and data block when reading data (see section 7.5.4) * @note this is set to N_CR until we can read CSD (see section 7.2.6) */ -static uint16_t n_ac = 8; +static uint32_t n_ac = 8; +/** is it a Standard Capacity SD card (true), or High Capacity SD cards (false) + * @note this is indicated in the Card Capacity Status bit or OCR (set for high capacity) + * @note this is important for addressing: for standard capacity cards the address is the byte number, for high capacity cards it is the 512-byte block number + */ +static bool sdsc = false; /** 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 @@ -122,7 +129,7 @@ static void flash_sdcard_send_command(uint8_t index, uint32_t argument) * @param[in] size size of response to read * @return response token R1 of 0xff if error occurred or card is not present */ -static bool flash_sdcard_command_response(uint8_t index, uint32_t argument, uint8_t* response, size_t size) +static uint8_t flash_sdcard_command_response(uint8_t index, uint32_t argument, uint8_t* response, size_t size) { // send command token 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) @@ -155,8 +162,11 @@ static bool flash_sdcard_command_response(uint8_t index, uint32_t argument, uint * @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 */ -static bool flash_sdcard_data_read(uint8_t index, uint32_t argument, uint8_t* data, size_t size) +static uint8_t flash_sdcard_data_read(uint8_t index, uint32_t argument, uint8_t* data, size_t size) { + if (size%2) { // can't (and shouldn't) read odd number of bytes + return 0xff; + } // send command token 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) @@ -168,9 +178,9 @@ static bool flash_sdcard_data_read(uint8_t index, uint32_t argument, uint8_t* da 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 && 0==size%2 && NULL!=data) { // we have to read a response + 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 (uint16_t i=0; i>8); // save byte + data[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 @@ -194,6 +206,7 @@ static bool flash_sdcard_data_read(uint8_t index, uint32_t argument, uint8_t* da 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 @@ -283,8 +296,10 @@ bool flash_sdcard_setup(void) return false; } // card power up status bit (bit 31) is set when power up is complete (see table 5-1) - // CCS is bit 30 in OCR, but we don't really care about the result (see table 5-1) - // for High Capacity cards (CCS set to 1) the data block is always 512 bytes, else this should be set using CMD16 (see section 7.2.3) + if (0x00==(r3[0]&0x80)) { + return false; + } + sdsc = (0==(r3[0]&0x40)); // CCS is bit 30 in OCR (see table 5-1) // now the card identification is complete and we should be in data-transfer mode (see figure 7-1) // we can switch clock frequency to fPP (max. 25 MHz) (see section 4.3/6.6.6) @@ -294,13 +309,62 @@ bool flash_sdcard_setup(void) spi_set_baudrate_prescaler(SPI(FLASH_SDCARD_SPI), SPI_CR1_BR_FPCLK_DIV_4); // set clock speed to 18 MHz (72/4=18, < 25 MHz) spi_enable(SPI(FLASH_SDCARD_SPI)); // enable SPI back - // send CMD9 (SEND_CSD) to get Card Specific Data (CSD) (see table section 7.2.6) + // send CMD9 (SEND_CSD) to get Card Specific Data (CSD) and calculate N_AC (see section 7.2.6) uint8_t csd[16] = {0}; // CSD response (see chapter 7.2.6) r1 = flash_sdcard_data_read(9, 0, csd, sizeof(csd)); // (see table 7-3) if (r1) { // error occurred return false; } - // we can switch to high speed mode clock frequency to fPP (max. 50 MHz) (see section 6.6.7) + // check if CSD structure version matches capacity (see section 5.3.1) + if ((sdsc && (csd[0]&0xc0)) || (!sdsc && 0x40!=(csd[0]&0xc0))) { + return false; + } + // we use our set minimum frequency 16 MHz to calculate time + if (sdsc) { // calculate N_AC using TAAC and NSAC + static const float TAAC_UNITS[] = {1E-9, 10E-9, 100E-9, 1E-6, 10E-6, 100E-6, 1E-3, 10E-3}; // (see table 5-5) + static const float TAAC_VALUES[] = {10.0, 1.0, 1.2, 1.3, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 7.0, 8.0}; // (see table 5-5) + double taac = TAAC_VALUES[(csd[1]>>2)&0xf]*TAAC_UNITS[csd[1]&0x7]; // time in ns + n_ac=100*((taac*16E6)+(csd[2]*100))/8; // (see section 7.5.4) + } else { // value is fixed to 100 ms + n_ac=100E-3*16E6/8; + } + + // ensure block length is 512 bytes for SDSC (should be per default) to we match SDHC/SDXC block size + if (sdsc) { + r1 = flash_sdcard_command_response(16, 512, NULL, 0); // set block size using CMD16 (SET_BLOCKLEN) (see table 7-3) + if (r1) { // error occurred + return false; + } + } + + // try to switch to high speed mode (see section 7.2.14/4.3.10) + if (csd[4]&0x40) { // ensure CMD6 is supported by checking if command class 10 is set + uint32_t n_ac_back = n_ac; // backup N_AC + n_ac = 100E-3*16E6/8; // temporarily set timeout to 100 ms (see section 4.3.10.1) + // query access mode (group function 1) to check if high speed is supported (fPP=50MHz at 3.3V, we can be faster) + uint8_t fnc[64] = {0}; // function status response (see table 4-12) + r1 = flash_sdcard_data_read(6, 0x00fffff1, fnc, sizeof(fnc)); // check high speed function using CMD6 (SWITCH_FUNC) to check (mode 0) access mode (function group 1) (see table 7-3/4-30) + if (r1) { // error occurred + return false; + } + if (0x1==(fnc[16]&0x0f)) { // we can to access mode function 1 (see table 4-12) + r1 = flash_sdcard_data_read(6, 0x80fffff1, fnc, sizeof(fnc)); // switch to high speed function using CMD6 (SWITCH_FUNC) to switch (mode 1) access mode (function group 1) (see table 7-3/4-30) + if (r1) { // error occurred + return false; + } + if (0x1!=(fnc[16]&0x0f)) { // could not switch to high speed + return false; + } + // we can switch clock frequency to fPP (max. 50 MHz) (see section 6.6.7) + 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 clock speed + spi_set_baudrate_prescaler(SPI(FLASH_SDCARD_SPI), SPI_CR1_BR_FPCLK_DIV_2); // set clock speed to 36 MHz (72/2=36 < 50 MHz) + spi_enable(SPI(FLASH_SDCARD_SPI)); // enable SPI back + n_ac_back /= 2; // since we go twice faster the N_AC timeout has to be halved + } + n_ac = n_ac_back; // restore N_AC + } return true; }