|
|
@@ -6,18 +6,13 @@ |
|
|
|
//see also |
|
|
|
//https://community.nxp.com/thread/99202 |
|
|
|
|
|
|
|
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1052__) || defined(__IMXRT1062__) |
|
|
|
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1062__) |
|
|
|
|
|
|
|
#include "core_pins.h" // include calls to kinetis.h or imxrt.h |
|
|
|
#include "usb_serial.h" // for Serial |
|
|
|
|
|
|
|
#include "NXP_SDHC.h" |
|
|
|
|
|
|
|
// Missing in Teensyduino 1.30 |
|
|
|
#ifndef MPU_CESR_VLD_MASK |
|
|
|
#define MPU_CESR_VLD_MASK 0x1u |
|
|
|
#endif |
|
|
|
|
|
|
|
/****************************************************************************** |
|
|
|
Constants |
|
|
|
******************************************************************************/ |
|
|
@@ -117,7 +112,7 @@ enum { |
|
|
|
#define SDHC_FIFO_BUFFER_SIZE 16 |
|
|
|
#define SDHC_BLOCK_SIZE 512 |
|
|
|
|
|
|
|
#if defined(__IMXRT1052__) || defined(__IMXRT1062__) |
|
|
|
#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))) |
|
|
@@ -294,6 +289,7 @@ enum { |
|
|
|
#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) // |
|
|
@@ -367,7 +363,7 @@ enum { |
|
|
|
#define SDHC_MMCBOOT (USDHC1_MMC_BOOT) // MMC Boot register |
|
|
|
#define SDHC_VENDOR2 (USDHC2_VEND_SPEC2) // Vendor Specific2 register |
|
|
|
// |
|
|
|
#define IRQ_SDHC IRQ_SDHC1 |
|
|
|
//#define IRQ_SDHC IRQ_SDHC1 |
|
|
|
|
|
|
|
#define SDHC_MAX_DVS (0xF + 1U) |
|
|
|
#define SDHC_MAX_CLKFS (0xFF + 1U) |
|
|
@@ -387,7 +383,7 @@ enum { |
|
|
|
#define IOMUXC_SW_PAD_CTL_PAD_DSE(n) (((n)&0x7)<<3) |
|
|
|
#define IOMUXC_SW_PAD_CTL_PAD_DSE_MASK ((0x7)<<3) |
|
|
|
|
|
|
|
#endif |
|
|
|
#endif // __IMXRT1062__ |
|
|
|
|
|
|
|
#define SDHC_IRQSIGEN_DMA_MASK (SDHC_IRQSIGEN_TCIEN | SDHC_IRQSIGEN_DINTIEN | SDHC_IRQSIGEN_DMAEIEN) |
|
|
|
#define CARD_STATUS_READY_FOR_DATA (1UL << 8) |
|
|
@@ -425,7 +421,7 @@ 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 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); |
|
|
@@ -473,21 +469,30 @@ uint8_t SDHC_CardInit(void) |
|
|
|
sdCardDesc.version2 = 0; |
|
|
|
sdCardDesc.numBlocks = 0; |
|
|
|
|
|
|
|
if (resS) return resS; |
|
|
|
if (resS) |
|
|
|
return resS; |
|
|
|
|
|
|
|
SDHC_IRQSIGEN = 0; |
|
|
|
|
|
|
|
resR = SDHC_CMD0_GoToIdle(); |
|
|
|
if (resR) { return sdCardDesc.status = SDHC_STATUS_NOINIT;} |
|
|
|
|
|
|
|
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) return sdCardDesc.status = SDHC_STATUS_NOINIT; |
|
|
|
sdCardDesc.highCapacity = 1; |
|
|
|
} |
|
|
|
else if (resR == SDHC_RESULT_NO_RESPONSE) |
|
|
|
{ // version 1 cards do not respond to CMD8 |
|
|
|
} |
|
|
|
else return sdCardDesc.status = SDHC_STATUS_NOINIT; |
|
|
|
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; |
|
|
|
|
|
|
@@ -512,7 +517,7 @@ uint8_t SDHC_CardInit(void) |
|
|
|
|
|
|
|
// 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; |
|
|
|
|
|
|
@@ -550,7 +555,7 @@ uint8_t SDHC_CardInit(void) |
|
|
|
// 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(); |
|
|
|
|
|
|
@@ -567,6 +572,7 @@ uint8_t SDHC_CardInit(void) |
|
|
|
return sdCardDesc.status; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
// FUNCTION: SDHC_CardReadBlock (disk_read) |
|
|
|
// SCOPE: SDHC public related function |
|
|
@@ -577,6 +583,41 @@ uint8_t SDHC_CardInit(void) |
|
|
|
// |
|
|
|
// 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; |
|
|
@@ -596,7 +637,7 @@ int SDHC_CardReadBlock(void * buff, uint32_t sector) |
|
|
|
|
|
|
|
// 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) ; |
|
|
@@ -604,10 +645,10 @@ int SDHC_CardReadBlock(void * buff, uint32_t sector) |
|
|
|
// 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 |
|
|
@@ -629,6 +670,7 @@ int SDHC_CardReadBlock(void * buff, uint32_t sector) |
|
|
|
|
|
|
|
return result; |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
// FUNCTION: SDHC_CardWriteBlock (disk_write) |
|
|
@@ -640,6 +682,37 @@ int SDHC_CardReadBlock(void * buff, uint32_t 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; |
|
|
@@ -665,15 +738,15 @@ int SDHC_CardWriteBlock(const void * buff, uint32_t sector) |
|
|
|
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 ; |
|
|
|
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 |
|
|
@@ -710,6 +783,7 @@ int SDHC_CardWriteBlock(const void * buff, uint32_t sector) |
|
|
|
|
|
|
|
return result; |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
/****************************************************************************** |
|
|
|
|
|
|
@@ -717,6 +791,7 @@ int SDHC_CardWriteBlock(const void * buff, uint32_t sector) |
|
|
|
|
|
|
|
******************************************************************************/ |
|
|
|
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) |
|
|
|
// Teensy 3.5 & 3.6 |
|
|
|
// initialize the SDHC Controller signals |
|
|
|
static void SDHC_InitGPIO(void) |
|
|
|
{ |
|
|
@@ -727,7 +802,7 @@ int SDHC_CardWriteBlock(const void * buff, uint32_t sector) |
|
|
|
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) |
|
|
|
{ |
|
|
@@ -738,7 +813,7 @@ int SDHC_CardWriteBlock(const void * buff, uint32_t sector) |
|
|
|
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 |
|
|
@@ -748,16 +823,15 @@ int SDHC_CardWriteBlock(const void * buff, uint32_t sector) |
|
|
|
// Enable SDHC clock. |
|
|
|
SIM_SCGC3 |= SIM_SCGC3_SDHC; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
uint32_t sdhcClock() |
|
|
|
{ return F_CPU; |
|
|
|
} |
|
|
|
|
|
|
|
#else |
|
|
|
|
|
|
|
// Teensy 4.0 |
|
|
|
static void SDHC_InitGPIO(void) |
|
|
|
{ |
|
|
|
{ //T4 |
|
|
|
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 |
|
|
@@ -780,7 +854,6 @@ int SDHC_CardWriteBlock(const void * buff, uint32_t sector) |
|
|
|
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) |
|
|
@@ -812,11 +885,11 @@ int SDHC_CardWriteBlock(const void * buff, uint32_t sector) |
|
|
|
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) |
|
|
|
//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) |
|
|
|
//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() |
|
|
@@ -878,7 +951,7 @@ static void sdhc_setSdclk(uint32_t kHzMax) { |
|
|
|
while ((f_pll / (sdclkfs * dvs) > maxSdclk) && (dvs < DVS_LIMIT)) { |
|
|
|
dvs++; |
|
|
|
} |
|
|
|
uint32_t m_sdClkKhz = f_pll / (1000 * sdclkfs * dvs); |
|
|
|
//uint32_t m_sdClkKhz = f_pll / (1000 * sdclkfs * dvs); |
|
|
|
|
|
|
|
sdclkfs >>= 1; |
|
|
|
dvs--; |
|
|
@@ -906,7 +979,7 @@ static void sdhc_setSdclk(uint32_t kHzMax) { |
|
|
|
// 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; |
|
|
|
// |
|
|
@@ -922,20 +995,21 @@ void sdhc_isr(void) |
|
|
|
|
|
|
|
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 (__IMXRT1052__) |
|
|
|
SDHC_SYSCTL |= 0xF; |
|
|
|
SDHC_MIX_CTRL |= 0x80000000; |
|
|
|
#endif |
|
|
|
#if defined (__IMXRT1062__) |
|
|
|
//SDHC_SYSCTL |= 0xF; |
|
|
|
SDHC_MIX_CTRL = 0x80000000; |
|
|
|
#endif |
|
|
|
|
|
|
|
/* Reset SDHC */ |
|
|
|
SDHC_SYSCTL |= SDHC_SYSCTL_RSTA | SDHC_SYSCTL_SDCLKFS(0x80); |
|
|
@@ -952,32 +1026,41 @@ static uint8_t SDHC_Init(void) |
|
|
|
|
|
|
|
/* 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_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 |
|
|
|
|
|
|
|
SDHC_PROCTL |= SDHC_PROCTL_D3CD; |
|
|
|
// SDHC_PROCTL = 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); |
|
|
|
|
|
|
|
#if defined(__IMXRT1052__) |
|
|
|
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; |
|
|
|
|
|
|
|
SDHC_IRQSTATEN = //SDHC_IRQSTAT_CRM | SDHC_IRQSTATEN_CIESEN | |
|
|
|
#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 < 500; ii++) { |
|
|
|
for (int ii = 0; ii < 1500; ii++) { |
|
|
|
SDHC_SYSCTL |= SDHC_SYSCTL_INITA; |
|
|
|
while (SDHC_SYSCTL & SDHC_SYSCTL_INITA) ; |
|
|
|
} |
|
|
@@ -1011,7 +1094,71 @@ static uint32_t SDHC_WaitStatus(uint32_t mask) |
|
|
|
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) |
|
|
|
{ |
|
|
@@ -1024,20 +1171,21 @@ static int SDHC_CMD_Do(uint32_t 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; |
|
|
|
return SDHC_RESULT_ERROR; |
|
|
|
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; |
|
|
|
if (SDHC_IRQSTAT & SDHC_IRQSTAT_CTOE) { |
|
|
|
SDHC_IRQSTAT |= SDHC_IRQSTAT_CTOE | SDHC_IRQSTAT_CC; |
|
|
|
return SDHC_RESULT_NO_RESPONSE; |
|
|
|
} |
|
|
|
SDHC_IRQSTAT |= SDHC_IRQSTAT_CC; |
|
|
|
|
|
|
@@ -1068,7 +1216,7 @@ static int SDHC_CMD2_Identify(void) |
|
|
|
|
|
|
|
SDHC_CMDARG = 0; |
|
|
|
|
|
|
|
xfertyp = (SDHC_XFERTYP_CMDINX(SDHC_CMD2) | SDHC_XFERTYP_CCCEN |
|
|
|
xfertyp = (SDHC_XFERTYP_CMDINX(SDHC_CMD2) | SDHC_XFERTYP_CCCEN |
|
|
|
| SDHC_XFERTYP_RSPTYP(SDHC_XFERTYP_RSPTYP_136)); |
|
|
|
|
|
|
|
result = SDHC_CMD_Do(xfertyp); |
|
|
@@ -1201,7 +1349,7 @@ static int SDHC_CMD12_StopTransferWaitForBusy(void) |
|
|
|
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; |
|
|
|
|