Преглед на файлове

Added SdFatSdioEX class

main
Bill Greiman преди 8 години
родител
ревизия
a3433c74ae
променени са 16 файла, в които са добавени 805 реда и са изтрити 195 реда
  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 Целия файл

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

+ 1
- 1
SdFat/examples/LowLatencyLoggerADXL345/LowLatencyLogger.ino Целия файл

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

+ 1
- 1
SdFat/examples/LowLatencyLoggerMPU6050/LowLatencyLogger.ino Целия файл

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

+ 3
- 1
SdFat/examples/SdFormatter/SdFormatter.ino Целия файл

ArduinoOutStream cout(Serial); ArduinoOutStream cout(Serial);


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

+ 6
- 2
SdFat/examples/SdInfo/SdInfo.ino Целия файл

const int8_t DISABLE_CHIP_SELECT = -1; const int8_t DISABLE_CHIP_SELECT = -1;


#if USE_SDIO #if USE_SDIO
SdFatSdio sd;
// Use faster SdioCardEX
SdFatSdioEX sd;
// SdFatSdio sd;
#else // USE_SDIO #else // USE_SDIO
SdFat sd; SdFat sd;
#endif // USE_SDIO #endif // USE_SDIO


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

+ 79
- 22
SdFat/examples/TeensySdioDemo/TeensySdioDemo.ino Целия файл

// Simple performance test for Teensy 3.5/3.6 SDHC. // Simple performance test for Teensy 3.5/3.6 SDHC.
// Demonstrates yield() efficiency. // 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" #include "SdFat.h"


// 32 KiB buffer. // 32 KiB buffer.


SdFatSdio sd; SdFatSdio sd;


SdFatSdioEX sdEx;

File file; File file;


uint8_t buf[BUF_DIM]; uint8_t buf[BUF_DIM];
// Number of yield calls. // Number of yield calls.
uint32_t yieldCalls = 0; uint32_t yieldCalls = 0;
// Max busy time for single yield call. // 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. // Replace "weak" system yield() function.
void yield() { void yield() {
// Only count cardBusy time. // Only count cardBusy time.
if (!sd.card()->dmaBusy()) {
if (!sdBusy()) {
return; return;
}
}
uint32_t m = micros(); uint32_t m = micros();
yieldCalls++; yieldCalls++;
while (sd.card()->dmaBusy()) {
while (sdBusy()) {
// Do something here. // Do something here.
} }
m = micros() - m; m = micros() - m;
yieldMicros += m; 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)) { if (!file.open("TeensyDemo.bin", O_RDWR | O_CREAT)) {
sd.errorHalt("open failed");
errorHalt("open failed");
} }
Serial.println("\nsize,write,read"); Serial.println("\nsize,write,read");
Serial.println("bytes,KB/sec,KB/sec"); Serial.println("bytes,KB/sec,KB/sec");
buf32[0] = n; buf32[0] = n;
buf32[nb/4 - 1] = n; buf32[nb/4 - 1] = n;
if (nb != file.write(buf, nb)) { if (nb != file.write(buf, nb)) {
sd.errorHalt("write failed");
errorHalt("write failed");
} }
} }
t = micros() - t; t = micros() - t;
for (uint32_t n = 0; n < nRdWr; n++) { for (uint32_t n = 0; n < nRdWr; n++) {
if ((int)nb != file.read(buf, nb)) { if ((int)nb != file.read(buf, nb)) {
sd.errorHalt("read failed");
errorHalt("read failed");
} }
// crude check of data. // crude check of data.
if (buf32[0] != n || buf32[nb/4 - 1] != n) { if (buf32[0] != n || buf32[nb/4 - 1] != n) {
sd.errorHalt("data check");
errorHalt("data check");
} }
} }
t = micros() - t; t = micros() - t;
Serial.print("yieldCalls "); Serial.print("yieldCalls ");
Serial.println(yieldCalls); Serial.println(yieldCalls);
Serial.print("yieldMaxUsec "); Serial.print("yieldMaxUsec ");
Serial.println(yieldMaxUsec);
Serial.println(yieldMaxUsec);
Serial.print("kHzSdClk "); Serial.print("kHzSdClk ");
Serial.println(sd.card()->kHzSdClk());
Serial.println(kHzSdClk());
Serial.println("Done"); 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 Целия файл



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

+ 3
- 4
SdFat/src/FatLib/FatFile.cpp Целия файл

} }
} }
n = 512*nb; n = 512*nb;
if (m_vol->cacheBlockNumber() <= block
if (block <= m_vol->cacheBlockNumber()
&& block < (m_vol->cacheBlockNumber() + nb)) { && block < (m_vol->cacheBlockNumber() + nb)) {
// flush cache if a block is in the cache // flush cache if a block is in the cache
if (!m_vol->cacheSync()) {
if (!m_vol->cacheSyncData()) {
DBG_FAIL_MACRO; DBG_FAIL_MACRO;
goto fail; goto fail;
} }
if (!isOpen()) { if (!isOpen()) {
return true; return true;
} }

if (m_flags & F_FILE_DIR_DIRTY) { if (m_flags & F_FILE_DIR_DIRTY) {
dir_t* dir = cacheDirEntry(FatCache::CACHE_FOR_WRITE); dir_t* dir = cacheDirEntry(FatCache::CACHE_FOR_WRITE);
// check for deleted by another open file object // check for deleted by another open file object
nBlock = maxBlocks; nBlock = maxBlocks;
} }
n = 512*nBlock; n = 512*nBlock;
if (m_vol->cacheBlockNumber() <= block
if (block <= m_vol->cacheBlockNumber()
&& block < (m_vol->cacheBlockNumber() + nBlock)) { && block < (m_vol->cacheBlockNumber() + nBlock)) {
// invalidate cache if block is in cache // invalidate cache if block is in cache
m_vol->cacheInvalidate(); m_vol->cacheInvalidate();

+ 4
- 0
SdFat/src/FatLib/FatVolume.h Целия файл

m_status = 0; m_status = 0;
m_lbn = 0XFFFFFFFF; m_lbn = 0XFFFFFFFF;
} }
/** \return dirty status */
bool isDirty() {
return m_status & CACHE_STATUS_DIRTY;
}
/** \return Logical block number for cached block. */ /** \return Logical block number for cached block. */
uint32_t lbn() { uint32_t lbn() {
return m_lbn; return m_lbn;

+ 15
- 8
SdFat/src/SdCard/SdInfo.h Целия файл

SD_CARD_ERROR_ACMD23, SD_CARD_ERROR_ACMD23,
SD_CARD_ERROR_ACMD41, 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_REG,
SD_CARD_ERROR_READ_START,
SD_CARD_ERROR_READ_TIMEOUT, SD_CARD_ERROR_READ_TIMEOUT,
SD_CARD_ERROR_STOP_TRAN, SD_CARD_ERROR_STOP_TRAN,
SD_CARD_ERROR_WRITE_TIMEOUT,
SD_CARD_ERROR_WRITE, 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; } sd_error_code_t;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// card types // card types

+ 162
- 3
SdFat/src/SdCard/SdioCard.h Целия файл

* or zero if an error occurs. * or zero if an error occurs.
*/ */
uint32_t cardSize(); uint32_t cardSize();
/** \return DMA transfer status. */
bool dmaBusy();
/** Erase a range of blocks. /** Erase a range of blocks.
* *
* \param[in] firstBlock The address of the first block in the range. * \param[in] firstBlock The address of the first block in the range.
* *
* \return The value true is returned for success and * \return The value true is returned for success and
* the value false is returned for failure. * the value false is returned for failure.
*/
*/
bool erase(uint32_t firstBlock, uint32_t lastBlock); bool erase(uint32_t firstBlock, uint32_t lastBlock);
/** /**
* \return code for the last error. See SdInfo.h for a list of error codes. * \return code for the last error. See SdInfo.h for a list of error codes.
uint32_t errorData(); uint32_t errorData();
/** \return error line for last error. Tmp function for debug. */ /** \return error line for last error. Tmp function for debug. */
uint32_t errorLine(); uint32_t errorLine();
/**
* Check for busy with CMD13.
*
* \return true if busy else false.
*/
bool isBusy();
/** \return the SD clock frequency in kHz. */ /** \return the SD clock frequency in kHz. */
uint32_t kHzSdClk(); uint32_t kHzSdClk();
/** /**
* \return true for success or false for failure. * \return true for success or false for failure.
*/ */
bool readCSD(void* csd); 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. /** Read OCR register.
* *
* \param[out] ocr Value of OCR register. * \param[out] ocr Value of OCR register.
* \return true for success else false. * \return true for success else false.
*/ */
bool readOCR(uint32_t* ocr); 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. */ /** \return success if sync successful. Not for user apps. */
bool syncBlocks(); bool syncBlocks();
/** Return the card type: SD V1, SD V2 or SDHC /** Return the card type: SD V1, SD V2 or SDHC
* the value false is returned for failure. * the value false is returned for failure.
*/ */
bool writeBlocks(uint32_t lba, const uint8_t* src, size_t nb); 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 #endif // SdioCard_h

+ 103
- 0
SdFat/src/SdCard/SdioCardEX.cpp Целия файл

/* 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 Целия файл

#if defined(__MK64FX512__) || defined(__MK66FX1M0__) #if defined(__MK64FX512__) || defined(__MK66FX1M0__)
#include "SdioCard.h" #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 = const uint32_t SDHC_IRQSTATEN_MASK =
SDHC_IRQSTATEN_DMAESEN | SDHC_IRQSTATEN_AC12ESEN | SDHC_IRQSTATEN_DMAESEN | SDHC_IRQSTATEN_AC12ESEN |
SDHC_IRQSTATEN_DEBESEN | SDHC_IRQSTATEN_DCESEN | SDHC_IRQSTATEN_DEBESEN | SDHC_IRQSTATEN_DCESEN |
SDHC_IRQSTATEN_DTOESEN | SDHC_IRQSTATEN_CIESEN | SDHC_IRQSTATEN_DTOESEN | SDHC_IRQSTATEN_CIESEN |
SDHC_IRQSTATEN_CEBESEN | SDHC_IRQSTATEN_CCESEN | 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; SDHC_IRQSTATEN_TCSEN | SDHC_IRQSTATEN_CCSEN;


const uint32_t SDHC_IRQSTAT_CMD_ERROR = const uint32_t SDHC_IRQSTAT_CMD_ERROR =
const uint32_t DATA_READ_MULTI_DMA = DATA_READ_DMA | SDHC_XFERTYP_MSBSEL | const uint32_t DATA_READ_MULTI_DMA = DATA_READ_DMA | SDHC_XFERTYP_MSBSEL |
SDHC_XFERTYP_AC12EN | SDHC_XFERTYP_BCEN; 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_DMA = SDHC_XFERTYP_DPSEL | SDHC_XFERTYP_DMAEN;


const uint32_t DATA_WRITE_MULTI_DMA = DATA_WRITE_DMA | SDHC_XFERTYP_MSBSEL | const uint32_t DATA_WRITE_MULTI_DMA = DATA_WRITE_DMA | SDHC_XFERTYP_MSBSEL |
SDHC_XFERTYP_AC12EN | SDHC_XFERTYP_BCEN; 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 ACMD6_XFERTYP = SDHC_XFERTYP_CMDINX(ACMD6) | CMD_RESP_R1;


const uint32_t ACMD41_XFERTYP = SDHC_XFERTYP_CMDINX(ACMD41) | CMD_RESP_R3; const uint32_t ACMD41_XFERTYP = SDHC_XFERTYP_CMDINX(ACMD41) | CMD_RESP_R3;


const uint32_t CMD10_XFERTYP = SDHC_XFERTYP_CMDINX(CMD10) | 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 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; const uint32_t CMD32_XFERTYP = SDHC_XFERTYP_CMDINX(CMD32) | CMD_RESP_R1;


const uint32_t CMD38_XFERTYP = SDHC_XFERTYP_CMDINX(CMD38) | CMD_RESP_R1b; const uint32_t CMD38_XFERTYP = SDHC_XFERTYP_CMDINX(CMD38) | CMD_RESP_R1b;


const uint32_t CMD55_XFERTYP = SDHC_XFERTYP_CMDINX(CMD55) | CMD_RESP_R1; 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 bool readReg16(uint32_t xfertyp, void* data);
static void setSdclk(uint32_t kHzMax); 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_version2;
static bool m_highCapacity; 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; 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 volatile uint32_t m_irqstat;
static uint32_t m_sdClkKhz = 0; static uint32_t m_sdClkKhz = 0;
static uint32_t m_ocr;
static cid_t m_cid; static cid_t m_cid;
static csd_t m_csd; 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__) #define sdError(code) setSdErrorCode(code, __LINE__)
inline bool setSdErrorCode(uint8_t code, uint32_t line) { inline bool setSdErrorCode(uint8_t code, uint32_t line) {
m_errorCode = code; m_errorCode = code;
m_errorLine = line; m_errorLine = line;
return false;
return false; // setSdErrorCode
} }
//============================================================================= //=============================================================================
// ISR
void sdhc_isr() { void sdhc_isr() {
SDHC_IRQSIGEN = 0; SDHC_IRQSIGEN = 0;
m_irqstat = SDHC_IRQSTAT; m_irqstat = SDHC_IRQSTAT;
SDHC_IRQSTAT = m_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) { static void enableGPIO(bool enable) {
PORTE_PCR5 = enable ? PORT_CMD_DATA : 0; // SDHC_D2 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 #ifdef HAS_KINETIS_MPU
// Allow SDHC Bus Master access. // Allow SDHC Bus Master access.
MPU_RGDAAC0 |= 0x0C000000; MPU_RGDAAC0 |= 0x0C000000;
} }
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
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, static bool rdWrBlocks(uint32_t xfertyp,
uint32_t lba, uint8_t* buf, size_t n) { uint32_t lba, uint8_t* buf, size_t n) {
if ((3 & (uint32_t)buf) || n == 0) { if ((3 & (uint32_t)buf) || n == 0) {
return sdError(SD_CARD_ERROR_DMA); 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(); enableDmaIrs();
SDHC_DSADDR = (uint32_t)buf; SDHC_DSADDR = (uint32_t)buf;
SDHC_CMDARG = m_highCapacity ? lba : 512*lba; SDHC_CMDARG = m_highCapacity ? lba : 512*lba;
return waitDmaStatus(); 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) { static void setSdclk(uint32_t kHzMax) {
// Enable the SDHC clock. // Enable the SDHC clock.
SDHC_SYSCTL |= SDHC_SYSCTL_SDCLKEN; 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; 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; uint32_t arg;
m_initDone = false;
m_errorCode = SD_CARD_ERROR_NONE; m_errorCode = SD_CARD_ERROR_NONE;
m_highCapacity = false; m_highCapacity = false;
m_version2 = false; m_version2 = false;


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


if (!cardCommand(CMD0_XFERTYP, 0)) { if (!cardCommand(CMD0_XFERTYP, 0)) {
return sdError(SD_CARD_ERROR_CMD0); 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; arg = m_version2 ? 0X40300000 : 0x00300000;
int i = 0;
uint32_t m = micros();
do { 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); return sdError(SD_CARD_ERROR_ACMD41);
} }
} while ((SDHC_CMDRSP0 & 0x80000000) == 0); } while ((SDHC_CMDRSP0 & 0x80000000) == 0);


m_ocr = SDHC_CMDRSP0; m_ocr = SDHC_CMDRSP0;
if (SDHC_CMDRSP0 & 0x40000000) { if (SDHC_CMDRSP0 & 0x40000000) {
// is high capacity
// Is high capacity.
m_highCapacity = true; m_highCapacity = true;
} }
if (!cardCommand(CMD2_XFERTYP, 0)) { if (!cardCommand(CMD2_XFERTYP, 0)) {
if (!cardCommand(CMD7_XFERTYP, m_rca)) { if (!cardCommand(CMD7_XFERTYP, m_rca)) {
return sdError(SD_CARD_ERROR_CMD7); return sdError(SD_CARD_ERROR_CMD7);
} }
// Set card to bus width four.
if (!cardAcmd(m_rca, ACMD6_XFERTYP, 2)) { if (!cardAcmd(m_rca, ACMD6_XFERTYP, 2)) {
return sdError(SD_CARD_ERROR_ACMD6); 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_MASK;
SDHC_PROCTL |= SDHC_PROCTL_DTW(SDHC_PROCTL_DTW_4BIT); 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]; uint8_t status[64];
if (cardCMD6(0X00FFFFFF, status) && (2 & status[13]) && if (cardCMD6(0X00FFFFFF, status) && (2 & status[13]) &&
cardCMD6(0X80FFFFF1, status) && (status[16] & 0XF) == 1) { cardCMD6(0X80FFFFF1, status) && (status[16] & 0XF) == 1) {
kbaudrate = 50000;
kHzSdClk = 50000;
} else { } else {
kbaudrate = 25000;
kHzSdClk = 25000;
} }

// disable GPIO // disable GPIO
enableGPIO(false); enableGPIO(false);


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


// enable GPIO // enable GPIO
enableGPIO(true); enableGPIO(true);
m_initDone = true;
return 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() { uint32_t SdioCard::cardSize() {
return sdCardCapacity(&m_csd); return sdCardCapacity(&m_csd);
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool SdioCard::dmaBusy() {
return m_waitCmd13 ? isBusy() : !m_dmaDone;
}
//-----------------------------------------------------------------------------
bool SdioCard::erase(uint32_t firstBlock, uint32_t lastBlock) { bool SdioCard::erase(uint32_t firstBlock, uint32_t lastBlock) {
csd_t csd;
if (!readCSD(&csd)) {
return false;
}
// check for single block erase // check for single block erase
if (!csd.v1.erase_blk_en) {
if (!m_csd.v1.erase_blk_en) {
// erase size mask // 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) { if ((firstBlock & m) != 0 || ((lastBlock + 1) & m) != 0) {
// error card can't erase specified area // error card can't erase specified area
return sdError(SD_CARD_ERROR_ERASE_SINGLE_BLOCK); return sdError(SD_CARD_ERROR_ERASE_SINGLE_BLOCK);
if (!cardCommand(CMD38_XFERTYP, 0)) { if (!cardCommand(CMD38_XFERTYP, 0)) {
return sdError(SD_CARD_ERROR_CMD38); return sdError(SD_CARD_ERROR_CMD38);
} }
while (isBusy()) {
if (waitTimeout(isBusyCMD13)) {
return sdError(SD_CARD_ERROR_ERASE_TIMEOUT);
} }
return true; return true;
} }
return m_errorLine; return m_errorLine;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool SdioCard::isBusy() {
return m_busyFcn ? m_busyFcn() : m_initDone && isBusyCMD13();
}
//-----------------------------------------------------------------------------
uint32_t SdioCard::kHzSdClk() { uint32_t SdioCard::kHzSdClk() {
return m_sdClkKhz; return m_sdClkKhz;
} }


uint8_t* ptr = (uint32_t)buf & 3 ? aligned : 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); return sdError(SD_CARD_ERROR_CMD18);
} }
if (ptr != buf) { if (ptr != buf) {
if ((uint32_t)buf & 3) { if ((uint32_t)buf & 3) {
for (size_t i = 0; i < n; i++, lba++, buf += 512) { for (size_t i = 0; i < n; i++, lba++, buf += 512) {
if (!readBlock(lba, buf)) { if (!readBlock(lba, buf)) {
return false;
return false; // readBlock will set errorCode.
} }
} }
return true; return true;
} }
if (!rdWrBlocks(CMD18_XFERTYP, lba, buf, n)) {
if (!rdWrBlocks(CMD18_DMA_XFERTYP, lba, buf, n)) {
return sdError(SD_CARD_ERROR_CMD18); return sdError(SD_CARD_ERROR_CMD18);
} }
return true; return true;
} }
//----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
bool SdioCard::readCID(void* cid) { bool SdioCard::readCID(void* cid) {
memcpy(cid, &m_cid, 16); memcpy(cid, &m_cid, 16);
return true; return true;
return true; 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) { bool SdioCard::readOCR(uint32_t* ocr) {
*ocr = m_ocr; *ocr = m_ocr;
return true; 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() { bool SdioCard::syncBlocks() {
return true; return true;
} }
} else { } else {
ptr = const_cast<uint8_t*>(buf); 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 sdError(SD_CARD_ERROR_CMD24);
} }
return true; return true;
if (3 & (uint32_t)ptr) { if (3 & (uint32_t)ptr) {
for (size_t i = 0; i < n; i++, lba++, ptr += 512) { for (size_t i = 0; i < n; i++, lba++, ptr += 512) {
if (!writeBlock(lba, ptr)) { if (!writeBlock(lba, ptr)) {
return false;
return false; // writeBlock will set errorCode.
} }
} }
return true; return true;
} }
if (!rdWrBlocks(CMD25_XFERTYP, lba, ptr, n)) {
if (!rdWrBlocks(CMD25_DMA_XFERTYP, lba, ptr, n)) {
return sdError(SD_CARD_ERROR_CMD25); return sdError(SD_CARD_ERROR_CMD25);
} }
return true; 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__) #endif // defined(__MK64FX512__) || defined(__MK66FX1M0__)

+ 43
- 10
SdFat/src/SdFat.h Целия файл

#include "SdCard/SdioCard.h" #include "SdCard/SdioCard.h"
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** SdFat version YYYYMMDD */ /** SdFat version YYYYMMDD */
#define SD_FAT_VERSION 20160905
#define SD_FAT_VERSION 20160913
//============================================================================== //==============================================================================
/** /**
* \class SdBaseFile * \class SdBaseFile
* \param[in] csPin SD card chip select pin. * \param[in] csPin SD card chip select pin.
* \param[in] spiSettings SPI speed, mode, and bit order. * \param[in] spiSettings SPI speed, mode, and bit order.
* \return true for success else false. * \return true for success else false.
*/
*/
bool begin(uint8_t csPin = SS, SPISettings spiSettings = SPI_FULL_SPEED) { bool begin(uint8_t csPin = SS, SPISettings spiSettings = SPI_FULL_SPEED) {
return m_card.begin(&m_spi, csPin, spiSettings) && return m_card.begin(&m_spi, csPin, spiSettings) &&
SdFileSystem::begin(); SdFileSystem::begin();
* \param[in] csPin SD card chip select pin. * \param[in] csPin SD card chip select pin.
* \param[in] settings SPI speed, mode, and bit order. * \param[in] settings SPI speed, mode, and bit order.
* \return true for success else false. * \return true for success else false.
*/
*/
bool cardBegin(uint8_t csPin = SS, SPISettings settings = SPI_FULL_SPEED) { bool cardBegin(uint8_t csPin = SS, SPISettings settings = SPI_FULL_SPEED) {
return m_card.begin(&m_spi, csPin, settings); return m_card.begin(&m_spi, csPin, settings);
} }
/** Initialize file system for diagnostic use only. /** Initialize file system for diagnostic use only.
* \return true for success else false. * \return true for success else false.
*/
*/
bool fsBegin() { bool fsBegin() {
return FatFileSystem::begin(card()); return FatFileSystem::begin(card());
} }
public: public:
/** Initialize SD card and file system. /** Initialize SD card and file system.
* \return true for success else false. * \return true for success else false.
*/
*/
bool begin() { bool begin() {
return m_card.begin() && SdFileSystem::begin(); return m_card.begin() && SdFileSystem::begin();
} }
/** Initialize SD card for diagnostic use only. /** Initialize SD card for diagnostic use only.
* *
* \return true for success else false. * \return true for success else false.
*/
*/
bool cardBegin() { bool cardBegin() {
return m_card.begin(); return m_card.begin();
} }
/** Initialize file system for diagnostic use only. /** Initialize file system for diagnostic use only.
* \return true for success else false. * \return true for success else false.
*/
*/
bool fsBegin() { bool fsBegin() {
return SdFileSystem::begin(); 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) #endif // ENABLE_SDIO_CLASS || defined(DOXYGEN)
//==============================================================================
//=============================================================================
#if ENABLE_SOFTWARE_SPI_CLASS || defined(DOXYGEN) #if ENABLE_SOFTWARE_SPI_CLASS || defined(DOXYGEN)
/** /**
* \class SdFatSoftSpi * \class SdFatSoftSpi
} }
/** Constructor with SPI port selection. /** Constructor with SPI port selection.
* \param[in] spiPort SPI port number. * \param[in] spiPort SPI port number.
*/
*/
explicit SdFatEX(uint8_t spiPort) { explicit SdFatEX(uint8_t spiPort) {
m_spi.setPort(spiPort); m_spi.setPort(spiPort);
} }
* \param[in] csPin SD card chip select pin. * \param[in] csPin SD card chip select pin.
* \param[in] spiSettings SPI speed, mode, and bit order. * \param[in] spiSettings SPI speed, mode, and bit order.
* \return true for success else false. * \return true for success else false.
*/
*/
bool begin(uint8_t csPin = SS, SPISettings spiSettings = SPI_FULL_SPEED) { bool begin(uint8_t csPin = SS, SPISettings spiSettings = SPI_FULL_SPEED) {
return m_card.begin(&m_spi, csPin, spiSettings) && return m_card.begin(&m_spi, csPin, spiSettings) &&
SdFileSystem::begin(); SdFileSystem::begin();

+ 1
- 0
SdFat/src/SdFatConfig.h Целия файл

/** Enable SDIO driver if available. */ /** Enable SDIO driver if available. */
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) #if defined(__MK64FX512__) || defined(__MK66FX1M0__)
#define ENABLE_SDIO_CLASS 1 #define ENABLE_SDIO_CLASS 1
#define ENABLE_SDIOEX_CLASS 1
#else // ENABLE_SDIO_CLASS #else // ENABLE_SDIO_CLASS
#define ENABLE_SDIO_CLASS 0 #define ENABLE_SDIO_CLASS 0
#endif // ENABLE_SDIO_CLASS #endif // ENABLE_SDIO_CLASS

+ 4
- 0
changes.txt Целия файл

13 Sep 2016

Added SdFatSdioEX class with Extended SD I/O.

5 Sep 2016 5 Sep 2016


Restructured classes to support SPI and SDIO controllers. Restructured classes to support SPI and SDIO controllers.

Loading…
Отказ
Запис