|  |  | @@ -20,21 +20,17 @@ | 
		
	
		
			
			|  |  |  | #if defined(__MK64FX512__) || defined(__MK66FX1M0__) | 
		
	
		
			
			|  |  |  | #include "SdioCard.h" | 
		
	
		
			
			|  |  |  | //============================================================================== | 
		
	
		
			
			|  |  |  | #ifndef SDHC_WML_RDWML_MASK | 
		
	
		
			
			|  |  |  | #define SDHC_WML_RDWML_MASK                 (0XFFU) | 
		
	
		
			
			|  |  |  | #endif | 
		
	
		
			
			|  |  |  | #ifndef SDHC_WML_RDWML_SHIFT | 
		
	
		
			
			|  |  |  | #define SDHC_WML_RDWML_SHIFT                (0U) | 
		
	
		
			
			|  |  |  | #endif | 
		
	
		
			
			|  |  |  | #define SDHC_PROCTL_DTW_4BIT                0x01 | 
		
	
		
			
			|  |  |  | #define SDHC_PROCTL_DTW_4BIT 0x01 | 
		
	
		
			
			|  |  |  | const uint32_t FIFO_WML = 16; | 
		
	
		
			
			|  |  |  | const uint32_t CMD8_RETRIES = 10; | 
		
	
		
			
			|  |  |  | const uint32_t BUSY_TIMEOUT_MICROS = 500000; | 
		
	
		
			
			|  |  |  | //============================================================================== | 
		
	
		
			
			|  |  |  | const uint32_t SDHC_IRQSTATEN_MASK = | 
		
	
		
			
			|  |  |  | SDHC_IRQSTATEN_DMAESEN | SDHC_IRQSTATEN_AC12ESEN | | 
		
	
		
			
			|  |  |  | SDHC_IRQSTATEN_DEBESEN | SDHC_IRQSTATEN_DCESEN | | 
		
	
		
			
			|  |  |  | SDHC_IRQSTATEN_DTOESEN | SDHC_IRQSTATEN_CIESEN | | 
		
	
		
			
			|  |  |  | SDHC_IRQSTATEN_CEBESEN | SDHC_IRQSTATEN_CCESEN | | 
		
	
		
			
			|  |  |  | SDHC_IRQSTATEN_CTOESEN | SDHC_IRQSTATEN_BRRSEN | | 
		
	
		
			
			|  |  |  | SDHC_IRQSTATEN_BWRSEN  | SDHC_IRQSTATEN_DINTSEN | | 
		
	
		
			
			|  |  |  | SDHC_IRQSTATEN_CTOESEN | SDHC_IRQSTATEN_DINTSEN | | 
		
	
		
			
			|  |  |  | SDHC_IRQSTATEN_TCSEN | SDHC_IRQSTATEN_CCSEN; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | const uint32_t SDHC_IRQSTAT_CMD_ERROR = | 
		
	
	
		
			
			|  |  | @@ -79,11 +75,18 @@ const uint32_t DATA_READ_DMA = DATA_READ | SDHC_XFERTYP_DMAEN; | 
		
	
		
			
			|  |  |  | const uint32_t DATA_READ_MULTI_DMA = DATA_READ_DMA | SDHC_XFERTYP_MSBSEL | | 
		
	
		
			
			|  |  |  | SDHC_XFERTYP_AC12EN | SDHC_XFERTYP_BCEN; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | const uint32_t DATA_READ_MULTI_PGM = DATA_READ | SDHC_XFERTYP_MSBSEL | | 
		
	
		
			
			|  |  |  | SDHC_XFERTYP_BCEN | SDHC_XFERTYP_AC12EN; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | const uint32_t DATA_WRITE_DMA = SDHC_XFERTYP_DPSEL | SDHC_XFERTYP_DMAEN; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | const uint32_t DATA_WRITE_MULTI_DMA = DATA_WRITE_DMA | SDHC_XFERTYP_MSBSEL | | 
		
	
		
			
			|  |  |  | SDHC_XFERTYP_AC12EN | SDHC_XFERTYP_BCEN; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | const uint32_t DATA_WRITE_MULTI_PGM = SDHC_XFERTYP_DPSEL | | 
		
	
		
			
			|  |  |  | SDHC_XFERTYP_MSBSEL | | 
		
	
		
			
			|  |  |  | SDHC_XFERTYP_BCEN | SDHC_XFERTYP_AC12EN; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | const uint32_t ACMD6_XFERTYP = SDHC_XFERTYP_CMDINX(ACMD6) | CMD_RESP_R1; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | const uint32_t ACMD41_XFERTYP = SDHC_XFERTYP_CMDINX(ACMD41) | CMD_RESP_R3; | 
		
	
	
		
			
			|  |  | @@ -105,19 +108,28 @@ const uint32_t CMD9_XFERTYP = SDHC_XFERTYP_CMDINX(CMD9) | CMD_RESP_R2; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | const uint32_t CMD10_XFERTYP = SDHC_XFERTYP_CMDINX(CMD10) | CMD_RESP_R2; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | const uint32_t CMD12_XFERTYP = SDHC_XFERTYP_CMDINX(CMD12) | CMD_RESP_R1b | | 
		
	
		
			
			|  |  |  | SDHC_XFERTYP_CMDTYP(3); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | const uint32_t CMD13_XFERTYP = SDHC_XFERTYP_CMDINX(CMD13) | CMD_RESP_R1; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | const uint32_t CMD17_XFERTYP = SDHC_XFERTYP_CMDINX(CMD17) | CMD_RESP_R1 | | 
		
	
		
			
			|  |  |  | DATA_READ_DMA; | 
		
	
		
			
			|  |  |  | const uint32_t CMD17_DMA_XFERTYP = SDHC_XFERTYP_CMDINX(CMD17) | CMD_RESP_R1 | | 
		
	
		
			
			|  |  |  | DATA_READ_DMA; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | const uint32_t CMD18_DMA_XFERTYP = SDHC_XFERTYP_CMDINX(CMD18) | CMD_RESP_R1 | | 
		
	
		
			
			|  |  |  | DATA_READ_MULTI_DMA; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | const uint32_t CMD18_PGM_XFERTYP = SDHC_XFERTYP_CMDINX(CMD18) | CMD_RESP_R1 | | 
		
	
		
			
			|  |  |  | DATA_READ_MULTI_PGM; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | const uint32_t CMD18_XFERTYP = SDHC_XFERTYP_CMDINX(CMD18) |  CMD_RESP_R1 | | 
		
	
		
			
			|  |  |  | DATA_READ_MULTI_DMA; | 
		
	
		
			
			|  |  |  | const uint32_t CMD24_DMA_XFERTYP = SDHC_XFERTYP_CMDINX(CMD24) | CMD_RESP_R1 | | 
		
	
		
			
			|  |  |  | DATA_WRITE_DMA; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | const uint32_t CMD24_XFERTYP = SDHC_XFERTYP_CMDINX(CMD24) | CMD_RESP_R1 | | 
		
	
		
			
			|  |  |  | DATA_WRITE_DMA; | 
		
	
		
			
			|  |  |  | const uint32_t CMD25_DMA_XFERTYP = SDHC_XFERTYP_CMDINX(CMD25) | CMD_RESP_R1 | | 
		
	
		
			
			|  |  |  | DATA_WRITE_MULTI_DMA; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | const uint32_t CMD25_XFERTYP = SDHC_XFERTYP_CMDINX(CMD25) | CMD_RESP_R1 | | 
		
	
		
			
			|  |  |  | DATA_WRITE_MULTI_DMA; | 
		
	
		
			
			|  |  |  | const uint32_t CMD25_PGM_XFERTYP = SDHC_XFERTYP_CMDINX(CMD25) | CMD_RESP_R1 | | 
		
	
		
			
			|  |  |  | DATA_WRITE_MULTI_PGM; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | const uint32_t CMD32_XFERTYP = SDHC_XFERTYP_CMDINX(CMD32) | CMD_RESP_R1; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
	
		
			
			|  |  | @@ -126,49 +138,109 @@ const uint32_t CMD33_XFERTYP = SDHC_XFERTYP_CMDINX(CMD33) | CMD_RESP_R1; | 
		
	
		
			
			|  |  |  | const uint32_t CMD38_XFERTYP = SDHC_XFERTYP_CMDINX(CMD38) | CMD_RESP_R1b; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | const uint32_t CMD55_XFERTYP = SDHC_XFERTYP_CMDINX(CMD55) | CMD_RESP_R1; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | //============================================================================= | 
		
	
		
			
			|  |  |  | static bool isBusy(); | 
		
	
		
			
			|  |  |  | static bool cardCommand(uint32_t xfertyp, uint32_t arg); | 
		
	
		
			
			|  |  |  | static void enableGPIO(bool enable); | 
		
	
		
			
			|  |  |  | static void enableDmaIrs(); | 
		
	
		
			
			|  |  |  | static void initSDHC(); | 
		
	
		
			
			|  |  |  | static bool isBusyCMD13(); | 
		
	
		
			
			|  |  |  | static bool isBusyCommandComplete(); | 
		
	
		
			
			|  |  |  | static bool isBusyCommandInhibit(); | 
		
	
		
			
			|  |  |  | static bool readReg16(uint32_t xfertyp, void* data); | 
		
	
		
			
			|  |  |  | static void setSdclk(uint32_t kHzMax); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | static uint8_t m_errorCode = SD_CARD_ERROR_INIT_NOT_CALLED; | 
		
	
		
			
			|  |  |  | static uint32_t m_errorLine = 0; | 
		
	
		
			
			|  |  |  | static bool yieldTimeout(bool (*fcn)()); | 
		
	
		
			
			|  |  |  | static bool waitDmaStatus(); | 
		
	
		
			
			|  |  |  | static bool waitTimeout(bool (*fcn)()); | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | static bool (*m_busyFcn)() = 0; | 
		
	
		
			
			|  |  |  | static bool m_initDone = false; | 
		
	
		
			
			|  |  |  | static bool m_version2; | 
		
	
		
			
			|  |  |  | static bool m_highCapacity; | 
		
	
		
			
			|  |  |  | static uint8_t m_errorCode = SD_CARD_ERROR_INIT_NOT_CALLED; | 
		
	
		
			
			|  |  |  | static uint32_t m_errorLine = 0; | 
		
	
		
			
			|  |  |  | static uint32_t m_rca; | 
		
	
		
			
			|  |  |  | bool m_waitCmd13 = false; | 
		
	
		
			
			|  |  |  | static volatile bool m_dmaDone = true; | 
		
	
		
			
			|  |  |  | static volatile bool m_dmaBusy = false; | 
		
	
		
			
			|  |  |  | static volatile uint32_t m_irqstat; | 
		
	
		
			
			|  |  |  | static uint32_t m_sdClkKhz = 0; | 
		
	
		
			
			|  |  |  | static uint32_t m_ocr; | 
		
	
		
			
			|  |  |  | static cid_t m_cid; | 
		
	
		
			
			|  |  |  | static csd_t m_csd; | 
		
	
		
			
			|  |  |  | static uint32_t m_ocr; | 
		
	
		
			
			|  |  |  | //============================================================================= | 
		
	
		
			
			|  |  |  | // Debug and error macros. | 
		
	
		
			
			|  |  |  | #define USE_DEBUG_MODE 0 | 
		
	
		
			
			|  |  |  | #if USE_DEBUG_MODE | 
		
	
		
			
			|  |  |  | #define DBG_IRQSTAT() if (SDHC_IRQSTAT) {Serial.print(__LINE__);\ | 
		
	
		
			
			|  |  |  | Serial.print(" IRQSTAT "); Serial.println(SDHC_IRQSTAT, HEX);} | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | static void printRegs(uint32_t line) { | 
		
	
		
			
			|  |  |  | Serial.print(line); | 
		
	
		
			
			|  |  |  | Serial.print(" PRSSTAT "); | 
		
	
		
			
			|  |  |  | Serial.print(SDHC_PRSSTAT, HEX); | 
		
	
		
			
			|  |  |  | Serial.print(" PROCTL "); | 
		
	
		
			
			|  |  |  | Serial.print(SDHC_PROCTL, HEX); | 
		
	
		
			
			|  |  |  | Serial.print(" IRQSTAT "); | 
		
	
		
			
			|  |  |  | Serial.print(SDHC_IRQSTAT, HEX); | 
		
	
		
			
			|  |  |  | Serial.print(" m_irqstat "); | 
		
	
		
			
			|  |  |  | Serial.println(m_irqstat, HEX); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | #else  // USE_DEBUG_MODE | 
		
	
		
			
			|  |  |  | #define DBG_IRQSTAT() | 
		
	
		
			
			|  |  |  | #endif  // USE_DEBUG_MODE | 
		
	
		
			
			|  |  |  | //============================================================================= | 
		
	
		
			
			|  |  |  | // Error function and macro. | 
		
	
		
			
			|  |  |  | #define sdError(code) setSdErrorCode(code, __LINE__) | 
		
	
		
			
			|  |  |  | inline bool setSdErrorCode(uint8_t code, uint32_t line) { | 
		
	
		
			
			|  |  |  | m_errorCode = code; | 
		
	
		
			
			|  |  |  | m_errorLine = line; | 
		
	
		
			
			|  |  |  | return false; | 
		
	
		
			
			|  |  |  | return false;  // setSdErrorCode | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //============================================================================= | 
		
	
		
			
			|  |  |  | // ISR | 
		
	
		
			
			|  |  |  | void sdhc_isr() { | 
		
	
		
			
			|  |  |  | SDHC_IRQSIGEN = 0; | 
		
	
		
			
			|  |  |  | m_irqstat = SDHC_IRQSTAT; | 
		
	
		
			
			|  |  |  | SDHC_IRQSTAT = m_irqstat; | 
		
	
		
			
			|  |  |  | m_dmaDone = true; | 
		
	
		
			
			|  |  |  | m_dmaBusy = false; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //============================================================================= | 
		
	
		
			
			|  |  |  | // Static functions. | 
		
	
		
			
			|  |  |  | static bool cardAcmd(uint32_t rca, uint32_t xfertyp, uint32_t arg) { | 
		
	
		
			
			|  |  |  | return cardCommand(CMD55_XFERTYP, rca) && cardCommand (xfertyp, arg); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | static void enableDmaIrs() { | 
		
	
		
			
			|  |  |  | m_dmaDone = false; | 
		
	
		
			
			|  |  |  | m_irqstat = 0; | 
		
	
		
			
			|  |  |  | static bool cardCommand(uint32_t xfertyp, uint32_t arg) { | 
		
	
		
			
			|  |  |  | DBG_IRQSTAT(); | 
		
	
		
			
			|  |  |  | if (waitTimeout(isBusyCommandInhibit)) { | 
		
	
		
			
			|  |  |  | return false;  // Caller will set errorCode. | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | SDHC_CMDARG = arg; | 
		
	
		
			
			|  |  |  | SDHC_XFERTYP = xfertyp; | 
		
	
		
			
			|  |  |  | if (waitTimeout(isBusyCommandComplete)) { | 
		
	
		
			
			|  |  |  | return false;  // Caller will set errorCode. | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | m_irqstat = SDHC_IRQSTAT; | 
		
	
		
			
			|  |  |  | SDHC_IRQSTAT = m_irqstat; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | return (m_irqstat & SDHC_IRQSTAT_CC) && | 
		
	
		
			
			|  |  |  | !(m_irqstat & SDHC_IRQSTAT_CMD_ERROR); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | static bool waitDmaStatus() { | 
		
	
		
			
			|  |  |  | while (!m_dmaDone) { | 
		
	
		
			
			|  |  |  | yield(); | 
		
	
		
			
			|  |  |  | static bool cardCMD6(uint32_t arg, uint8_t* status) { | 
		
	
		
			
			|  |  |  | // CMD6 returns 64 bytes. | 
		
	
		
			
			|  |  |  | if (waitTimeout(isBusyCMD13)) { | 
		
	
		
			
			|  |  |  | return sdError(SD_CARD_ERROR_CMD13); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | return (m_irqstat & SDHC_IRQSTAT_TC) && !(m_irqstat & SDHC_IRQSTAT_ERROR); | 
		
	
		
			
			|  |  |  | enableDmaIrs(); | 
		
	
		
			
			|  |  |  | SDHC_DSADDR  = (uint32_t)status; | 
		
	
		
			
			|  |  |  | SDHC_CMDARG = arg; | 
		
	
		
			
			|  |  |  | SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(1) | SDHC_BLKATTR_BLKSIZE(64); | 
		
	
		
			
			|  |  |  | SDHC_IRQSIGEN = SDHC_IRQSIGEN_MASK; | 
		
	
		
			
			|  |  |  | SDHC_XFERTYP = CMD6_XFERTYP; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | if (!waitDmaStatus()) { | 
		
	
		
			
			|  |  |  | return sdError(SD_CARD_ERROR_CMD6); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | return true; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | static void enableGPIO(bool enable) { | 
		
	
	
		
			
			|  |  | @@ -183,7 +255,12 @@ static void enableGPIO(bool enable) { | 
		
	
		
			
			|  |  |  | PORTE_PCR5 = enable ? PORT_CMD_DATA : 0;  // SDHC_D2 | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | static void SDHC_Init() { | 
		
	
		
			
			|  |  |  | static void enableDmaIrs() { | 
		
	
		
			
			|  |  |  | m_dmaBusy = true; | 
		
	
		
			
			|  |  |  | m_irqstat = 0; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | static void initSDHC() { | 
		
	
		
			
			|  |  |  | #ifdef HAS_KINETIS_MPU | 
		
	
		
			
			|  |  |  | // Allow SDHC Bus Master access. | 
		
	
		
			
			|  |  |  | MPU_RGDAAC0 |= 0x0C000000; | 
		
	
	
		
			
			|  |  | @@ -215,16 +292,46 @@ static void SDHC_Init() { | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | static bool isBusyCMD13() { | 
		
	
		
			
			|  |  |  | if (!cardCommand(CMD13_XFERTYP, m_rca)) { | 
		
	
		
			
			|  |  |  | // Caller will timeout. | 
		
	
		
			
			|  |  |  | return true; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | return !(SDHC_CMDRSP0 & CARD_STATUS_READY_FOR_DATA); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | static bool isBusyCommandComplete() { | 
		
	
		
			
			|  |  |  | return !(SDHC_IRQSTAT &(SDHC_IRQSTAT_CC | SDHC_IRQSTAT_CMD_ERROR)); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | static bool isBusyCommandInhibit() { | 
		
	
		
			
			|  |  |  | return SDHC_PRSSTAT & SDHC_PRSSTAT_CIHB; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | static bool isBusyDMA() { | 
		
	
		
			
			|  |  |  | return m_dmaBusy; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | static bool isBusyFifoRead() { | 
		
	
		
			
			|  |  |  | return !(SDHC_PRSSTAT & SDHC_PRSSTAT_BREN); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | static bool isBusyFifoWrite() { | 
		
	
		
			
			|  |  |  | return !(SDHC_PRSSTAT & SDHC_PRSSTAT_BWEN); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | static bool isBusyTransferComplete() { | 
		
	
		
			
			|  |  |  | return !(SDHC_IRQSTAT & (SDHC_IRQSTAT_TC | SDHC_IRQSTAT_ERROR)); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | static bool rdWrBlocks(uint32_t xfertyp, | 
		
	
		
			
			|  |  |  | uint32_t lba, uint8_t* buf, size_t n) { | 
		
	
		
			
			|  |  |  | if ((3 & (uint32_t)buf) || n == 0) { | 
		
	
		
			
			|  |  |  | return sdError(SD_CARD_ERROR_DMA); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | m_waitCmd13 = true; | 
		
	
		
			
			|  |  |  | while (isBusy()) { | 
		
	
		
			
			|  |  |  | yield(); | 
		
	
		
			
			|  |  |  | if (yieldTimeout(isBusyCMD13)) { | 
		
	
		
			
			|  |  |  | return sdError(SD_CARD_ERROR_CMD13); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | m_waitCmd13 = false; | 
		
	
		
			
			|  |  |  | enableDmaIrs(); | 
		
	
		
			
			|  |  |  | SDHC_DSADDR  = (uint32_t)buf; | 
		
	
		
			
			|  |  |  | SDHC_CMDARG = m_highCapacity ? lba : 512*lba; | 
		
	
	
		
			
			|  |  | @@ -235,30 +342,18 @@ static bool rdWrBlocks(uint32_t xfertyp, | 
		
	
		
			
			|  |  |  | return waitDmaStatus(); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | static bool cardCommand(uint32_t xfertyp, uint32_t arg) { | 
		
	
		
			
			|  |  |  | SDHC_CMDARG = arg; | 
		
	
		
			
			|  |  |  | SDHC_XFERTYP = xfertyp; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | do { | 
		
	
		
			
			|  |  |  | m_irqstat = SDHC_IRQSTAT; | 
		
	
		
			
			|  |  |  | } while (!(m_irqstat & (SDHC_IRQSTAT_CC | SDHC_IRQSTAT_CMD_ERROR))); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | SDHC_IRQSTAT = m_irqstat; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | return (m_irqstat & SDHC_IRQSTAT_CC) && | 
		
	
		
			
			|  |  |  | !(m_irqstat & SDHC_IRQSTAT_CMD_ERROR); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //------------------------------------------------------------------------------ | 
		
	
		
			
			|  |  |  | static bool cardAcmd(uint32_t rca, uint32_t xfertyp, uint32_t arg) { | 
		
	
		
			
			|  |  |  | return cardCommand(CMD55_XFERTYP, rca) && cardCommand (xfertyp, arg); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | static bool isBusy() { | 
		
	
		
			
			|  |  |  | if (!cardCommand(CMD13_XFERTYP, m_rca)) { | 
		
	
		
			
			|  |  |  | // Should have timeout in caller? | 
		
	
		
			
			|  |  |  | return true; | 
		
	
		
			
			|  |  |  | // Read 16 byte CID or CSD register. | 
		
	
		
			
			|  |  |  | static bool readReg16(uint32_t xfertyp, void* data) { | 
		
	
		
			
			|  |  |  | uint8_t* d = reinterpret_cast<uint8_t*>(data); | 
		
	
		
			
			|  |  |  | if (!cardCommand(xfertyp, m_rca)) { | 
		
	
		
			
			|  |  |  | return false;  // Caller will set errorCode. | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | return !(SDHC_CMDRSP0 & CARD_STATUS_READY_FOR_DATA); | 
		
	
		
			
			|  |  |  | uint32_t sr[] = {SDHC_CMDRSP0, SDHC_CMDRSP1, SDHC_CMDRSP2, SDHC_CMDRSP3}; | 
		
	
		
			
			|  |  |  | for (int i = 0; i < 15; i++) { | 
		
	
		
			
			|  |  |  | d[14 - i] = sr[i/4] >> 8*(i%4); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | d[15] = 0; | 
		
	
		
			
			|  |  |  | return true; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | static void setSdclk(uint32_t kHzMax) { | 
		
	
	
		
			
			|  |  | @@ -294,55 +389,99 @@ static void setSdclk(uint32_t kHzMax) { | 
		
	
		
			
			|  |  |  | // Enable the SDHC clock. | 
		
	
		
			
			|  |  |  | SDHC_SYSCTL |= SDHC_SYSCTL_SDCLKEN; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //------------------------------------------------------------------------------ | 
		
	
		
			
			|  |  |  | static bool cardCMD6(uint32_t arg, uint8_t* status) { | 
		
	
		
			
			|  |  |  | // CMD6 returns 64 bytes. | 
		
	
		
			
			|  |  |  | while (isBusy()) { | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | enableDmaIrs(); | 
		
	
		
			
			|  |  |  | SDHC_DSADDR  = (uint32_t)status; | 
		
	
		
			
			|  |  |  | SDHC_CMDARG = arg; | 
		
	
		
			
			|  |  |  | SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(1) | SDHC_BLKATTR_BLKSIZE(64); | 
		
	
		
			
			|  |  |  | SDHC_IRQSIGEN = SDHC_IRQSIGEN_MASK; | 
		
	
		
			
			|  |  |  | SDHC_XFERTYP = CMD6_XFERTYP; | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | static bool transferStop() { | 
		
	
		
			
			|  |  |  | DBG_IRQSTAT(); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | if (!waitDmaStatus()) { | 
		
	
		
			
			|  |  |  | return sdError(SD_CARD_ERROR_CMD6); | 
		
	
		
			
			|  |  |  | if (!cardCommand(CMD12_XFERTYP, 0)) { | 
		
	
		
			
			|  |  |  | return sdError(SD_CARD_ERROR_CMD12); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | if (yieldTimeout(isBusyCMD13)) { | 
		
	
		
			
			|  |  |  | return sdError(SD_CARD_ERROR_CMD13); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | // Save registers before reset DAT lines. | 
		
	
		
			
			|  |  |  | uint32_t irqsststen = SDHC_IRQSTATEN; | 
		
	
		
			
			|  |  |  | uint32_t proctl = SDHC_PROCTL & ~SDHC_PROCTL_SABGREQ; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | // Do reset to clear CDIHB.  Should be a better way! | 
		
	
		
			
			|  |  |  | SDHC_SYSCTL |= SDHC_SYSCTL_RSTD; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | // Restore registers. | 
		
	
		
			
			|  |  |  | SDHC_IRQSTATEN = irqsststen; | 
		
	
		
			
			|  |  |  | SDHC_PROCTL = proctl; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | return true; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //------------------------------------------------------------------------------ | 
		
	
		
			
			|  |  |  | static bool cardInit() { | 
		
	
		
			
			|  |  |  | uint32_t kbaudrate; | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | // Return true if timeout occurs. | 
		
	
		
			
			|  |  |  | static bool yieldTimeout(bool (*fcn)()) { | 
		
	
		
			
			|  |  |  | m_busyFcn = fcn; | 
		
	
		
			
			|  |  |  | uint32_t m = micros(); | 
		
	
		
			
			|  |  |  | while (fcn()) { | 
		
	
		
			
			|  |  |  | if ((micros() - m) > BUSY_TIMEOUT_MICROS) { | 
		
	
		
			
			|  |  |  | m_busyFcn = 0; | 
		
	
		
			
			|  |  |  | return true; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | yield(); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | m_busyFcn = 0; | 
		
	
		
			
			|  |  |  | return false;  // Caller will set errorCode. | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | static bool waitDmaStatus() { | 
		
	
		
			
			|  |  |  | if (yieldTimeout(isBusyDMA)) { | 
		
	
		
			
			|  |  |  | return false;  // Caller will set errorCode. | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | return (m_irqstat & SDHC_IRQSTAT_TC) && !(m_irqstat & SDHC_IRQSTAT_ERROR); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | // Return true if timeout occurs. | 
		
	
		
			
			|  |  |  | static bool waitTimeout(bool (*fcn)()) { | 
		
	
		
			
			|  |  |  | uint32_t m = micros(); | 
		
	
		
			
			|  |  |  | while (fcn()) { | 
		
	
		
			
			|  |  |  | if ((micros() - m) > BUSY_TIMEOUT_MICROS) { | 
		
	
		
			
			|  |  |  | return true; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | return false;  // Caller will set errorCode. | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //============================================================================= | 
		
	
		
			
			|  |  |  | bool SdioCard::begin() { | 
		
	
		
			
			|  |  |  | uint32_t kHzSdClk; | 
		
	
		
			
			|  |  |  | uint32_t arg; | 
		
	
		
			
			|  |  |  | m_initDone = false; | 
		
	
		
			
			|  |  |  | m_errorCode = SD_CARD_ERROR_NONE; | 
		
	
		
			
			|  |  |  | m_highCapacity = false; | 
		
	
		
			
			|  |  |  | m_version2 = false; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | // initialize controller. | 
		
	
		
			
			|  |  |  | SDHC_Init(); | 
		
	
		
			
			|  |  |  | initSDHC(); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | if (!cardCommand(CMD0_XFERTYP, 0)) { | 
		
	
		
			
			|  |  |  | return sdError(SD_CARD_ERROR_CMD0); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | if (cardCommand(CMD8_XFERTYP, 0X1AA)) { | 
		
	
		
			
			|  |  |  | if (SDHC_CMDRSP0 != 0X1AA) { | 
		
	
		
			
			|  |  |  | return sdError(SD_CARD_ERROR_CMD8); | 
		
	
		
			
			|  |  |  | // Try several times for case of reset delay. | 
		
	
		
			
			|  |  |  | for (uint32_t i = 0; i < CMD8_RETRIES; i++) { | 
		
	
		
			
			|  |  |  | if (cardCommand(CMD8_XFERTYP, 0X1AA)) { | 
		
	
		
			
			|  |  |  | if (SDHC_CMDRSP0 != 0X1AA) { | 
		
	
		
			
			|  |  |  | return sdError(SD_CARD_ERROR_CMD8); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | m_version2 = true; | 
		
	
		
			
			|  |  |  | break; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | m_version2 = true; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | arg = m_version2 ? 0X40300000 : 0x00300000; | 
		
	
		
			
			|  |  |  | int i = 0; | 
		
	
		
			
			|  |  |  | uint32_t m = micros(); | 
		
	
		
			
			|  |  |  | do { | 
		
	
		
			
			|  |  |  | if (!cardAcmd(0, ACMD41_XFERTYP, arg) || i++ > 1000) { | 
		
	
		
			
			|  |  |  | if (!cardAcmd(0, ACMD41_XFERTYP, arg) || | 
		
	
		
			
			|  |  |  | ((micros() - m) > BUSY_TIMEOUT_MICROS)) { | 
		
	
		
			
			|  |  |  | return sdError(SD_CARD_ERROR_ACMD41); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } while ((SDHC_CMDRSP0 & 0x80000000) == 0); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | m_ocr = SDHC_CMDRSP0; | 
		
	
		
			
			|  |  |  | if (SDHC_CMDRSP0 & 0x40000000) { | 
		
	
		
			
			|  |  |  | // is high capacity | 
		
	
		
			
			|  |  |  | // Is high capacity. | 
		
	
		
			
			|  |  |  | m_highCapacity = true; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | if (!cardCommand(CMD2_XFERTYP, 0)) { | 
		
	
	
		
			
			|  |  | @@ -362,80 +501,45 @@ static bool cardInit() { | 
		
	
		
			
			|  |  |  | if (!cardCommand(CMD7_XFERTYP, m_rca)) { | 
		
	
		
			
			|  |  |  | return sdError(SD_CARD_ERROR_CMD7); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Set card to bus width four. | 
		
	
		
			
			|  |  |  | if (!cardAcmd(m_rca, ACMD6_XFERTYP, 2)) { | 
		
	
		
			
			|  |  |  | return sdError(SD_CARD_ERROR_ACMD6); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | // Set Data bus width to four. | 
		
	
		
			
			|  |  |  | // Set SDHC to bus width four. | 
		
	
		
			
			|  |  |  | SDHC_PROCTL &= ~SDHC_PROCTL_DTW_MASK; | 
		
	
		
			
			|  |  |  | SDHC_PROCTL |= SDHC_PROCTL_DTW(SDHC_PROCTL_DTW_4BIT); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | SDHC_WML = SDHC_WML_RDWML(FIFO_WML) | SDHC_WML_WRWML(FIFO_WML); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | // Determine if High Speed mode is supported and set frequency. | 
		
	
		
			
			|  |  |  | uint8_t status[64]; | 
		
	
		
			
			|  |  |  | if (cardCMD6(0X00FFFFFF, status) && (2 & status[13]) && | 
		
	
		
			
			|  |  |  | cardCMD6(0X80FFFFF1, status) && (status[16] & 0XF) == 1) { | 
		
	
		
			
			|  |  |  | kbaudrate = 50000; | 
		
	
		
			
			|  |  |  | kHzSdClk = 50000; | 
		
	
		
			
			|  |  |  | } else { | 
		
	
		
			
			|  |  |  | kbaudrate = 25000; | 
		
	
		
			
			|  |  |  | kHzSdClk = 25000; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | // disable GPIO | 
		
	
		
			
			|  |  |  | enableGPIO(false); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | // Set the SDHC SCK frequency. | 
		
	
		
			
			|  |  |  | setSdclk(kbaudrate); | 
		
	
		
			
			|  |  |  | setSdclk(kHzSdClk); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | // enable GPIO | 
		
	
		
			
			|  |  |  | enableGPIO(true); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | m_initDone = true; | 
		
	
		
			
			|  |  |  | return true; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | static bool readReg16(uint32_t xfertyp, void* data) { | 
		
	
		
			
			|  |  |  | if (!cardCommand(xfertyp, m_rca)) { | 
		
	
		
			
			|  |  |  | return false; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | uint8_t* d = reinterpret_cast<uint8_t*>(data); | 
		
	
		
			
			|  |  |  | d[0] = SDHC_CMDRSP3 >> 16; | 
		
	
		
			
			|  |  |  | d[1] = SDHC_CMDRSP3 >> 8; | 
		
	
		
			
			|  |  |  | d[2] = SDHC_CMDRSP3; | 
		
	
		
			
			|  |  |  | d[3] = SDHC_CMDRSP2 >> 24; | 
		
	
		
			
			|  |  |  | d[4] = SDHC_CMDRSP2 >> 16; | 
		
	
		
			
			|  |  |  | d[5] = SDHC_CMDRSP2 >> 8; | 
		
	
		
			
			|  |  |  | d[6] = SDHC_CMDRSP2; | 
		
	
		
			
			|  |  |  | d[7] = SDHC_CMDRSP1 >> 24; | 
		
	
		
			
			|  |  |  | d[8] = SDHC_CMDRSP1 >> 16; | 
		
	
		
			
			|  |  |  | d[9] = SDHC_CMDRSP1 >> 8; | 
		
	
		
			
			|  |  |  | d[10] = SDHC_CMDRSP1; | 
		
	
		
			
			|  |  |  | d[11] = SDHC_CMDRSP0 >> 24; | 
		
	
		
			
			|  |  |  | d[12] = SDHC_CMDRSP0 >> 16; | 
		
	
		
			
			|  |  |  | d[13] = SDHC_CMDRSP0 >> 8; | 
		
	
		
			
			|  |  |  | d[14] = SDHC_CMDRSP0; | 
		
	
		
			
			|  |  |  | d[15] = 0; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | return true; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //============================================================================= | 
		
	
		
			
			|  |  |  | bool SdioCard::begin() { | 
		
	
		
			
			|  |  |  | return cardInit(); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | uint32_t SdioCard::cardSize() { | 
		
	
		
			
			|  |  |  | return sdCardCapacity(&m_csd); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | bool SdioCard::dmaBusy() { | 
		
	
		
			
			|  |  |  | return m_waitCmd13 ? isBusy() : !m_dmaDone; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | bool SdioCard::erase(uint32_t firstBlock, uint32_t lastBlock) { | 
		
	
		
			
			|  |  |  | csd_t csd; | 
		
	
		
			
			|  |  |  | if (!readCSD(&csd)) { | 
		
	
		
			
			|  |  |  | return false; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | // check for single block erase | 
		
	
		
			
			|  |  |  | if (!csd.v1.erase_blk_en) { | 
		
	
		
			
			|  |  |  | if (!m_csd.v1.erase_blk_en) { | 
		
	
		
			
			|  |  |  | // erase size mask | 
		
	
		
			
			|  |  |  | uint8_t m = (csd.v1.sector_size_high << 1) | csd.v1.sector_size_low; | 
		
	
		
			
			|  |  |  | uint8_t m = (m_csd.v1.sector_size_high << 1) | m_csd.v1.sector_size_low; | 
		
	
		
			
			|  |  |  | if ((firstBlock & m) != 0 || ((lastBlock + 1) & m) != 0) { | 
		
	
		
			
			|  |  |  | // error card can't erase specified area | 
		
	
		
			
			|  |  |  | return sdError(SD_CARD_ERROR_ERASE_SINGLE_BLOCK); | 
		
	
	
		
			
			|  |  | @@ -454,7 +558,8 @@ bool SdioCard::erase(uint32_t firstBlock, uint32_t lastBlock) { | 
		
	
		
			
			|  |  |  | if (!cardCommand(CMD38_XFERTYP, 0)) { | 
		
	
		
			
			|  |  |  | return sdError(SD_CARD_ERROR_CMD38); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | while (isBusy()) { | 
		
	
		
			
			|  |  |  | if (waitTimeout(isBusyCMD13)) { | 
		
	
		
			
			|  |  |  | return sdError(SD_CARD_ERROR_ERASE_TIMEOUT); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | return true; | 
		
	
		
			
			|  |  |  | } | 
		
	
	
		
			
			|  |  | @@ -471,6 +576,10 @@ uint32_t SdioCard::errorLine() { | 
		
	
		
			
			|  |  |  | return m_errorLine; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | bool SdioCard::isBusy() { | 
		
	
		
			
			|  |  |  | return m_busyFcn ? m_busyFcn() : m_initDone && isBusyCMD13(); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | uint32_t SdioCard::kHzSdClk() { | 
		
	
		
			
			|  |  |  | return m_sdClkKhz; | 
		
	
		
			
			|  |  |  | } | 
		
	
	
		
			
			|  |  | @@ -480,7 +589,7 @@ bool SdioCard::readBlock(uint32_t lba, uint8_t* buf) { | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | uint8_t* ptr = (uint32_t)buf & 3 ? aligned : buf; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | if (!rdWrBlocks(CMD17_XFERTYP, lba, ptr, 1)) { | 
		
	
		
			
			|  |  |  | if (!rdWrBlocks(CMD17_DMA_XFERTYP, lba, ptr, 1)) { | 
		
	
		
			
			|  |  |  | return sdError(SD_CARD_ERROR_CMD18); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | if (ptr != buf) { | 
		
	
	
		
			
			|  |  | @@ -493,17 +602,17 @@ bool SdioCard::readBlocks(uint32_t lba, uint8_t* buf, size_t n) { | 
		
	
		
			
			|  |  |  | if ((uint32_t)buf & 3) { | 
		
	
		
			
			|  |  |  | for (size_t i = 0; i < n; i++, lba++, buf += 512) { | 
		
	
		
			
			|  |  |  | if (!readBlock(lba, buf)) { | 
		
	
		
			
			|  |  |  | return false; | 
		
	
		
			
			|  |  |  | return false;  // readBlock will set errorCode. | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | return true; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | if (!rdWrBlocks(CMD18_XFERTYP, lba, buf, n)) { | 
		
	
		
			
			|  |  |  | if (!rdWrBlocks(CMD18_DMA_XFERTYP, lba, buf, n)) { | 
		
	
		
			
			|  |  |  | return sdError(SD_CARD_ERROR_CMD18); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | return true; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //---------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | bool SdioCard::readCID(void* cid) { | 
		
	
		
			
			|  |  |  | memcpy(cid, &m_cid, 16); | 
		
	
		
			
			|  |  |  | return true; | 
		
	
	
		
			
			|  |  | @@ -514,11 +623,74 @@ bool SdioCard::readCSD(void* csd) { | 
		
	
		
			
			|  |  |  | return true; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | bool SdioCard::readData(uint8_t *dst) { | 
		
	
		
			
			|  |  |  | DBG_IRQSTAT(); | 
		
	
		
			
			|  |  |  | uint32_t *p32 = reinterpret_cast<uint32_t*>(dst); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | if (!(SDHC_PRSSTAT & SDHC_PRSSTAT_RTA)) { | 
		
	
		
			
			|  |  |  | SDHC_PROCTL &= ~SDHC_PROCTL_SABGREQ; | 
		
	
		
			
			|  |  |  | if ((SDHC_BLKATTR & 0XFFFF0000) == 0X10000) { | 
		
	
		
			
			|  |  |  | // Don't stop at block gap if last block.  Allows auto CMD12. | 
		
	
		
			
			|  |  |  | SDHC_PROCTL |= SDHC_PROCTL_CREQ; | 
		
	
		
			
			|  |  |  | } else { | 
		
	
		
			
			|  |  |  | noInterrupts(); | 
		
	
		
			
			|  |  |  | SDHC_PROCTL |= SDHC_PROCTL_CREQ; | 
		
	
		
			
			|  |  |  | SDHC_PROCTL |= SDHC_PROCTL_SABGREQ; | 
		
	
		
			
			|  |  |  | interrupts(); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | if (waitTimeout(isBusyFifoRead)) { | 
		
	
		
			
			|  |  |  | return sdError(SD_CARD_ERROR_READ_FIFO); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | for (uint32_t iw = 0 ; iw < 512/(4*FIFO_WML); iw++) { | 
		
	
		
			
			|  |  |  | while (0 == (SDHC_PRSSTAT & SDHC_PRSSTAT_BREN)) { | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | for (uint32_t i = 0; i < FIFO_WML; i++) { | 
		
	
		
			
			|  |  |  | p32[i] = SDHC_DATPORT; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | p32 += FIFO_WML; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | if (waitTimeout(isBusyTransferComplete)) { | 
		
	
		
			
			|  |  |  | return sdError(SD_CARD_ERROR_READ_TIMEOUT); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | m_irqstat = SDHC_IRQSTAT; | 
		
	
		
			
			|  |  |  | SDHC_IRQSTAT = m_irqstat; | 
		
	
		
			
			|  |  |  | return (m_irqstat & SDHC_IRQSTAT_TC) && !(m_irqstat & SDHC_IRQSTAT_ERROR); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | bool SdioCard::readOCR(uint32_t* ocr) { | 
		
	
		
			
			|  |  |  | *ocr = m_ocr; | 
		
	
		
			
			|  |  |  | return true; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | bool SdioCard::readStart(uint32_t lba) { | 
		
	
		
			
			|  |  |  | // K66/K65 Errata - SDHC: Does not support Infinite Block Transfer Mode. | 
		
	
		
			
			|  |  |  | return sdError(SD_CARD_ERROR_FUNCTION_NOT_SUPPORTED); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | // SDHC will do Auto CMD12 after count blocks. | 
		
	
		
			
			|  |  |  | bool SdioCard::readStart(uint32_t lba, uint32_t count) { | 
		
	
		
			
			|  |  |  | DBG_IRQSTAT(); | 
		
	
		
			
			|  |  |  | if (count > 0XFFFF) { | 
		
	
		
			
			|  |  |  | return sdError(SD_CARD_ERROR_READ_START); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | if (yieldTimeout(isBusyCMD13)) { | 
		
	
		
			
			|  |  |  | return sdError(SD_CARD_ERROR_CMD13); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | if (count > 1) { | 
		
	
		
			
			|  |  |  | SDHC_PROCTL |= SDHC_PROCTL_SABGREQ; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(count) | SDHC_BLKATTR_BLKSIZE(512); | 
		
	
		
			
			|  |  |  | if (!cardCommand(CMD18_PGM_XFERTYP, m_highCapacity ? lba : 512*lba)) { | 
		
	
		
			
			|  |  |  | return sdError(SD_CARD_ERROR_CMD18); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | return true; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | bool SdioCard::readStop() { | 
		
	
		
			
			|  |  |  | return transferStop(); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | bool SdioCard::syncBlocks() { | 
		
	
		
			
			|  |  |  | return true; | 
		
	
		
			
			|  |  |  | } | 
		
	
	
		
			
			|  |  | @@ -537,7 +709,7 @@ bool SdioCard::writeBlock(uint32_t lba, const uint8_t* buf) { | 
		
	
		
			
			|  |  |  | } else { | 
		
	
		
			
			|  |  |  | ptr = const_cast<uint8_t*>(buf); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | if (!rdWrBlocks(CMD24_XFERTYP, lba, ptr, 1)) { | 
		
	
		
			
			|  |  |  | if (!rdWrBlocks(CMD24_DMA_XFERTYP, lba, ptr, 1)) { | 
		
	
		
			
			|  |  |  | return sdError(SD_CARD_ERROR_CMD24); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | return true; | 
		
	
	
		
			
			|  |  | @@ -548,14 +720,76 @@ bool SdioCard::writeBlocks(uint32_t lba, const uint8_t* buf, size_t n) { | 
		
	
		
			
			|  |  |  | if (3 & (uint32_t)ptr) { | 
		
	
		
			
			|  |  |  | for (size_t i = 0; i < n; i++, lba++, ptr += 512) { | 
		
	
		
			
			|  |  |  | if (!writeBlock(lba, ptr)) { | 
		
	
		
			
			|  |  |  | return false; | 
		
	
		
			
			|  |  |  | return false;  // writeBlock will set errorCode. | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | return true; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | if (!rdWrBlocks(CMD25_XFERTYP, lba, ptr, n)) { | 
		
	
		
			
			|  |  |  | if (!rdWrBlocks(CMD25_DMA_XFERTYP, lba, ptr, n)) { | 
		
	
		
			
			|  |  |  | return sdError(SD_CARD_ERROR_CMD25); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | return true; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | bool SdioCard::writeData(const uint8_t* src) { | 
		
	
		
			
			|  |  |  | DBG_IRQSTAT(); | 
		
	
		
			
			|  |  |  | const uint32_t* p32 = reinterpret_cast<const uint32_t*>(src); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | if (!(SDHC_PRSSTAT & SDHC_PRSSTAT_WTA)) { | 
		
	
		
			
			|  |  |  | SDHC_PROCTL &= ~SDHC_PROCTL_SABGREQ; | 
		
	
		
			
			|  |  |  | // Don't stop at block gap if last block.  Allows auto CMD12. | 
		
	
		
			
			|  |  |  | if ((SDHC_BLKATTR & 0XFFFF0000) == 0X10000) { | 
		
	
		
			
			|  |  |  | SDHC_PROCTL |= SDHC_PROCTL_CREQ; | 
		
	
		
			
			|  |  |  | } else { | 
		
	
		
			
			|  |  |  | SDHC_PROCTL |= SDHC_PROCTL_CREQ; | 
		
	
		
			
			|  |  |  | SDHC_PROCTL |= SDHC_PROCTL_SABGREQ; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | if (waitTimeout(isBusyFifoWrite)) { | 
		
	
		
			
			|  |  |  | return sdError(SD_CARD_ERROR_WRITE_FIFO); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | for (uint32_t iw = 0 ; iw < 512/(4*FIFO_WML); iw++) { | 
		
	
		
			
			|  |  |  | while (0 == (SDHC_PRSSTAT & SDHC_PRSSTAT_BWEN)) { | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | for (uint32_t i = 0; i < FIFO_WML; i++) { | 
		
	
		
			
			|  |  |  | SDHC_DATPORT = p32[i]; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | p32 += FIFO_WML; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | if (waitTimeout(isBusyTransferComplete)) { | 
		
	
		
			
			|  |  |  | return sdError(SD_CARD_ERROR_WRITE_TIMEOUT); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | m_irqstat = SDHC_IRQSTAT; | 
		
	
		
			
			|  |  |  | SDHC_IRQSTAT = m_irqstat; | 
		
	
		
			
			|  |  |  | return (m_irqstat & SDHC_IRQSTAT_TC) && !(m_irqstat & SDHC_IRQSTAT_ERROR); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | bool SdioCard::writeStart(uint32_t lba) { | 
		
	
		
			
			|  |  |  | // K66/K65 Errata - SDHC: Does not support Infinite Block Transfer Mode. | 
		
	
		
			
			|  |  |  | return sdError(SD_CARD_ERROR_FUNCTION_NOT_SUPPORTED); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | // SDHC will do Auto CMD12 after count blocks. | 
		
	
		
			
			|  |  |  | bool SdioCard::writeStart(uint32_t lba, uint32_t count) { | 
		
	
		
			
			|  |  |  | if (count > 0XFFFF) { | 
		
	
		
			
			|  |  |  | return sdError(SD_CARD_ERROR_WRITE_START); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | DBG_IRQSTAT(); | 
		
	
		
			
			|  |  |  | if (yieldTimeout(isBusyCMD13)) { | 
		
	
		
			
			|  |  |  | return sdError(SD_CARD_ERROR_CMD13); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | if (count > 1) { | 
		
	
		
			
			|  |  |  | SDHC_PROCTL |= SDHC_PROCTL_SABGREQ; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(count) | SDHC_BLKATTR_BLKSIZE(512); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | if (!cardCommand(CMD25_PGM_XFERTYP, m_highCapacity ? lba : 512*lba)) { | 
		
	
		
			
			|  |  |  | return sdError(SD_CARD_ERROR_CMD25); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | return true; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | //----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | bool SdioCard::writeStop() { | 
		
	
		
			
			|  |  |  | return transferStop(); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | #endif  // defined(__MK64FX512__) || defined(__MK66FX1M0__) |