Skip to content

Commit

Permalink
Avoid MISO missing pull-up problem
Browse files Browse the repository at this point in the history
  • Loading branch information
greiman committed Jan 2, 2019
1 parent 356c5e4 commit 37c1f26
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 31 deletions.
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=SdFat
version=1.0.12
version=1.0.13
author=Bill Greiman <[email protected]>
maintainer=Bill Greiman <[email protected]>
sentence=FAT16/FAT32 file system for SD cards.
Expand Down
159 changes: 135 additions & 24 deletions src/SdCard/SdSpiCard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,115 @@
* DEALINGS IN THE SOFTWARE.
*/
#include "SdSpiCard.h"
//==============================================================================
// debug trace macro
#define SD_TRACE(m, b)
// #define SD_TRACE(m, b) Serial.print(m);Serial.println(b);
#define SD_CS_DBG(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
// CRC functions
Expand Down Expand Up @@ -137,13 +241,11 @@ bool SdSpiCard::begin(SdSpiDriver* spi, uint8_t csPin, SPISettings settings) {
spiSend(0XFF);
}
spiSelect();

// command to go idle in SPI mode
while (cardCommand(CMD0, 0) != R1_IDLE_STATE) {
if (isTimedOut(t0, SD_INIT_TIMEOUT)) {
error(SD_CARD_ERROR_CMD0);
goto fail;
}
delayMS(SD_CMD0_DELAY);
if (cardCommand(CMD0, 0) != R1_IDLE_STATE) {
error(SD_CARD_ERROR_CMD0);
goto fail;
}
#if USE_SD_CRC
if (cardCommand(CMD59, 1) != R1_IDLE_STATE) {
Expand All @@ -152,33 +254,31 @@ bool SdSpiCard::begin(SdSpiDriver* spi, uint8_t csPin, SPISettings settings) {
}
#endif // USE_SD_CRC
// check SD version
while (1) {
if (cardCommand(CMD8, 0x1AA) == (R1_ILLEGAL_COMMAND | R1_IDLE_STATE)) {
type(SD_CARD_TYPE_SD1);
break;
}
if (cardCommand(CMD8, 0x1AA) == (R1_ILLEGAL_COMMAND | R1_IDLE_STATE)) {
type(SD_CARD_TYPE_SD1);
} else {
for (uint8_t i = 0; i < 4; i++) {
m_status = spiReceive();
}
if (m_status == 0XAA) {
type(SD_CARD_TYPE_SD2);
break;
}
if (isTimedOut(t0, SD_INIT_TIMEOUT)) {
} else {
error(SD_CARD_ERROR_CMD8);
goto fail;
}
}
// initialize card and send host supports SDHC if SD2
arg = type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0;

DBG_BEGIN_TIME(DBG_ACMD41_TIME);
while (cardAcmd(ACMD41, arg) != R1_READY_STATE) {
DBG_EVENT_COUNT(DBG_ACMD41_COUNT);
// check for timeout
if (isTimedOut(t0, SD_INIT_TIMEOUT)) {
error(SD_CARD_ERROR_ACMD41);
goto fail;
}
}
DBG_END_TIME(DBG_ACMD41_TIME);
// if SD2 read OCR register to check for SDHC card
if (type() == SD_CARD_TYPE_SD2) {
if (cardCommand(CMD58, 0)) {
Expand Down Expand Up @@ -208,8 +308,12 @@ uint8_t SdSpiCard::cardCommand(uint8_t cmd, uint32_t arg) {
if (!m_spiActive) {
spiStart();
}
// wait if busy
waitNotBusy(SD_CMD_TIMEOUT);
// wait if busy unless CMD0
if (cmd != CMD0) {
DBG_BEGIN_TIME(DBG_CMD_BUSY);
waitNotBusy(SD_CMD_TIMEOUT);
DBG_END_TIME(DBG_CMD_BUSY);
}

#if USE_SD_CRC
// form message
Expand All @@ -234,18 +338,15 @@ uint8_t SdSpiCard::cardCommand(uint8_t cmd, uint32_t arg) {
for (int8_t i = 3; i >= 0; i--) {
spiSend(pa[i]);
}

// send CRC - correct for CMD0 with arg zero or CMD8 with arg 0X1AA
spiSend(cmd == CMD0 ? 0X95 : 0X87);
#endif // USE_SD_CRC

// skip stuff byte for stop read
if (cmd == CMD12) {
spiReceive();
}
// discard first fill byte to avoid MISO pull-up problem.
spiReceive();

// wait for response
for (uint8_t i = 0; ((m_status = spiReceive()) & 0X80) && i != 0XFF; i++) {
// there are 1-8 fill bytes before response. fill bytes should be 0XFF.
for (uint8_t i = 0; ((m_status = spiReceive()) & 0X80) && i < 10; i++) {
}
return m_status;
}
Expand Down Expand Up @@ -280,10 +381,12 @@ bool SdSpiCard::erase(uint32_t firstBlock, uint32_t lastBlock) {
error(SD_CARD_ERROR_ERASE);
goto fail;
}
DBG_BEGIN_TIME(DBG_ERASE_BUSY);
if (!waitNotBusy(SD_ERASE_TIMEOUT)) {
error(SD_CARD_ERROR_ERASE_TIMEOUT);
goto fail;
}
DBG_END_TIME(DBG_ERASE_BUSY);
spiStop();
return true;

Expand Down Expand Up @@ -367,6 +470,7 @@ bool SdSpiCard::readData(uint8_t* dst, size_t count) {
#if USE_SD_CRC
uint16_t crc;
#endif // USE_SD_CRC
DBG_BEGIN_TIME(DBG_WAIT_READ);
// wait for start block token
uint16_t t0 = curTimeMS();
while ((m_status = spiReceive()) == 0XFF) {
Expand All @@ -375,6 +479,7 @@ bool SdSpiCard::readData(uint8_t* dst, size_t count) {
goto fail;
}
}
DBG_END_TIME(DBG_WAIT_READ);
if (m_status != DATA_START_BLOCK) {
error(SD_CARD_ERROR_READ);
goto fail;
Expand Down Expand Up @@ -543,10 +648,12 @@ bool SdSpiCard::writeBlock(uint32_t blockNumber, const uint8_t* src) {

#if CHECK_FLASH_PROGRAMMING
// wait for flash programming to complete
DBG_BEGIN_TIME(DBG_WRITE_FLASH);
if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
error(SD_CARD_ERROR_FLASH_PROGRAMMING);
goto fail;
}
DBG_END_TIME(DBG_WRITE_FLASH);
// response is r2 so get and check two bytes for nonzero
if (cardCommand(CMD13, 0) || spiReceive()) {
error(SD_CARD_ERROR_CMD13);
Expand Down Expand Up @@ -580,10 +687,12 @@ bool SdSpiCard::writeBlocks(uint32_t block, const uint8_t* src, size_t count) {
//------------------------------------------------------------------------------
bool SdSpiCard::writeData(const uint8_t* src) {
// wait for previous write to finish
DBG_BEGIN_TIME(DBG_WRITE_BUSY);
if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
error(SD_CARD_ERROR_WRITE_TIMEOUT);
goto fail;
}
DBG_END_TIME(DBG_WRITE_BUSY);
if (!writeData(WRITE_MULTIPLE_TOKEN, src)) {
goto fail;
}
Expand Down Expand Up @@ -657,9 +766,11 @@ bool SdSpiCard::writeStart(uint32_t blockNumber, uint32_t eraseCount) {
}
//------------------------------------------------------------------------------
bool SdSpiCard::writeStop() {
DBG_BEGIN_TIME(DBG_WRITE_STOP);
if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
goto fail;
}
DBG_END_TIME(DBG_WRITE_STOP);
spiSend(STOP_TRAN_TOKEN);
spiStop();
return true;
Expand Down
2 changes: 1 addition & 1 deletion src/SdFat.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
#endif // INCLUDE_SDIOS
//------------------------------------------------------------------------------
/** SdFat version */
#define SD_FAT_VERSION "1.0.12"
#define SD_FAT_VERSION "1.0.13"
//==============================================================================
/**
* \class SdBaseFile
Expand Down
5 changes: 0 additions & 5 deletions src/SysCall.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,6 @@ inline uint16_t curTimeMS() {
return millis();
}
//------------------------------------------------------------------------------
/** Delay milliseconds */
inline void delayMS(uint16_t ms) {
delay(ms);
}
//------------------------------------------------------------------------------
/**
* \class SysCall
* \brief SysCall - Class to wrap system calls.
Expand Down

0 comments on commit 37c1f26

Please sign in to comment.