add card speed switching

This commit is contained in:
King Kévin 2017-06-28 15:41:53 +02:00
parent ce72dd8ccc
commit 0909297bc2
1 changed files with 75 additions and 11 deletions

View File

@ -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<n_ac && sbt!=0xfe; i++) { // wait for N_AC before reading data block (see section 7.5.2.1)
for (uint32_t i=0; i<n_ac && sbt!=0xfe; i++) { // wait for N_AC before reading data block (see section 7.5.2.1)
sbt = flash_sdcard_spi_read(); // get start block token (see section 7.3.3.2)
}
if (0xfe==sbt) { // start block token received (see section 7.3.3.2)
@ -182,9 +192,11 @@ static bool flash_sdcard_data_read(uint8_t index, uint32_t argument, uint8_t* da
SPI_CRC_PR(FLASH_SDCARD_SPI) = 0x1021; // set CRC-16-CCITT polynomial for data blocks (x^16+x^12+x^5+1) (see section 7.2.3)
spi_enable_crc(SPI(FLASH_SDCARD_SPI)); // enable and clear CRC
spi_enable(SPI(FLASH_SDCARD_SPI)); // enable SPI back
// get block data
// get block data (ideally use DMA, but switching makes it more complex and this part doesn't take too much time)
for (size_t i=0; i<size/2; i++) {
data[i*2] = flash_sdcard_spi_read(); // get word
uint16_t word = flash_sdcard_spi_read(); // get word
data[i*2+0] = (word>>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;
}