1443 lines
60 KiB
C++
1443 lines
60 KiB
C++
// 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 <stdio.h>
|
|
#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<uintptr_t>(static_cast<const void*>(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<uintptr_t>(static_cast<const void*>(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<SDHC_FIFO_BUFFER_SIZE; j++) {
|
|
SDHC_DATPORT = *pData++;
|
|
}
|
|
SDHC_IRQSTAT |= SDHC_IRQSTAT_BWR;
|
|
|
|
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;
|
|
}
|
|
}
|
|
return SDHC_RESULT_OK;
|
|
}
|
|
|
|
// sends the command to SDcard
|
|
static int SDHC_CMD_Do(uint32_t xfertyp)
|
|
{
|
|
// Card removal check preparation
|
|
SDHC_IRQSTAT |= SDHC_IRQSTAT_CRM;
|
|
|
|
// Wait for cmd line idle // to do timeout PRSSTAT[CDIHB] and the PRSSTAT[CIHB]
|
|
while ((SDHC_PRSSTAT & SDHC_PRSSTAT_CIHB) || (SDHC_PRSSTAT & SDHC_PRSSTAT_CDIHB)) { };
|
|
SDHC_XFERTYP = xfertyp;
|
|
|
|
/* Wait for response */
|
|
const uint32_t mask = SDHC_IRQSTAT_CIE | SDHC_IRQSTAT_CEBE | SDHC_IRQSTAT_CCE | SDHC_IRQSTAT_CC;
|
|
if (SDHC_WaitStatus(mask) != SDHC_IRQSTAT_CC) {
|
|
//SDHC_IRQSTAT |= mask;
|
|
SDHC_IRQSTAT |= (mask | SDHC_IRQSTAT_CTOE);
|
|
return SDHC_RESULT_ERROR;
|
|
}
|
|
/* Check card removal */
|
|
if (SDHC_IRQSTAT & SDHC_IRQSTAT_CRM) {
|
|
SDHC_IRQSTAT |= SDHC_IRQSTAT_CTOE | SDHC_IRQSTAT_CC;
|
|
return SDHC_RESULT_NOT_READY;
|
|
}
|
|
|
|
/* Get response, if available */
|
|
if (SDHC_IRQSTAT & SDHC_IRQSTAT_CTOE) {
|
|
SDHC_IRQSTAT |= SDHC_IRQSTAT_CTOE | SDHC_IRQSTAT_CC;
|
|
return SDHC_RESULT_NO_RESPONSE;
|
|
}
|
|
SDHC_IRQSTAT |= SDHC_IRQSTAT_CC;
|
|
|
|
return SDHC_RESULT_OK;
|
|
}
|
|
|
|
// sends CMD0 to put SDCARD to idle
|
|
static int SDHC_CMD0_GoToIdle(void)
|
|
{
|
|
uint32_t xfertyp;
|
|
int result;
|
|
|
|
SDHC_CMDARG = 0;
|
|
|
|
xfertyp = (SDHC_XFERTYP_CMDINX(SDHC_CMD0) | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_NO));
|
|
|
|
result = SDHC_CMD_Do(xfertyp);
|
|
|
|
if (result == SDHC_RESULT_OK) { (void)SDHC_CMDRSP0; }
|
|
return result;
|
|
}
|
|
|
|
// sends CMD2 to identify card
|
|
static int SDHC_CMD2_Identify(void)
|
|
{
|
|
uint32_t xfertyp;
|
|
int result;
|
|
|
|
SDHC_CMDARG = 0;
|
|
|
|
xfertyp = (SDHC_XFERTYP_CMDINX(SDHC_CMD2) | SDHC_XFERTYP_CCCEN
|
|
| SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_136));
|
|
|
|
result = SDHC_CMD_Do(xfertyp);
|
|
|
|
if (result == SDHC_RESULT_OK) { (void)SDHC_CMDRSP0; }
|
|
|
|
return result;
|
|
}
|
|
|
|
// sends CMD 3 to get address
|
|
static int SDHC_CMD3_GetAddress(void)
|
|
{
|
|
uint32_t xfertyp;
|
|
int result;
|
|
|
|
SDHC_CMDARG = 0;
|
|
|
|
xfertyp = (SDHC_XFERTYP_CMDINX(SDHC_CMD3) | 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 ACMD6 to set bus width
|
|
static int SDHC_ACMD6_SetBusWidth(uint32_t address, uint32_t width)
|
|
{
|
|
uint32_t xfertyp;
|
|
int result;
|
|
|
|
SDHC_CMDARG = address;
|
|
// 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 = width;
|
|
|
|
// Send CMD6
|
|
xfertyp = (SDHC_XFERTYP_CMDINX(SDHC_CMD6) | 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 CMD 7 to select card
|
|
static int SDHC_CMD7_SelectCard(uint32_t address)
|
|
{
|
|
uint32_t xfertyp;
|
|
int result;
|
|
|
|
SDHC_CMDARG = address;
|
|
|
|
xfertyp = (SDHC_XFERTYP_CMDINX(SDHC_CMD7) | SDHC_XFERTYP_CICEN |
|
|
SDHC_XFERTYP_CCCEN | SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_48BUSY));
|
|
|
|
result = SDHC_CMD_Do(xfertyp);
|
|
|
|
if (result == SDHC_RESULT_OK) {(void)SDHC_CMDRSP0; }
|
|
return result;
|
|
}
|
|
|
|
// CMD8 to send interface condition
|
|
static int SDHC_CMD8_SetInterface(uint32_t cond)
|
|
{
|
|
uint32_t xfertyp;
|
|
int result;
|
|
|
|
SDHC_CMDARG = cond;
|
|
|
|
xfertyp = (SDHC_XFERTYP_CMDINX(SDHC_CMD8) | 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 CMD 9 to get interface condition
|
|
static int SDHC_CMD9_GetParameters(uint32_t address)
|
|
{
|
|
uint32_t xfertyp;
|
|
int result;
|
|
|
|
SDHC_CMDARG = address;
|
|
|
|
xfertyp = (SDHC_XFERTYP_CMDINX(SDHC_CMD9) | SDHC_XFERTYP_CCCEN |
|
|
SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_136));
|
|
|
|
result = SDHC_CMD_Do(xfertyp);
|
|
|
|
if (result == SDHC_RESULT_OK) {
|
|
//(void)SDHC_CMDRSP0;
|
|
sdCardDesc.tranSpeed = SDHC_CMDRSP2 >> 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__
|