|
|
|
|
|
|
|
|
* 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__) |