// adapted for Arduino SD library by Paul Stoffregen // following code is modified by Walter Zimmer from // from version provided by // Petr Gargulak (NXP Employee) //https://community.nxp.com/servlet/JiveServlet/download/339474-1-263510/SDHC_K60_Baremetal.ZIP //see also //https://community.nxp.com/thread/99202 #if defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1062__) #include "core_pins.h" // include calls to kinetis.h or imxrt.h #include "usb_serial.h" // for Serial #include "NXP_SDHC.h" /****************************************************************************** Constants ******************************************************************************/ enum { SDHC_RESULT_OK = 0, /* 0: Successful */ SDHC_RESULT_ERROR, /* 1: R/W Error */ SDHC_RESULT_WRPRT, /* 2: Write Protected */ SDHC_RESULT_NOT_READY, /* 3: Not Ready */ SDHC_RESULT_PARERR, /* 4: Invalid Parameter */ SDHC_RESULT_NO_RESPONSE /* 5: No Response */ // from old diskio.h }; /*void print_result(int n) { switch (n) { case SDHC_RESULT_OK: serial_print("OK\n"); break; case SDHC_RESULT_ERROR: serial_print("R/W Error\n"); break; case SDHC_RESULT_WRPRT: serial_print("Write Protect\n"); break; case SDHC_RESULT_NOT_READY: serial_print("Not Ready\n"); break; case SDHC_RESULT_PARERR: serial_print("Invalid Param\n"); break; case SDHC_RESULT_NO_RESPONSE: serial_print("No Response\n"); break; default: serial_print("Unknown result\n"); } }*/ #define IO_SDHC_ATTRIBS (IO_DEV_ATTR_READ | IO_DEV_ATTR_REMOVE | IO_DEV_ATTR_SEEK | IO_DEV_ATTR_WRITE | IO_DEV_ATTR_BLOCK_MODE) #define SDHC_XFERTYP_RSPTYP_NO (0x00) #define SDHC_XFERTYP_RSPTYP_136 (0x01) #define SDHC_XFERTYP_RSPTYP_48 (0x02) #define SDHC_XFERTYP_RSPTYP_48BUSY (0x03) #define SDHC_XFERTYP_CMDTYP_ABORT (0x03) #define SDHC_PROCTL_EMODE_INVARIANT (0x02) #define SDHC_PROCTL_DTW_1BIT (0x00) #define SDHC_PROCTL_DTW_4BIT (0x01) #define SDHC_PROCTL_DTW_8BIT (0x10) #define SDHC_INITIALIZATION_MAX_CNT 100000 /* SDHC commands */ #define SDHC_CMD0 (0) #define SDHC_CMD1 (1) #define SDHC_CMD2 (2) #define SDHC_CMD3 (3) #define SDHC_CMD4 (4) #define SDHC_CMD5 (5) #define SDHC_CMD6 (6) #define SDHC_CMD7 (7) #define SDHC_CMD8 (8) #define SDHC_CMD9 (9) #define SDHC_CMD10 (10) #define SDHC_CMD11 (11) #define SDHC_CMD12 (12) #define SDHC_CMD13 (13) #define SDHC_CMD15 (15) #define SDHC_CMD16 (16) #define SDHC_CMD17 (17) #define SDHC_CMD18 (18) #define SDHC_CMD20 (20) #define SDHC_CMD24 (24) #define SDHC_CMD25 (25) #define SDHC_CMD26 (26) #define SDHC_CMD27 (27) #define SDHC_CMD28 (28) #define SDHC_CMD29 (29) #define SDHC_CMD30 (30) #define SDHC_CMD32 (32) #define SDHC_CMD33 (33) #define SDHC_CMD34 (34) #define SDHC_CMD35 (35) #define SDHC_CMD36 (36) #define SDHC_CMD37 (37) #define SDHC_CMD38 (38) #define SDHC_CMD39 (39) #define SDHC_CMD40 (40) #define SDHC_CMD42 (42) #define SDHC_CMD52 (52) #define SDHC_CMD53 (53) #define SDHC_CMD55 (55) #define SDHC_CMD56 (56) #define SDHC_CMD59 (59) #define SDHC_CMD60 (60) #define SDHC_CMD61 (61) #define SDHC_ACMD6 (0x40 + 6) #define SDHC_ACMD13 (0x40 + 13) #define SDHC_ACMD22 (0x40 + 22) #define SDHC_ACMD23 (0x40 + 23) #define SDHC_ACMD41 (0x40 + 41) #define SDHC_ACMD42 (0x40 + 42) #define SDHC_ACMD51 (0x40 + 51) #define SDHC_FIFO_BUFFER_SIZE 16 #define SDHC_BLOCK_SIZE 512 #if defined(__IMXRT1062__) #define MAKE_REG_MASK(m,s) (((uint32_t)(((uint32_t)(m) << s)))) #define MAKE_REG_GET(x,m,s) (((uint32_t)(((uint32_t)(x)>>s) & m))) #define MAKE_REG_SET(x,m,s) (((uint32_t)(((uint32_t)(x) & m) << s))) #define SDHC_BLKATTR_BLKSIZE_MASK MAKE_REG_MASK(0x1FFF,0) //uint32_t)(((n) & 0x1FFF)<<0) // Transfer Block Size Mask #define SDHC_BLKATTR_BLKSIZE(n) MAKE_REG_SET(n,0x1FFF,0) //uint32_t)(((n) & 0x1FFF)<<0) // Transfer Block Size #define SDHC_BLKATTR_BLKCNT_MASK MAKE_REG_MASK(0x1FFF,16) //((uint32_t)0x1FFF<<16) #define SDHC_BLKATTR_BLKCNT(n) MAKE_REG_SET(n,0x1FFF,16) //(uint32_t)(((n) & 0x1FFF)<<16) // Blocks Count For Current Transfer #define SDHC_XFERTYP_CMDINX(n) MAKE_REG_SET(n,0x3F,24) //(uint32_t)(((n) & 0x3F)<<24)// Command Index #define SDHC_XFERTYP_CMDTYP(n) MAKE_REG_SET(n,0x3,22) //(uint32_t)(((n) & 0x3)<<22) // Command Type #define SDHC_XFERTYP_DPSEL MAKE_REG_MASK(0x1,21) //((uint32_t)0x00200000) // Data Present Select #define SDHC_XFERTYP_CICEN MAKE_REG_MASK(0x1,20) //((uint32_t)0x00100000) // Command Index Check Enable #define SDHC_XFERTYP_CCCEN MAKE_REG_MASK(0x1,19) //((uint32_t)0x00080000) // Command CRC Check Enable #define SDHC_XFERTYP_RSPTYP(n) MAKE_REG_SET(n,0x3,16) //(uint32_t)(((n) & 0x3)<<16) // Response Type Select #define SDHC_XFERTYP_MSBSEL MAKE_REG_MASK(0x1,5) //((uint32_t)0x00000020) // Multi/Single Block Select #define SDHC_XFERTYP_DTDSEL MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Data Transfer Direction Select #define SDHC_XFERTYP_AC12EN MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004) // Auto CMD12 Enable #define SDHC_XFERTYP_BCEN MAKE_REG_MASK(0x1,1) //((uint32_t)0x00000002) // Block Count Enable #define SDHC_XFERTYP_DMAEN MAKE_REG_MASK(0x3,0) //((uint32_t)0x00000001) // DMA Enable #define SDHC_PRSSTAT_DLSL_MASK MAKE_REG_MASK(0xFF,24) //((uint32_t)0xFF000000) // DAT Line Signal Level #define SDHC_PRSSTAT_CLSL MAKE_REG_MASK(0x1,23) //((uint32_t)0x00800000) // CMD Line Signal Level #define SDHC_PRSSTAT_WPSPL MAKE_REG_MASK(0x1,19) // #define SDHC_PRSSTAT_CDPL MAKE_REG_MASK(0x1,18) // #define SDHC_PRSSTAT_CINS MAKE_REG_MASK(0x1,16) //((uint32_t)0x00010000) // Card Inserted #define SDHC_PRSSTAT_TSCD MAKE_REG_MASK(0x1,15) #define SDHC_PRSSTAT_RTR MAKE_REG_MASK(0x1,12) #define SDHC_PRSSTAT_BREN MAKE_REG_MASK(0x1,11) //((uint32_t)0x00000800) // Buffer Read Enable #define SDHC_PRSSTAT_BWEN MAKE_REG_MASK(0x1,10) //((uint32_t)0x00000400) // Buffer Write Enable #define SDHC_PRSSTAT_RTA MAKE_REG_MASK(0x1,9) //((uint32_t)0x00000200) // Read Transfer Active #define SDHC_PRSSTAT_WTA MAKE_REG_MASK(0x1,8) //((uint32_t)0x00000100) // Write Transfer Active #define SDHC_PRSSTAT_SDOFF MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // SD Clock Gated Off Internally #define SDHC_PRSSTAT_PEROFF MAKE_REG_MASK(0x1,6) //((uint32_t)0x00000040) // SDHC clock Gated Off Internally #define SDHC_PRSSTAT_HCKOFF MAKE_REG_MASK(0x1,5) //((uint32_t)0x00000020) // System Clock Gated Off Internally #define SDHC_PRSSTAT_IPGOFF MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Bus Clock Gated Off Internally #define SDHC_PRSSTAT_SDSTB MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008) // SD Clock Stable #define SDHC_PRSSTAT_DLA MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004) // Data Line Active #define SDHC_PRSSTAT_CDIHB MAKE_REG_MASK(0x1,1) //((uint32_t)0x00000002) // Command Inhibit (DAT) #define SDHC_PRSSTAT_CIHB MAKE_REG_MASK(0x1,0) //((uint32_t)0x00000001) // Command Inhibit (CMD) #define SDHC_PROTCT_NONEXACT_BLKRD MAKE_REG_MASK(0x1,30) // #define SDHC_PROTCT_BURST_LENEN(n) MAKE_REG_SET(n,0x7,12) // #define SDHC_PROCTL_WECRM MAKE_REG_MASK(0x1,26) //((uint32_t)0x04000000) // Wakeup Event Enable On SD Card Removal #define SDHC_PROCTL_WECINS MAKE_REG_MASK(0x1,25) //((uint32_t)0x02000000) // Wakeup Event Enable On SD Card Insertion #define SDHC_PROCTL_WECINT MAKE_REG_MASK(0x1,24) //((uint32_t)0x01000000) // Wakeup Event Enable On Card Interrupt #define SDHC_PROCTL_RD_DONE_NOBLK MAKE_REG_MASK(0x1,20) // #define SDHC_PROCTL_IABG MAKE_REG_MASK(0x1,19) //((uint32_t)0x00080000) // Interrupt At Block Gap #define SDHC_PROCTL_RWCTL MAKE_REG_MASK(0x1,18) //((uint32_t)0x00040000) // Read Wait Control #define SDHC_PROCTL_CREQ MAKE_REG_MASK(0x1,17) //((uint32_t)0x00020000) // Continue Request #define SDHC_PROCTL_SABGREQ MAKE_REG_MASK(0x1,16) //((uint32_t)0x00010000) // Stop At Block Gap Request #define SDHC_PROCTL_DMAS(n) MAKE_REG_SET(n,0x3,8) //(uint32_t)(((n) & 0x3)<<8) // DMA Select #define SDHC_PROCTL_CDSS MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // Card Detect Signal Selection #define SDHC_PROCTL_CDTL MAKE_REG_MASK(0x1,6) //((uint32_t)0x00000040) // Card Detect Test Level #define SDHC_PROCTL_EMODE(n) MAKE_REG_SET(n,0x3,4) //(uint32_t)(((n) & 0x3)<<4) // Endian Mode #define SDHC_PROCTL_EMODE_MASK MAKE_REG_MASK(0x3,4) //(uint32_t)((0x3)<<4) // Endian Mode #define SDHC_PROCTL_D3CD MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008) // DAT3 As Card Detection Pin #define SDHC_PROCTL_DTW(n) MAKE_REG_SET(n,0x3,1) //(uint32_t)(((n) & 0x3)<<1) // Data Transfer Width, 0=1bit, 1=4bit, 2=8bit #define SDHC_PROCTL_DTW_MASK MAKE_REG_MASK(0x3,1) //((uint32_t)0x00000006) #define SDHC_PROCTL_LCTL MAKE_REG_MASK(0x1,0) //((uint32_t)0x00000001) // LED Control #define SDHC_SYSCTL_RSTT MAKE_REG_MASK(0x1,28) // #define SDHC_SYSCTL_INITA MAKE_REG_MASK(0x1,27) //((uint32_t)0x08000000) // Initialization Active #define SDHC_SYSCTL_RSTD MAKE_REG_MASK(0x1,26) //((uint32_t)0x04000000) // Software Reset For DAT Line #define SDHC_SYSCTL_RSTC MAKE_REG_MASK(0x1,25) //((uint32_t)0x02000000) // Software Reset For CMD Line #define SDHC_SYSCTL_RSTA MAKE_REG_MASK(0x1,24) //((uint32_t)0x01000000) // Software Reset For ALL #define SDHC_SYSCTL_DTOCV(n) MAKE_REG_SET(n,0xF,16) //(uint32_t)(((n) & 0xF)<<16) // Data Timeout Counter Value #define SDHC_SYSCTL_DTOCV_MASK MAKE_REG_MASK(0xF,16) //((uint32_t)0x000F0000) #define SDHC_SYSCTL_SDCLKFS(n) MAKE_REG_SET(n,0xFF,8) //(uint32_t)(((n) & 0xFF)<<8) // SDCLK Frequency Select #define SDHC_SYSCTL_SDCLKFS_MASK MAKE_REG_MASK(0xFF,8) //((uint32_t)0x0000FF00) #define SDHC_SYSCTL_DVS(n) MAKE_REG_SET(n,0xF,4) //(uint32_t)(((n) & 0xF)<<4) // Divisor #define SDHC_SYSCTL_DVS_MASK MAKE_REG_MASK(0xF,4) //((uint32_t)0x000000F0) #define SDHC_SYSCTL_SDCLKEN ((uint32_t)0x00000008) // SD Clock Enable #define SDHC_SYSCTL_PEREN ((uint32_t)0x00000004) // Peripheral Clock Enable #define SDHC_SYSCTL_HCKEN ((uint32_t)0x00000002) // System Clock Enable #define SDHC_SYSCTL_IPGEN ((uint32_t)0x00000001) // IPG Clock Enable #define SDHC_IRQSTAT_DMAE MAKE_REG_MASK(0x1,28) //((uint32_t)0x10000000) // DMA Error #define SDHC_IRQSTAT_TNE MAKE_REG_MASK(0x1,26) // #define SDHC_IRQSTAT_AC12E MAKE_REG_MASK(0x1,24) //((uint32_t)0x01000000) // Auto CMD12 Error #define SDHC_IRQSTAT_DEBE MAKE_REG_MASK(0x1,22) //((uint32_t)0x00400000) // Data End Bit Error #define SDHC_IRQSTAT_DCE MAKE_REG_MASK(0x1,21) //((uint32_t)0x00200000) // Data CRC Error #define SDHC_IRQSTAT_DTOE MAKE_REG_MASK(0x1,20) //((uint32_t)0x00100000) // Data Timeout Error #define SDHC_IRQSTAT_CIE MAKE_REG_MASK(0x1,19) //((uint32_t)0x00080000) // Command Index Error #define SDHC_IRQSTAT_CEBE MAKE_REG_MASK(0x1,18) //((uint32_t)0x00040000) // Command End Bit Error #define SDHC_IRQSTAT_CCE MAKE_REG_MASK(0x1,17) //((uint32_t)0x00020000) // Command CRC Error #define SDHC_IRQSTAT_CTOE MAKE_REG_MASK(0x1,16) //((uint32_t)0x00010000) // Command Timeout Error #define SDHC_IRQSTAT_TP MAKE_REG_MASK(0x1,14) // #define SDHC_IRQSTAT_RTE MAKE_REG_MASK(0x1,12) // #define SDHC_IRQSTAT_CINT MAKE_REG_MASK(0x1,8) //((uint32_t)0x00000100) // Card Interrupt #define SDHC_IRQSTAT_CRM MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // Card Removal #define SDHC_IRQSTAT_CINS MAKE_REG_MASK(0x1,6) //((uint32_t)0x00000040) // Card Insertion #define SDHC_IRQSTAT_BRR MAKE_REG_MASK(0x1,5) //((uint32_t)0x00000020) // Buffer Read Ready #define SDHC_IRQSTAT_BWR MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Buffer Write Ready #define SDHC_IRQSTAT_DINT MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008) // DMA Interrupt #define SDHC_IRQSTAT_BGE MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004) // Block Gap Event #define SDHC_IRQSTAT_TC MAKE_REG_MASK(0x1,1) //((uint32_t)0x00000002) // Transfer Complete #define SDHC_IRQSTAT_CC MAKE_REG_MASK(0x1,0) //((uint32_t)0x00000001) // Command Complete #define SDHC_IRQSTATEN_DMAESEN MAKE_REG_MASK(0x1,28) //((uint32_t)0x10000000) // DMA Error Status Enable #define SDHC_IRQSTATEN_TNESEN MAKE_REG_MASK(0x1,26) // #define SDHC_IRQSTATEN_AC12ESEN MAKE_REG_MASK(0x1,24) //((uint32_t)0x01000000) // Auto CMD12 Error Status Enable #define SDHC_IRQSTATEN_DEBESEN MAKE_REG_MASK(0x1,22) //((uint32_t)0x00400000) // Data End Bit Error Status Enable #define SDHC_IRQSTATEN_DCESEN MAKE_REG_MASK(0x1,21) //((uint32_t)0x00200000) // Data CRC Error Status Enable #define SDHC_IRQSTATEN_DTOESEN MAKE_REG_MASK(0x1,20) //((uint32_t)0x00100000) // Data Timeout Error Status Enable #define SDHC_IRQSTATEN_CIESEN MAKE_REG_MASK(0x1,19) //((uint32_t)0x00080000) // Command Index Error Status Enable #define SDHC_IRQSTATEN_CEBESEN MAKE_REG_MASK(0x1,18) //((uint32_t)0x00040000) // Command End Bit Error Status Enable #define SDHC_IRQSTATEN_CCESEN MAKE_REG_MASK(0x1,17) //((uint32_t)0x00020000) // Command CRC Error Status Enable #define SDHC_IRQSTATEN_CTOESEN MAKE_REG_MASK(0x1,16) //((uint32_t)0x00010000) // Command Timeout Error Status Enable #define SDHC_IRQSTATEN_TPSEN MAKE_REG_MASK(0x1,14) // #define SDHC_IRQSTATEN_RTESEN MAKE_REG_MASK(0x1,12) // #define SDHC_IRQSTATEN_CINTSEN MAKE_REG_MASK(0x1,8) //((uint32_t)0x00000100) // Card Interrupt Status Enable #define SDHC_IRQSTATEN_CRMSEN MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // Card Removal Status Enable #define SDHC_IRQSTATEN_CINSEN MAKE_REG_MASK(0x1,6) //((uint32_t)0x00000040) // Card Insertion Status Enable #define SDHC_IRQSTATEN_BRRSEN MAKE_REG_MASK(0x1,5) //((uint32_t)0x00000020) // Buffer Read Ready Status Enable #define SDHC_IRQSTATEN_BWRSEN MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Buffer Write Ready Status Enable #define SDHC_IRQSTATEN_DINTSEN MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008) // DMA Interrupt Status Enable #define SDHC_IRQSTATEN_BGESEN MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004) // Block Gap Event Status Enable #define SDHC_IRQSTATEN_TCSEN MAKE_REG_MASK(0x1,1) //((uint32_t)0x00000002) // Transfer Complete Status Enable #define SDHC_IRQSTATEN_CCSEN MAKE_REG_MASK(0x1,0) //((uint32_t)0x00000001) // Command Complete Status Enable #define SDHC_IRQSIGEN_DMAEIEN MAKE_REG_MASK(0x1,28) //((uint32_t)0x10000000) // DMA Error Interrupt Enable #define SDHC_IRQSIGEN_TNEIEN MAKE_REG_MASK(0x1,26) // #define SDHC_IRQSIGEN_AC12EIEN MAKE_REG_MASK(0x1,24) //((uint32_t)0x01000000) // Auto CMD12 Error Interrupt Enable #define SDHC_IRQSIGEN_DEBEIEN MAKE_REG_MASK(0x1,22) //((uint32_t)0x00400000) // Data End Bit Error Interrupt Enable #define SDHC_IRQSIGEN_DCEIEN MAKE_REG_MASK(0x1,21) //((uint32_t)0x00200000) // Data CRC Error Interrupt Enable #define SDHC_IRQSIGEN_DTOEIEN MAKE_REG_MASK(0x1,20) //((uint32_t)0x00100000) // Data Timeout Error Interrupt Enable #define SDHC_IRQSIGEN_CIEIEN MAKE_REG_MASK(0x1,19) //((uint32_t)0x00080000) // Command Index Error Interrupt Enable #define SDHC_IRQSIGEN_CEBEIEN MAKE_REG_MASK(0x1,18) //((uint32_t)0x00040000) // Command End Bit Error Interrupt Enable #define SDHC_IRQSIGEN_CCEIEN MAKE_REG_MASK(0x1,17) //((uint32_t)0x00020000) // Command CRC Error Interrupt Enable #define SDHC_IRQSIGEN_CTOEIEN MAKE_REG_MASK(0x1,16) //((uint32_t)0x00010000) // Command Timeout Error Interrupt Enable #define SDHC_IRQSIGEN_TPIEN MAKE_REG_MASK(0x1,14) // #define SDHC_IRQSIGEN_RTEIEN MAKE_REG_MASK(0x1,12) // #define SDHC_IRQSIGEN_CINTIEN MAKE_REG_MASK(0x1,8) //((uint32_t)0x00000100) // Card Interrupt Interrupt Enable #define SDHC_IRQSIGEN_CRMIEN MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // Card Removal Interrupt Enable #define SDHC_IRQSIGEN_CINSIEN MAKE_REG_MASK(0x1,6) //((uint32_t)0x00000040) // Card Insertion Interrupt Enable #define SDHC_IRQSIGEN_BRRIEN MAKE_REG_MASK(0x1,5) //((uint32_t)0x00000020) // Buffer Read Ready Interrupt Enable #define SDHC_IRQSIGEN_BWRIEN MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Buffer Write Ready Interrupt Enable #define SDHC_IRQSIGEN_DINTIEN MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008) // DMA Interrupt Interrupt Enable #define SDHC_IRQSIGEN_BGEIEN MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004) // Block Gap Event Interrupt Enable #define SDHC_IRQSIGEN_TCIEN MAKE_REG_MASK(0x1,1) //((uint32_t)0x00000002) // Transfer Complete Interrupt Enable #define SDHC_IRQSIGEN_CCIEN MAKE_REG_MASK(0x1,0) //((uint32_t)0x00000001) // Command Complete Interrupt Enable #define SDHC_AC12ERR_SMPLCLK_SEL MAKE_REG_MASK(0x1,23) // #define SDHC_AC12ERR_EXEC_TUNING MAKE_REG_MASK(0x1,22) // #define SDHC_AC12ERR_CNIBAC12E MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // Command Not Issued By Auto CMD12 Error #define SDHC_AC12ERR_AC12IE MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Auto CMD12 Index Error #define SDHC_AC12ERR_AC12CE MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008) // Auto CMD12 CRC Error #define SDHC_AC12ERR_AC12EBE MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004) // Auto CMD12 End Bit Error #define SDHC_AC12ERR_AC12TOE MAKE_REG_MASK(0x1,1) //((uint32_t)0x00000002) // Auto CMD12 Timeout Error #define SDHC_AC12ERR_AC12NE MAKE_REG_MASK(0x1,0) //((uint32_t)0x00000001) // Auto CMD12 Not Executed #define SDHC_HTCAPBLT_VS18 MAKE_REG_MASK(0x1,26) // #define SDHC_HTCAPBLT_VS30 MAKE_REG_MASK(0x1,25) // #define SDHC_HTCAPBLT_VS33 MAKE_REG_MASK(0x1,24) // #define SDHC_HTCAPBLT_SRS MAKE_REG_MASK(0x1,23) // #define SDHC_HTCAPBLT_DMAS MAKE_REG_MASK(0x1,22) // #define SDHC_HTCAPBLT_HSS MAKE_REG_MASK(0x1,21) // #define SDHC_HTCAPBLT_ADMAS MAKE_REG_MASK(0x1,20) // #define SDHC_HTCAPBLT_MBL_VAL MAKE_REG_GET((USDHC1_HOST_CTRL_CAP),0x7,16) // #define SDHC_HTCAPBLT_RETUN_MODE MAKE_REG_GET((USDHC1_HOST_CTRL_CAP),0x3,14) // #define SDHC_HTCAPBLT_TUNE_SDR50 MAKE_REG_MASK(0x1,13) // #define SDHC_HTCAPBLT_TIME_RETUN(n) MAKE_REG_SET(n,0xF,8) // #define SDHC_WML_WR_BRSTLEN_MASK MAKE_REG_MASK(0x1F,24) // #define SDHC_WML_RD_BRSTLEN_MASK MAKE_REG_MASK(0x1F,8) // #define SDHC_WML_WR_WML_MASK MAKE_REG_MASK(0xFF,16) // #define SDHC_WML_RD_WML_MASK MAKE_REG_MASK(0xFF,0) // #define SDHC_WML_WR_BRSTLEN(n) MAKE_REG_SET(n,0x1F,24) //(uint32_t)(((n) & 0x7F)<<16) // Write Burst Len #define SDHC_WML_RD_BRSTLEN(n) MAKE_REG_SET(n,0x1F,8) //(uint32_t)(((n) & 0x7F)<<0) // Read Burst Len #define SDHC_WML_WR_WML(n) MAKE_REG_SET(n,0xFF,16) //(uint32_t)(((n) & 0x7F)<<16) // Write Watermark Level #define SDHC_WML_RD_WML(n) MAKE_REG_SET(n,0xFF,0) //(uint32_t)(((n) & 0x7F)<<0) // Read Watermark Level #define SDHC_WML_WRWML(n) MAKE_REG_SET(n,0xFF,16) //(uint32_t)(((n) & 0x7F)<<16) // Write Watermark Level #define SDHC_WML_RDWML(n) MAKE_REG_SET(n,0xFF,0) //(uint32_t)(((n) & 0x7F)<<0) // Read Watermark Level // Teensy 4.0 only #define SDHC_MIX_CTRL_DMAEN MAKE_REG_MASK(0x1,0) // #define SDHC_MIX_CTRL_BCEN MAKE_REG_MASK(0x1,1) // #define SDHC_MIX_CTRL_AC12EN MAKE_REG_MASK(0x1,2) // #define SDHC_MIX_CTRL_DDR_EN MAKE_REG_MASK(0x1,3) // #define SDHC_MIX_CTRL_DTDSEL MAKE_REG_MASK(0x1,4) // #define SDHC_MIX_CTRL_MSBSEL MAKE_REG_MASK(0x1,5) // #define SDHC_MIX_CTRL_NIBBLE_POS MAKE_REG_MASK(0x1,6) // #define SDHC_MIX_CTRL_AC23EN MAKE_REG_MASK(0x1,7) // #define SDHC_FEVT_CINT MAKE_REG_MASK(0x1,31) //((uint32_t)0x80000000) // Force Event Card Interrupt #define SDHC_FEVT_DMAE MAKE_REG_MASK(0x1,28) //((uint32_t)0x10000000) // Force Event DMA Error #define SDHC_FEVT_AC12E MAKE_REG_MASK(0x1,24) //((uint32_t)0x01000000) // Force Event Auto CMD12 Error #define SDHC_FEVT_DEBE MAKE_REG_MASK(0x1,22) //((uint32_t)0x00400000) // Force Event Data End Bit Error #define SDHC_FEVT_DCE MAKE_REG_MASK(0x1,21) //((uint32_t)0x00200000) // Force Event Data CRC Error #define SDHC_FEVT_DTOE MAKE_REG_MASK(0x1,20) //((uint32_t)0x00100000) // Force Event Data Timeout Error #define SDHC_FEVT_CIE MAKE_REG_MASK(0x1,19) //((uint32_t)0x00080000) // Force Event Command Index Error #define SDHC_FEVT_CEBE MAKE_REG_MASK(0x1,18) //((uint32_t)0x00040000) // Force Event Command End Bit Error #define SDHC_FEVT_CCE MAKE_REG_MASK(0x1,17) //((uint32_t)0x00020000) // Force Event Command CRC Error #define SDHC_FEVT_CTOE MAKE_REG_MASK(0x1,16) //((uint32_t)0x00010000) // Force Event Command Timeout Error #define SDHC_FEVT_CNIBAC12E MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // Force Event Command Not Executed By Auto Command 12 Error #define SDHC_FEVT_AC12IE MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Force Event Auto Command 12 Index Error #define SDHC_FEVT_AC12EBE MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008) // Force Event Auto Command 12 End Bit Error #define SDHC_FEVT_AC12CE MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004) // Force Event Auto Command 12 CRC Error #define SDHC_FEVT_AC12TOE MAKE_REG_MASK(0x1,1) //((uint32_t)0x00000002) // Force Event Auto Command 12 Time Out Error #define SDHC_FEVT_AC12NE MAKE_REG_MASK(0x1,0) //((uint32_t)0x00000001) // Force Event Auto Command 12 Not Executed #define SDHC_ADMAES_ADMADCE MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008) #define SDHC_ADMAES_ADMALME MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004) #define SDHC_ADMAES_ADMAES_MASK MAKE_REG_MASK(0x3,0) //((uint32_t)0x00000003) #define SDHC_MMCBOOT_BOOTBLKCNT(n) MAKE_REG_MASK(0xFF,16) //(uint32_t)(((n) & 0xFFF)<<16) // stop at block gap value of automatic mode #define SDHC_MMCBOOT_AUTOSABGEN MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // enable auto stop at block gap function #define SDHC_MMCBOOT_BOOTEN MAKE_REG_MASK(0x1,6) //((uint32_t)0x00000040) // Boot Mode Enable #define SDHC_MMCBOOT_BOOTMODE MAKE_REG_MASK(0x1,5) //((uint32_t)0x00000020) // Boot Mode Select #define SDHC_MMCBOOT_BOOTACK MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Boot Ack Mode Select #define SDHC_MMCBOOT_DTOCVACK(n) MAKE_REG_MASK(0xF,0) //(uint32_t)(((n) & 0xF)<<0) // Boot ACK Time Out Counter Value //#define SDHC_HOSTVER (*(volatile uint32_t *)0x400B10FC) // Host Controller Version #define CCM_ANALOG_PFD_528_PFD0_FRAC_MASK 0x3f #define CCM_ANALOG_PFD_528_PFD0_FRAC(n) ((n) & CCM_ANALOG_PFD_528_PFD0_FRAC_MASK) #define CCM_ANALOG_PFD_528_PFD1_FRAC_MASK (0x3f<<8) #define CCM_ANALOG_PFD_528_PFD1_FRAC(n) (((n)<<8) & CCM_ANALOG_PFD_528_PFD1_FRAC_MASK) #define CCM_ANALOG_PFD_528_PFD2_FRAC_MASK (0x3f<<16) #define CCM_ANALOG_PFD_528_PFD2_FRAC(n) (((n)<<16) & CCM_ANALOG_PFD_528_PFD2_FRAC_MASK) #define CCM_ANALOG_PFD_528_PFD3_FRAC_MASK ((0x3f<<24) #define CCM_ANALOG_PFD_528_PFD3_FRAC(n) (((n)<<24) & CCM_ANALOG_PFD_528_PFD3_FRAC_MASK) #define SDHC_DSADDR (USDHC1_DS_ADDR ) // DMA System Address register #define SDHC_BLKATTR (USDHC1_BLK_ATT) // Block Attributes register #define SDHC_CMDARG (USDHC1_CMD_ARG) // Command Argument register #define SDHC_XFERTYP (USDHC1_CMD_XFR_TYP) // Transfer Type register #define SDHC_CMDRSP0 (USDHC1_CMD_RSP0) // Command Response 0 #define SDHC_CMDRSP1 (USDHC1_CMD_RSP1) // Command Response 1 #define SDHC_CMDRSP2 (USDHC1_CMD_RSP2) // Command Response 2 #define SDHC_CMDRSP3 (USDHC1_CMD_RSP3) // Command Response 3 #define SDHC_DATPORT (USDHC1_DATA_BUFF_ACC_PORT) // Buffer Data Port register #define SDHC_PRSSTAT (USDHC1_PRES_STATE) // Present State register #define SDHC_PROCTL (USDHC1_PROT_CTRL) // Protocol Control register #define SDHC_SYSCTL (USDHC1_SYS_CTRL) // System Control register #define SDHC_IRQSTAT (USDHC1_INT_STATUS) // Interrupt Status register #define SDHC_IRQSTATEN (USDHC1_INT_STATUS_EN) // Interrupt Status Enable register #define SDHC_IRQSIGEN (USDHC1_INT_SIGNAL_EN) // Interrupt Signal Enable register #define SDHC_AC12ERR (USDHC1_AUTOCMD12_ERR_STATUS) // Auto CMD12 Error Status Register #define SDHC_HTCAPBLT (USDHC1_HOST_CTRL_CAP) // Host Controller Capabilities #define SDHC_WML (USDHC1_WTMK_LVL) // Watermark Level Register #define SDHC_MIX_CTRL (USDHC1_MIX_CTRL) // Mixer Control #define SDHC_FEVT (USDHC1_FORCE_EVENT) // Force Event register #define SDHC_ADMAES (USDHC1_ADMA_ERR_STATUS) // ADMA Error Status register #define SDHC_ADSADDR (USDHC1_ADMA_SYS_ADDR) // ADMA System Addressregister #define SDHC_VENDOR (USDHC1_VEND_SPEC) // Vendor Specific register #define SDHC_MMCBOOT (USDHC1_MMC_BOOT) // MMC Boot register #define SDHC_VENDOR2 (USDHC2_VEND_SPEC2) // Vendor Specific2 register // //#define IRQ_SDHC IRQ_SDHC1 #define SDHC_MAX_DVS (0xF + 1U) #define SDHC_MAX_CLKFS (0xFF + 1U) #define SDHC_PREV_DVS(x) ((x) -= 1U) #define SDHC_PREV_CLKFS(x, y) ((x) >>= (y)) #define CCM_CSCDR1_USDHC1_CLK_PODF_MASK (0x7<<11) #define CCM_CSCDR1_USDHC1_CLK_PODF(n) (((n)&0x7)<<11) #define IOMUXC_SW_PAD_CTL_PAD_SRE ((0x1<)<0) #define IOMUXC_SW_PAD_CTL_PAD_PKE ((0x1)<<12) #define IOMUXC_SW_PAD_CTL_PAD_PUE ((0x1)<<13) #define IOMUXC_SW_PAD_CTL_PAD_HYS ((0x1)<<16) #define IOMUXC_SW_PAD_CTL_PAD_SPEED(n) (((n)&0x3)<<6) #define IOMUXC_SW_PAD_CTL_PAD_PUS(n) (((n)&0x3)<<14) #define IOMUXC_SW_PAD_CTL_PAD_PUS_MASK ((0x3)<<14) #define IOMUXC_SW_PAD_CTL_PAD_DSE(n) (((n)&0x7)<<3) #define IOMUXC_SW_PAD_CTL_PAD_DSE_MASK ((0x7)<<3) #endif // __IMXRT1062__ #define SDHC_IRQSIGEN_DMA_MASK (SDHC_IRQSIGEN_TCIEN | SDHC_IRQSIGEN_DINTIEN | SDHC_IRQSIGEN_DMAEIEN) #define CARD_STATUS_READY_FOR_DATA (1UL << 8) /****************************************************************************** Types ******************************************************************************/ typedef struct { uint8_t status; uint8_t highCapacity; uint8_t version2; uint8_t tranSpeed; uint32_t address; uint32_t numBlocks; uint32_t lastCardStatus; } SD_CARD_DESCRIPTOR; /****************************************************************************** Global functions ******************************************************************************/ /****************************************************************************** Private variables ******************************************************************************/ static SD_CARD_DESCRIPTOR sdCardDesc; static volatile uint32_t dmaDone=0; // /****************************************************************************** Forward declaration of private functions ******************************************************************************/ static void sdhc_setSdclk(uint32_t kHzMax); static uint8_t SDHC_Init(void); static void SDHC_InitGPIO(void); static void SDHC_ReleaseGPIO(void); //static void SDHC_SetClock(uint32_t sysctl); static uint32_t SDHC_WaitStatus(uint32_t mask); static int SDHC_ReadBlock(uint32_t* pData); static int SDHC_WriteBlock(const uint32_t* pData); static int SDHC_CMD_Do(uint32_t xfertyp); static int SDHC_CMD0_GoToIdle(void); static int SDHC_CMD2_Identify(void); static int SDHC_CMD3_GetAddress(void); static int SDHC_ACMD6_SetBusWidth(uint32_t address, uint32_t width); static int SDHC_CMD7_SelectCard(uint32_t address); static int SDHC_CMD8_SetInterface(uint32_t cond); static int SDHC_CMD9_GetParameters(uint32_t address); static int SDHC_CMD12_StopTransfer(void); static int SDHC_CMD12_StopTransferWaitForBusy(void); static int SDHC_CMD16_SetBlockSize(uint32_t block_size); static int SDHC_CMD17_ReadBlock(uint32_t sector); static int SDHC_CMD24_WriteBlock(uint32_t sector); static int SDHC_ACMD41_SendOperationCond(uint32_t cond); /****************************************************************************** Public functions ******************************************************************************/ uint8_t SDHC_CardGetType(void) { if (sdCardDesc.status) return 0; if (sdCardDesc.version2 == 0) return 1; // SD_CARD_TYPE_SD1 if (sdCardDesc.highCapacity == 0) return 2; // SD_CARD_TYPE_SD2 return 3; // SD_CARD_TYPE_SDHC } //----------------------------------------------------------------------------- // initialize the SDHC Controller and SD Card // returns status of initialization(OK, nonInit, noCard, CardProtected) uint8_t SDHC_CardInit(void) { uint8_t resS; int resR; resS = SDHC_Init(); sdCardDesc.status = resS; sdCardDesc.address = 0; sdCardDesc.highCapacity = 0; sdCardDesc.version2 = 0; sdCardDesc.numBlocks = 0; if (resS) return resS; SDHC_IRQSIGEN = 0; resR = SDHC_CMD0_GoToIdle(); if (resR) { sdCardDesc.status = SDHC_STATUS_NOINIT; return SDHC_STATUS_NOINIT; } resR = SDHC_CMD8_SetInterface(0x000001AA); // 3.3V and AA check pattern if (resR == SDHC_RESULT_OK) { if (SDHC_CMDRSP0 != 0x000001AA) { sdCardDesc.status = SDHC_STATUS_NOINIT; return SDHC_STATUS_NOINIT; } sdCardDesc.highCapacity = 1; } else if (resR == SDHC_RESULT_NO_RESPONSE) { // version 1 cards do not respond to CMD8 } else { sdCardDesc.status = SDHC_STATUS_NOINIT; return SDHC_STATUS_NOINIT; } if (SDHC_ACMD41_SendOperationCond(0)) return sdCardDesc.status = SDHC_STATUS_NOINIT; if (SDHC_CMDRSP0 & 0x300000) { uint32_t condition = 0x00300000; if (sdCardDesc.highCapacity) condition |= 0x40000000; // uint32_t ii = 0; do { ii++; if (SDHC_ACMD41_SendOperationCond(condition)) { resS = SDHC_STATUS_NOINIT; break; } } while ((!(SDHC_CMDRSP0 & 0x80000000)) && (ii < SDHC_INITIALIZATION_MAX_CNT)); if (resS) return resS; if ((ii >= SDHC_INITIALIZATION_MAX_CNT) || (!(SDHC_CMDRSP0 & 0x40000000))) sdCardDesc.highCapacity = 0; } // Card identify if (SDHC_CMD2_Identify()) return sdCardDesc.status = SDHC_STATUS_NOINIT; // Get card address if (SDHC_CMD3_GetAddress()) return sdCardDesc.status = SDHC_STATUS_NOINIT; sdCardDesc.address = SDHC_CMDRSP0 & 0xFFFF0000; // Get card parameters if (SDHC_CMD9_GetParameters(sdCardDesc.address)) return sdCardDesc.status = SDHC_STATUS_NOINIT; if (!(SDHC_CMDRSP3 & 0x00C00000)) { uint32_t read_bl_len, c_size, c_size_mult; read_bl_len = (SDHC_CMDRSP2 >> 8) & 0x0F; c_size = SDHC_CMDRSP2 & 0x03; c_size = (c_size << 10) | (SDHC_CMDRSP1 >> 22); c_size_mult = (SDHC_CMDRSP1 >> 7) & 0x07; sdCardDesc.numBlocks = (c_size + 1) * (1 << (c_size_mult + 2)) * (1 << (read_bl_len - 9)); } else { uint32_t c_size; sdCardDesc.version2 = 1; c_size = (SDHC_CMDRSP1 >> 8) & 0x003FFFFF; sdCardDesc.numBlocks = (c_size + 1) << 10; } // Select card if (SDHC_CMD7_SelectCard(sdCardDesc.address)) return sdCardDesc.status = SDHC_STATUS_NOINIT; // Set Block Size to 512 // Block Size in SDHC Controller is already set to 512 by SDHC_Init(); // Set 512 Block size in SD card if (SDHC_CMD16_SetBlockSize(SDHC_BLOCK_SIZE)) return sdCardDesc.status = SDHC_STATUS_NOINIT; // Set 4 bit data bus width if (SDHC_ACMD6_SetBusWidth(sdCardDesc.address, 2)) return sdCardDesc.status = SDHC_STATUS_NOINIT; // Set Data bus width also in SDHC controller SDHC_PROCTL &= ~SDHC_PROCTL_DTW_MASK; SDHC_PROCTL |= SDHC_PROCTL_DTW(SDHC_PROCTL_DTW_4BIT); // De-Init GPIO SDHC_ReleaseGPIO(); // Set the SDHC default baud rate sdhc_setSdclk(25000); // SDHC_SetClock(SDHC_SYSCTL_25MHZ); // TODO: use CMD6 and CMD9 to detect if card supports 50 MHz // then use CMD4 to configure card to high speed mode, // and SDHC_SetClock() for 50 MHz config // Init GPIO SDHC_InitGPIO(); return sdCardDesc.status; } //----------------------------------------------------------------------------- // FUNCTION: SDHC_CardReadBlock (disk_read) // SCOPE: SDHC public related function // DESCRIPTION: Function read block to disk // // PARAMETERS: buff - pointer on buffer where read data should be stored // sector - index of sector // // RETURNS: result of operation //----------------------------------------------------------------------------- #if 1 // read a block from disk, using polling // buff - pointer on buffer where read data should be stored // sector - index of start sector int SDHC_CardReadBlock(void * buff, uint32_t sector) { int result; uint32_t* pData = (uint32_t*)buff; // Check if this is ready if (sdCardDesc.status != 0) return SDHC_RESULT_NOT_READY; // Convert LBA to uint8_t address if needed if (!sdCardDesc.highCapacity) sector *= 512; SDHC_IRQSTAT = 0xffff; #if defined(__IMXRT1062__) SDHC_MIX_CTRL |= SDHC_MIX_CTRL_DTDSEL; #endif // Just single block mode is needed result = SDHC_CMD17_ReadBlock(sector); if(result != SDHC_RESULT_OK) return result; result = SDHC_ReadBlock(pData); // finish up while (!(SDHC_IRQSTAT & SDHC_IRQSTAT_TC)) { } // wait for transfer to complete SDHC_IRQSTAT = (SDHC_IRQSTAT_TC | SDHC_IRQSTAT_BRR | SDHC_IRQSTAT_AC12E); return result; } #else // read a block from disk, using DMA & interrupts int SDHC_CardReadBlock(void * buff, uint32_t sector) { int result=0; uint32_t* pData = (uint32_t*)buff; /* check alignment for DMA */ if (reinterpret_cast(static_cast(buff)) % 4) { return -1; } // Serial.print("Sector: "); Serial.println(sector); Serial.flush(); // Check if this is ready if (sdCardDesc.status != 0) return SDHC_RESULT_NOT_READY; while ((SDHC_PRSSTAT & SDHC_PRSSTAT_CIHB) || (SDHC_PRSSTAT & SDHC_PRSSTAT_CDIHB)); // Convert LBA to BYTE address if needed if (!sdCardDesc.highCapacity) sector *= 512; // clear status SDHC_IRQSTAT = SDHC_IRQSTAT; // use dma: disabling polling uint32_t irqstat = SDHC_IRQSTATEN; irqstat &= ~(SDHC_IRQSTATEN_BRRSEN | SDHC_IRQSTATEN_BWRSEN | SDHC_IRQSTATEN_CCSEN) ; irqstat &= ~(SDHC_IRQSTATEN_DCESEN | SDHC_IRQSTATEN_CCESEN) ; // enable status irqstat |= SDHC_IRQSTATEN_DMAESEN | SDHC_IRQSTATEN_DINTSEN | SDHC_IRQSTATEN_TCSEN ; SDHC_IRQSTATEN = irqstat; uint32_t sigen = SDHC_IRQSIGEN; sigen |= SDHC_IRQSIGEN_DMA_MASK ; SDHC_SYSCTL |= SDHC_SYSCTL_HCKEN; #if defined(__IMXRT1052__) || defined(__IMXRT1062__) SDHC_MIX_CTRL |= SDHC_MIX_CTRL_DTDSEL ; // read SDHC_MIX_CTRL |= SDHC_MIX_CTRL_DMAEN ; // DMA #endif uint32_t xfertyp = SDHC_XFERTYP_CMDINX(SDHC_CMD17) | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48) | SDHC_XFERTYP_DPSEL | SDHC_XFERTYP_DTDSEL | SDHC_XFERTYP_DMAEN; dmaDone=0; SDHC_DSADDR = (uint32_t)buff; SDHC_CMDARG = sector; SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(1) | SDHC_BLKATTR_BLKSIZE(512); SDHC_IRQSIGEN = sigen; SDHC_XFERTYP = xfertyp; // while(!dmaDone); SDHC_IRQSTAT &= (SDHC_IRQSTAT_CC | SDHC_IRQSTAT_TC); return result; } #endif //----------------------------------------------------------------------------- // FUNCTION: SDHC_CardWriteBlock (disk_write) // SCOPE: SDHC public related function // DESCRIPTION: Function write block to disk // // PARAMETERS: buff - pointer on buffer where is stored data // sector - index of sector // // RETURNS: result of operation //----------------------------------------------------------------------------- #if 1 int SDHC_CardWriteBlock(const void * buff, uint32_t sector) { int result; const uint32_t *pData = (const uint32_t *)buff; // Check if this is ready if (sdCardDesc.status != 0) return SDHC_RESULT_NOT_READY; // Convert LBA to uint8_t address if needed if(!sdCardDesc.highCapacity) sector *= 512; //SDHC_IRQSTAT = 0xffff; SDHC_IRQSTAT = SDHC_IRQSTAT; #if defined(__IMXRT1062__) SDHC_MIX_CTRL &= ~SDHC_MIX_CTRL_DTDSEL; #endif // Just single block mode is needed result = SDHC_CMD24_WriteBlock(sector); if (result != SDHC_RESULT_OK) return result; result = SDHC_WriteBlock(pData); // finish up while (!(SDHC_IRQSTAT & SDHC_IRQSTAT_TC)) { } // wait for transfer to complete SDHC_IRQSTAT = (SDHC_IRQSTAT_TC | SDHC_IRQSTAT_BWR | SDHC_IRQSTAT_AC12E); return result; } #else int SDHC_CardWriteBlock(const void * buff, uint32_t sector) { int result=0; const uint32_t *pData = (const uint32_t *)buff; /* check alignment for DMA */ if (reinterpret_cast(static_cast(buff)) % 4) { return -1; } // Check if this is ready if (sdCardDesc.status != 0) return SDHC_RESULT_NOT_READY; while ((SDHC_PRSSTAT & SDHC_PRSSTAT_CIHB) || (SDHC_PRSSTAT & SDHC_PRSSTAT_CDIHB)) ; // Convert LBA to uint8_t address if needed if (!sdCardDesc.highCapacity) sector *= 512; // clear status SDHC_IRQSTAT = SDHC_IRQSTAT; uint32_t irqstat = SDHC_IRQSTATEN; // use dma: disabling polling irqstat &= ~(SDHC_IRQSTATEN_BRRSEN | SDHC_IRQSTATEN_BWRSEN | SDHC_IRQSTATEN_CCSEN) ; irqstat &= ~(SDHC_IRQSTATEN_DCESEN | SDHC_IRQSTATEN_CCESEN) ; // enable status irqstat |= /*SDHC_IRQSTATEN_DCESEN | SDHC_IRQSTATEN_CCESEN | */SDHC_IRQSTATEN_DMAESEN ; irqstat |= SDHC_IRQSTATEN_DINTSEN | SDHC_IRQSTATEN_TCSEN ; SDHC_IRQSTATEN = irqstat; uint32_t sigen = SDHC_IRQSIGEN; sigen |= SDHC_IRQSIGEN_DMA_MASK ; SDHC_SYSCTL |= SDHC_SYSCTL_HCKEN; #if defined(__IMXRT1052__) SDHC_MIX_CTRL &= ~ SDHC_MIX_CTRL_DTDSEL; // write SDHC_MIX_CTRL |= SDHC_MIX_CTRL_DMAEN ; //DMA #endif uint32_t xfertyp = SDHC_XFERTYP_CMDINX(SDHC_CMD24) | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48) | SDHC_XFERTYP_DPSEL | SDHC_XFERTYP_DMAEN; dmaDone=0; SDHC_DSADDR = (uint32_t)buff; SDHC_CMDARG = sector; SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(1) | SDHC_BLKATTR_BLKSIZE(512); SDHC_IRQSIGEN = sigen; SDHC_XFERTYP = xfertyp; // while(!dmaDone); SDHC_IRQSTAT &= (SDHC_IRQSTAT_CC | SDHC_IRQSTAT_TC); while(SDHC_PRSSTAT & SDHC_PRSSTAT_DLA); //check for uSD status do { while ((SDHC_PRSSTAT & SDHC_PRSSTAT_CIHB) || (SDHC_PRSSTAT & SDHC_PRSSTAT_CDIHB)) ; SDHC_IRQSTATEN |= SDHC_IRQSTATEN_CCSEN; SDHC_IRQSTAT=SDHC_IRQSTAT; // CMD13 to check uSD status xfertyp = (SDHC_XFERTYP_CMDINX(SDHC_CMD13) | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48)); // SDHC_CMDARG = sdCardDesc.address; SDHC_XFERTYP = xfertyp; while(!(SDHC_IRQSTAT & SDHC_IRQSTAT_CC)); SDHC_IRQSTAT &= SDHC_IRQSTAT_CC; } while(SDHC_CMDRSP0 & 0x200); // while data? // } while(!(SDHC_CMDRSP0 & CARD_STATUS_READY_FOR_DATA )); return result; } #endif /****************************************************************************** Private functions ******************************************************************************/ #if defined(__MK64FX512__) || defined(__MK66FX1M0__) // Teensy 3.5 & 3.6 // initialize the SDHC Controller signals static void SDHC_InitGPIO(void) { PORTE_PCR0 = PORT_PCR_MUX(4) | PORT_PCR_PS | PORT_PCR_PE | PORT_PCR_DSE; /* SDHC.D1 */ PORTE_PCR1 = PORT_PCR_MUX(4) | PORT_PCR_PS | PORT_PCR_PE | PORT_PCR_DSE; /* SDHC.D0 */ PORTE_PCR2 = PORT_PCR_MUX(4) | PORT_PCR_DSE; /* SDHC.CLK */ PORTE_PCR3 = PORT_PCR_MUX(4) | PORT_PCR_PS | PORT_PCR_PE | PORT_PCR_DSE; /* SDHC.CMD */ PORTE_PCR4 = PORT_PCR_MUX(4) | PORT_PCR_PS | PORT_PCR_PE | PORT_PCR_DSE; /* SDHC.D3 */ PORTE_PCR5 = PORT_PCR_MUX(4) | PORT_PCR_PS | PORT_PCR_PE | PORT_PCR_DSE; /* SDHC.D2 */ } // release the SDHC Controller signals static void SDHC_ReleaseGPIO(void) { PORTE_PCR0 = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; /* PULLUP SDHC.D1 */ PORTE_PCR1 = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; /* PULLUP SDHC.D0 */ PORTE_PCR2 = 0; /* SDHC.CLK */ PORTE_PCR3 = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; /* PULLUP SDHC.CMD */ PORTE_PCR4 = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; /* PULLUP SDHC.D3 */ PORTE_PCR5 = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; /* PULLUP SDHC.D2 */ } void initClock() { #ifdef HAS_KINETIS_MPU // Allow SDHC Bus Master access. MPU_RGDAAC0 |= 0x0C000000; #endif // Enable SDHC clock. SIM_SCGC3 |= SIM_SCGC3_SDHC; } uint32_t sdhcClock() { return F_CPU; } #else // Teensy 4.0 static void SDHC_InitGPIO(void) { IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_04 = 0; //DAT2 IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_05 = 0; //DAT3 IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_00 = 0; //CMD //3.3V IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_01 = 0; //CLK //GND IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_02 = 0; //DAT0 IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_03 = 0; //DAT1 const uint32_t CLOCK_MASK = IOMUXC_SW_PAD_CTL_PAD_PKE | IOMUXC_SW_PAD_CTL_PAD_DSE(1) | 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)); IOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B0_04 = DATA_MASK; IOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B0_05 = DATA_MASK; IOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B0_00 = DATA_MASK; IOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B0_01 = CLOCK_MASK; IOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B0_02 = DATA_MASK; IOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B0_03 = DATA_MASK; } static void SDHC_ReleaseGPIO(void) { IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_04 = 5; //GPIO3_IO16 IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_05 = 5; //GPIO3_IO17 IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_00 = 5; //GPIO3_IO12 //3.3V IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_01 = 5; //GPIO3_IO13 //GND IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_02 = 5; //GPIO3_IO14 IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_03 = 5; //GPIO3_IO15 } 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); // PLL2PFD2 CCM_CSCMR1 |= CCM_CSCMR1_USDHC1_CLK_SEL; // PLL2PFD0 CCM_CSCDR1 |= CCM_CSCDR1_USDHC1_CLK_PODF((7)); // &0x7 // for testing //CCM_CCOSR = CCM_CCOSR_CLKO1_EN | CCM_CCOSR_CLKO1_DIV(7) | CCM_CCOSR_CLKO1_SEL(1); //(1: SYS_PLL/2) //IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_04 = 6; //CCM_CLKO1 (0 is USDHC1_DAT2) // for testing //CCM_CCOSR |= (CCM_CCOSR_CLKO2_EN | CCM_CCOSR_CLKO2_DIV(7) | CCM_CCOSR_CLKO2_SEL(3)); //(3: usdhc1_clk_root)) //IOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_05 = 6; //CCM_CLKO2 (0 is USDHC1_DAT3) } uint32_t sdhcClock() { uint32_t divider = ((CCM_CSCDR1 >> 11) & 0x7) + 1; uint32_t PLL2PFD0 = (528000000U * 3) / ((CCM_ANALOG_PFD_528 & 0x3F) / 6) / divider; return PLL2PFD0; } #endif /* //may be useful for debugging static void printRegs() { // Serial.print("DS_ADDR: "); Serial.println(SDHC_DSADDR,HEX); // DMA System Address register Serial.print("BLK_ATT: "); Serial.println(SDHC_BLKATTR,HEX); // Block Attributes register // Serial.print("CMD_ARG: "); Serial.println(SDHC_CMDARG,HEX); // Command Argument register // Serial.print("CMD_XFR_TYP: "); Serial.println(SDHC_XFERTYP,HEX); // Transfer Type register // Serial.print("CMD_RSP0: "); Serial.println(SDHC_CMDRSP0,HEX); // Command Response 0 // Serial.print("CMD_RSP1: "); Serial.println(SDHC_CMDRSP1,HEX); // Command Response 1 // Serial.print("CMD_RSP2: "); Serial.println(SDHC_CMDRSP2,HEX); // Command Response 2 // Serial.print("CMD_RSP3: "); Serial.println(SDHC_CMDRSP3,HEX); // Command Response 3 // Serial.print("DATA_BUFF_ACC_POR: "); Serial.println(SDHC_DATPORT,HEX); // Buffer Data Port register Serial.print("PRES_STATE: "); Serial.println(SDHC_PRSSTAT,HEX); // Present State register Serial.print("PROT_CTRL: "); Serial.println(SDHC_PROCTL,HEX); // Protocol Control register Serial.print("SYS_CTRL: "); Serial.println(SDHC_SYSCTL,HEX); // System Control register Serial.print("INT_STATUS: "); Serial.println(SDHC_IRQSTAT,HEX); // Interrupt Status register Serial.print("INT_STATUS_EN: "); Serial.println(SDHC_IRQSTATEN,HEX); // Interrupt Status Enable register Serial.print("INT_SIGNAL_EN: "); Serial.println(SDHC_IRQSIGEN,HEX); // Interrupt Signal Enable register // Serial.print("AUTOCMD12_ERR_STATUS: "); Serial.println(SDHC_AC12ERR,HEX); // Auto CMD12 Error Status Register Serial.print("HOST_CTRL_CAP: "); Serial.println(SDHC_HTCAPBLT,HEX); // Host Controller Capabilities Serial.print("WTMK_LVL: "); Serial.println(SDHC_WML,HEX); // Watermark Level Register #if defined(__IMXRT1052__) Serial.print("MIX_CTRL: "); Serial.println(SDHC_MIX_CTRL,HEX); // Mixer Control #endif // Serial.print("FORCE_EVENT: "); Serial.println(SDHC_FEVT,HEX); // Force Event register // Serial.print("ADMA_ERR_STATUS: "); Serial.println(SDHC_ADMAES,HEX); // ADMA Error Status register // Serial.print("ADMA_SYS_ADDR: "); Serial.println(SDHC_ADSADDR,HEX); // ADMA System Addressregister Serial.print("VEND_SPEC: "); Serial.println(SDHC_VENDOR,HEX); // Vendor Specific register // Serial.print("MMC_BOOT: "); Serial.println(SDHC_MMCBOOT,HEX); // MMC Boot register #if defined(__IMXRT1052__) Serial.print("VEND_SPEC2: "); Serial.println(SDHC_VENDOR2,HEX); // Vendor Specific2 register #endif } */ static void sdhc_setSdclk(uint32_t kHzMax) { const uint32_t DVS_LIMIT = 0X10; const uint32_t SDCLKFS_LIMIT = 0X100; uint32_t dvs = 1; uint32_t sdclkfs = 1; uint32_t maxSdclk = 1000 * kHzMax; // uint32_t f_pll = F_CPU; uint32_t f_pll = sdhcClock(); while ((f_pll / (sdclkfs * DVS_LIMIT) > maxSdclk) && (sdclkfs < SDCLKFS_LIMIT)) { sdclkfs <<= 1; } while ((f_pll / (sdclkfs * dvs) > maxSdclk) && (dvs < DVS_LIMIT)) { dvs++; } //uint32_t m_sdClkKhz = f_pll / (1000 * sdclkfs * dvs); sdclkfs >>= 1; dvs--; #if defined(__MK64FX512__) || defined(__MK66FX1M0__) // Disable SDHC clock. SDHC_SYSCTL &= ~SDHC_SYSCTL_SDCLKEN; #endif // Change dividers. uint32_t sysctl = SDHC_SYSCTL & ~(SDHC_SYSCTL_DTOCV_MASK | SDHC_SYSCTL_DVS_MASK | SDHC_SYSCTL_SDCLKFS_MASK); SDHC_SYSCTL = sysctl | SDHC_SYSCTL_DTOCV(0x0E) | SDHC_SYSCTL_DVS(dvs) | SDHC_SYSCTL_SDCLKFS(sdclkfs); // Wait until the SDHC clock is stable. while (!(SDHC_PRSSTAT & SDHC_PRSSTAT_SDSTB)) { } #if defined(__MK64FX512__) || defined(__MK66FX1M0__) // Enable the SDHC clock. SDHC_SYSCTL |= SDHC_SYSCTL_SDCLKEN; #endif // Serial.printf("setSdclk: %d %d : %x %x\n\r", f_pll, m_sdClkKhz, sdclkfs, dvs); } #if 0 void sdhc_isr(void) { SDHC_IRQSIGEN &= ~SDHC_IRQSIGEN_DMA_MASK; // // Serial.print("IRQ1: "); Serial.println(SDHC_IRQSTAT,HEX); while(!(SDHC_IRQSTAT & SDHC_IRQSTAT_TC));// SDHC_IRQSTAT &= ~SDHC_IRQSTAT_TC; #if defined(__IMXRT1052__) SDHC_MIX_CTRL &= ~(SDHC_MIX_CTRL_AC23EN | SDHC_MIX_CTRL_DMAEN) ; #endif // for T3.6, seems not to hurt for T4 if(SDHC_SYSCTL & SDHC_SYSCTL_HCKEN) SDHC_SYSCTL &= ~SDHC_SYSCTL_HCKEN; SDHC_PROCTL &= ~SDHC_PROCTL_D3CD; SDHC_PROCTL |= SDHC_PROCTL_D3CD; dmaDone=1; } #endif // initialize the SDHC Controller // returns status of initialization(OK, nonInit, noCard, CardProtected) static uint8_t SDHC_Init(void) { initClock(); // De-init GPIO - to prevent unwanted clocks on bus SDHC_ReleaseGPIO(); #if defined (__IMXRT1062__) //SDHC_SYSCTL |= 0xF; SDHC_MIX_CTRL = 0x80000000; #endif /* Reset SDHC */ SDHC_SYSCTL |= SDHC_SYSCTL_RSTA | SDHC_SYSCTL_SDCLKFS(0x80); while (SDHC_SYSCTL & SDHC_SYSCTL_RSTA) ; // wait /* Set the SDHC initial baud rate divider and start */ sdhc_setSdclk(400); /* Poll inhibit bits */ while (SDHC_PRSSTAT & (SDHC_PRSSTAT_CIHB | SDHC_PRSSTAT_CDIHB)) ; /* Init GPIO again */ SDHC_InitGPIO(); /* Initial values */ // to do - Check values SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(1) | SDHC_BLKATTR_BLKSIZE(512); //SDHC_PROCTL &= ~SDHC_PROCTL_DMAS(3); // clear ADMA //SDHC_PROCTL |= SDHC_PROCTL_D3CD; //SDHC_PROCTL = SDHC_PROCTL_EMODE(SDHC_PROCTL_EMODE_INVARIANT) | SDHC_PROCTL_D3CD; SDHC_PROCTL = (SDHC_PROCTL & ~(SDHC_PROCTL_EMODE(3))) | (SDHC_PROCTL_EMODE(SDHC_PROCTL_EMODE_INVARIANT) | SDHC_PROCTL_D3CD ); //SDHC_WML = SDHC_WML_RDWML(SDHC_FIFO_BUFFER_SIZE) | SDHC_WML_WRWML(SDHC_FIFO_BUFFER_SIZE); //Serial.printf("SDHC_WML = %08X\n", SDHC_WML); // prints 08100810 (good) //#if defined(__IMXRT1062__) //SDHC_VENDOR = 0x2000F801; // (1<<29 | 0x1F<<11 | 1); //SDHC_VENDOR2 &= ~(1<<12); //switch off ACMD23 sharing SDMA //#endif /* Enable requests */ // clear interrupt status SDHC_IRQSTAT = SDHC_IRQSTAT; #if 1 SDHC_IRQSTATEN = 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_CRMSEN | SDHC_IRQSTATEN_TCSEN | SDHC_IRQSTATEN_CCSEN; #else SDHC_IRQSTATEN = //SDHC_IRQSTAT_CRM | SDHC_IRQSTATEN_CIESEN | SDHC_IRQSTATEN_TCSEN | SDHC_IRQSTATEN_CCSEN; attachInterruptVector(IRQ_SDHC, sdhc_isr); NVIC_SET_PRIORITY(IRQ_SDHC, 6 * 16); NVIC_ENABLE_IRQ(IRQ_SDHC); #endif // initial clocks... SD spec says only 74 clocks are needed, but if Teensy rebooted // while the card was in middle of an operation, thousands of clock cycles can be // needed to get the card to complete a prior command and return to a usable state. for (int ii = 0; ii < 1500; ii++) { SDHC_SYSCTL |= SDHC_SYSCTL_INITA; while (SDHC_SYSCTL & SDHC_SYSCTL_INITA) ; } // to do - check if this needed SDHC_IRQSTAT |= SDHC_IRQSTAT_CRM; // Check card if (SDHC_PRSSTAT & SDHC_PRSSTAT_CINS) { return 0; } else { return SDHC_STATUS_NODISK; } } /****************************************************************************** Private SD Card functions ******************************************************************************/ // waits for status bits sets static uint32_t SDHC_WaitStatus(uint32_t mask) { uint32_t result; uint32_t timeout = 1 << 24; do { result = SDHC_IRQSTAT & mask; timeout--; } while (!result && (timeout)); if (timeout) return result; return 0; } // reads one block static int SDHC_ReadBlock(uint32_t* pData) { uint32_t i, irqstat; const uint32_t i_max = ((SDHC_BLOCK_SIZE) / (4 * SDHC_FIFO_BUFFER_SIZE)); for (i = 0; i < i_max; i++) { irqstat = SDHC_IRQSTAT; SDHC_IRQSTAT = irqstat | SDHC_IRQSTAT_BRR; if (irqstat & (SDHC_IRQSTAT_DEBE | SDHC_IRQSTAT_DCE | SDHC_IRQSTAT_DTOE)) { SDHC_IRQSTAT = irqstat | SDHC_IRQSTAT_BRR | SDHC_IRQSTAT_DEBE | SDHC_IRQSTAT_DCE | SDHC_IRQSTAT_DTOE; SDHC_CMD12_StopTransferWaitForBusy(); return SDHC_RESULT_ERROR; } while (!(SDHC_PRSSTAT & SDHC_PRSSTAT_BREN)) { }; *pData++ = SDHC_DATPORT; *pData++ = SDHC_DATPORT; *pData++ = SDHC_DATPORT; *pData++ = SDHC_DATPORT; *pData++ = SDHC_DATPORT; *pData++ = SDHC_DATPORT; *pData++ = SDHC_DATPORT; *pData++ = SDHC_DATPORT; *pData++ = SDHC_DATPORT; *pData++ = SDHC_DATPORT; *pData++ = SDHC_DATPORT; *pData++ = SDHC_DATPORT; *pData++ = SDHC_DATPORT; *pData++ = SDHC_DATPORT; *pData++ = SDHC_DATPORT; *pData++ = SDHC_DATPORT; } return SDHC_RESULT_OK; } // writes one block static int SDHC_WriteBlock(const uint32_t* pData) { uint32_t i, i_max, j; i_max = ((SDHC_BLOCK_SIZE) / (4 * SDHC_FIFO_BUFFER_SIZE)); for(i = 0; i < i_max; i++) { while (!(SDHC_IRQSTAT & SDHC_IRQSTAT_BWR)) ; // wait if (SDHC_IRQSTAT & (SDHC_IRQSTAT_DEBE | SDHC_IRQSTAT_DCE | SDHC_IRQSTAT_DTOE)) { SDHC_IRQSTAT |= SDHC_IRQSTAT_DEBE | SDHC_IRQSTAT_DCE | SDHC_IRQSTAT_DTOE | SDHC_IRQSTAT_BWR; (void)SDHC_CMD12_StopTransferWaitForBusy(); return SDHC_RESULT_ERROR; } for(j=0; j> 24; } return result; } // sends CMD12 to stop transfer static int SDHC_CMD12_StopTransfer(void) { uint32_t xfertyp; int result; SDHC_CMDARG = 0; xfertyp = (SDHC_XFERTYP_CMDINX(SDHC_CMD12) | SDHC_XFERTYP_CMDTYP(SDHC_XFERTYP_CMDTYP_ABORT) | SDHC_XFERTYP_CICEN | SDHC_XFERTYP_CCCEN | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48BUSY)); result = SDHC_CMD_Do(xfertyp); if (result == SDHC_RESULT_OK) { } return result; } // sends CMD12 to stop transfer and first waits to ready SDCArd static int SDHC_CMD12_StopTransferWaitForBusy(void) { uint32_t timeOut = 1000; int result; do { result = SDHC_CMD12_StopTransfer(); timeOut--; } while (timeOut && (SDHC_PRSSTAT & SDHC_PRSSTAT_DLA) && result == SDHC_RESULT_OK); if (result != SDHC_RESULT_OK) return result; if (!timeOut) return SDHC_RESULT_NO_RESPONSE; return SDHC_RESULT_OK; } // sends CMD16 to set block size static int SDHC_CMD16_SetBlockSize(uint32_t block_size) { uint32_t xfertyp; int result; SDHC_CMDARG = block_size; xfertyp = (SDHC_XFERTYP_CMDINX(SDHC_CMD16) | SDHC_XFERTYP_CICEN | SDHC_XFERTYP_CCCEN | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48)); result = SDHC_CMD_Do(xfertyp); if (result == SDHC_RESULT_OK) { (void)SDHC_CMDRSP0; } return result; } // sends CMD17 to read one block static int SDHC_CMD17_ReadBlock(uint32_t sector) { uint32_t xfertyp; int result; SDHC_CMDARG = sector; SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(1) | 512; xfertyp = (SDHC_XFERTYP_CMDINX(SDHC_CMD17) | SDHC_XFERTYP_CICEN | SDHC_XFERTYP_CCCEN | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48) | SDHC_XFERTYP_DTDSEL | SDHC_XFERTYP_DPSEL); result = SDHC_CMD_Do(xfertyp); if (result == SDHC_RESULT_OK) { ( void)SDHC_CMDRSP0; } return result; } // sends CMD24 to write one block static int SDHC_CMD24_WriteBlock(uint32_t sector) { uint32_t xfertyp; int result; SDHC_CMDARG = sector; SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(1) | 512; xfertyp = (SDHC_XFERTYP_CMDINX(SDHC_CMD24) | SDHC_XFERTYP_CICEN | SDHC_XFERTYP_CCCEN | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48) | SDHC_XFERTYP_DPSEL); result = SDHC_CMD_Do(xfertyp); if (result == SDHC_RESULT_OK) { (void)SDHC_CMDRSP0; } return result; } // ACMD 41 to send operation condition static int SDHC_ACMD41_SendOperationCond(uint32_t cond) { uint32_t xfertyp; int result; SDHC_CMDARG = 0; // first send CMD 55 Application specific command xfertyp = (SDHC_XFERTYP_CMDINX(SDHC_CMD55) | SDHC_XFERTYP_CICEN | SDHC_XFERTYP_CCCEN | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48)); result = SDHC_CMD_Do(xfertyp); if (result == SDHC_RESULT_OK) { (void)SDHC_CMDRSP0; } else { return result; } SDHC_CMDARG = cond; // Send 41CMD xfertyp = (SDHC_XFERTYP_CMDINX(SDHC_ACMD41) | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48)); result = SDHC_CMD_Do(xfertyp); if (result == SDHC_RESULT_OK) { (void)SDHC_CMDRSP0; } return result; } #endif // __MK64FX512__ or __MK66FX1M0__ or __IMXRT1052__