Avoid MISO missing pull-up problem

This commit is contained in:
Bill Greiman 2019-01-02 08:53:16 -08:00
parent 356c5e417c
commit 37c1f2606b
4 changed files with 137 additions and 31 deletions

View file

@ -1,5 +1,5 @@
name=SdFat name=SdFat
version=1.0.12 version=1.0.13
author=Bill Greiman <fat16lib@sbcglobal.net> author=Bill Greiman <fat16lib@sbcglobal.net>
maintainer=Bill Greiman <fat16lib@sbcglobal.net> maintainer=Bill Greiman <fat16lib@sbcglobal.net>
sentence=FAT16/FAT32 file system for SD cards. sentence=FAT16/FAT32 file system for SD cards.

View file

@ -23,11 +23,115 @@
* DEALINGS IN THE SOFTWARE. * DEALINGS IN THE SOFTWARE.
*/ */
#include "SdSpiCard.h" #include "SdSpiCard.h"
//==============================================================================
// debug trace macro // debug trace macro
#define SD_TRACE(m, b) #define SD_TRACE(m, b)
// #define SD_TRACE(m, b) Serial.print(m);Serial.println(b); // #define SD_TRACE(m, b) Serial.print(m);Serial.println(b);
#define SD_CS_DBG(m) #define SD_CS_DBG(m)
// #define SD_CS_DBG(m) Serial.println(F(m)); // #define SD_CS_DBG(m) Serial.println(F(m));
#define DBG_PROFILE_TIME 0
#if DBG_PROFILE_TIME
#define DBG_TAG_LIST\
DBG_TAG(DBG_ACMD41_TIME, "ACMD41 time")\
DBG_TAG(DBG_CMD_BUSY, "cmd busy")\
DBG_TAG(DBG_ERASE_BUSY, "erase busy")\
DBG_TAG(DBG_WAIT_READ, "wait read")\
DBG_TAG(DBG_WRITE_FLASH, "write flash")\
DBG_TAG(DBG_WRITE_BUSY, "write busy")\
DBG_TAG(DBG_WRITE_STOP, "write stop")\
DBG_TAG(DBG_ACMD41_COUNT, "ACMD41 count")
#define DBG_TIME_DIM DBG_ACMD41_COUNT
enum DbgTag {
#define DBG_TAG(tag, str) tag,
DBG_TAG_LIST
DBG_COUNT_DIM
#undef DBG_TAG
};
static uint32_t dbgCount[DBG_COUNT_DIM];
static uint32_t dbgBgnTime[DBG_TIME_DIM];
static uint32_t dbgMaxTime[DBG_TIME_DIM];
static uint32_t dbgMinTime[DBG_TIME_DIM];
static uint32_t dbgTotalTime[DBG_TIME_DIM];
//------------------------------------------------------------------------------
static void dbgBeginTime(DbgTag tag) {
dbgBgnTime[tag] = micros();
}
//------------------------------------------------------------------------------
static void dbgEndTime(DbgTag tag) {
uint32_t m = micros() - dbgBgnTime[tag];
dbgTotalTime[tag] += m;
if (m > dbgMaxTime[tag]) {
dbgMaxTime[tag] = m;
}
if (m < dbgMinTime[tag]) {
dbgMinTime[tag] = m;
}
dbgCount[tag]++;
}
//------------------------------------------------------------------------------
static void dbgEventCount(DbgTag tag) {
dbgCount[tag]++;
}
//------------------------------------------------------------------------------
void dbgInitTime() {
for (int i = 0; i < DBG_COUNT_DIM; i++) {
dbgCount[i] = 0;
if (i < DBG_TIME_DIM) {
dbgMaxTime[i] = 0;
dbgMinTime[i] = 9999999;
dbgTotalTime[i] = 0;
}
}
}
//------------------------------------------------------------------------------
static void dbgPrintTagText(uint8_t tag) {
#define DBG_TAG(e, m) case e: Serial.print(F(m)); break;
switch (tag) {
DBG_TAG_LIST
}
#undef DBG_TAG
}
//------------------------------------------------------------------------------
void dbgPrintTime() {
Serial.println();
Serial.println(F("======================="));
Serial.println(F("item,event,min,max,avg"));
Serial.println(F("tag,count,usec,usec,usec"));
for (int i = 0; i < DBG_COUNT_DIM; i++) {
if (dbgCount[i]) {
dbgPrintTagText(i);
Serial.print(',');
Serial.print(dbgCount[i]);
if (i < DBG_TIME_DIM) {
Serial.print(',');
Serial.print(dbgMinTime[i]);
Serial.print(',');
Serial.print(dbgMaxTime[i]);
Serial.print(',');
Serial.print(dbgTotalTime[i]/dbgCount[i]);
}
Serial.println();
}
}
Serial.println(F("======================="));
Serial.println();
}
#undef DBG_TAG_LIST
#define DBG_BEGIN_TIME(tag) dbgBeginTime(tag)
#define DBG_END_TIME(tag) dbgEndTime(tag)
#define DBG_EVENT_COUNT(tag) dbgEventCount(tag)
#else // DBG_PROFILE_TIME
#define DBG_BEGIN_TIME(tag)
#define DBG_END_TIME(tag)
#define DBG_EVENT_COUNT(tag)
void dbgInitTime() {}
void dbgPrintTime() {}
#endif // DBG_PROFILE_TIME
//============================================================================== //==============================================================================
#if USE_SD_CRC #if USE_SD_CRC
// CRC functions // CRC functions
@ -137,13 +241,11 @@ bool SdSpiCard::begin(SdSpiDriver* spi, uint8_t csPin, SPISettings settings) {
spiSend(0XFF); spiSend(0XFF);
} }
spiSelect(); spiSelect();
// command to go idle in SPI mode // command to go idle in SPI mode
while (cardCommand(CMD0, 0) != R1_IDLE_STATE) { if (cardCommand(CMD0, 0) != R1_IDLE_STATE) {
if (isTimedOut(t0, SD_INIT_TIMEOUT)) { error(SD_CARD_ERROR_CMD0);
error(SD_CARD_ERROR_CMD0); goto fail;
goto fail;
}
delayMS(SD_CMD0_DELAY);
} }
#if USE_SD_CRC #if USE_SD_CRC
if (cardCommand(CMD59, 1) != R1_IDLE_STATE) { if (cardCommand(CMD59, 1) != R1_IDLE_STATE) {
@ -152,33 +254,31 @@ bool SdSpiCard::begin(SdSpiDriver* spi, uint8_t csPin, SPISettings settings) {
} }
#endif // USE_SD_CRC #endif // USE_SD_CRC
// check SD version // check SD version
while (1) { if (cardCommand(CMD8, 0x1AA) == (R1_ILLEGAL_COMMAND | R1_IDLE_STATE)) {
if (cardCommand(CMD8, 0x1AA) == (R1_ILLEGAL_COMMAND | R1_IDLE_STATE)) { type(SD_CARD_TYPE_SD1);
type(SD_CARD_TYPE_SD1); } else {
break;
}
for (uint8_t i = 0; i < 4; i++) { for (uint8_t i = 0; i < 4; i++) {
m_status = spiReceive(); m_status = spiReceive();
} }
if (m_status == 0XAA) { if (m_status == 0XAA) {
type(SD_CARD_TYPE_SD2); type(SD_CARD_TYPE_SD2);
break; } else {
}
if (isTimedOut(t0, SD_INIT_TIMEOUT)) {
error(SD_CARD_ERROR_CMD8); error(SD_CARD_ERROR_CMD8);
goto fail; goto fail;
} }
} }
// initialize card and send host supports SDHC if SD2 // initialize card and send host supports SDHC if SD2
arg = type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0; arg = type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0;
DBG_BEGIN_TIME(DBG_ACMD41_TIME);
while (cardAcmd(ACMD41, arg) != R1_READY_STATE) { while (cardAcmd(ACMD41, arg) != R1_READY_STATE) {
DBG_EVENT_COUNT(DBG_ACMD41_COUNT);
// check for timeout // check for timeout
if (isTimedOut(t0, SD_INIT_TIMEOUT)) { if (isTimedOut(t0, SD_INIT_TIMEOUT)) {
error(SD_CARD_ERROR_ACMD41); error(SD_CARD_ERROR_ACMD41);
goto fail; goto fail;
} }
} }
DBG_END_TIME(DBG_ACMD41_TIME);
// if SD2 read OCR register to check for SDHC card // if SD2 read OCR register to check for SDHC card
if (type() == SD_CARD_TYPE_SD2) { if (type() == SD_CARD_TYPE_SD2) {
if (cardCommand(CMD58, 0)) { if (cardCommand(CMD58, 0)) {
@ -208,8 +308,12 @@ uint8_t SdSpiCard::cardCommand(uint8_t cmd, uint32_t arg) {
if (!m_spiActive) { if (!m_spiActive) {
spiStart(); spiStart();
} }
// wait if busy // wait if busy unless CMD0
waitNotBusy(SD_CMD_TIMEOUT); if (cmd != CMD0) {
DBG_BEGIN_TIME(DBG_CMD_BUSY);
waitNotBusy(SD_CMD_TIMEOUT);
DBG_END_TIME(DBG_CMD_BUSY);
}
#if USE_SD_CRC #if USE_SD_CRC
// form message // form message
@ -234,18 +338,15 @@ uint8_t SdSpiCard::cardCommand(uint8_t cmd, uint32_t arg) {
for (int8_t i = 3; i >= 0; i--) { for (int8_t i = 3; i >= 0; i--) {
spiSend(pa[i]); spiSend(pa[i]);
} }
// send CRC - correct for CMD0 with arg zero or CMD8 with arg 0X1AA // send CRC - correct for CMD0 with arg zero or CMD8 with arg 0X1AA
spiSend(cmd == CMD0 ? 0X95 : 0X87); spiSend(cmd == CMD0 ? 0X95 : 0X87);
#endif // USE_SD_CRC #endif // USE_SD_CRC
// skip stuff byte for stop read // discard first fill byte to avoid MISO pull-up problem.
if (cmd == CMD12) { spiReceive();
spiReceive();
}
// wait for response // there are 1-8 fill bytes before response. fill bytes should be 0XFF.
for (uint8_t i = 0; ((m_status = spiReceive()) & 0X80) && i != 0XFF; i++) { for (uint8_t i = 0; ((m_status = spiReceive()) & 0X80) && i < 10; i++) {
} }
return m_status; return m_status;
} }
@ -280,10 +381,12 @@ bool SdSpiCard::erase(uint32_t firstBlock, uint32_t lastBlock) {
error(SD_CARD_ERROR_ERASE); error(SD_CARD_ERROR_ERASE);
goto fail; goto fail;
} }
DBG_BEGIN_TIME(DBG_ERASE_BUSY);
if (!waitNotBusy(SD_ERASE_TIMEOUT)) { if (!waitNotBusy(SD_ERASE_TIMEOUT)) {
error(SD_CARD_ERROR_ERASE_TIMEOUT); error(SD_CARD_ERROR_ERASE_TIMEOUT);
goto fail; goto fail;
} }
DBG_END_TIME(DBG_ERASE_BUSY);
spiStop(); spiStop();
return true; return true;
@ -367,6 +470,7 @@ bool SdSpiCard::readData(uint8_t* dst, size_t count) {
#if USE_SD_CRC #if USE_SD_CRC
uint16_t crc; uint16_t crc;
#endif // USE_SD_CRC #endif // USE_SD_CRC
DBG_BEGIN_TIME(DBG_WAIT_READ);
// wait for start block token // wait for start block token
uint16_t t0 = curTimeMS(); uint16_t t0 = curTimeMS();
while ((m_status = spiReceive()) == 0XFF) { while ((m_status = spiReceive()) == 0XFF) {
@ -375,6 +479,7 @@ bool SdSpiCard::readData(uint8_t* dst, size_t count) {
goto fail; goto fail;
} }
} }
DBG_END_TIME(DBG_WAIT_READ);
if (m_status != DATA_START_BLOCK) { if (m_status != DATA_START_BLOCK) {
error(SD_CARD_ERROR_READ); error(SD_CARD_ERROR_READ);
goto fail; goto fail;
@ -543,10 +648,12 @@ bool SdSpiCard::writeBlock(uint32_t blockNumber, const uint8_t* src) {
#if CHECK_FLASH_PROGRAMMING #if CHECK_FLASH_PROGRAMMING
// wait for flash programming to complete // wait for flash programming to complete
DBG_BEGIN_TIME(DBG_WRITE_FLASH);
if (!waitNotBusy(SD_WRITE_TIMEOUT)) { if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
error(SD_CARD_ERROR_FLASH_PROGRAMMING); error(SD_CARD_ERROR_FLASH_PROGRAMMING);
goto fail; goto fail;
} }
DBG_END_TIME(DBG_WRITE_FLASH);
// response is r2 so get and check two bytes for nonzero // response is r2 so get and check two bytes for nonzero
if (cardCommand(CMD13, 0) || spiReceive()) { if (cardCommand(CMD13, 0) || spiReceive()) {
error(SD_CARD_ERROR_CMD13); error(SD_CARD_ERROR_CMD13);
@ -580,10 +687,12 @@ bool SdSpiCard::writeBlocks(uint32_t block, const uint8_t* src, size_t count) {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
bool SdSpiCard::writeData(const uint8_t* src) { bool SdSpiCard::writeData(const uint8_t* src) {
// wait for previous write to finish // wait for previous write to finish
DBG_BEGIN_TIME(DBG_WRITE_BUSY);
if (!waitNotBusy(SD_WRITE_TIMEOUT)) { if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
error(SD_CARD_ERROR_WRITE_TIMEOUT); error(SD_CARD_ERROR_WRITE_TIMEOUT);
goto fail; goto fail;
} }
DBG_END_TIME(DBG_WRITE_BUSY);
if (!writeData(WRITE_MULTIPLE_TOKEN, src)) { if (!writeData(WRITE_MULTIPLE_TOKEN, src)) {
goto fail; goto fail;
} }
@ -657,9 +766,11 @@ fail:
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
bool SdSpiCard::writeStop() { bool SdSpiCard::writeStop() {
DBG_BEGIN_TIME(DBG_WRITE_STOP);
if (!waitNotBusy(SD_WRITE_TIMEOUT)) { if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
goto fail; goto fail;
} }
DBG_END_TIME(DBG_WRITE_STOP);
spiSend(STOP_TRAN_TOKEN); spiSend(STOP_TRAN_TOKEN);
spiStop(); spiStop();
return true; return true;

View file

@ -37,7 +37,7 @@
#endif // INCLUDE_SDIOS #endif // INCLUDE_SDIOS
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** SdFat version */ /** SdFat version */
#define SD_FAT_VERSION "1.0.12" #define SD_FAT_VERSION "1.0.13"
//============================================================================== //==============================================================================
/** /**
* \class SdBaseFile * \class SdBaseFile

View file

@ -52,11 +52,6 @@ inline uint16_t curTimeMS() {
return millis(); return millis();
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** Delay milliseconds */
inline void delayMS(uint16_t ms) {
delay(ms);
}
//------------------------------------------------------------------------------
/** /**
* \class SysCall * \class SysCall
* \brief SysCall - Class to wrap system calls. * \brief SysCall - Class to wrap system calls.