Browse Source

Add Teensy 4.0 SDIO support

main
Bill Greiman 5 years ago
parent
commit
5cb74d4e33
12 changed files with 635 additions and 233 deletions
  1. +2
    -0
      README.md
  2. +1
    -1
      examples/TeensyRtcTimestamp/TeensyRtcTimestamp.ino
  3. +13
    -4
      examples/TeensySdioDemo/TeensySdioDemo.ino
  4. +2
    -1
      examples/bench/bench.ino
  5. +1
    -1
      library.properties
  6. +1
    -0
      src/FreeStack.cpp
  7. +3
    -1
      src/FreeStack.h
  8. +1
    -0
      src/SdCard/CPPLINT.cfg
  9. +0
    -1
      src/SdCard/SdioCard.h
  10. +331
    -224
      src/SdCard/SdioTeensy.cpp
  11. +277
    -0
      src/SdCard/SdioTeensy.h
  12. +3
    -0
      src/SdFatConfig.h

+ 2
- 0
README.md View File

### Warning: This is an early beta version of SdFat Version 2. ### Warning: This is an early beta version of SdFat Version 2.


September 19, 2019 - added support for Teensy 4.0 SDIO.

This library is in early development and features may change. This library is in early development and features may change.
It will clearly have bugs. I am posting this version to get comments and It will clearly have bugs. I am posting this version to get comments and
help finding bugs/compatibility problems. help finding bugs/compatibility problems.

+ 1
- 1
examples/TeensyRtcTimestamp/TeensyRtcTimestamp.ino View File

// Test of time-stamp callback with Teensy3.
// Test of time-stamp callback with Teensy 3/4.
// The upload time will be used to set the RTC. // The upload time will be used to set the RTC.
// You must arrange for syncing the RTC. // You must arrange for syncing the RTC.
#include "SdFat.h" #include "SdFat.h"

+ 13
- 4
examples/TeensySdioDemo/TeensySdioDemo.ino View File

// Simple performance test for Teensy 3.5/3.6 SDHC.
// Simple performance test for Teensy 3.5/3.6 4.0 SDHC.
// Demonstrates yield() efficiency for SDIO modes. // Demonstrates yield() efficiency for SDIO modes.
// Uses built-in SD for SPI modes.
#include "SdFat.h" #include "SdFat.h"


// Use built-in SD for SPI modes on Teensy 3.5/3.6.
// Teensy 4.0 use first SPI port.
// SDCARD_SS_PIN is defined for the built-in SD on some boards.
#ifndef SDCARD_SS_PIN
const uint8_t SD_CS_PIN = SS;
#else // SDCARD_SS_PIN
// Assume built-in SD is used.
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#endif // SDCARD_SS_PIN

// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h, // SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT. // 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
#define SD_FAT_TYPE 3 #define SD_FAT_TYPE 3
} }
Serial.println("\nDMA SDIO mode - slow for small transfers."); Serial.println("\nDMA SDIO mode - slow for small transfers.");
} else if (c == '3') { } else if (c == '3') {
if (!sd.begin(SdSpiConfig(SDCARD_SS_PIN, DEDICATED_SPI, SD_SCK_MHZ(50)))) {
if (!sd.begin(SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SD_SCK_MHZ(50)))) {
errorHalt("begin failed"); errorHalt("begin failed");
} }
Serial.println("\nDedicated SPI mode."); Serial.println("\nDedicated SPI mode.");
} else if (c == '4') { } else if (c == '4') {
if (!sd.begin(SdSpiConfig(SDCARD_SS_PIN, SHARED_SPI, SD_SCK_MHZ(50)))) {
if (!sd.begin(SdSpiConfig(SD_CS_PIN, SHARED_SPI, SD_SCK_MHZ(50)))) {
errorHalt("begin failed"); errorHalt("begin failed");
} }
Serial.println("\nShared SPI mode - slow for small transfers."); Serial.println("\nShared SPI mode - slow for small transfers.");

+ 2
- 1
examples/bench/bench.ino View File

while (!Serial.available()) { while (!Serial.available()) {
SysCall::yield(); SysCall::yield();
} }
#if HAS_UNUSED_STACK
cout << F("FreeStack: ") << FreeStack() << endl; cout << F("FreeStack: ") << FreeStack() << endl;
#endif // HAS_UNUSED_STACK


if (!sd.begin(SD_CONFIG)) { if (!sd.begin(SD_CONFIG)) {
sd.initErrorHalt(&Serial); sd.initErrorHalt(&Serial);

+ 1
- 1
library.properties View File

name=SdFat name=SdFat
version=2.0.0-beta.2
version=2.0.0-beta.3
license=MIT license=MIT
author=Bill Greiman <fat16lib@sbcglobal.net> author=Bill Greiman <fat16lib@sbcglobal.net>
maintainer=Bill Greiman <fat16lib@sbcglobal.net> maintainer=Bill Greiman <fat16lib@sbcglobal.net>

+ 1
- 0
src/FreeStack.cpp View File

* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE. * DEALINGS IN THE SOFTWARE.
*/ */
#define FREE_STACK_CPP
#include "FreeStack.h" #include "FreeStack.h"
#if HAS_UNUSED_STACK #if HAS_UNUSED_STACK
#ifdef __AVR__ #ifdef __AVR__

+ 3
- 1
src/FreeStack.h View File

inline int FreeStack() { inline int FreeStack() {
return System.freeMemory(); return System.freeMemory();
} }
#elif defined(__arm__)
#elif defined(__arm__) && !defined(__IMXRT1062__)
#define HAS_UNUSED_STACK 1 #define HAS_UNUSED_STACK 1
extern "C" char* sbrk(int incr); extern "C" char* sbrk(int incr);
inline int FreeStack() { inline int FreeStack() {
return reinterpret_cast<char*>(sp) - reinterpret_cast<char*>(sbrk(0)); return reinterpret_cast<char*>(sp) - reinterpret_cast<char*>(sbrk(0));
} }
#else // defined(__AVR__) || defined(DOXYGEN) #else // defined(__AVR__) || defined(DOXYGEN)
#ifndef FREE_STACK_CPP
#warning FreeStack is not defined for this system. #warning FreeStack is not defined for this system.
#endif // FREE_STACK_CPP
inline int FreeStack() { inline int FreeStack() {
return 0; return 0;
} }

+ 1
- 0
src/SdCard/CPPLINT.cfg View File

exclude_files=SdioTeensy.h

+ 0
- 1
src/SdCard/SdioCard.h View File

static const uint8_t READ_STATE = 1; static const uint8_t READ_STATE = 1;
static const uint8_t WRITE_STATE = 2; static const uint8_t WRITE_STATE = 2;
uint32_t m_curSector; uint32_t m_curSector;
uint32_t m_limitSector;
SdioConfig m_sdioConfig; SdioConfig m_sdioConfig;
uint8_t m_curState; uint8_t m_curState;
}; };

+ 331
- 224
src/SdCard/SdioTeensy.cpp View File

* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE. * DEALINGS IN THE SOFTWARE.
*/ */
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1062__)
#include "SdioTeensy.h"
#include "SdCardInfo.h" #include "SdCardInfo.h"
#include "SdioCard.h" #include "SdioCard.h"
//==============================================================================
// limit of K66 due to errata KINETIS_K_0N65N. // limit of K66 due to errata KINETIS_K_0N65N.
const uint32_t MAX_SDHC_COUNT = 0XFFFF; const uint32_t MAX_SDHC_COUNT = 0XFFFF;


//============================================================================== //==============================================================================
#define SDHC_PROCTL_DTW_4BIT 0x01 #define SDHC_PROCTL_DTW_4BIT 0x01
const uint32_t FIFO_WML = 16; const uint32_t FIFO_WML = 16;
const uint32_t CMD8_RETRIES = 10;
const uint32_t CMD8_RETRIES = 3;
const uint32_t BUSY_TIMEOUT_MICROS = 1000000; const uint32_t BUSY_TIMEOUT_MICROS = 1000000;
//============================================================================== //==============================================================================
const uint32_t SDHC_IRQSTATEN_MASK = const uint32_t SDHC_IRQSTATEN_MASK =
SDHC_IRQSIGEN_DTOEIEN | SDHC_IRQSIGEN_CIEIEN | SDHC_IRQSIGEN_DTOEIEN | SDHC_IRQSIGEN_CIEIEN |
SDHC_IRQSIGEN_CEBEIEN | SDHC_IRQSIGEN_CCEIEN | SDHC_IRQSIGEN_CEBEIEN | SDHC_IRQSIGEN_CCEIEN |
SDHC_IRQSIGEN_CTOEIEN | SDHC_IRQSIGEN_TCIEN; SDHC_IRQSIGEN_CTOEIEN | SDHC_IRQSIGEN_TCIEN;
//=============================================================================
//==============================================================================
const uint32_t CMD_RESP_NONE = SDHC_XFERTYP_RSPTYP(0); const uint32_t CMD_RESP_NONE = SDHC_XFERTYP_RSPTYP(0);


const uint32_t CMD_RESP_R1 = SDHC_XFERTYP_CICEN | SDHC_XFERTYP_CCCEN | const uint32_t CMD_RESP_R1 = SDHC_XFERTYP_CICEN | SDHC_XFERTYP_CCCEN |


const uint32_t CMD_RESP_R7 = CMD_RESP_R1; const uint32_t CMD_RESP_R7 = CMD_RESP_R1;


#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
const uint32_t DATA_READ = SDHC_XFERTYP_DTDSEL | SDHC_XFERTYP_DPSEL; const uint32_t DATA_READ = SDHC_XFERTYP_DTDSEL | SDHC_XFERTYP_DPSEL;


const uint32_t DATA_READ_DMA = DATA_READ | SDHC_XFERTYP_DMAEN; const uint32_t DATA_READ_DMA = DATA_READ | SDHC_XFERTYP_DMAEN;
SDHC_XFERTYP_AC12EN | SDHC_XFERTYP_BCEN; SDHC_XFERTYP_AC12EN | SDHC_XFERTYP_BCEN;


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


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 DATA_WRITE_MULTI_PGM = SDHC_XFERTYP_DPSEL | SDHC_XFERTYP_MSBSEL |
SDHC_XFERTYP_BCEN;

#elif defined(__IMXRT1062__)
// Use low bits for SDHC_MIX_CTRL since bits 15-0 of SDHC_XFERTYP are reserved.
const uint32_t SDHC_MIX_CTRL_MASK = SDHC_MIX_CTRL_DMAEN | SDHC_MIX_CTRL_BCEN |
SDHC_MIX_CTRL_AC12EN |
SDHC_MIX_CTRL_DDR_EN |
SDHC_MIX_CTRL_DTDSEL |
SDHC_MIX_CTRL_MSBSEL |
SDHC_MIX_CTRL_NIBBLE_POS |
SDHC_MIX_CTRL_AC23EN;

const uint32_t DATA_READ = SDHC_MIX_CTRL_DTDSEL | SDHC_XFERTYP_DPSEL;

const uint32_t DATA_READ_DMA = DATA_READ | SDHC_MIX_CTRL_DMAEN;

const uint32_t DATA_READ_MULTI_DMA = DATA_READ_DMA | SDHC_MIX_CTRL_MSBSEL |
SDHC_MIX_CTRL_AC12EN | SDHC_MIX_CTRL_BCEN;

const uint32_t DATA_READ_MULTI_PGM = DATA_READ | SDHC_MIX_CTRL_MSBSEL;


const uint32_t DATA_WRITE_DMA = SDHC_XFERTYP_DPSEL | SDHC_MIX_CTRL_DMAEN;

const uint32_t DATA_WRITE_MULTI_DMA = DATA_WRITE_DMA | SDHC_MIX_CTRL_MSBSEL |
SDHC_MIX_CTRL_AC12EN | SDHC_MIX_CTRL_BCEN;

const uint32_t DATA_WRITE_MULTI_PGM = SDHC_XFERTYP_DPSEL | SDHC_MIX_CTRL_MSBSEL;

#endif // defined(__MK64FX512__) || defined(__MK66FX1M0__)


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 CMD55_XFERTYP = SDHC_XFERTYP_CMDINX(CMD55) | CMD_RESP_R1; const uint32_t CMD55_XFERTYP = SDHC_XFERTYP_CMDINX(CMD55) | CMD_RESP_R1;


//=============================================================================
//==============================================================================
static bool cardCommand(uint32_t xfertyp, uint32_t arg); static bool cardCommand(uint32_t xfertyp, uint32_t arg);
static void enableGPIO(bool enable); static void enableGPIO(bool enable);
static void enableDmaIrs(); static void enableDmaIrs();
static bool yieldTimeout(bool (*fcn)()); static bool yieldTimeout(bool (*fcn)());
static bool waitDmaStatus(); static bool waitDmaStatus();
static bool waitTimeout(bool (*fcn)()); static bool waitTimeout(bool (*fcn)());
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
static bool (*m_busyFcn)() = 0; static bool (*m_busyFcn)() = 0;
static bool m_initDone = false; static bool m_initDone = false;
static bool m_version2; static bool m_version2;
static uint32_t m_ocr; 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;
//=============================================================================
//==============================================================================
#define DBG_TRACE Serial.print("TRACE."); Serial.println(__LINE__); delay(200);
#define USE_DEBUG_MODE 0 #define USE_DEBUG_MODE 0
#if USE_DEBUG_MODE #if USE_DEBUG_MODE
#define DBG_IRQSTAT() if (SDHC_IRQSTAT) {Serial.print(__LINE__);\ #define DBG_IRQSTAT() if (SDHC_IRQSTAT) {Serial.print(__LINE__);\


static void printRegs(uint32_t line) { static void printRegs(uint32_t line) {
Serial.print(line); Serial.print(line);
Serial.print(" SDHC_BLKATTR ");
Serial.print(SDHC_BLKATTR, HEX);
Serial.print(" XFERTYP ");
Serial.print(SDHC_XFERTYP, HEX);
Serial.print(" PRSSTAT "); Serial.print(" PRSSTAT ");
Serial.print(SDHC_PRSSTAT, HEX); Serial.print(SDHC_PRSSTAT, HEX);
Serial.print(" PROCTL "); Serial.print(" PROCTL ");
#else // USE_DEBUG_MODE #else // USE_DEBUG_MODE
#define DBG_IRQSTAT() #define DBG_IRQSTAT()
#endif // USE_DEBUG_MODE #endif // USE_DEBUG_MODE
//=============================================================================
//==============================================================================
// Error function and macro. // 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; // setSdErrorCode
#if USE_DEBUG_MODE
printRegs(line);
#endif // USE_DEBUG_MODE
return false;
} }
//=============================================================================
//==============================================================================
// ISR // ISR
void sdhc_isr() {
static void sdIrs() {
SDHC_IRQSIGEN = 0; SDHC_IRQSIGEN = 0;
m_irqstat = SDHC_IRQSTAT; m_irqstat = SDHC_IRQSTAT;
SDHC_IRQSTAT = m_irqstat; SDHC_IRQSTAT = m_irqstat;
#if defined(__IMXRT1062__)
SDHC_MIX_CTRL &= ~(SDHC_MIX_CTRL_AC23EN | SDHC_MIX_CTRL_DMAEN);
#endif
m_dmaBusy = false; m_dmaBusy = false;
} }
//=============================================================================
//==============================================================================
// GPIO and clock functions.
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
//------------------------------------------------------------------------------
static void enableGPIO(bool enable) {
const uint32_t PORT_CLK = PORT_PCR_MUX(4) | PORT_PCR_DSE;
const uint32_t PORT_CMD_DATA = PORT_CLK | PORT_PCR_PE | PORT_PCR_PS;
const uint32_t PORT_PUP = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS;

PORTE_PCR0 = enable ? PORT_CMD_DATA : PORT_PUP; // SDHC_D1
PORTE_PCR1 = enable ? PORT_CMD_DATA : PORT_PUP; // SDHC_D0
PORTE_PCR2 = enable ? PORT_CLK : PORT_PUP; // SDHC_CLK
PORTE_PCR3 = enable ? PORT_CMD_DATA : PORT_PUP; // SDHC_CMD
PORTE_PCR4 = enable ? PORT_CMD_DATA : PORT_PUP; // SDHC_D3
PORTE_PCR5 = enable ? PORT_CMD_DATA : PORT_PUP; // SDHC_D2
}
//------------------------------------------------------------------------------
static void initClock() {
#ifdef HAS_KINETIS_MPU
// Allow SDHC Bus Master access.
MPU_RGDAAC0 |= 0x0C000000;
#endif // HAS_KINETIS_MPU
// Enable SDHC clock.
SIM_SCGC3 |= SIM_SCGC3_SDHC;
}
static uint32_t baseClock() { return F_CPU;}

#elif defined(__IMXRT1062__)
//------------------------------------------------------------------------------
static void gpioMux(uint8_t mode) {
IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_04 = mode; // DAT2
IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_05 = mode; // DAT3
IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_00 = mode; // CMD
IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_01 = mode; // CLK
IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_02 = mode; // DAT0
IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_03 = mode; // DAT1
}
//------------------------------------------------------------------------------
// add speed strength args?
static void enableGPIO(bool enable) {
const uint32_t CLOCK_MASK = IOMUXC_SW_PAD_CTL_PAD_PKE |
// IOMUXC_SW_PAD_CTL_PAD_DSE(1) |
IOMUXC_SW_PAD_CTL_PAD_DSE(4) | ///// WHG
IOMUXC_SW_PAD_CTL_PAD_SPEED(2);

const uint32_t DATA_MASK = CLOCK_MASK | IOMUXC_SW_PAD_CTL_PAD_PUE |
IOMUXC_SW_PAD_CTL_PAD_PUS(1);
if (enable) {
gpioMux(0);
IOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B0_04 = DATA_MASK; // DAT2
IOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B0_05 = DATA_MASK; // DAT3
IOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B0_00 = DATA_MASK; // CMD
IOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B0_01 = CLOCK_MASK; // CLK
IOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B0_02 = DATA_MASK; // DAT0
IOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B0_03 = DATA_MASK; // DAT1
} else {
gpioMux(5);
}
}
//------------------------------------------------------------------------------
static void initClock() {
/* set PDF_528 PLL2PFD0 */
CCM_ANALOG_PFD_528 |= (1 << 7);
CCM_ANALOG_PFD_528 &= ~(0x3F << 0);
CCM_ANALOG_PFD_528 |= ((24) & 0x3F << 0); // 12 - 35
CCM_ANALOG_PFD_528 &= ~(1 << 7);

/* Enable USDHC clock. */
CCM_CCGR6 |= CCM_CCGR6_USDHC1(CCM_CCGR_ON);
CCM_CSCDR1 &= ~(CCM_CSCDR1_USDHC1_CLK_PODF_MASK);
CCM_CSCMR1 |= CCM_CSCMR1_USDHC1_CLK_SEL; // PLL2PFD0
// CCM_CSCDR1 |= CCM_CSCDR1_USDHC1_CLK_PODF((7)); / &0x7 WHG
CCM_CSCDR1 |= CCM_CSCDR1_USDHC1_CLK_PODF((1));
}
//------------------------------------------------------------------------------
static uint32_t baseClock() {
uint32_t divider = ((CCM_CSCDR1 >> 11) & 0x7) + 1;
return (528000000U * 3)/((CCM_ANALOG_PFD_528 & 0x3F)/6)/divider;
}
#endif // defined(__MK64FX512__) || defined(__MK66FX1M0__)
//==============================================================================
// Static functions. // Static functions.
static bool cardAcmd(uint32_t rca, uint32_t xfertyp, uint32_t arg) { static bool cardAcmd(uint32_t rca, uint32_t xfertyp, uint32_t arg) {
return cardCommand(CMD55_XFERTYP, rca) && cardCommand (xfertyp, arg); return cardCommand(CMD55_XFERTYP, rca) && cardCommand (xfertyp, arg);
} }
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
static bool cardCommand(uint32_t xfertyp, uint32_t arg) { static bool cardCommand(uint32_t xfertyp, uint32_t arg) {
DBG_IRQSTAT(); DBG_IRQSTAT();
if (waitTimeout(isBusyCommandInhibit)) { if (waitTimeout(isBusyCommandInhibit)) {
return false; // Caller will set errorCode. return false; // Caller will set errorCode.
} }
SDHC_CMDARG = arg; SDHC_CMDARG = arg;
#if defined(__IMXRT1062__)
// Set MIX_CTRL if data transfer.
if (xfertyp & SDHC_XFERTYP_DPSEL) {
SDHC_MIX_CTRL &= ~SDHC_MIX_CTRL_MASK;
SDHC_MIX_CTRL |= xfertyp & SDHC_MIX_CTRL_MASK;
}
xfertyp &= ~SDHC_MIX_CTRL_MASK;
#endif // defined(__IMXRT1062__)
SDHC_XFERTYP = xfertyp; SDHC_XFERTYP = xfertyp;
if (waitTimeout(isBusyCommandComplete)) { if (waitTimeout(isBusyCommandComplete)) {
return false; // Caller will set errorCode. return false; // Caller will set errorCode.
return (m_irqstat & SDHC_IRQSTAT_CC) && return (m_irqstat & SDHC_IRQSTAT_CC) &&
!(m_irqstat & SDHC_IRQSTAT_CMD_ERROR); !(m_irqstat & SDHC_IRQSTAT_CMD_ERROR);
} }
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
static bool cardCMD6(uint32_t arg, uint8_t* status) { static bool cardCMD6(uint32_t arg, uint8_t* status) {
// CMD6 returns 64 bytes. // CMD6 returns 64 bytes.
if (waitTimeout(isBusyCMD13)) { if (waitTimeout(isBusyCMD13)) {
} }
enableDmaIrs(); enableDmaIrs();
SDHC_DSADDR = (uint32_t)status; SDHC_DSADDR = (uint32_t)status;
SDHC_CMDARG = arg;
SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(1) | SDHC_BLKATTR_BLKSIZE(64); SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(1) | SDHC_BLKATTR_BLKSIZE(64);
SDHC_IRQSIGEN = SDHC_IRQSIGEN_MASK; SDHC_IRQSIGEN = SDHC_IRQSIGEN_MASK;
SDHC_XFERTYP = CMD6_XFERTYP;

if (!waitDmaStatus()) {
if (!cardCommand(CMD6_XFERTYP, arg)) {
return sdError(SD_CARD_ERROR_CMD6); return sdError(SD_CARD_ERROR_CMD6);
} }
if (!waitDmaStatus()) {
return sdError(SD_CARD_ERROR_DMA);
}
return true; return true;
} }
//-----------------------------------------------------------------------------
static void enableGPIO(bool enable) {
const uint32_t PORT_CLK = PORT_PCR_MUX(4) | PORT_PCR_DSE;
const uint32_t PORT_CMD_DATA = PORT_CLK | PORT_PCR_PE | PORT_PCR_PS;
const uint32_t PORT_PUP = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS;

PORTE_PCR0 = enable ? PORT_CMD_DATA : PORT_PUP; // SDHC_D1
PORTE_PCR1 = enable ? PORT_CMD_DATA : PORT_PUP; // SDHC_D0
PORTE_PCR2 = enable ? PORT_CLK : PORT_PUP; // SDHC_CLK
PORTE_PCR3 = enable ? PORT_CMD_DATA : PORT_PUP; // SDHC_CMD
PORTE_PCR4 = enable ? PORT_CMD_DATA : PORT_PUP; // SDHC_D3
PORTE_PCR5 = enable ? PORT_CMD_DATA : PORT_PUP; // SDHC_D2
}
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
static void enableDmaIrs() { static void enableDmaIrs() {
m_dmaBusy = true; m_dmaBusy = true;
m_irqstat = 0; m_irqstat = 0;
} }
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
static void initSDHC() { static void initSDHC() {
#ifdef HAS_KINETIS_MPU
// Allow SDHC Bus Master access.
MPU_RGDAAC0 |= 0x0C000000;
#endif // HAS_KINETIS_MPU
// Enable SDHC clock.
SIM_SCGC3 |= SIM_SCGC3_SDHC;
initClock();


// Disable GPIO clock. // Disable GPIO clock.
enableGPIO(false); enableGPIO(false);


#if defined (__IMXRT1062__)
SDHC_MIX_CTRL |= 0x80000000;
#endif

// Reset SDHC. Use default Water Mark Level of 16. // Reset SDHC. Use default Water Mark Level of 16.
SDHC_SYSCTL = SDHC_SYSCTL_RSTA;
SDHC_SYSCTL |= SDHC_SYSCTL_RSTA | SDHC_SYSCTL_SDCLKFS(0x80);

while (SDHC_SYSCTL & SDHC_SYSCTL_RSTA) { while (SDHC_SYSCTL & SDHC_SYSCTL_RSTA) {
} }

// Set initial SCK rate. // Set initial SCK rate.
setSdclk(400); setSdclk(400);


// Enable desired IRQSTAT bits. // Enable desired IRQSTAT bits.
SDHC_IRQSTATEN = SDHC_IRQSTATEN_MASK; SDHC_IRQSTATEN = SDHC_IRQSTATEN_MASK;


attachInterruptVector(IRQ_SDHC, sdIrs);
NVIC_SET_PRIORITY(IRQ_SDHC, 6*16); NVIC_SET_PRIORITY(IRQ_SDHC, 6*16);
NVIC_ENABLE_IRQ(IRQ_SDHC); NVIC_ENABLE_IRQ(IRQ_SDHC);


while (SDHC_SYSCTL & SDHC_SYSCTL_INITA) { while (SDHC_SYSCTL & SDHC_SYSCTL_INITA) {
} }
} }
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
static uint32_t statusCMD13() { static uint32_t statusCMD13() {
return cardCommand(CMD13_XFERTYP, m_rca) ? SDHC_CMDRSP0 : 0; return cardCommand(CMD13_XFERTYP, m_rca) ? SDHC_CMDRSP0 : 0;
} }
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
static bool isBusyCMD13() { static bool isBusyCMD13() {
if (!cardCommand(CMD13_XFERTYP, m_rca)) { if (!cardCommand(CMD13_XFERTYP, m_rca)) {
// Caller will timeout. // Caller will timeout.
} }
return !(SDHC_CMDRSP0 & CARD_STATUS_READY_FOR_DATA); return !(SDHC_CMDRSP0 & CARD_STATUS_READY_FOR_DATA);
} }
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
static bool isBusyCommandComplete() { static bool isBusyCommandComplete() {
return !(SDHC_IRQSTAT &(SDHC_IRQSTAT_CC | SDHC_IRQSTAT_CMD_ERROR));
return !(SDHC_IRQSTAT & (SDHC_IRQSTAT_CC | SDHC_IRQSTAT_CMD_ERROR));
} }
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
static bool isBusyCommandInhibit() { static bool isBusyCommandInhibit() {
return SDHC_PRSSTAT & SDHC_PRSSTAT_CIHB; return SDHC_PRSSTAT & SDHC_PRSSTAT_CIHB;
} }
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
static bool isBusyDMA() { static bool isBusyDMA() {
return m_dmaBusy; return m_dmaBusy;
} }
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
static bool isBusyFifoRead() { static bool isBusyFifoRead() {
return !(SDHC_PRSSTAT & SDHC_PRSSTAT_BREN); return !(SDHC_PRSSTAT & SDHC_PRSSTAT_BREN);
} }
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
static bool isBusyFifoWrite() { static bool isBusyFifoWrite() {
return !(SDHC_PRSSTAT & SDHC_PRSSTAT_BWEN); return !(SDHC_PRSSTAT & SDHC_PRSSTAT_BWEN);
} }
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
static bool isBusyTransferComplete() { static bool isBusyTransferComplete() {
return !(SDHC_IRQSTAT & (SDHC_IRQSTAT_TC | SDHC_IRQSTAT_ERROR)); return !(SDHC_IRQSTAT & (SDHC_IRQSTAT_TC | SDHC_IRQSTAT_ERROR));
} }
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
static bool rdWrSectors(uint32_t xfertyp, static bool rdWrSectors(uint32_t xfertyp,
uint32_t sector, uint8_t* buf, size_t n) { uint32_t sector, uint8_t* buf, size_t n) {
if ((3 & (uint32_t)buf) || n == 0) { if ((3 & (uint32_t)buf) || n == 0) {
} }
enableDmaIrs(); enableDmaIrs();
SDHC_DSADDR = (uint32_t)buf; SDHC_DSADDR = (uint32_t)buf;
SDHC_CMDARG = m_highCapacity ? sector : 512*sector;
SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(n) | SDHC_BLKATTR_BLKSIZE(512); SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(n) | SDHC_BLKATTR_BLKSIZE(512);
SDHC_IRQSIGEN = SDHC_IRQSIGEN_MASK; SDHC_IRQSIGEN = SDHC_IRQSIGEN_MASK;
SDHC_XFERTYP = xfertyp;

if (!cardCommand(xfertyp, m_highCapacity ? sector : 512*sector)) {
return false;
}
return waitDmaStatus(); return waitDmaStatus();
} }
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Read 16 byte CID or CSD register. // Read 16 byte CID or CSD register.
static bool readReg16(uint32_t xfertyp, void* data) { static bool readReg16(uint32_t xfertyp, void* data) {
uint8_t* d = reinterpret_cast<uint8_t*>(data); uint8_t* d = reinterpret_cast<uint8_t*>(data);
d[15] = 0; d[15] = 0;
return true; return true;
} }
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
static void setSdclk(uint32_t kHzMax) { static void setSdclk(uint32_t kHzMax) {
const uint32_t DVS_LIMIT = 0X10; const uint32_t DVS_LIMIT = 0X10;
const uint32_t SDCLKFS_LIMIT = 0X100; const uint32_t SDCLKFS_LIMIT = 0X100;
uint32_t dvs = 1; uint32_t dvs = 1;
uint32_t sdclkfs = 1; uint32_t sdclkfs = 1;
uint32_t maxSdclk = 1000*kHzMax; uint32_t maxSdclk = 1000*kHzMax;
uint32_t base = baseClock();


while ((F_CPU/(sdclkfs*DVS_LIMIT) > maxSdclk) && (sdclkfs < SDCLKFS_LIMIT)) {
while ((base/(sdclkfs*DVS_LIMIT) > maxSdclk) && (sdclkfs < SDCLKFS_LIMIT)) {
sdclkfs <<= 1; sdclkfs <<= 1;
} }
while ((F_CPU/(sdclkfs*dvs) > maxSdclk) && (dvs < DVS_LIMIT)) {
while ((base/(sdclkfs*dvs) > maxSdclk) && (dvs < DVS_LIMIT)) {
dvs++; dvs++;
} }
m_sdClkKhz = F_CPU/(1000*sdclkfs*dvs);
m_sdClkKhz = base/(1000*sdclkfs*dvs);
sdclkfs >>= 1; sdclkfs >>= 1;
dvs--; dvs--;
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
// Disable SDHC clock. // Disable SDHC clock.
SDHC_SYSCTL &= ~SDHC_SYSCTL_SDCLKEN; SDHC_SYSCTL &= ~SDHC_SYSCTL_SDCLKEN;
#endif // defined(__MK64FX512__) || defined(__MK66FX1M0__)


// Change dividers. // Change dividers.
uint32_t sysctl = SDHC_SYSCTL & ~(SDHC_SYSCTL_DTOCV_MASK uint32_t sysctl = SDHC_SYSCTL & ~(SDHC_SYSCTL_DTOCV_MASK
// Wait until the SDHC clock is stable. // Wait until the SDHC clock is stable.
while (!(SDHC_PRSSTAT & SDHC_PRSSTAT_SDSTB)) { while (!(SDHC_PRSSTAT & SDHC_PRSSTAT_SDSTB)) {
} }

#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
// Enable the SDHC clock. // Enable the SDHC clock.
SDHC_SYSCTL |= SDHC_SYSCTL_SDCLKEN; SDHC_SYSCTL |= SDHC_SYSCTL_SDCLKEN;
#endif // defined(__MK64FX512__) || defined(__MK66FX1M0__)
} }
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
static bool transferStop() { static bool transferStop() {
DBG_IRQSTAT();

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

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

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

return true; return true;
} }
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Return true if timeout occurs. // Return true if timeout occurs.
static bool yieldTimeout(bool (*fcn)()) { static bool yieldTimeout(bool (*fcn)()) {
m_busyFcn = fcn; m_busyFcn = fcn;
m_busyFcn = 0; m_busyFcn = 0;
return false; // Caller will set errorCode. return false; // Caller will set errorCode.
} }
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
static bool waitDmaStatus() { static bool waitDmaStatus() {
if (yieldTimeout(isBusyDMA)) { if (yieldTimeout(isBusyDMA)) {
return false; // Caller will set errorCode. return false; // Caller will set errorCode.
} }
return (m_irqstat & SDHC_IRQSTAT_TC) && !(m_irqstat & SDHC_IRQSTAT_ERROR); return (m_irqstat & SDHC_IRQSTAT_TC) && !(m_irqstat & SDHC_IRQSTAT_ERROR);
} }
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Return true if timeout occurs. // Return true if timeout occurs.
static bool waitTimeout(bool (*fcn)()) { static bool waitTimeout(bool (*fcn)()) {
uint32_t m = micros(); uint32_t m = micros();
} }
return false; // Caller will set errorCode. return false; // Caller will set errorCode.
} }
//=============================================================================
//==============================================================================
// Start of SdioCard member functions.
//==============================================================================
bool SdioCard::begin(SdioConfig sdioConfig) { bool SdioCard::begin(SdioConfig sdioConfig) {
uint32_t kHzSdClk; uint32_t kHzSdClk;
uint32_t arg; uint32_t arg;


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

if (!cardCommand(CMD0_XFERTYP, 0)) { if (!cardCommand(CMD0_XFERTYP, 0)) {
return sdError(SD_CARD_ERROR_CMD0); return sdError(SD_CARD_ERROR_CMD0);
} }
} }
} }
arg = m_version2 ? 0X40300000 : 0x00300000; arg = m_version2 ? 0X40300000 : 0x00300000;
uint32_t m = micros();
int m = micros();
do { do {
if (!cardAcmd(0, ACMD41_XFERTYP, arg) || if (!cardAcmd(0, ACMD41_XFERTYP, arg) ||
((micros() - m) > BUSY_TIMEOUT_MICROS)) { ((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.
SDHC_WML = SDHC_WML_RDWML(FIFO_WML) | SDHC_WML_WRWML(FIFO_WML); SDHC_WML = SDHC_WML_RDWML(FIFO_WML) | SDHC_WML_WRWML(FIFO_WML);


// Determine if High Speed mode is supported and set frequency. // Determine if High Speed mode is supported and set frequency.
// Check status[16] for error 0XF or status[16] for new mode 0X1.
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) {
} else { } else {
kHzSdClk = 25000; kHzSdClk = 25000;
} }
// disable GPIO
// Disable GPIO.
enableGPIO(false); enableGPIO(false);


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


// enable GPIO
// Enable GPIO.
enableGPIO(true); enableGPIO(true);
m_initDone = true; m_initDone = true;
return true; return true;
} }
//-----------------------------------------------------------------------------
uint32_t SdioCard::sectorCount() {
return sdCardCapacity(&m_csd);
}
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool SdioCard::erase(uint32_t firstSector, uint32_t lastSector) { bool SdioCard::erase(uint32_t firstSector, uint32_t lastSector) {
// check for single sector erase // check for single sector erase
if (!m_csd.v1.erase_blk_en) { if (!m_csd.v1.erase_blk_en) {
} }
return true; return true;
} }
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
uint8_t SdioCard::errorCode() const { uint8_t SdioCard::errorCode() const {
return m_errorCode; return m_errorCode;
} }
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
uint32_t SdioCard::errorData() const { uint32_t SdioCard::errorData() const {
return m_irqstat; return m_irqstat;
} }
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
uint32_t SdioCard::errorLine() const { uint32_t SdioCard::errorLine() const {
return m_errorLine; return m_errorLine;
} }
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool SdioCard::isBusy() { bool SdioCard::isBusy() {
return m_busyFcn ? m_busyFcn() : m_initDone && isBusyCMD13(); return m_busyFcn ? m_busyFcn() : m_initDone && isBusyCMD13();
} }
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
uint32_t SdioCard::kHzSdClk() { uint32_t SdioCard::kHzSdClk() {
return m_sdClkKhz; return m_sdClkKhz;
} }
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool SdioCard::readCID(cid_t* cid) {
memcpy(cid, &m_cid, 16);
return true;
}
//------------------------------------------------------------------------------
bool SdioCard::readCSD(csd_t* csd) {
memcpy(csd, &m_csd, 16);
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;
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::readSector(uint32_t sector, uint8_t* dst) { bool SdioCard::readSector(uint32_t sector, uint8_t* dst) {
if (m_sdioConfig.useDma()) { if (m_sdioConfig.useDma()) {
uint8_t aligned[512]; uint8_t aligned[512];
uint8_t* ptr = (uint32_t)dst & 3 ? aligned : dst; uint8_t* ptr = (uint32_t)dst & 3 ? aligned : dst;


if (!rdWrSectors(CMD17_DMA_XFERTYP, sector, ptr, 1)) { if (!rdWrSectors(CMD17_DMA_XFERTYP, sector, ptr, 1)) {
return sdError(SD_CARD_ERROR_CMD18);
return sdError(SD_CARD_ERROR_CMD17);
} }
if (ptr != dst) { if (ptr != dst) {
memcpy(dst, aligned, 512); memcpy(dst, aligned, 512);
if (!syncDevice()) { if (!syncDevice()) {
return false; return false;
} }
m_limitSector = (sector + MAX_SDHC_COUNT) & ~RU_MASK;
if (!SdioCard::readStart(sector, m_limitSector - sector)) {
if (!readStart(sector)) {
return false; return false;
} }
m_curSector = sector; m_curSector = sector;
m_curState = READ_STATE; m_curState = READ_STATE;
} }
if (!SdioCard::readData(dst)) {
if (!readData(dst)) {
return false; return false;
} }
m_curSector++;
if (m_curSector >= m_limitSector) {
m_curState = IDLE_STATE;
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
if ((SDHC_BLKATTR & 0XFFFF0000) == 0) {
if (!syncDevice()) {
return false;
}
} }
#endif // defined(__MK64FX512__) || defined(__MK66FX1M0__)
m_curSector++;
} }
return true; return true;
} }
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool SdioCard::readSectors(uint32_t sector, uint8_t* dst, size_t n) { bool SdioCard::readSectors(uint32_t sector, uint8_t* dst, size_t n) {
if (m_sdioConfig.useDma()) { if (m_sdioConfig.useDma()) {
if ((uint32_t)dst & 3) { if ((uint32_t)dst & 3) {
} }
return true; return true;
} }
//-----------------------------------------------------------------------------
bool SdioCard::readCID(cid_t* cid) {
memcpy(cid, &m_cid, 16);
return true;
}
//-----------------------------------------------------------------------------
bool SdioCard::readCSD(csd_t* csd) {
memcpy(csd, &m_csd, 16);
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 sector gap if last sector. 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 sector) {
// K66/K65 Errata - SDHC: Does not support Infinite Sector Transfer Mode.
return sdError(SD_CARD_ERROR_FUNCTION_NOT_SUPPORTED);
}
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
// SDHC will do Auto CMD12 after count sectors. // SDHC will do Auto CMD12 after count sectors.
bool SdioCard::readStart(uint32_t sector, uint32_t count) {
bool SdioCard::readStart(uint32_t sector) {
DBG_IRQSTAT(); DBG_IRQSTAT();
if (count > 0XFFFF) {
return sdError(SD_CARD_ERROR_READ_START);
}
if (yieldTimeout(isBusyCMD13)) { if (yieldTimeout(isBusyCMD13)) {
return sdError(SD_CARD_ERROR_CMD13); return sdError(SD_CARD_ERROR_CMD13);
} }
if (count > 1) {
SDHC_PROCTL |= SDHC_PROCTL_SABGREQ;
}
SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(count) | SDHC_BLKATTR_BLKSIZE(512);
SDHC_PROCTL |= SDHC_PROCTL_SABGREQ;
#if defined(__IMXRT1062__)
// Infinite transfer.
SDHC_BLKATTR = SDHC_BLKATTR_BLKSIZE(512);
#else // defined(__IMXRT1062__)
// Errata - can't do infinite transfer.
SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(0XFFFF) | SDHC_BLKATTR_BLKSIZE(512);
#endif // defined(__IMXRT1062__)

if (!cardCommand(CMD18_PGM_XFERTYP, m_highCapacity ? sector : 512*sector)) { if (!cardCommand(CMD18_PGM_XFERTYP, m_highCapacity ? sector : 512*sector)) {
return sdError(SD_CARD_ERROR_CMD18); return sdError(SD_CARD_ERROR_CMD18);
} }
return true; return true;
} }
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool SdioCard::readStop() { bool SdioCard::readStop() {
return transferStop(); return transferStop();
} }
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
uint32_t SdioCard::sectorCount() {
return sdCardCapacity(&m_csd);
}
//------------------------------------------------------------------------------
uint32_t SdioCard::status() { uint32_t SdioCard::status() {
return statusCMD13(); return statusCMD13();
} }
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool SdioCard::syncDevice() { bool SdioCard::syncDevice() {
if (m_curState == READ_STATE) { if (m_curState == READ_STATE) {
m_curState = IDLE_STATE; m_curState = IDLE_STATE;
if (!SdioCard::readStop()) {
if (!readStop()) {
return false; return false;
} }
} else if (m_curState == WRITE_STATE) { } else if (m_curState == WRITE_STATE) {
m_curState = IDLE_STATE; m_curState = IDLE_STATE;
if (!SdioCard::writeStop()) {
if (!writeStop()) {
return false; return false;
} }
} }
SD_CARD_TYPE_SDHC : SD_CARD_TYPE_SD2 : SD_CARD_TYPE_SD1; SD_CARD_TYPE_SDHC : SD_CARD_TYPE_SD2 : SD_CARD_TYPE_SD1;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
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;
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::writeSector(uint32_t sector, const uint8_t* src) { bool SdioCard::writeSector(uint32_t sector, const uint8_t* src) {
if (m_sdioConfig.useDma()) { if (m_sdioConfig.useDma()) {
uint8_t *ptr; uint8_t *ptr;
} else { } else {
ptr = const_cast<uint8_t*>(src); ptr = const_cast<uint8_t*>(src);
} }
if (!rdWrSectors(CMD24_DMA_XFERTYP, sector, ptr, 1)) {
if (!rdWrSectors(CMD24_DMA_XFERTYP, sector, ptr, 1)) {
return sdError(SD_CARD_ERROR_CMD24); return sdError(SD_CARD_ERROR_CMD24);
} }
} else { } else {
if (!syncDevice()) { if (!syncDevice()) {
return false; return false;
} }
m_limitSector = (sector + MAX_SDHC_COUNT) & ~RU_MASK;
if (!SdioCard::writeStart(sector , m_limitSector - sector)) {
if (!writeStart(sector )) {
return false; return false;
} }
m_curSector = sector; m_curSector = sector;
m_curState = WRITE_STATE; m_curState = WRITE_STATE;
} }
if (!SdioCard::writeData(src)) {
if (!writeData(src)) {
return false; return false;
} }
m_curSector++; m_curSector++;
if (m_curSector >= m_limitSector) {
m_curState = IDLE_STATE;
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
// End transfer with CMD12 if required.
if ((SDHC_BLKATTR & 0XFFFF0000) == 0) {
if (!syncDevice()) {
return false;
}
} }
#endif // defined(__MK64FX512__) || defined(__MK66FX1M0__)
} }
return true; return true;
} }
return sdError(SD_CARD_ERROR_CMD25); return sdError(SD_CARD_ERROR_CMD25);
} }
} else { } else {
for (size_t i = 0; i < n; i++) {
if (!writeSector(sector + i, src + i*512UL)) {
return false;
for (size_t i = 0; i < n; i++) {
if (!writeSector(sector + i, src + i*512UL)) {
return false;
}
} }
} }
}
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 sector gap if last sector. 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 sector) { bool SdioCard::writeStart(uint32_t sector) {
// K66/K65 Errata - SDHC: Does not support Infinite Sector Transfer Mode.
return sdError(SD_CARD_ERROR_FUNCTION_NOT_SUPPORTED);
}
//-----------------------------------------------------------------------------
// SDHC will do Auto CMD12 after count sectors.
bool SdioCard::writeStart(uint32_t sector, uint32_t count) {
if (count > 0XFFFF) {
return sdError(SD_CARD_ERROR_WRITE_START);
}
DBG_IRQSTAT();
if (yieldTimeout(isBusyCMD13)) { if (yieldTimeout(isBusyCMD13)) {
return sdError(SD_CARD_ERROR_CMD13); return sdError(SD_CARD_ERROR_CMD13);
} }
if (count > 1) {
SDHC_PROCTL |= SDHC_PROCTL_SABGREQ;
}
SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(count) | SDHC_BLKATTR_BLKSIZE(512);
SDHC_PROCTL &= ~SDHC_PROCTL_SABGREQ;


#if defined(__IMXRT1062__)
// Infinite transfer.
SDHC_BLKATTR = SDHC_BLKATTR_BLKSIZE(512);
#else // defined(__IMXRT1062__)
// Errata - can't do infinite transfer.
SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(0XFFFF) | SDHC_BLKATTR_BLKSIZE(512);
#endif // defined(__IMXRT1062__)
if (!cardCommand(CMD25_PGM_XFERTYP, m_highCapacity ? sector : 512*sector)) { if (!cardCommand(CMD25_PGM_XFERTYP, m_highCapacity ? sector : 512*sector)) {
return sdError(SD_CARD_ERROR_CMD25); return sdError(SD_CARD_ERROR_CMD25);
} }
return true; return true;
} }
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool SdioCard::writeStop() { bool SdioCard::writeStop() {
return transferStop(); return transferStop();
} }
#endif // defined(__MK64FX512__) || defined(__MK66FX1M0__)
#endif // defined(__MK64FX512__) defined(__MK66FX1M0__) defined(__IMXRT1062__)

+ 277
- 0
src/SdCard/SdioTeensy.h View File

#ifndef SdioTeensy_h
#define SdioTeensy_h

// From Paul's SD.h driver.

#if defined(__IMXRT1062__)
#define MAKE_REG_MASK(m,s) (((uint32_t)(((uint32_t)(m) << s))))
#define MAKE_REG_GET(x,m,s) (((uint32_t)(((uint32_t)(x)>>s) & m)))
#define MAKE_REG_SET(x,m,s) (((uint32_t)(((uint32_t)(x) & m) << s)))

#define SDHC_BLKATTR_BLKSIZE_MASK MAKE_REG_MASK(0x1FFF,0) //uint32_t)(((n) & 0x1FFF)<<0) // Transfer Block Size Mask
#define SDHC_BLKATTR_BLKSIZE(n) MAKE_REG_SET(n,0x1FFF,0) //uint32_t)(((n) & 0x1FFF)<<0) // Transfer Block Size
#define SDHC_BLKATTR_BLKCNT_MASK MAKE_REG_MASK(0x1FFF,16) //((uint32_t)0x1FFF<<16)
#define SDHC_BLKATTR_BLKCNT(n) MAKE_REG_SET(n,0x1FFF,16) //(uint32_t)(((n) & 0x1FFF)<<16) // Blocks Count For Current Transfer

#define SDHC_XFERTYP_CMDINX(n) MAKE_REG_SET(n,0x3F,24) //(uint32_t)(((n) & 0x3F)<<24)// Command Index
#define SDHC_XFERTYP_CMDTYP(n) MAKE_REG_SET(n,0x3,22) //(uint32_t)(((n) & 0x3)<<22) // Command Type
#define SDHC_XFERTYP_DPSEL MAKE_REG_MASK(0x1,21) //((uint32_t)0x00200000) // Data Present Select
#define SDHC_XFERTYP_CICEN MAKE_REG_MASK(0x1,20) //((uint32_t)0x00100000) // Command Index Check Enable
#define SDHC_XFERTYP_CCCEN MAKE_REG_MASK(0x1,19) //((uint32_t)0x00080000) // Command CRC Check Enable
#define SDHC_XFERTYP_RSPTYP(n) MAKE_REG_SET(n,0x3,16) //(uint32_t)(((n) & 0x3)<<16) // Response Type Select
#define SDHC_XFERTYP_MSBSEL MAKE_REG_MASK(0x1,5) //((uint32_t)0x00000020) // Multi/Single Block Select
#define SDHC_XFERTYP_DTDSEL MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Data Transfer Direction Select
#define SDHC_XFERTYP_AC12EN MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004) // Auto CMD12 Enable
#define SDHC_XFERTYP_BCEN MAKE_REG_MASK(0x1,1) //((uint32_t)0x00000002) // Block Count Enable
#define SDHC_XFERTYP_DMAEN MAKE_REG_MASK(0x3,0) //((uint32_t)0x00000001) // DMA Enable

#define SDHC_PRSSTAT_DLSL_MASK MAKE_REG_MASK(0xFF,24) //((uint32_t)0xFF000000) // DAT Line Signal Level
#define SDHC_PRSSTAT_CLSL MAKE_REG_MASK(0x1,23) //((uint32_t)0x00800000) // CMD Line Signal Level
#define SDHC_PRSSTAT_WPSPL MAKE_REG_MASK(0x1,19) //
#define SDHC_PRSSTAT_CDPL MAKE_REG_MASK(0x1,18) //
#define SDHC_PRSSTAT_CINS MAKE_REG_MASK(0x1,16) //((uint32_t)0x00010000) // Card Inserted
#define SDHC_PRSSTAT_TSCD MAKE_REG_MASK(0x1,15)
#define SDHC_PRSSTAT_RTR MAKE_REG_MASK(0x1,12)
#define SDHC_PRSSTAT_BREN MAKE_REG_MASK(0x1,11) //((uint32_t)0x00000800) // Buffer Read Enable
#define SDHC_PRSSTAT_BWEN MAKE_REG_MASK(0x1,10) //((uint32_t)0x00000400) // Buffer Write Enable
#define SDHC_PRSSTAT_RTA MAKE_REG_MASK(0x1,9) //((uint32_t)0x00000200) // Read Transfer Active
#define SDHC_PRSSTAT_WTA MAKE_REG_MASK(0x1,8) //((uint32_t)0x00000100) // Write Transfer Active
#define SDHC_PRSSTAT_SDOFF MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // SD Clock Gated Off Internally
#define SDHC_PRSSTAT_PEROFF MAKE_REG_MASK(0x1,6) //((uint32_t)0x00000040) // SDHC clock Gated Off Internally
#define SDHC_PRSSTAT_HCKOFF MAKE_REG_MASK(0x1,5) //((uint32_t)0x00000020) // System Clock Gated Off Internally
#define SDHC_PRSSTAT_IPGOFF MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Bus Clock Gated Off Internally
#define SDHC_PRSSTAT_SDSTB MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008) // SD Clock Stable
#define SDHC_PRSSTAT_DLA MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004) // Data Line Active
#define SDHC_PRSSTAT_CDIHB MAKE_REG_MASK(0x1,1) //((uint32_t)0x00000002) // Command Inhibit (DAT)
#define SDHC_PRSSTAT_CIHB MAKE_REG_MASK(0x1,0) //((uint32_t)0x00000001) // Command Inhibit (CMD)

#define SDHC_PROTCT_NONEXACT_BLKRD MAKE_REG_MASK(0x1,30) //
#define SDHC_PROTCT_BURST_LENEN(n) MAKE_REG_SET(n,0x7,12) //
#define SDHC_PROCTL_WECRM MAKE_REG_MASK(0x1,26) //((uint32_t)0x04000000) // Wakeup Event Enable On SD Card Removal
#define SDHC_PROCTL_WECINS MAKE_REG_MASK(0x1,25) //((uint32_t)0x02000000) // Wakeup Event Enable On SD Card Insertion
#define SDHC_PROCTL_WECINT MAKE_REG_MASK(0x1,24) //((uint32_t)0x01000000) // Wakeup Event Enable On Card Interrupt
#define SDHC_PROCTL_RD_DONE_NOBLK MAKE_REG_MASK(0x1,20) //
#define SDHC_PROCTL_IABG MAKE_REG_MASK(0x1,19) //((uint32_t)0x00080000) // Interrupt At Block Gap
#define SDHC_PROCTL_RWCTL MAKE_REG_MASK(0x1,18) //((uint32_t)0x00040000) // Read Wait Control
#define SDHC_PROCTL_CREQ MAKE_REG_MASK(0x1,17) //((uint32_t)0x00020000) // Continue Request
#define SDHC_PROCTL_SABGREQ MAKE_REG_MASK(0x1,16) //((uint32_t)0x00010000) // Stop At Block Gap Request
#define SDHC_PROCTL_DMAS(n) MAKE_REG_SET(n,0x3,8) //(uint32_t)(((n) & 0x3)<<8) // DMA Select
#define SDHC_PROCTL_CDSS MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // Card Detect Signal Selection
#define SDHC_PROCTL_CDTL MAKE_REG_MASK(0x1,6) //((uint32_t)0x00000040) // Card Detect Test Level
#define SDHC_PROCTL_EMODE(n) MAKE_REG_SET(n,0x3,4) //(uint32_t)(((n) & 0x3)<<4) // Endian Mode
#define SDHC_PROCTL_EMODE_MASK MAKE_REG_MASK(0x3,4) //(uint32_t)((0x3)<<4) // Endian Mode
#define SDHC_PROCTL_D3CD MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008) // DAT3 As Card Detection Pin
#define SDHC_PROCTL_DTW(n) MAKE_REG_SET(n,0x3,1) //(uint32_t)(((n) & 0x3)<<1) // Data Transfer Width, 0=1bit, 1=4bit, 2=8bit
#define SDHC_PROCTL_DTW_MASK MAKE_REG_MASK(0x3,1) //((uint32_t)0x00000006)
#define SDHC_PROCTL_LCTL MAKE_REG_MASK(0x1,0) //((uint32_t)0x00000001) // LED Control

#define SDHC_SYSCTL_RSTT MAKE_REG_MASK(0x1,28) //
#define SDHC_SYSCTL_INITA MAKE_REG_MASK(0x1,27) //((uint32_t)0x08000000) // Initialization Active
#define SDHC_SYSCTL_RSTD MAKE_REG_MASK(0x1,26) //((uint32_t)0x04000000) // Software Reset For DAT Line
#define SDHC_SYSCTL_RSTC MAKE_REG_MASK(0x1,25) //((uint32_t)0x02000000) // Software Reset For CMD Line
#define SDHC_SYSCTL_RSTA MAKE_REG_MASK(0x1,24) //((uint32_t)0x01000000) // Software Reset For ALL
#define SDHC_SYSCTL_DTOCV(n) MAKE_REG_SET(n,0xF,16) //(uint32_t)(((n) & 0xF)<<16) // Data Timeout Counter Value
#define SDHC_SYSCTL_DTOCV_MASK MAKE_REG_MASK(0xF,16) //((uint32_t)0x000F0000)
#define SDHC_SYSCTL_SDCLKFS(n) MAKE_REG_SET(n,0xFF,8) //(uint32_t)(((n) & 0xFF)<<8) // SDCLK Frequency Select
#define SDHC_SYSCTL_SDCLKFS_MASK MAKE_REG_MASK(0xFF,8) //((uint32_t)0x0000FF00)
#define SDHC_SYSCTL_DVS(n) MAKE_REG_SET(n,0xF,4) //(uint32_t)(((n) & 0xF)<<4) // Divisor
#define SDHC_SYSCTL_DVS_MASK MAKE_REG_MASK(0xF,4) //((uint32_t)0x000000F0)

#define SDHC_SYSCTL_SDCLKEN ((uint32_t)0x00000008) // SD Clock Enable
#define SDHC_SYSCTL_PEREN ((uint32_t)0x00000004) // Peripheral Clock Enable
#define SDHC_SYSCTL_HCKEN ((uint32_t)0x00000002) // System Clock Enable
#define SDHC_SYSCTL_IPGEN ((uint32_t)0x00000001) // IPG Clock Enable

#define SDHC_IRQSTAT_DMAE MAKE_REG_MASK(0x1,28) //((uint32_t)0x10000000) // DMA Error
#define SDHC_IRQSTAT_TNE MAKE_REG_MASK(0x1,26) //
#define SDHC_IRQSTAT_AC12E MAKE_REG_MASK(0x1,24) //((uint32_t)0x01000000) // Auto CMD12 Error
#define SDHC_IRQSTAT_DEBE MAKE_REG_MASK(0x1,22) //((uint32_t)0x00400000) // Data End Bit Error
#define SDHC_IRQSTAT_DCE MAKE_REG_MASK(0x1,21) //((uint32_t)0x00200000) // Data CRC Error
#define SDHC_IRQSTAT_DTOE MAKE_REG_MASK(0x1,20) //((uint32_t)0x00100000) // Data Timeout Error
#define SDHC_IRQSTAT_CIE MAKE_REG_MASK(0x1,19) //((uint32_t)0x00080000) // Command Index Error
#define SDHC_IRQSTAT_CEBE MAKE_REG_MASK(0x1,18) //((uint32_t)0x00040000) // Command End Bit Error
#define SDHC_IRQSTAT_CCE MAKE_REG_MASK(0x1,17) //((uint32_t)0x00020000) // Command CRC Error
#define SDHC_IRQSTAT_CTOE MAKE_REG_MASK(0x1,16) //((uint32_t)0x00010000) // Command Timeout Error
#define SDHC_IRQSTAT_TP MAKE_REG_MASK(0x1,14) //
#define SDHC_IRQSTAT_RTE MAKE_REG_MASK(0x1,12) //
#define SDHC_IRQSTAT_CINT MAKE_REG_MASK(0x1,8) //((uint32_t)0x00000100) // Card Interrupt
#define SDHC_IRQSTAT_CRM MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // Card Removal
#define SDHC_IRQSTAT_CINS MAKE_REG_MASK(0x1,6) //((uint32_t)0x00000040) // Card Insertion
#define SDHC_IRQSTAT_BRR MAKE_REG_MASK(0x1,5) //((uint32_t)0x00000020) // Buffer Read Ready
#define SDHC_IRQSTAT_BWR MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Buffer Write Ready
#define SDHC_IRQSTAT_DINT MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008) // DMA Interrupt
#define SDHC_IRQSTAT_BGE MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004) // Block Gap Event
#define SDHC_IRQSTAT_TC MAKE_REG_MASK(0x1,1) //((uint32_t)0x00000002) // Transfer Complete
#define SDHC_IRQSTAT_CC MAKE_REG_MASK(0x1,0) //((uint32_t)0x00000001) // Command Complete

#define SDHC_IRQSTATEN_DMAESEN MAKE_REG_MASK(0x1,28) //((uint32_t)0x10000000) // DMA Error Status Enable
#define SDHC_IRQSTATEN_TNESEN MAKE_REG_MASK(0x1,26) //
#define SDHC_IRQSTATEN_AC12ESEN MAKE_REG_MASK(0x1,24) //((uint32_t)0x01000000) // Auto CMD12 Error Status Enable
#define SDHC_IRQSTATEN_DEBESEN MAKE_REG_MASK(0x1,22) //((uint32_t)0x00400000) // Data End Bit Error Status Enable
#define SDHC_IRQSTATEN_DCESEN MAKE_REG_MASK(0x1,21) //((uint32_t)0x00200000) // Data CRC Error Status Enable
#define SDHC_IRQSTATEN_DTOESEN MAKE_REG_MASK(0x1,20) //((uint32_t)0x00100000) // Data Timeout Error Status Enable
#define SDHC_IRQSTATEN_CIESEN MAKE_REG_MASK(0x1,19) //((uint32_t)0x00080000) // Command Index Error Status Enable
#define SDHC_IRQSTATEN_CEBESEN MAKE_REG_MASK(0x1,18) //((uint32_t)0x00040000) // Command End Bit Error Status Enable
#define SDHC_IRQSTATEN_CCESEN MAKE_REG_MASK(0x1,17) //((uint32_t)0x00020000) // Command CRC Error Status Enable
#define SDHC_IRQSTATEN_CTOESEN MAKE_REG_MASK(0x1,16) //((uint32_t)0x00010000) // Command Timeout Error Status Enable
#define SDHC_IRQSTATEN_TPSEN MAKE_REG_MASK(0x1,14) //
#define SDHC_IRQSTATEN_RTESEN MAKE_REG_MASK(0x1,12) //
#define SDHC_IRQSTATEN_CINTSEN MAKE_REG_MASK(0x1,8) //((uint32_t)0x00000100) // Card Interrupt Status Enable
#define SDHC_IRQSTATEN_CRMSEN MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // Card Removal Status Enable
#define SDHC_IRQSTATEN_CINSEN MAKE_REG_MASK(0x1,6) //((uint32_t)0x00000040) // Card Insertion Status Enable
#define SDHC_IRQSTATEN_BRRSEN MAKE_REG_MASK(0x1,5) //((uint32_t)0x00000020) // Buffer Read Ready Status Enable
#define SDHC_IRQSTATEN_BWRSEN MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Buffer Write Ready Status Enable
#define SDHC_IRQSTATEN_DINTSEN MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008) // DMA Interrupt Status Enable
#define SDHC_IRQSTATEN_BGESEN MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004) // Block Gap Event Status Enable
#define SDHC_IRQSTATEN_TCSEN MAKE_REG_MASK(0x1,1) //((uint32_t)0x00000002) // Transfer Complete Status Enable
#define SDHC_IRQSTATEN_CCSEN MAKE_REG_MASK(0x1,0) //((uint32_t)0x00000001) // Command Complete Status Enable

#define SDHC_IRQSIGEN_DMAEIEN MAKE_REG_MASK(0x1,28) //((uint32_t)0x10000000) // DMA Error Interrupt Enable
#define SDHC_IRQSIGEN_TNEIEN MAKE_REG_MASK(0x1,26) //
#define SDHC_IRQSIGEN_AC12EIEN MAKE_REG_MASK(0x1,24) //((uint32_t)0x01000000) // Auto CMD12 Error Interrupt Enable
#define SDHC_IRQSIGEN_DEBEIEN MAKE_REG_MASK(0x1,22) //((uint32_t)0x00400000) // Data End Bit Error Interrupt Enable
#define SDHC_IRQSIGEN_DCEIEN MAKE_REG_MASK(0x1,21) //((uint32_t)0x00200000) // Data CRC Error Interrupt Enable
#define SDHC_IRQSIGEN_DTOEIEN MAKE_REG_MASK(0x1,20) //((uint32_t)0x00100000) // Data Timeout Error Interrupt Enable
#define SDHC_IRQSIGEN_CIEIEN MAKE_REG_MASK(0x1,19) //((uint32_t)0x00080000) // Command Index Error Interrupt Enable
#define SDHC_IRQSIGEN_CEBEIEN MAKE_REG_MASK(0x1,18) //((uint32_t)0x00040000) // Command End Bit Error Interrupt Enable
#define SDHC_IRQSIGEN_CCEIEN MAKE_REG_MASK(0x1,17) //((uint32_t)0x00020000) // Command CRC Error Interrupt Enable
#define SDHC_IRQSIGEN_CTOEIEN MAKE_REG_MASK(0x1,16) //((uint32_t)0x00010000) // Command Timeout Error Interrupt Enable
#define SDHC_IRQSIGEN_TPIEN MAKE_REG_MASK(0x1,14) //
#define SDHC_IRQSIGEN_RTEIEN MAKE_REG_MASK(0x1,12) //
#define SDHC_IRQSIGEN_CINTIEN MAKE_REG_MASK(0x1,8) //((uint32_t)0x00000100) // Card Interrupt Interrupt Enable
#define SDHC_IRQSIGEN_CRMIEN MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // Card Removal Interrupt Enable
#define SDHC_IRQSIGEN_CINSIEN MAKE_REG_MASK(0x1,6) //((uint32_t)0x00000040) // Card Insertion Interrupt Enable
#define SDHC_IRQSIGEN_BRRIEN MAKE_REG_MASK(0x1,5) //((uint32_t)0x00000020) // Buffer Read Ready Interrupt Enable
#define SDHC_IRQSIGEN_BWRIEN MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Buffer Write Ready Interrupt Enable
#define SDHC_IRQSIGEN_DINTIEN MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008) // DMA Interrupt Interrupt Enable
#define SDHC_IRQSIGEN_BGEIEN MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004) // Block Gap Event Interrupt Enable
#define SDHC_IRQSIGEN_TCIEN MAKE_REG_MASK(0x1,1) //((uint32_t)0x00000002) // Transfer Complete Interrupt Enable
#define SDHC_IRQSIGEN_CCIEN MAKE_REG_MASK(0x1,0) //((uint32_t)0x00000001) // Command Complete Interrupt Enable

#define SDHC_AC12ERR_SMPLCLK_SEL MAKE_REG_MASK(0x1,23) //
#define SDHC_AC12ERR_EXEC_TUNING MAKE_REG_MASK(0x1,22) //
#define SDHC_AC12ERR_CNIBAC12E MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // Command Not Issued By Auto CMD12 Error
#define SDHC_AC12ERR_AC12IE MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Auto CMD12 Index Error
#define SDHC_AC12ERR_AC12CE MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008) // Auto CMD12 CRC Error
#define SDHC_AC12ERR_AC12EBE MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004) // Auto CMD12 End Bit Error
#define SDHC_AC12ERR_AC12TOE MAKE_REG_MASK(0x1,1) //((uint32_t)0x00000002) // Auto CMD12 Timeout Error
#define SDHC_AC12ERR_AC12NE MAKE_REG_MASK(0x1,0) //((uint32_t)0x00000001) // Auto CMD12 Not Executed

#define SDHC_HTCAPBLT_VS18 MAKE_REG_MASK(0x1,26) //
#define SDHC_HTCAPBLT_VS30 MAKE_REG_MASK(0x1,25) //
#define SDHC_HTCAPBLT_VS33 MAKE_REG_MASK(0x1,24) //
#define SDHC_HTCAPBLT_SRS MAKE_REG_MASK(0x1,23) //
#define SDHC_HTCAPBLT_DMAS MAKE_REG_MASK(0x1,22) //
#define SDHC_HTCAPBLT_HSS MAKE_REG_MASK(0x1,21) //
#define SDHC_HTCAPBLT_ADMAS MAKE_REG_MASK(0x1,20) //
#define SDHC_HTCAPBLT_MBL_VAL MAKE_REG_GET((USDHC1_HOST_CTRL_CAP),0x7,16) //
#define SDHC_HTCAPBLT_RETUN_MODE MAKE_REG_GET((USDHC1_HOST_CTRL_CAP),0x3,14) //
#define SDHC_HTCAPBLT_TUNE_SDR50 MAKE_REG_MASK(0x1,13) //
#define SDHC_HTCAPBLT_TIME_RETUN(n) MAKE_REG_SET(n,0xF,8) //

#define SDHC_WML_WR_BRSTLEN_MASK MAKE_REG_MASK(0x1F,24) //
#define SDHC_WML_RD_BRSTLEN_MASK MAKE_REG_MASK(0x1F,8) //
#define SDHC_WML_WR_WML_MASK MAKE_REG_MASK(0xFF,16) //
#define SDHC_WML_RD_WML_MASK MAKE_REG_MASK(0xFF,0) //
#define SDHC_WML_WR_BRSTLEN(n) MAKE_REG_SET(n,0x1F,24) //(uint32_t)(((n) & 0x7F)<<16) // Write Burst Len
#define SDHC_WML_RD_BRSTLEN(n) MAKE_REG_SET(n,0x1F,8) //(uint32_t)(((n) & 0x7F)<<0) // Read Burst Len
#define SDHC_WML_WR_WML(n) MAKE_REG_SET(n,0xFF,16) //(uint32_t)(((n) & 0x7F)<<16) // Write Watermark Level
#define SDHC_WML_RD_WML(n) MAKE_REG_SET(n,0xFF,0) //(uint32_t)(((n) & 0x7F)<<0) // Read Watermark Level
#define SDHC_WML_WRWML(n) MAKE_REG_SET(n,0xFF,16) //(uint32_t)(((n) & 0x7F)<<16) // Write Watermark Level
#define SDHC_WML_RDWML(n) MAKE_REG_SET(n,0xFF,0) //(uint32_t)(((n) & 0x7F)<<0) // Read Watermark Level

// Teensy 4.0 only
#define SDHC_MIX_CTRL_DMAEN MAKE_REG_MASK(0x1,0) //
#define SDHC_MIX_CTRL_BCEN MAKE_REG_MASK(0x1,1) //
#define SDHC_MIX_CTRL_AC12EN MAKE_REG_MASK(0x1,2) //
#define SDHC_MIX_CTRL_DDR_EN MAKE_REG_MASK(0x1,3) //
#define SDHC_MIX_CTRL_DTDSEL MAKE_REG_MASK(0x1,4) //
#define SDHC_MIX_CTRL_MSBSEL MAKE_REG_MASK(0x1,5) //
#define SDHC_MIX_CTRL_NIBBLE_POS MAKE_REG_MASK(0x1,6) //
#define SDHC_MIX_CTRL_AC23EN MAKE_REG_MASK(0x1,7) //

#define SDHC_FEVT_CINT MAKE_REG_MASK(0x1,31) //((uint32_t)0x80000000) // Force Event Card Interrupt
#define SDHC_FEVT_DMAE MAKE_REG_MASK(0x1,28) //((uint32_t)0x10000000) // Force Event DMA Error
#define SDHC_FEVT_AC12E MAKE_REG_MASK(0x1,24) //((uint32_t)0x01000000) // Force Event Auto CMD12 Error
#define SDHC_FEVT_DEBE MAKE_REG_MASK(0x1,22) //((uint32_t)0x00400000) // Force Event Data End Bit Error
#define SDHC_FEVT_DCE MAKE_REG_MASK(0x1,21) //((uint32_t)0x00200000) // Force Event Data CRC Error
#define SDHC_FEVT_DTOE MAKE_REG_MASK(0x1,20) //((uint32_t)0x00100000) // Force Event Data Timeout Error
#define SDHC_FEVT_CIE MAKE_REG_MASK(0x1,19) //((uint32_t)0x00080000) // Force Event Command Index Error
#define SDHC_FEVT_CEBE MAKE_REG_MASK(0x1,18) //((uint32_t)0x00040000) // Force Event Command End Bit Error
#define SDHC_FEVT_CCE MAKE_REG_MASK(0x1,17) //((uint32_t)0x00020000) // Force Event Command CRC Error
#define SDHC_FEVT_CTOE MAKE_REG_MASK(0x1,16) //((uint32_t)0x00010000) // Force Event Command Timeout Error
#define SDHC_FEVT_CNIBAC12E MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // Force Event Command Not Executed By Auto Command 12 Error
#define SDHC_FEVT_AC12IE MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Force Event Auto Command 12 Index Error
#define SDHC_FEVT_AC12EBE MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008) // Force Event Auto Command 12 End Bit Error
#define SDHC_FEVT_AC12CE MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004) // Force Event Auto Command 12 CRC Error
#define SDHC_FEVT_AC12TOE MAKE_REG_MASK(0x1,1) //((uint32_t)0x00000002) // Force Event Auto Command 12 Time Out Error
#define SDHC_FEVT_AC12NE MAKE_REG_MASK(0x1,0) //((uint32_t)0x00000001) // Force Event Auto Command 12 Not Executed

#define SDHC_ADMAES_ADMADCE MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008)
#define SDHC_ADMAES_ADMALME MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004)
#define SDHC_ADMAES_ADMAES_MASK MAKE_REG_MASK(0x3,0) //((uint32_t)0x00000003)

#define SDHC_MMCBOOT_BOOTBLKCNT(n) MAKE_REG_MASK(0xFF,16) //(uint32_t)(((n) & 0xFFF)<<16) // stop at block gap value of automatic mode
#define SDHC_MMCBOOT_AUTOSABGEN MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // enable auto stop at block gap function
#define SDHC_MMCBOOT_BOOTEN MAKE_REG_MASK(0x1,6) //((uint32_t)0x00000040) // Boot Mode Enable
#define SDHC_MMCBOOT_BOOTMODE MAKE_REG_MASK(0x1,5) //((uint32_t)0x00000020) // Boot Mode Select
#define SDHC_MMCBOOT_BOOTACK MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Boot Ack Mode Select
#define SDHC_MMCBOOT_DTOCVACK(n) MAKE_REG_MASK(0xF,0) //(uint32_t)(((n) & 0xF)<<0) // Boot ACK Time Out Counter Value
//#define SDHC_HOSTVER (*(volatile uint32_t *)0x400B10FC) // Host Controller Version

#define CCM_ANALOG_PFD_528_PFD0_FRAC_MASK 0x3f
#define CCM_ANALOG_PFD_528_PFD0_FRAC(n) ((n) & CCM_ANALOG_PFD_528_PFD0_FRAC_MASK)
#define CCM_ANALOG_PFD_528_PFD1_FRAC_MASK (0x3f<<8)
#define CCM_ANALOG_PFD_528_PFD1_FRAC(n) (((n)<<8) & CCM_ANALOG_PFD_528_PFD1_FRAC_MASK)
#define CCM_ANALOG_PFD_528_PFD2_FRAC_MASK (0x3f<<16)
#define CCM_ANALOG_PFD_528_PFD2_FRAC(n) (((n)<<16) & CCM_ANALOG_PFD_528_PFD2_FRAC_MASK)
#define CCM_ANALOG_PFD_528_PFD3_FRAC_MASK ((0x3f<<24)
#define CCM_ANALOG_PFD_528_PFD3_FRAC(n) (((n)<<24) & CCM_ANALOG_PFD_528_PFD3_FRAC_MASK)

#define SDHC_DSADDR (USDHC1_DS_ADDR ) // DMA System Address register
#define SDHC_BLKATTR (USDHC1_BLK_ATT) // Block Attributes register
#define SDHC_CMDARG (USDHC1_CMD_ARG) // Command Argument register
#define SDHC_XFERTYP (USDHC1_CMD_XFR_TYP) // Transfer Type register
#define SDHC_CMDRSP0 (USDHC1_CMD_RSP0) // Command Response 0
#define SDHC_CMDRSP1 (USDHC1_CMD_RSP1) // Command Response 1
#define SDHC_CMDRSP2 (USDHC1_CMD_RSP2) // Command Response 2
#define SDHC_CMDRSP3 (USDHC1_CMD_RSP3) // Command Response 3
#define SDHC_DATPORT (USDHC1_DATA_BUFF_ACC_PORT) // Buffer Data Port register
#define SDHC_PRSSTAT (USDHC1_PRES_STATE) // Present State register
#define SDHC_PROCTL (USDHC1_PROT_CTRL) // Protocol Control register
#define SDHC_SYSCTL (USDHC1_SYS_CTRL) // System Control register
#define SDHC_IRQSTAT (USDHC1_INT_STATUS) // Interrupt Status register
#define SDHC_IRQSTATEN (USDHC1_INT_STATUS_EN) // Interrupt Status Enable register
#define SDHC_IRQSIGEN (USDHC1_INT_SIGNAL_EN) // Interrupt Signal Enable register
#define SDHC_AC12ERR (USDHC1_AUTOCMD12_ERR_STATUS) // Auto CMD12 Error Status Register
#define SDHC_HTCAPBLT (USDHC1_HOST_CTRL_CAP) // Host Controller Capabilities
#define SDHC_WML (USDHC1_WTMK_LVL) // Watermark Level Register
#define SDHC_MIX_CTRL (USDHC1_MIX_CTRL) // Mixer Control
#define SDHC_FEVT (USDHC1_FORCE_EVENT) // Force Event register
#define SDHC_ADMAES (USDHC1_ADMA_ERR_STATUS) // ADMA Error Status register
#define SDHC_ADSADDR (USDHC1_ADMA_SYS_ADDR) // ADMA System Addressregister
#define SDHC_VENDOR (USDHC1_VEND_SPEC) // Vendor Specific register
#define SDHC_MMCBOOT (USDHC1_MMC_BOOT) // MMC Boot register
#define SDHC_VENDOR2 (USDHC2_VEND_SPEC2) // Vendor Specific2 register
//
#define IRQ_SDHC IRQ_SDHC1

#define SDHC_MAX_DVS (0xF + 1U)
#define SDHC_MAX_CLKFS (0xFF + 1U)
#define SDHC_PREV_DVS(x) ((x) -= 1U)
#define SDHC_PREV_CLKFS(x, y) ((x) >>= (y))

#define CCM_CSCDR1_USDHC1_CLK_PODF_MASK (0x7<<11)
#define CCM_CSCDR1_USDHC1_CLK_PODF(n) (((n)&0x7)<<11)

#define IOMUXC_SW_PAD_CTL_PAD_SRE ((0x1<)<0)
#define IOMUXC_SW_PAD_CTL_PAD_PKE ((0x1)<<12)
#define IOMUXC_SW_PAD_CTL_PAD_PUE ((0x1)<<13)
#define IOMUXC_SW_PAD_CTL_PAD_HYS ((0x1)<<16)
#define IOMUXC_SW_PAD_CTL_PAD_SPEED(n) (((n)&0x3)<<6)
#define IOMUXC_SW_PAD_CTL_PAD_PUS(n) (((n)&0x3)<<14)
#define IOMUXC_SW_PAD_CTL_PAD_PUS_MASK ((0x3)<<14)
#define IOMUXC_SW_PAD_CTL_PAD_DSE(n) (((n)&0x7)<<3)
#define IOMUXC_SW_PAD_CTL_PAD_DSE_MASK ((0x7)<<3)
#endif // defined(__IMXRT1062__)
#endif // SdioTeensy_h

+ 3
- 0
src/SdFatConfig.h View File

#endif // SDCARD_SPI #endif // SDCARD_SPI
#define HAS_SDIO_CLASS 1 #define HAS_SDIO_CLASS 1
#endif // defined(__MK64FX512__) || defined(__MK66FX1M0__) #endif // defined(__MK64FX512__) || defined(__MK66FX1M0__)
#if defined(__IMXRT1062__)
#define HAS_SDIO_CLASS 1
#endif // defined(__IMXRT1062__)
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** /**
* Determine the default SPI configuration. * Determine the default SPI configuration.

Loading…
Cancel
Save