Parcourir la source

Added SdFatSdioEX class

main
Bill Greiman il y a 8 ans
Parent
révision
a3433c74ae
16 fichiers modifiés avec 805 ajouts et 195 suppressions
  1. +1
    -1
      SdFat/examples/LowLatencyLogger/LowLatencyLogger.ino
  2. +1
    -1
      SdFat/examples/LowLatencyLoggerADXL345/LowLatencyLogger.ino
  3. +1
    -1
      SdFat/examples/LowLatencyLoggerMPU6050/LowLatencyLogger.ino
  4. +3
    -1
      SdFat/examples/SdFormatter/SdFormatter.ino
  5. +6
    -2
      SdFat/examples/SdInfo/SdInfo.ino
  6. +79
    -22
      SdFat/examples/TeensySdioDemo/TeensySdioDemo.ino
  7. +4
    -1
      SdFat/examples/bench/bench.ino
  8. +3
    -4
      SdFat/src/FatLib/FatFile.cpp
  9. +4
    -0
      SdFat/src/FatLib/FatVolume.h
  10. +15
    -8
      SdFat/src/SdCard/SdInfo.h
  11. +162
    -3
      SdFat/src/SdCard/SdioCard.h
  12. +103
    -0
      SdFat/src/SdCard/SdioCardEX.cpp
  13. +375
    -141
      SdFat/src/SdCard/SdioTeensy.cpp
  14. +43
    -10
      SdFat/src/SdFat.h
  15. +1
    -0
      SdFat/src/SdFatConfig.h
  16. +4
    -0
      changes.txt

+ 1
- 1
SdFat/examples/LowLatencyLogger/LowLatencyLogger.ino Voir le fichier

@@ -377,7 +377,7 @@ void recordBinFile() {
// Start a multiple block write.
if (!sd.card()->writeStart(binFile.firstBlock())) {
error("writeBStart failed");
error("writeStart failed");
}
Serial.print(F("FreeStack: "));
Serial.println(FreeStack());

+ 1
- 1
SdFat/examples/LowLatencyLoggerADXL345/LowLatencyLogger.ino Voir le fichier

@@ -377,7 +377,7 @@ void recordBinFile() {
// Start a multiple block write.
if (!sd.card()->writeStart(binFile.firstBlock())) {
error("writeBStart failed");
error("writeStart failed");
}
Serial.print(F("FreeStack: "));
Serial.println(FreeStack());

+ 1
- 1
SdFat/examples/LowLatencyLoggerMPU6050/LowLatencyLogger.ino Voir le fichier

@@ -377,7 +377,7 @@ void recordBinFile() {
// Start a multiple block write.
if (!sd.card()->writeStart(binFile.firstBlock())) {
error("writeBStart failed");
error("writeStart failed");
}
Serial.print(F("FreeStack: "));
Serial.println(FreeStack());

+ 3
- 1
SdFat/examples/SdFormatter/SdFormatter.ino Voir le fichier

@@ -38,7 +38,9 @@ const uint8_t chipSelect = SS;
ArduinoOutStream cout(Serial);

#if USE_SDIO
SdioCard card;
// Use faster SdioCardEX
SdioCardEX card;
// SdioCard card;
#else // USE_SDIO
Sd2Card card;
#endif // USE_SDIO

+ 6
- 2
SdFat/examples/SdInfo/SdInfo.ino Voir le fichier

@@ -23,7 +23,9 @@ const uint8_t SD_CHIP_SELECT = SS;
const int8_t DISABLE_CHIP_SELECT = -1;

#if USE_SDIO
SdFatSdio sd;
// Use faster SdioCardEX
SdFatSdioEX sd;
// SdFatSdio sd;
#else // USE_SDIO
SdFat sd;
#endif // USE_SDIO
@@ -151,6 +153,7 @@ void setup() {

// F stores strings in flash to save RAM
cout << F("SdFat version: ") << SD_FAT_VERSION << endl;
#if !USE_SDIO
if (DISABLE_CHIP_SELECT < 0) {
cout << F(
"\nAssuming the SD is the only SPI device.\n"
@@ -163,6 +166,7 @@ void setup() {
}
cout << F("\nAssuming the SD chip select pin is: ") <<int(SD_CHIP_SELECT);
cout << F("\nEdit SD_CHIP_SELECT to change the SD chip select pin.\n");
#endif // !USE_SDIO
}
//------------------------------------------------------------------------------
void loop() {
@@ -187,7 +191,7 @@ void loop() {
// Initialize at the highest speed supported by the board that is
// not over 50 MHz. Try a lower speed if SPI errors occur.
if (!sd.cardBegin(SD_CHIP_SELECT, SD_SCK_MHZ(50))) {
sdErrorMsg("\ncardBegin failed");
sdErrorMsg("cardBegin failed");
return;
}
#endif // USE_SDIO

+ 79
- 22
SdFat/examples/TeensySdioDemo/TeensySdioDemo.ino Voir le fichier

@@ -1,6 +1,10 @@
// Simple performance test for Teensy 3.5/3.6 SDHC.
// Demonstrates yield() efficiency.

// Warning SdFatSdio and SdFatSdioEX normally should
// not both be used in a program.
// Each has its own cache and member variables.

#include "SdFat.h"

// 32 KiB buffer.
@@ -11,6 +15,8 @@ const uint32_t FILE_SIZE = 256UL*BUF_DIM;

SdFatSdio sd;

SdFatSdioEX sdEx;

File file;

uint8_t buf[BUF_DIM];
@@ -25,17 +31,35 @@ uint32_t yieldMicros = 0;
// Number of yield calls.
uint32_t yieldCalls = 0;
// Max busy time for single yield call.
uint32_t yieldMaxUsec = 0;
uint32_t yieldMaxUsec = 0;
// Control access to the two versions of SdFat.
bool useEx = false;
//-----------------------------------------------------------------------------
bool sdBusy() {
return useEx ? sdEx.card()->isBusy() : sd.card()->isBusy();
}
//-----------------------------------------------------------------------------
void errorHalt(const char* msg) {
if (useEx) {
sdEx.errorHalt(msg);
} else {
sd.errorHalt(msg);
}
}
//------------------------------------------------------------------------------
uint32_t kHzSdClk() {
return useEx ? sdEx.card()->kHzSdClk() : sd.card()->kHzSdClk();
}
//------------------------------------------------------------------------------
// Replace "weak" system yield() function.
void yield() {
// Only count cardBusy time.
if (!sd.card()->dmaBusy()) {
if (!sdBusy()) {
return;
}
}
uint32_t m = micros();
yieldCalls++;
while (sd.card()->dmaBusy()) {
while (sdBusy()) {
// Do something here.
}
m = micros() - m;
@@ -45,18 +69,14 @@ void yield() {
yieldMicros += m;
}
//-----------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
while (!Serial) {
}
Serial.println("Type any character to begin");
while (!Serial.available()) {
}
if (!sd.begin()) {
sd.initErrorHalt();
}
void runTest() {
// Zero Stats
totalMicros = 0;
yieldMicros = 0;
yieldCalls = 0;
yieldMaxUsec = 0;
if (!file.open("TeensyDemo.bin", O_RDWR | O_CREAT)) {
sd.errorHalt("open failed");
errorHalt("open failed");
}
Serial.println("\nsize,write,read");
Serial.println("bytes,KB/sec,KB/sec");
@@ -71,7 +91,7 @@ void setup() {
buf32[0] = n;
buf32[nb/4 - 1] = n;
if (nb != file.write(buf, nb)) {
sd.errorHalt("write failed");
errorHalt("write failed");
}
}
t = micros() - t;
@@ -83,11 +103,11 @@ void setup() {
for (uint32_t n = 0; n < nRdWr; n++) {
if ((int)nb != file.read(buf, nb)) {
sd.errorHalt("read failed");
errorHalt("read failed");
}
// crude check of data.
if (buf32[0] != n || buf32[nb/4 - 1] != n) {
sd.errorHalt("data check");
errorHalt("data check");
}
}
t = micros() - t;
@@ -102,11 +122,48 @@ void setup() {
Serial.print("yieldCalls ");
Serial.println(yieldCalls);
Serial.print("yieldMaxUsec ");
Serial.println(yieldMaxUsec);
Serial.println(yieldMaxUsec);
Serial.print("kHzSdClk ");
Serial.println(sd.card()->kHzSdClk());
Serial.println(kHzSdClk());
Serial.println("Done");
}

void loop() {
//-----------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
while (!Serial) {
}
Serial.println("SdFatSdioEX uses extended multi-block transfers without DMA.");
Serial.println("SdFatSdio uses a traditional DMA SDIO implementation.");
Serial.println("Note the difference is speed and busy yield time.\n");
}
//-----------------------------------------------------------------------------
void loop() {
do {
delay(10);
} while (Serial.available() && Serial.read());

Serial.println("Type '1' for SdFatSdioEX or '2' for SdFatSdio");
while (!Serial.available()) {
}
char c = Serial.read();
if (c != '1' && c != '2') {
Serial.println("Invalid input");
return;
}
if (c =='1') {
useEx = true;
if (!sdEx.begin()) {
sd.initErrorHalt("SdFatSdioEX begin() failed");
}
// make sdEx the current volume.
sdEx.chvol();
} else {
useEx = false;
if (!sd.begin()) {
sd.initErrorHalt("SdFatSdio begin() failed");
}
// make sd the current volume.
sd.chvol();
}
runTest();
}

+ 4
- 1
SdFat/examples/bench/bench.ino Voir le fichier

@@ -32,7 +32,10 @@ uint8_t buf[BUF_SIZE];

// file system
#if USE_SDIO
SdFatSdio sd;
// Traditional DMA version.
// SdFatSdio sd;
// Faster version.
SdFatSdioEX sd;
#else // USE_SDIO
SdFat sd;
#endif // USE_SDIO

+ 3
- 4
SdFat/src/FatLib/FatFile.cpp Voir le fichier

@@ -774,10 +774,10 @@ int FatFile::read(void* buf, size_t nbyte) {
}
}
n = 512*nb;
if (m_vol->cacheBlockNumber() <= block
if (block <= m_vol->cacheBlockNumber()
&& block < (m_vol->cacheBlockNumber() + nb)) {
// flush cache if a block is in the cache
if (!m_vol->cacheSync()) {
if (!m_vol->cacheSyncData()) {
DBG_FAIL_MACRO;
goto fail;
}
@@ -1160,7 +1160,6 @@ bool FatFile::sync() {
if (!isOpen()) {
return true;
}

if (m_flags & F_FILE_DIR_DIRTY) {
dir_t* dir = cacheDirEntry(FatCache::CACHE_FOR_WRITE);
// check for deleted by another open file object
@@ -1445,7 +1444,7 @@ int FatFile::write(const void* buf, size_t nbyte) {
nBlock = maxBlocks;
}
n = 512*nBlock;
if (m_vol->cacheBlockNumber() <= block
if (block <= m_vol->cacheBlockNumber()
&& block < (m_vol->cacheBlockNumber() + nBlock)) {
// invalidate cache if block is in cache
m_vol->cacheInvalidate();

+ 4
- 0
SdFat/src/FatLib/FatVolume.h Voir le fichier

@@ -126,6 +126,10 @@ class FatCache {
m_status = 0;
m_lbn = 0XFFFFFFFF;
}
/** \return dirty status */
bool isDirty() {
return m_status & CACHE_STATUS_DIRTY;
}
/** \return Logical block number for cached block. */
uint32_t lbn() {
return m_lbn;

+ 15
- 8
SdFat/src/SdCard/SdInfo.h Voir le fichier

@@ -65,18 +65,25 @@ typedef enum {
SD_CARD_ERROR_ACMD23,
SD_CARD_ERROR_ACMD41,

// Misc errors.
SD_CARD_ERROR_DMA = 0X50,
SD_CARD_ERROR_ERASE,
SD_CARD_ERROR_ERASE_SINGLE_BLOCK,
SD_CARD_ERROR_ERASE_TIMEOUT,
SD_CARD_ERROR_INIT_NOT_CALLED,
SD_CARD_ERROR_READ,
// Read/write errors
SD_CARD_ERROR_READ = 0X50,
SD_CARD_ERROR_READ_FIFO,
SD_CARD_ERROR_READ_REG,
SD_CARD_ERROR_READ_START,
SD_CARD_ERROR_READ_TIMEOUT,
SD_CARD_ERROR_STOP_TRAN,
SD_CARD_ERROR_WRITE_TIMEOUT,
SD_CARD_ERROR_WRITE,
SD_CARD_ERROR_WRITE_FIFO,
SD_CARD_ERROR_WRITE_START,
SD_CARD_ERROR_WRITE_TIMEOUT,

// Misc errors.
SD_CARD_ERROR_DMA = 0X60,
SD_CARD_ERROR_ERASE,
SD_CARD_ERROR_ERASE_SINGLE_BLOCK,
SD_CARD_ERROR_ERASE_TIMEOUT,
SD_CARD_ERROR_INIT_NOT_CALLED,
SD_CARD_ERROR_FUNCTION_NOT_SUPPORTED
} sd_error_code_t;
//------------------------------------------------------------------------------
// card types

+ 162
- 3
SdFat/src/SdCard/SdioCard.h Voir le fichier

@@ -38,8 +38,6 @@ class SdioCard : public BaseBlockDriver {
* or zero if an error occurs.
*/
uint32_t cardSize();
/** \return DMA transfer status. */
bool dmaBusy();
/** Erase a range of blocks.
*
* \param[in] firstBlock The address of the first block in the range.
@@ -52,7 +50,7 @@ class SdioCard : public BaseBlockDriver {
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
*/
bool erase(uint32_t firstBlock, uint32_t lastBlock);
/**
* \return code for the last error. See SdInfo.h for a list of error codes.
@@ -62,6 +60,12 @@ class SdioCard : public BaseBlockDriver {
uint32_t errorData();
/** \return error line for last error. Tmp function for debug. */
uint32_t errorLine();
/**
* Check for busy with CMD13.
*
* \return true if busy else false.
*/
bool isBusy();
/** \return the SD clock frequency in kHz. */
uint32_t kHzSdClk();
/**
@@ -102,12 +106,48 @@ class SdioCard : public BaseBlockDriver {
* \return true for success or false for failure.
*/
bool readCSD(void* csd);
/** Read one data block in a multiple block read sequence
*
* \param[out] dst Pointer to the location for the data to be read.
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool readData(uint8_t *dst);
/** Read OCR register.
*
* \param[out] ocr Value of OCR register.
* \return true for success else false.
*/
bool readOCR(uint32_t* ocr);
/** Start a read multiple blocks sequence.
*
* \param[in] lba Address of first block in sequence.
*
* \note This function is used with readData() and readStop() for optimized
* multiple block reads. SPI chipSelect must be low for the entire sequence.
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool readStart(uint32_t lba);
/** Start a read multiple blocks sequence.
*
* \param[in] lba Address of first block in sequence.
* \param[in] count Maximum block count.
* \note This function is used with readData() and readStop() for optimized
* multiple block reads. SPI chipSelect must be low for the entire sequence.
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool readStart(uint32_t lba, uint32_t count);
/** End a read multiple blocks sequence.
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool readStop();
/** \return success if sync successful. Not for user apps. */
bool syncBlocks();
/** Return the card type: SD V1, SD V2 or SDHC
@@ -133,5 +173,124 @@ class SdioCard : public BaseBlockDriver {
* the value false is returned for failure.
*/
bool writeBlocks(uint32_t lba, const uint8_t* src, size_t nb);
/** Write one data block in a multiple block write sequence.
* \param[in] src Pointer to the location of the data to be written.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool writeData(const uint8_t* src);
/** Start a write multiple blocks sequence.
*
* \param[in] lba Address of first block in sequence.
*
* \note This function is used with writeData() and writeStop()
* for optimized multiple block writes.
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool writeStart(uint32_t lba);
/** Start a write multiple blocks sequence.
*
* \param[in] lba Address of first block in sequence.
* \param[in] count Maximum block count.
* \note This function is used with writeData() and writeStop()
* for optimized multiple block writes.
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool writeStart(uint32_t lba, uint32_t count);

/** End a write multiple blocks sequence.
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool writeStop();
};
//==============================================================================
/**
* \class SdioCardEX
* \brief Extended SD I/O block driver.
*/
class SdioCardEX : public SdioCard {
public:
/** Initialize the SD card
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool begin() {
m_curState = IDLE_STATE;
return SdioCard::begin();
}
/** Erase a range of blocks.
*
* \param[in] firstBlock The address of the first block in the range.
* \param[in] lastBlock The address of the last block in the range.
*
* \note This function requests the SD card to do a flash erase for a
* range of blocks. The data on the card after an erase operation is
* either 0 or 1, depends on the card vendor. The card must support
* single block erase.
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool erase(uint32_t firstBlock, uint32_t lastBlock) {
return syncBlocks() && SdioCard::erase(firstBlock, lastBlock);
}
/**
* Read a 512 byte block from an SD card.
*
* \param[in] block Logical block to be read.
* \param[out] dst Pointer to the location that will receive the data.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool readBlock(uint32_t block, uint8_t* dst);
/** End multi-block transfer and go to idle state.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool syncBlocks();
/**
* Writes a 512 byte block to an SD card.
*
* \param[in] block Logical block to be written.
* \param[in] src Pointer to the location of the data to be written.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool writeBlock(uint32_t block, const uint8_t* src);
/**
* Read multiple 512 byte blocks from an SD card.
*
* \param[in] block Logical block to be read.
* \param[in] nb Number of blocks to be read.
* \param[out] dst Pointer to the location that will receive the data.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool readBlocks(uint32_t block, uint8_t* dst, size_t nb);
/**
* Write multiple 512 byte blocks to an SD card.
*
* \param[in] block Logical block to be written.
* \param[in] nb Number of blocks to be written.
* \param[in] src Pointer to the location of the data to be written.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool writeBlocks(uint32_t block, const uint8_t* src, size_t nb);

private:
static const uint32_t IDLE_STATE = 0;
static const uint32_t READ_STATE = 1;
static const uint32_t WRITE_STATE = 2;
uint32_t m_curLba;
uint32_t m_limitLba;
uint8_t m_curState;
};
#endif // SdioCard_h

+ 103
- 0
SdFat/src/SdCard/SdioCardEX.cpp Voir le fichier

@@ -0,0 +1,103 @@
/* Arduino SdFat Library
* Copyright (C) 2016 by William Greiman
*
* This file is part of the Arduino SdFat Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Arduino SdFat Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include "SdioCard.h"

// limit of K66 due to errata KINETIS_K_0N65N.
const uint32_t MAX_SDHC_COUNT = 0XFFFF;

// Max RU is 1024 blocks.
const uint32_t RU_MASK = 0X03FF;

bool SdioCardEX::readBlock(uint32_t lba, uint8_t* dst) {
if (m_curState != READ_STATE || lba != m_curLba) {
if (!syncBlocks()) {
return false;
}
m_limitLba = (lba + MAX_SDHC_COUNT) & ~RU_MASK;
if (!SdioCard::readStart(lba, m_limitLba - lba)) {
return false;
}
m_curLba = lba;
m_curState = READ_STATE;
}
if (!SdioCard::readData(dst)) {
return false;
}
m_curLba++;
if (m_curLba >= m_limitLba) {
m_curState = IDLE_STATE;
}
return true;
}
//-----------------------------------------------------------------------------
bool SdioCardEX::readBlocks(uint32_t lba, uint8_t* dst, size_t nb) {
for (size_t i = 0; i < nb; i++) {
if (!readBlock(lba + i, dst + i*512UL)) {
return false;
}
}
return true;
}
//-----------------------------------------------------------------------------
bool SdioCardEX::syncBlocks() {
if (m_curState == READ_STATE) {
m_curState = IDLE_STATE;
if (!SdioCard::readStop()) {
return false;
}
} else if (m_curState == WRITE_STATE) {
m_curState = IDLE_STATE;
if (!SdioCard::writeStop()) {
return false;
}
}
return true;
}
//-----------------------------------------------------------------------------
bool SdioCardEX::writeBlock(uint32_t lba, const uint8_t* src) {
if (m_curState != WRITE_STATE || m_curLba != lba) {
if (!syncBlocks()) {
return false;
}
m_limitLba = (lba + MAX_SDHC_COUNT) & ~RU_MASK;
if (!SdioCard::writeStart(lba , m_limitLba - lba)) {
return false;
}
m_curLba = lba;
m_curState = WRITE_STATE;
}
if (!SdioCard::writeData(src)) {
return false;
}
m_curLba++;
if (m_curLba >= m_limitLba) {
m_curState = IDLE_STATE;
}
return true;
}
//-----------------------------------------------------------------------------
bool SdioCardEX::writeBlocks(uint32_t lba, const uint8_t* src, size_t nb) {
for (size_t i = 0; i < nb; i++) {
if (!writeBlock(lba + i, src + i*512UL)) {
return false;
}
}
return true;
}

+ 375
- 141
SdFat/src/SdCard/SdioTeensy.cpp Voir le fichier

@@ -20,21 +20,17 @@
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
#include "SdioCard.h"
//==============================================================================
#ifndef SDHC_WML_RDWML_MASK
#define SDHC_WML_RDWML_MASK (0XFFU)
#endif
#ifndef SDHC_WML_RDWML_SHIFT
#define SDHC_WML_RDWML_SHIFT (0U)
#endif
#define SDHC_PROCTL_DTW_4BIT 0x01
#define SDHC_PROCTL_DTW_4BIT 0x01
const uint32_t FIFO_WML = 16;
const uint32_t CMD8_RETRIES = 10;
const uint32_t BUSY_TIMEOUT_MICROS = 500000;
//==============================================================================
const uint32_t SDHC_IRQSTATEN_MASK =
SDHC_IRQSTATEN_DMAESEN | SDHC_IRQSTATEN_AC12ESEN |
SDHC_IRQSTATEN_DEBESEN | SDHC_IRQSTATEN_DCESEN |
SDHC_IRQSTATEN_DTOESEN | SDHC_IRQSTATEN_CIESEN |
SDHC_IRQSTATEN_CEBESEN | SDHC_IRQSTATEN_CCESEN |
SDHC_IRQSTATEN_CTOESEN | SDHC_IRQSTATEN_BRRSEN |
SDHC_IRQSTATEN_BWRSEN | SDHC_IRQSTATEN_DINTSEN |
SDHC_IRQSTATEN_CTOESEN | SDHC_IRQSTATEN_DINTSEN |
SDHC_IRQSTATEN_TCSEN | SDHC_IRQSTATEN_CCSEN;

const uint32_t SDHC_IRQSTAT_CMD_ERROR =
@@ -79,11 +75,18 @@ const uint32_t DATA_READ_DMA = DATA_READ | SDHC_XFERTYP_DMAEN;
const uint32_t DATA_READ_MULTI_DMA = DATA_READ_DMA | SDHC_XFERTYP_MSBSEL |
SDHC_XFERTYP_AC12EN | SDHC_XFERTYP_BCEN;

const uint32_t DATA_READ_MULTI_PGM = DATA_READ | SDHC_XFERTYP_MSBSEL |
SDHC_XFERTYP_BCEN | SDHC_XFERTYP_AC12EN;

const uint32_t DATA_WRITE_DMA = SDHC_XFERTYP_DPSEL | SDHC_XFERTYP_DMAEN;

const uint32_t DATA_WRITE_MULTI_DMA = DATA_WRITE_DMA | SDHC_XFERTYP_MSBSEL |
SDHC_XFERTYP_AC12EN | SDHC_XFERTYP_BCEN;

const uint32_t DATA_WRITE_MULTI_PGM = SDHC_XFERTYP_DPSEL |
SDHC_XFERTYP_MSBSEL |
SDHC_XFERTYP_BCEN | SDHC_XFERTYP_AC12EN;

const uint32_t ACMD6_XFERTYP = SDHC_XFERTYP_CMDINX(ACMD6) | CMD_RESP_R1;

const uint32_t ACMD41_XFERTYP = SDHC_XFERTYP_CMDINX(ACMD41) | CMD_RESP_R3;
@@ -105,19 +108,28 @@ const uint32_t CMD9_XFERTYP = SDHC_XFERTYP_CMDINX(CMD9) | CMD_RESP_R2;

const uint32_t CMD10_XFERTYP = SDHC_XFERTYP_CMDINX(CMD10) | CMD_RESP_R2;

const uint32_t CMD12_XFERTYP = SDHC_XFERTYP_CMDINX(CMD12) | CMD_RESP_R1b |
SDHC_XFERTYP_CMDTYP(3);

const uint32_t CMD13_XFERTYP = SDHC_XFERTYP_CMDINX(CMD13) | CMD_RESP_R1;

const uint32_t CMD17_XFERTYP = SDHC_XFERTYP_CMDINX(CMD17) | CMD_RESP_R1 |
DATA_READ_DMA;
const uint32_t CMD17_DMA_XFERTYP = SDHC_XFERTYP_CMDINX(CMD17) | CMD_RESP_R1 |
DATA_READ_DMA;

const uint32_t CMD18_DMA_XFERTYP = SDHC_XFERTYP_CMDINX(CMD18) | CMD_RESP_R1 |
DATA_READ_MULTI_DMA;

const uint32_t CMD18_PGM_XFERTYP = SDHC_XFERTYP_CMDINX(CMD18) | CMD_RESP_R1 |
DATA_READ_MULTI_PGM;

const uint32_t CMD18_XFERTYP = SDHC_XFERTYP_CMDINX(CMD18) | CMD_RESP_R1 |
DATA_READ_MULTI_DMA;
const uint32_t CMD24_DMA_XFERTYP = SDHC_XFERTYP_CMDINX(CMD24) | CMD_RESP_R1 |
DATA_WRITE_DMA;

const uint32_t CMD24_XFERTYP = SDHC_XFERTYP_CMDINX(CMD24) | CMD_RESP_R1 |
DATA_WRITE_DMA;
const uint32_t CMD25_DMA_XFERTYP = SDHC_XFERTYP_CMDINX(CMD25) | CMD_RESP_R1 |
DATA_WRITE_MULTI_DMA;

const uint32_t CMD25_XFERTYP = SDHC_XFERTYP_CMDINX(CMD25) | CMD_RESP_R1 |
DATA_WRITE_MULTI_DMA;
const uint32_t CMD25_PGM_XFERTYP = SDHC_XFERTYP_CMDINX(CMD25) | CMD_RESP_R1 |
DATA_WRITE_MULTI_PGM;

const uint32_t CMD32_XFERTYP = SDHC_XFERTYP_CMDINX(CMD32) | CMD_RESP_R1;

@@ -126,49 +138,109 @@ const uint32_t CMD33_XFERTYP = SDHC_XFERTYP_CMDINX(CMD33) | CMD_RESP_R1;
const uint32_t CMD38_XFERTYP = SDHC_XFERTYP_CMDINX(CMD38) | CMD_RESP_R1b;

const uint32_t CMD55_XFERTYP = SDHC_XFERTYP_CMDINX(CMD55) | CMD_RESP_R1;

//=============================================================================
static bool isBusy();
static bool cardCommand(uint32_t xfertyp, uint32_t arg);
static void enableGPIO(bool enable);
static void enableDmaIrs();
static void initSDHC();
static bool isBusyCMD13();
static bool isBusyCommandComplete();
static bool isBusyCommandInhibit();
static bool readReg16(uint32_t xfertyp, void* data);
static void setSdclk(uint32_t kHzMax);

static uint8_t m_errorCode = SD_CARD_ERROR_INIT_NOT_CALLED;
static uint32_t m_errorLine = 0;
static bool yieldTimeout(bool (*fcn)());
static bool waitDmaStatus();
static bool waitTimeout(bool (*fcn)());
//-----------------------------------------------------------------------------
static bool (*m_busyFcn)() = 0;
static bool m_initDone = false;
static bool m_version2;
static bool m_highCapacity;
static uint8_t m_errorCode = SD_CARD_ERROR_INIT_NOT_CALLED;
static uint32_t m_errorLine = 0;
static uint32_t m_rca;
bool m_waitCmd13 = false;
static volatile bool m_dmaDone = true;
static volatile bool m_dmaBusy = false;
static volatile uint32_t m_irqstat;
static uint32_t m_sdClkKhz = 0;
static uint32_t m_ocr;
static cid_t m_cid;
static csd_t m_csd;
static uint32_t m_ocr;
//=============================================================================
// Debug and error macros.
#define USE_DEBUG_MODE 0
#if USE_DEBUG_MODE
#define DBG_IRQSTAT() if (SDHC_IRQSTAT) {Serial.print(__LINE__);\
Serial.print(" IRQSTAT "); Serial.println(SDHC_IRQSTAT, HEX);}

static void printRegs(uint32_t line) {
Serial.print(line);
Serial.print(" PRSSTAT ");
Serial.print(SDHC_PRSSTAT, HEX);
Serial.print(" PROCTL ");
Serial.print(SDHC_PROCTL, HEX);
Serial.print(" IRQSTAT ");
Serial.print(SDHC_IRQSTAT, HEX);
Serial.print(" m_irqstat ");
Serial.println(m_irqstat, HEX);
}
#else // USE_DEBUG_MODE
#define DBG_IRQSTAT()
#endif // USE_DEBUG_MODE
//=============================================================================
// Error function and macro.
#define sdError(code) setSdErrorCode(code, __LINE__)
inline bool setSdErrorCode(uint8_t code, uint32_t line) {
m_errorCode = code;
m_errorLine = line;
return false;
return false; // setSdErrorCode
}
//=============================================================================
// ISR
void sdhc_isr() {
SDHC_IRQSIGEN = 0;
m_irqstat = SDHC_IRQSTAT;
SDHC_IRQSTAT = m_irqstat;
m_dmaDone = true;
m_dmaBusy = false;
}
//=============================================================================
// Static functions.
static bool cardAcmd(uint32_t rca, uint32_t xfertyp, uint32_t arg) {
return cardCommand(CMD55_XFERTYP, rca) && cardCommand (xfertyp, arg);
}
//-----------------------------------------------------------------------------
static void enableDmaIrs() {
m_dmaDone = false;
m_irqstat = 0;
static bool cardCommand(uint32_t xfertyp, uint32_t arg) {
DBG_IRQSTAT();
if (waitTimeout(isBusyCommandInhibit)) {
return false; // Caller will set errorCode.
}
SDHC_CMDARG = arg;
SDHC_XFERTYP = xfertyp;
if (waitTimeout(isBusyCommandComplete)) {
return false; // Caller will set errorCode.
}
m_irqstat = SDHC_IRQSTAT;
SDHC_IRQSTAT = m_irqstat;

return (m_irqstat & SDHC_IRQSTAT_CC) &&
!(m_irqstat & SDHC_IRQSTAT_CMD_ERROR);
}
//-----------------------------------------------------------------------------
static bool waitDmaStatus() {
while (!m_dmaDone) {
yield();
static bool cardCMD6(uint32_t arg, uint8_t* status) {
// CMD6 returns 64 bytes.
if (waitTimeout(isBusyCMD13)) {
return sdError(SD_CARD_ERROR_CMD13);
}
return (m_irqstat & SDHC_IRQSTAT_TC) && !(m_irqstat & SDHC_IRQSTAT_ERROR);
enableDmaIrs();
SDHC_DSADDR = (uint32_t)status;
SDHC_CMDARG = arg;
SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(1) | SDHC_BLKATTR_BLKSIZE(64);
SDHC_IRQSIGEN = SDHC_IRQSIGEN_MASK;
SDHC_XFERTYP = CMD6_XFERTYP;

if (!waitDmaStatus()) {
return sdError(SD_CARD_ERROR_CMD6);
}
return true;
}
//-----------------------------------------------------------------------------
static void enableGPIO(bool enable) {
@@ -183,7 +255,12 @@ static void enableGPIO(bool enable) {
PORTE_PCR5 = enable ? PORT_CMD_DATA : 0; // SDHC_D2
}
//-----------------------------------------------------------------------------
static void SDHC_Init() {
static void enableDmaIrs() {
m_dmaBusy = true;
m_irqstat = 0;
}
//-----------------------------------------------------------------------------
static void initSDHC() {
#ifdef HAS_KINETIS_MPU
// Allow SDHC Bus Master access.
MPU_RGDAAC0 |= 0x0C000000;
@@ -215,16 +292,46 @@ static void SDHC_Init() {
}
}
//-----------------------------------------------------------------------------
static bool isBusyCMD13() {
if (!cardCommand(CMD13_XFERTYP, m_rca)) {
// Caller will timeout.
return true;
}
return !(SDHC_CMDRSP0 & CARD_STATUS_READY_FOR_DATA);
}
//-----------------------------------------------------------------------------
static bool isBusyCommandComplete() {
return !(SDHC_IRQSTAT &(SDHC_IRQSTAT_CC | SDHC_IRQSTAT_CMD_ERROR));
}
//-----------------------------------------------------------------------------
static bool isBusyCommandInhibit() {
return SDHC_PRSSTAT & SDHC_PRSSTAT_CIHB;
}
//-----------------------------------------------------------------------------
static bool isBusyDMA() {
return m_dmaBusy;
}
//-----------------------------------------------------------------------------
static bool isBusyFifoRead() {
return !(SDHC_PRSSTAT & SDHC_PRSSTAT_BREN);
}
//-----------------------------------------------------------------------------
static bool isBusyFifoWrite() {
return !(SDHC_PRSSTAT & SDHC_PRSSTAT_BWEN);
}
//-----------------------------------------------------------------------------
static bool isBusyTransferComplete() {
return !(SDHC_IRQSTAT & (SDHC_IRQSTAT_TC | SDHC_IRQSTAT_ERROR));
}
//-----------------------------------------------------------------------------
static bool rdWrBlocks(uint32_t xfertyp,
uint32_t lba, uint8_t* buf, size_t n) {
if ((3 & (uint32_t)buf) || n == 0) {
return sdError(SD_CARD_ERROR_DMA);
}
m_waitCmd13 = true;
while (isBusy()) {
yield();
if (yieldTimeout(isBusyCMD13)) {
return sdError(SD_CARD_ERROR_CMD13);
}
m_waitCmd13 = false;
enableDmaIrs();
SDHC_DSADDR = (uint32_t)buf;
SDHC_CMDARG = m_highCapacity ? lba : 512*lba;
@@ -235,30 +342,18 @@ static bool rdWrBlocks(uint32_t xfertyp,
return waitDmaStatus();
}
//-----------------------------------------------------------------------------
static bool cardCommand(uint32_t xfertyp, uint32_t arg) {
SDHC_CMDARG = arg;
SDHC_XFERTYP = xfertyp;

do {
m_irqstat = SDHC_IRQSTAT;
} while (!(m_irqstat & (SDHC_IRQSTAT_CC | SDHC_IRQSTAT_CMD_ERROR)));

SDHC_IRQSTAT = m_irqstat;

return (m_irqstat & SDHC_IRQSTAT_CC) &&
!(m_irqstat & SDHC_IRQSTAT_CMD_ERROR);
}
//------------------------------------------------------------------------------
static bool cardAcmd(uint32_t rca, uint32_t xfertyp, uint32_t arg) {
return cardCommand(CMD55_XFERTYP, rca) && cardCommand (xfertyp, arg);
}
//-----------------------------------------------------------------------------
static bool isBusy() {
if (!cardCommand(CMD13_XFERTYP, m_rca)) {
// Should have timeout in caller?
return true;
// Read 16 byte CID or CSD register.
static bool readReg16(uint32_t xfertyp, void* data) {
uint8_t* d = reinterpret_cast<uint8_t*>(data);
if (!cardCommand(xfertyp, m_rca)) {
return false; // Caller will set errorCode.
}
return !(SDHC_CMDRSP0 & CARD_STATUS_READY_FOR_DATA);
uint32_t sr[] = {SDHC_CMDRSP0, SDHC_CMDRSP1, SDHC_CMDRSP2, SDHC_CMDRSP3};
for (int i = 0; i < 15; i++) {
d[14 - i] = sr[i/4] >> 8*(i%4);
}
d[15] = 0;
return true;
}
//-----------------------------------------------------------------------------
static void setSdclk(uint32_t kHzMax) {
@@ -294,55 +389,99 @@ static void setSdclk(uint32_t kHzMax) {
// Enable the SDHC clock.
SDHC_SYSCTL |= SDHC_SYSCTL_SDCLKEN;
}
//------------------------------------------------------------------------------
static bool cardCMD6(uint32_t arg, uint8_t* status) {
// CMD6 returns 64 bytes.
while (isBusy()) {
}
enableDmaIrs();
SDHC_DSADDR = (uint32_t)status;
SDHC_CMDARG = arg;
SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(1) | SDHC_BLKATTR_BLKSIZE(64);
SDHC_IRQSIGEN = SDHC_IRQSIGEN_MASK;
SDHC_XFERTYP = CMD6_XFERTYP;
//-----------------------------------------------------------------------------
static bool transferStop() {
DBG_IRQSTAT();

if (!waitDmaStatus()) {
return sdError(SD_CARD_ERROR_CMD6);
if (!cardCommand(CMD12_XFERTYP, 0)) {
return sdError(SD_CARD_ERROR_CMD12);
}
if (yieldTimeout(isBusyCMD13)) {
return sdError(SD_CARD_ERROR_CMD13);
}
// Save registers before reset DAT lines.
uint32_t irqsststen = SDHC_IRQSTATEN;
uint32_t proctl = SDHC_PROCTL & ~SDHC_PROCTL_SABGREQ;

// Do reset to clear CDIHB. Should be a better way!
SDHC_SYSCTL |= SDHC_SYSCTL_RSTD;

// Restore registers.
SDHC_IRQSTATEN = irqsststen;
SDHC_PROCTL = proctl;

return true;
}
//------------------------------------------------------------------------------
static bool cardInit() {
uint32_t kbaudrate;
//-----------------------------------------------------------------------------
// Return true if timeout occurs.
static bool yieldTimeout(bool (*fcn)()) {
m_busyFcn = fcn;
uint32_t m = micros();
while (fcn()) {
if ((micros() - m) > BUSY_TIMEOUT_MICROS) {
m_busyFcn = 0;
return true;
}
yield();
}
m_busyFcn = 0;
return false; // Caller will set errorCode.
}
//-----------------------------------------------------------------------------
static bool waitDmaStatus() {
if (yieldTimeout(isBusyDMA)) {
return false; // Caller will set errorCode.
}
return (m_irqstat & SDHC_IRQSTAT_TC) && !(m_irqstat & SDHC_IRQSTAT_ERROR);
}
//-----------------------------------------------------------------------------
// Return true if timeout occurs.
static bool waitTimeout(bool (*fcn)()) {
uint32_t m = micros();
while (fcn()) {
if ((micros() - m) > BUSY_TIMEOUT_MICROS) {
return true;
}
}
return false; // Caller will set errorCode.
}
//=============================================================================
bool SdioCard::begin() {
uint32_t kHzSdClk;
uint32_t arg;
m_initDone = false;
m_errorCode = SD_CARD_ERROR_NONE;
m_highCapacity = false;
m_version2 = false;

// initialize controller.
SDHC_Init();
initSDHC();

if (!cardCommand(CMD0_XFERTYP, 0)) {
return sdError(SD_CARD_ERROR_CMD0);
}
if (cardCommand(CMD8_XFERTYP, 0X1AA)) {
if (SDHC_CMDRSP0 != 0X1AA) {
return sdError(SD_CARD_ERROR_CMD8);
// Try several times for case of reset delay.
for (uint32_t i = 0; i < CMD8_RETRIES; i++) {
if (cardCommand(CMD8_XFERTYP, 0X1AA)) {
if (SDHC_CMDRSP0 != 0X1AA) {
return sdError(SD_CARD_ERROR_CMD8);
}
m_version2 = true;
break;
}
m_version2 = true;
}

arg = m_version2 ? 0X40300000 : 0x00300000;
int i = 0;
uint32_t m = micros();
do {
if (!cardAcmd(0, ACMD41_XFERTYP, arg) || i++ > 1000) {
if (!cardAcmd(0, ACMD41_XFERTYP, arg) ||
((micros() - m) > BUSY_TIMEOUT_MICROS)) {
return sdError(SD_CARD_ERROR_ACMD41);
}
} while ((SDHC_CMDRSP0 & 0x80000000) == 0);

m_ocr = SDHC_CMDRSP0;
if (SDHC_CMDRSP0 & 0x40000000) {
// is high capacity
// Is high capacity.
m_highCapacity = true;
}
if (!cardCommand(CMD2_XFERTYP, 0)) {
@@ -362,80 +501,45 @@ static bool cardInit() {
if (!cardCommand(CMD7_XFERTYP, m_rca)) {
return sdError(SD_CARD_ERROR_CMD7);
}
// Set card to bus width four.
if (!cardAcmd(m_rca, ACMD6_XFERTYP, 2)) {
return sdError(SD_CARD_ERROR_ACMD6);
}
// Set Data bus width to four.
// Set SDHC to bus width four.
SDHC_PROCTL &= ~SDHC_PROCTL_DTW_MASK;
SDHC_PROCTL |= SDHC_PROCTL_DTW(SDHC_PROCTL_DTW_4BIT);

SDHC_WML = SDHC_WML_RDWML(FIFO_WML) | SDHC_WML_WRWML(FIFO_WML);

// Determine if High Speed mode is supported and set frequency.
uint8_t status[64];
if (cardCMD6(0X00FFFFFF, status) && (2 & status[13]) &&
cardCMD6(0X80FFFFF1, status) && (status[16] & 0XF) == 1) {
kbaudrate = 50000;
kHzSdClk = 50000;
} else {
kbaudrate = 25000;
kHzSdClk = 25000;
}

// disable GPIO
enableGPIO(false);

// Set the SDHC SCK frequency.
setSdclk(kbaudrate);
setSdclk(kHzSdClk);

// enable GPIO
enableGPIO(true);
m_initDone = true;
return true;
}
//-----------------------------------------------------------------------------
static bool readReg16(uint32_t xfertyp, void* data) {
if (!cardCommand(xfertyp, m_rca)) {
return false;
}
uint8_t* d = reinterpret_cast<uint8_t*>(data);
d[0] = SDHC_CMDRSP3 >> 16;
d[1] = SDHC_CMDRSP3 >> 8;
d[2] = SDHC_CMDRSP3;
d[3] = SDHC_CMDRSP2 >> 24;
d[4] = SDHC_CMDRSP2 >> 16;
d[5] = SDHC_CMDRSP2 >> 8;
d[6] = SDHC_CMDRSP2;
d[7] = SDHC_CMDRSP1 >> 24;
d[8] = SDHC_CMDRSP1 >> 16;
d[9] = SDHC_CMDRSP1 >> 8;
d[10] = SDHC_CMDRSP1;
d[11] = SDHC_CMDRSP0 >> 24;
d[12] = SDHC_CMDRSP0 >> 16;
d[13] = SDHC_CMDRSP0 >> 8;
d[14] = SDHC_CMDRSP0;
d[15] = 0;

return true;
}
//=============================================================================
bool SdioCard::begin() {
return cardInit();
}
//-----------------------------------------------------------------------------
uint32_t SdioCard::cardSize() {
return sdCardCapacity(&m_csd);
}
//-----------------------------------------------------------------------------
bool SdioCard::dmaBusy() {
return m_waitCmd13 ? isBusy() : !m_dmaDone;
}
//-----------------------------------------------------------------------------
bool SdioCard::erase(uint32_t firstBlock, uint32_t lastBlock) {
csd_t csd;
if (!readCSD(&csd)) {
return false;
}
// check for single block erase
if (!csd.v1.erase_blk_en) {
if (!m_csd.v1.erase_blk_en) {
// erase size mask
uint8_t m = (csd.v1.sector_size_high << 1) | csd.v1.sector_size_low;
uint8_t m = (m_csd.v1.sector_size_high << 1) | m_csd.v1.sector_size_low;
if ((firstBlock & m) != 0 || ((lastBlock + 1) & m) != 0) {
// error card can't erase specified area
return sdError(SD_CARD_ERROR_ERASE_SINGLE_BLOCK);
@@ -454,7 +558,8 @@ bool SdioCard::erase(uint32_t firstBlock, uint32_t lastBlock) {
if (!cardCommand(CMD38_XFERTYP, 0)) {
return sdError(SD_CARD_ERROR_CMD38);
}
while (isBusy()) {
if (waitTimeout(isBusyCMD13)) {
return sdError(SD_CARD_ERROR_ERASE_TIMEOUT);
}
return true;
}
@@ -471,6 +576,10 @@ uint32_t SdioCard::errorLine() {
return m_errorLine;
}
//-----------------------------------------------------------------------------
bool SdioCard::isBusy() {
return m_busyFcn ? m_busyFcn() : m_initDone && isBusyCMD13();
}
//-----------------------------------------------------------------------------
uint32_t SdioCard::kHzSdClk() {
return m_sdClkKhz;
}
@@ -480,7 +589,7 @@ bool SdioCard::readBlock(uint32_t lba, uint8_t* buf) {

uint8_t* ptr = (uint32_t)buf & 3 ? aligned : buf;

if (!rdWrBlocks(CMD17_XFERTYP, lba, ptr, 1)) {
if (!rdWrBlocks(CMD17_DMA_XFERTYP, lba, ptr, 1)) {
return sdError(SD_CARD_ERROR_CMD18);
}
if (ptr != buf) {
@@ -493,17 +602,17 @@ bool SdioCard::readBlocks(uint32_t lba, uint8_t* buf, size_t n) {
if ((uint32_t)buf & 3) {
for (size_t i = 0; i < n; i++, lba++, buf += 512) {
if (!readBlock(lba, buf)) {
return false;
return false; // readBlock will set errorCode.
}
}
return true;
}
if (!rdWrBlocks(CMD18_XFERTYP, lba, buf, n)) {
if (!rdWrBlocks(CMD18_DMA_XFERTYP, lba, buf, n)) {
return sdError(SD_CARD_ERROR_CMD18);
}
return true;
}
//----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
bool SdioCard::readCID(void* cid) {
memcpy(cid, &m_cid, 16);
return true;
@@ -514,11 +623,74 @@ bool SdioCard::readCSD(void* csd) {
return true;
}
//-----------------------------------------------------------------------------
bool SdioCard::readData(uint8_t *dst) {
DBG_IRQSTAT();
uint32_t *p32 = reinterpret_cast<uint32_t*>(dst);

if (!(SDHC_PRSSTAT & SDHC_PRSSTAT_RTA)) {
SDHC_PROCTL &= ~SDHC_PROCTL_SABGREQ;
if ((SDHC_BLKATTR & 0XFFFF0000) == 0X10000) {
// Don't stop at block gap if last block. Allows auto CMD12.
SDHC_PROCTL |= SDHC_PROCTL_CREQ;
} else {
noInterrupts();
SDHC_PROCTL |= SDHC_PROCTL_CREQ;
SDHC_PROCTL |= SDHC_PROCTL_SABGREQ;
interrupts();
}
}
if (waitTimeout(isBusyFifoRead)) {
return sdError(SD_CARD_ERROR_READ_FIFO);
}
for (uint32_t iw = 0 ; iw < 512/(4*FIFO_WML); iw++) {
while (0 == (SDHC_PRSSTAT & SDHC_PRSSTAT_BREN)) {
}
for (uint32_t i = 0; i < FIFO_WML; i++) {
p32[i] = SDHC_DATPORT;
}
p32 += FIFO_WML;
}
if (waitTimeout(isBusyTransferComplete)) {
return sdError(SD_CARD_ERROR_READ_TIMEOUT);
}
m_irqstat = SDHC_IRQSTAT;
SDHC_IRQSTAT = m_irqstat;
return (m_irqstat & SDHC_IRQSTAT_TC) && !(m_irqstat & SDHC_IRQSTAT_ERROR);
}
//-----------------------------------------------------------------------------
bool SdioCard::readOCR(uint32_t* ocr) {
*ocr = m_ocr;
return true;
}
//-----------------------------------------------------------------------------
bool SdioCard::readStart(uint32_t lba) {
// K66/K65 Errata - SDHC: Does not support Infinite Block Transfer Mode.
return sdError(SD_CARD_ERROR_FUNCTION_NOT_SUPPORTED);
}
//-----------------------------------------------------------------------------
// SDHC will do Auto CMD12 after count blocks.
bool SdioCard::readStart(uint32_t lba, uint32_t count) {
DBG_IRQSTAT();
if (count > 0XFFFF) {
return sdError(SD_CARD_ERROR_READ_START);
}
if (yieldTimeout(isBusyCMD13)) {
return sdError(SD_CARD_ERROR_CMD13);
}
if (count > 1) {
SDHC_PROCTL |= SDHC_PROCTL_SABGREQ;
}
SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(count) | SDHC_BLKATTR_BLKSIZE(512);
if (!cardCommand(CMD18_PGM_XFERTYP, m_highCapacity ? lba : 512*lba)) {
return sdError(SD_CARD_ERROR_CMD18);
}
return true;
}
//-----------------------------------------------------------------------------
bool SdioCard::readStop() {
return transferStop();
}
//-----------------------------------------------------------------------------
bool SdioCard::syncBlocks() {
return true;
}
@@ -537,7 +709,7 @@ bool SdioCard::writeBlock(uint32_t lba, const uint8_t* buf) {
} else {
ptr = const_cast<uint8_t*>(buf);
}
if (!rdWrBlocks(CMD24_XFERTYP, lba, ptr, 1)) {
if (!rdWrBlocks(CMD24_DMA_XFERTYP, lba, ptr, 1)) {
return sdError(SD_CARD_ERROR_CMD24);
}
return true;
@@ -548,14 +720,76 @@ bool SdioCard::writeBlocks(uint32_t lba, const uint8_t* buf, size_t n) {
if (3 & (uint32_t)ptr) {
for (size_t i = 0; i < n; i++, lba++, ptr += 512) {
if (!writeBlock(lba, ptr)) {
return false;
return false; // writeBlock will set errorCode.
}
}
return true;
}
if (!rdWrBlocks(CMD25_XFERTYP, lba, ptr, n)) {
if (!rdWrBlocks(CMD25_DMA_XFERTYP, lba, ptr, n)) {
return sdError(SD_CARD_ERROR_CMD25);
}
return true;
}
//-----------------------------------------------------------------------------
bool SdioCard::writeData(const uint8_t* src) {
DBG_IRQSTAT();
const uint32_t* p32 = reinterpret_cast<const uint32_t*>(src);

if (!(SDHC_PRSSTAT & SDHC_PRSSTAT_WTA)) {
SDHC_PROCTL &= ~SDHC_PROCTL_SABGREQ;
// Don't stop at block gap if last block. Allows auto CMD12.
if ((SDHC_BLKATTR & 0XFFFF0000) == 0X10000) {
SDHC_PROCTL |= SDHC_PROCTL_CREQ;
} else {
SDHC_PROCTL |= SDHC_PROCTL_CREQ;
SDHC_PROCTL |= SDHC_PROCTL_SABGREQ;
}
}
if (waitTimeout(isBusyFifoWrite)) {
return sdError(SD_CARD_ERROR_WRITE_FIFO);
}
for (uint32_t iw = 0 ; iw < 512/(4*FIFO_WML); iw++) {
while (0 == (SDHC_PRSSTAT & SDHC_PRSSTAT_BWEN)) {
}
for (uint32_t i = 0; i < FIFO_WML; i++) {
SDHC_DATPORT = p32[i];
}
p32 += FIFO_WML;
}
if (waitTimeout(isBusyTransferComplete)) {
return sdError(SD_CARD_ERROR_WRITE_TIMEOUT);
}
m_irqstat = SDHC_IRQSTAT;
SDHC_IRQSTAT = m_irqstat;
return (m_irqstat & SDHC_IRQSTAT_TC) && !(m_irqstat & SDHC_IRQSTAT_ERROR);
}
//-----------------------------------------------------------------------------
bool SdioCard::writeStart(uint32_t lba) {
// K66/K65 Errata - SDHC: Does not support Infinite Block Transfer Mode.
return sdError(SD_CARD_ERROR_FUNCTION_NOT_SUPPORTED);
}
//-----------------------------------------------------------------------------
// SDHC will do Auto CMD12 after count blocks.
bool SdioCard::writeStart(uint32_t lba, uint32_t count) {
if (count > 0XFFFF) {
return sdError(SD_CARD_ERROR_WRITE_START);
}
DBG_IRQSTAT();
if (yieldTimeout(isBusyCMD13)) {
return sdError(SD_CARD_ERROR_CMD13);
}
if (count > 1) {
SDHC_PROCTL |= SDHC_PROCTL_SABGREQ;
}
SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(count) | SDHC_BLKATTR_BLKSIZE(512);

if (!cardCommand(CMD25_PGM_XFERTYP, m_highCapacity ? lba : 512*lba)) {
return sdError(SD_CARD_ERROR_CMD25);
}
return true;
}
//-----------------------------------------------------------------------------
bool SdioCard::writeStop() {
return transferStop();
}
#endif // defined(__MK64FX512__) || defined(__MK66FX1M0__)

+ 43
- 10
SdFat/src/SdFat.h Voir le fichier

@@ -29,7 +29,7 @@
#include "SdCard/SdioCard.h"
//------------------------------------------------------------------------------
/** SdFat version YYYYMMDD */
#define SD_FAT_VERSION 20160905
#define SD_FAT_VERSION 20160913
//==============================================================================
/**
* \class SdBaseFile
@@ -317,7 +317,7 @@ class SdFat : public SdFileSystem<SdSpiCard> {
* \param[in] csPin SD card chip select pin.
* \param[in] spiSettings SPI speed, mode, and bit order.
* \return true for success else false.
*/
*/
bool begin(uint8_t csPin = SS, SPISettings spiSettings = SPI_FULL_SPEED) {
return m_card.begin(&m_spi, csPin, spiSettings) &&
SdFileSystem::begin();
@@ -327,13 +327,13 @@ class SdFat : public SdFileSystem<SdSpiCard> {
* \param[in] csPin SD card chip select pin.
* \param[in] settings SPI speed, mode, and bit order.
* \return true for success else false.
*/
*/
bool cardBegin(uint8_t csPin = SS, SPISettings settings = SPI_FULL_SPEED) {
return m_card.begin(&m_spi, csPin, settings);
}
/** Initialize file system for diagnostic use only.
* \return true for success else false.
*/
*/
bool fsBegin() {
return FatFileSystem::begin(card());
}
@@ -351,26 +351,59 @@ class SdFatSdio : public SdFileSystem<SdioCard> {
public:
/** Initialize SD card and file system.
* \return true for success else false.
*/
*/
bool begin() {
return m_card.begin() && SdFileSystem::begin();
}
/** Initialize SD card for diagnostic use only.
*
* \return true for success else false.
*/
*/
bool cardBegin() {
return m_card.begin();
}
/** Initialize file system for diagnostic use only.
* \return true for success else false.
*/
*/
bool fsBegin() {
return SdFileSystem::begin();
}
};
#if ENABLE_SDIOEX_CLASS || defined(DOXYGEN)
//-----------------------------------------------------------------------------
/**
* \class SdFatSdioEX
* \brief SdFat class using SDIO.
*/
class SdFatSdioEX : public SdFileSystem<SdioCardEX> {
public:
/** Initialize SD card and file system.
* \return true for success else false.
*/
bool begin() {
return m_card.begin() && SdFileSystem::begin();
}
/** \return Pointer to SD card object */
SdioCardEX* card() {
return &m_card;
}
/** Initialize SD card for diagnostic use only.
*
* \return true for success else false.
*/
bool cardBegin() {
return m_card.begin();
}
/** Initialize file system for diagnostic use only.
* \return true for success else false.
*/
bool fsBegin() {
return SdFileSystem::begin();
}
};
#endif // ENABLE_SDIOEX_CLASS || defined(DOXYGEN)
#endif // ENABLE_SDIO_CLASS || defined(DOXYGEN)
//==============================================================================
//=============================================================================
#if ENABLE_SOFTWARE_SPI_CLASS || defined(DOXYGEN)
/**
* \class SdFatSoftSpi
@@ -407,7 +440,7 @@ class SdFatEX : public SdFileSystem<SdSpiCardEX> {
}
/** Constructor with SPI port selection.
* \param[in] spiPort SPI port number.
*/
*/
explicit SdFatEX(uint8_t spiPort) {
m_spi.setPort(spiPort);
}
@@ -417,7 +450,7 @@ class SdFatEX : public SdFileSystem<SdSpiCardEX> {
* \param[in] csPin SD card chip select pin.
* \param[in] spiSettings SPI speed, mode, and bit order.
* \return true for success else false.
*/
*/
bool begin(uint8_t csPin = SS, SPISettings spiSettings = SPI_FULL_SPEED) {
return m_card.begin(&m_spi, csPin, spiSettings) &&
SdFileSystem::begin();

+ 1
- 0
SdFat/src/SdFatConfig.h Voir le fichier

@@ -160,6 +160,7 @@
/** Enable SDIO driver if available. */
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
#define ENABLE_SDIO_CLASS 1
#define ENABLE_SDIOEX_CLASS 1
#else // ENABLE_SDIO_CLASS
#define ENABLE_SDIO_CLASS 0
#endif // ENABLE_SDIO_CLASS

+ 4
- 0
changes.txt Voir le fichier

@@ -1,3 +1,7 @@
13 Sep 2016

Added SdFatSdioEX class with Extended SD I/O.

5 Sep 2016

Restructured classes to support SPI and SDIO controllers.

Chargement…
Annuler
Enregistrer