Files
zSoft/teensy3/NXP_SDHC.cpp

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__