📄 sd.c
字号:
if(isTx)
SD_WaitCardNotBusy();
#ifdef SD_STOP_SLOW
while(*(volatile kal_uint16*)(SDC_STA) & SDC_STA_R1BSY);
do{
SD_GetStatus(gSD.mRCA,(kal_uint32*)&status);
}while((status & R1_CUR_STATE) >> 9 != TRAN_STA);
#endif
return NO_ERROR;
}
/*************************************************************************
* FUNCTION
* SD_GetStatus
*
* DESCRIPTION
* addressed send status
*
* PARAMETERS
*
* RETURNS
* SDC_CMD_STATUS
*
* GLOBALS AFFECTED
*
* NOTE
*
*************************************************************************/
SDC_CMD_STATUS SD_GetStatus(kal_uint16 rca, kal_uint32* resp)
{
SDC_CMD_STATUS status;
if((status = SD_Send_Cmd(SDC_CMD_CMD13,(kal_uint32)rca <<16))!=NO_ERROR)
return status;
MSDC_ReadReg32(SDC_RESP0,resp);
return NO_ERROR;
}
/*************************************************************************
* FUNCTION
* SD_SetBlength
*
* DESCRIPTION
* set block length
*
* PARAMETERS
* BKLength: block length u want to set
*
* RETURNS
* SDC_CMD_STATUS
*
* GLOBALS AFFECTED
* gSD.mBKLength
*
* NOTE
*
*************************************************************************/
SDC_CMD_STATUS SD_SetBlength(kal_uint32 BKLength)
{
SDC_CMD_STATUS status;
// maximal value of block length is 2048
if(BKLength > SDC_MAX_BKLENGTH)
return ERR_INVALID_BKLENGTH;
if(!gSD.mCSD.r_blk_part && BKLength < gSD.mCSD.max_r_blk_len )
return ERR_INVALID_BKLENGTH;
if((status = SD_Send_Cmd(SDC_CMD_CMD16,BKLength))!=NO_ERROR)
return status;
//read R1
status = SD_CheckStatus();
// 2. configure the controller
gSD.mBKLength = BKLength;
BitFieldWrite32((kal_uint32*)SDC_CFG,BKLength,SDC_CFG_BLKLEN);
return NO_ERROR;
}
/*************************************************************************
* FUNCTION
* SD_ReadSingleBlock
*
* DESCRIPTION
* 1. read a single block form data_adrs of card to the rxbuffer
* 2. the block length is set by set block length
*
* PARAMETERS
* data_adrs: starting address to read
* rxbuffer: as name
*
* RETURNS
* SDC_CMD_STATUS
*
* GLOBALS AFFECTED
*
* NOTE
* the size of rxbuffer should be 4*n (n : integer)
*
*************************************************************************/
SDC_CMD_STATUS SD_ReadSingleBlock(kal_uint32 data_adrs, kal_uint32* rxbuffer)
{
kal_uint32 count;
SDC_CMD_STATUS status;
EnableMSDC_DMA();
count = MSDC_SD_BLOCK_SIZE;
MSDC_DMATransferFirst((kal_uint32)rxbuffer,count,KAL_FALSE);
if((status = SD_Send_Cmd(SDC_CMD_CMD17,data_adrs))!=NO_ERROR)
goto ERR_Exit;
if((status = SD_CheckStatus())!=NO_ERROR)
goto ERR_Exit;
status = MSDC_DMATransferFinal();
if(status != NO_ERROR)
{
goto ERR_Exit;
}
if((status = SD_WaitDatRdyOrTo())!=NO_ERROR)
goto ERR_Exit;
DisableMSDC_DMA();
MSDC_CLR_FIFO();
return NO_ERROR;
ERR_Exit:
{
kal_uint32 tmp;
#ifdef MSDC_USE_INT
kal_set_eg_events(MSDC_Events, 0, KAL_AND);
#endif
DisableMSDC_DMA();
RESET_MSDC();
// SD_StopTrans(KAL_FALSE);
SD_GetStatus(gSD.mRCA,(kal_uint32*)&tmp);
MSDC_ReadReg32(SDC_DATSTA,&tmp);
MSDC_CLR_FIFO();
return status;
}
}
/*************************************************************************
* FUNCTION
* SD_ReadMultiBlock
*
* DESCRIPTION
* read num of blocks into rxbuffer
*
* PARAMETERS
* data_adrs: starting address to read
* rxbuffer: as name
* num: number of blocks to read
*
* RETURNS
* SDC_CMD_STATUS
*
* GLOBALS AFFECTED
*
* NOTE
*
*************************************************************************/
SDC_CMD_STATUS SD_ReadMultiBlock(kal_uint32 data_adrs, kal_uint32* rxbuffer, kal_uint32 num)
{
SDC_CMD_STATUS status;
kal_uint32 j, count;
#ifndef MSDC_DMA
kal_uint32 i;
#endif
EnableMSDC_DMA();
count = MSDC_SD_BLOCK_SIZE;
MSDC_DMATransferFirst((kal_uint32)rxbuffer,count*num,KAL_FALSE);
if((status = SD_Send_Cmd(SDC_CMD_CMD18,data_adrs))!=NO_ERROR)
goto ERR_Exit;
if((status = SD_CheckStatus())!=NO_ERROR)
goto ERR_Exit;
count = MSDC_SD_BLOCK_SIZE;
status = MSDC_DMATransferFinal();
if(status != NO_ERROR)
goto ERR_Exit;
if((status = SD_WaitDatRdyOrTo())!=NO_ERROR)
goto ERR_Exit;
MSDC_CLR_INT();
DisableMSDC_DMA();
if(gSD.flags & SD_FLAG_MMC_MRSW_FAIL)
{
kal_uint32 delay = 200;
while(delay--);
}
if((status = SD_StopTrans(KAL_FALSE))!=NO_ERROR)
if((data_adrs/gSD.mBKLength + j) < gSD.mBKNum)
goto ERR_Exit;
MSDC_CLR_FIFO();
return NO_ERROR;
ERR_Exit:
#ifdef MSDC_USE_INT
kal_set_eg_events(MSDC_Events, 0, KAL_AND);
#endif
DisableMSDC_DMA();
RESET_MSDC();
SD_StopTrans(KAL_FALSE);
SD_GetStatus(gSD.mRCA,(kal_uint32*)&j);
MSDC_ReadReg32(SDC_DATSTA,&j);
MSDC_CLR_FIFO();
return status;
}
/*************************************************************************
* FUNCTION
* SD_WriteSingleBlock
*
* DESCRIPTION
* write a single block
*
* PARAMETERS
* address: starting address to write
* txbuffer: as name
*
* RETURNS
* SDC_CMD_STATUS
*
* GLOBALS AFFECTED
*
* NOTE
* block length is set by Set_Block_Length
*
*************************************************************************/
SDC_CMD_STATUS SD_WriteSingleBlock(kal_uint32 address, kal_uint32* txbuffer)
{
SDC_CMD_STATUS status;
kal_uint32 count;
if(gSD.mWPEnabled)
return ERR_WRITE_PROTECT;
EnableMSDC_DMA();
count = MSDC_SD_BLOCK_SIZE;
MSDC_DMATransferFirst((kal_uint32)txbuffer,count,KAL_TRUE);
if((status = SD_Send_Cmd(SDC_CMD_CMD24,address))!=NO_ERROR)
goto ERR_Exit;
if((status = SD_CheckStatus())!=NO_ERROR)
goto ERR_Exit;
status = MSDC_DMATransferFinal();
if(status != NO_ERROR)
goto ERR_Exit;
// wait R1b interrupt because cmd24 is configured as R1b response but cmd25 needn't
//if((status = SD_WaitCardNotBusy())!=NO_ERROR)
// goto ERR_Exit;
DisableMSDC_DMA();
if((status = SD_WaitDatRdyOrTo())!=NO_ERROR)
goto ERR_Exit;
return NO_ERROR;
ERR_Exit:
{
kal_uint32 tmp;
#ifdef MSDC_USE_INT
kal_set_eg_events(MSDC_Events, 0, KAL_AND);
#endif
DisableMSDC_DMA();
RESET_MSDC();
//SD_StopTrans(KAL_TRUE);
SD_GetStatus(gSD.mRCA,(kal_uint32*)&tmp);
MSDC_ReadReg32(SDC_DATSTA,&tmp);
return status;
}
}
/*************************************************************************
* FUNCTION
* SD_WriteMultiBlock
*
* DESCRIPTION
* write num blocks starting at address
*
* PARAMETERS
* address: starting address to write
* txbuffer: as name
* num: number of blocks to write
*
* RETURNS
* SDC_CMD_STATUS
*
* GLOBALS AFFECTED
*
* NOTE
* block length is set by Set_Block_Length
*
*************************************************************************/
SDC_CMD_STATUS SD_WriteMultiBlock(kal_uint32 address, kal_uint32* txbuffer, kal_uint32 num)
{
SDC_CMD_STATUS status;
kal_uint32 count;
if(gSD.mWPEnabled)
return ERR_WRITE_PROTECT;
EnableMSDC_DMA();
count = MSDC_SD_BLOCK_SIZE;
MSDC_DMATransferFirst((kal_uint32)txbuffer,count,KAL_TRUE);
if((status = SD_Send_Cmd(SDC_CMD_CMD25,address))!=NO_ERROR)
goto ERR_Exit;
// read R1
if((status = SD_CheckStatus())!=NO_ERROR)
goto ERR_Exit;
#if 0
/* under construction !*/
/* under construction !*/
/* under construction !*/
/* under construction !*/
/* under construction !*/
/* under construction !*/
#else
{
kal_uint32 j;
for(j=0;j<num;j++)
{
if(gMSDC_Handle.mIsInitialized == KAL_FALSE)
{
status = ERR_CARD_NOT_PRESENT;
goto ERR_Exit;
}
if(j!=0)
MSDC_DMATransferFirst((kal_uint32)txbuffer,count,KAL_TRUE);
status = MSDC_DMATransferFinal();
if(status != NO_ERROR)
goto ERR_Exit;
txbuffer += count;
if((status = SD_WaitDatRdyOrTo())!=NO_ERROR)
goto ERR_Exit;
}
}
#endif
DisableMSDC_DMA();
if((status = SD_StopTrans(KAL_TRUE))!=NO_ERROR)
goto ERR_Exit;
MSDC_CLR_INT();
#ifdef MSDC_USE_INT
kal_set_eg_events(MSDC_Events, 0, KAL_AND);
#endif
return NO_ERROR;
ERR_Exit:
{
kal_uint32 tmp;
#ifdef MSDC_USE_INT
kal_set_eg_events(MSDC_Events, 0, KAL_AND);
#endif
DisableMSDC_DMA();
RESET_MSDC();
SD_StopTrans(KAL_TRUE);
SD_GetStatus(gSD.mRCA,(kal_uint32*)&tmp);
MSDC_ReadReg32(SDC_DATSTA,&tmp);
return status;
}
}
/*************************************************************************
* FUNCTION
* SD_SetBusWidth
*
* DESCRIPTION
* ACMD6: set the data width 00 for 1 bit, 10 for 4 bits
*
* PARAMETERS
* width: indicate the bus width
*
* RETURNS
* SDC_CMD_STATUS
*
* GLOBALS AFFECTED
*
* NOTE
* Not every card support 4-bits bus
* only for SD
*
*************************************************************************/
SDC_CMD_STATUS SD_SetBusWidth(SD_BITWIDTH width)
{
SDC_CMD_STATUS status;
// check if card support 4 bits bus
if((width == BIT_4W) && !(gSD.mSCR.bus_width&0x04))
return ERR_NOT_SUPPORT_4BITS;
// send APP_CMD
if((status = SD_Cmd55(gSD.mRCA))!=NO_ERROR)
return status;
// send cmd6
if((status = SD_Send_Cmd(SDC_CMD_ACMD6,width))!=NO_ERROR)
return status;
//read R1
if((status = SD_CheckStatus())!=NO_ERROR)
return status;
// set the controler MDLEN to enalbe 4bits bus width
MSDC_SET_BIT32(SDC_CFG,SDC_CFG_MDLEN);
gSD.bus_width = 4;
return NO_ERROR;
}
/*************************************************************************
* FUNCTION
* SD_ReadSCR
*
* DESCRIPTION
* ACMD51: read the SD Configuration Register(8bytes block read)
*
* PARAMETERS
* scr: used for store SCR
*
* RETURNS
* SDC_CMD_STATUS
*
* GLOBALS AFFECTED
*
* NOTE
* Make sure the size of SCR is 8 bytes
*
*************************************************************************/
SDC_CMD_STATUS SD_ReadSCR(kal_uint32* scr)
{
SDC_CMD_STATUS status;
kal_uint32 blklen,i, t1;
ASSERT((kal_uint32)scr % 4 == 0);
// save the original block length
blklen = gSD.mBKLength;
// set block length(MSDC_CFG)
if((status = SD_SetBlength(8))!=NO_ERROR)
return status;
// send APP_CMD
if((status = SD_Cmd55(gSD.mRCA))!=NO_ERROR)
return status;
// send command
if((status = SD_Send_Cmd(SDC_CMD_ACMD51,SDC_NO_ARG))!=NO_ERROR)
return status;
//read R1
if((status = SD_CheckStatus())!=NO_ERROR)
return status;
// read data(8bytes)
// failed to use DMA with burst mode
t1 = drv_get_current_time();
MSDC_START_TIMER(MSDC_TIMEOUT_PERIOD_DAT);
for(i=0;i<2;)
{
if(drv_get_duration_ms(t1) > MSDC_TIMEOUT_PERIOD_DAT*11)
gMSDC_Handle.is_timeout = KAL_TRUE;
if(!gMSDC_Handle.mIsPresent)
return ERR_CARD_NOT_PRESENT;
if(gMSDC_Handle.is_timeout)
return MSDC_GPT_TIMEOUT_ERR;
if(!MSDC_IS_FIFO_EMPTY)
{
*(kal_uint32*)(scr+i) = *(volatile kal_uint32*)MSDC_DAT;
i++;
}
}
MSDC_STOP_TIMER();
// analysis scr
SD_AnalysisSCR(scr);
// clean EVENT_SDDATIRQ
#ifdef MSDC_USE_INT
kal_set_eg_events(MSDC_Events, 0, KAL_AND);
#endif
MSDC_CLR_FIFO();
return NO_ERROR;
}
/*************************************************************************
* FUNCTION
* SD_SetPreEraseBlk
*
* DESCRIPTION
* ACMD23: set the number of write blocksto be pre-erased before writing
* used for faster multiple Block Write
*
* PARAMETERS
* num: used for storing number of blocks during multi-block operation
*
* RETURNS
* SDC_CMD_STATUS
*
* GLOBALS AFFECTED
*
* NOTE
*
*************************************************************************/
SDC_CMD_STATUS SD_SetPreEraseBlk(kal_uint32 num)
{
SDC_CMD_STATUS status;
//[22:0] number of blocks
num &= 0x003FFF;
// send APP_CMD
if((status = SD_Cmd55(gSD.mRCA))!=NO_ERROR)
return status;
// send CMD23
if((status = SD_Send_Cmd(SDC_CMD_ACMD23,num))!=NO_ERROR)
return status;
//read R1
if((status = SD_CheckStatus())!=NO_ERROR)
return status;
return NO_ERROR;
}
/*************************************************************************
* FUNCTION
* SD_EraseCmdClass
*
* DESCRIPTION
* groups of erase commands including CMD32 ~CMD38
*
* PARAMETERS
* cmd: indicate which command to execute
* address: starting address wiht write protection
*
* RETURNS
* SDC_CMD_STATUS
*
* GLOBALS AFFECTED
*
* NOTE
* CMD34~CMD37 are only for MMC
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -