本帖最后由 gaoke231 于 2020-3-31 23:04 编辑
在卡中指定地址写一个块
SD_Err SD_WriteBlock(uint32_t addr, uint32_t *writebuff, uint16_t BlockSize)
{
SD_Err Status = SD_OK;
uint8_t power = 0, cardstate = 0;
uint32_t timeout = 0, bytestransferred = 0;
uint32_t cardstatus = 0, count = 0, restwords = 0;
uint32_t *tempbuff = writebuff;
if (writebuff == NULL)
{
Status = SD_INVALID_PARAMETER;
return(Status);
}
TransferError = SD_OK;
TransferEnd = 0;
TotalNumberOfBytes = 0;
/* Clear all DSM configuration */
SDIO_DataInitStructure.SDIO_DataTimeOut = 0;
SDIO_DataInitStructure.SDIO_DataLength = 0;
SDIO_DataInitStructure.SDIO_DataBlockSize = SDIO_DATABLOCKSIZE_1B;
SDIO_DataInitStructure.SDIO_TransDirection = SDIO_TRANSDIRECTION_TOCARD;
SDIO_DataInitStructure.SDIO_TransMode = SDIO_TRANSMODE_BLOCK;
SDIO_DataInitStructure.SDIO_DSMState = SDIO_DSMSTATE_DISABLE;
SDIO_DataConfig(&SDIO_DataInitStructure);
SDIO_DMA_Enable(DISABLE);
/* Check whether the card is locked */
if (SDIO_GetResponse(SDIO_RESP1) & SD_CARD_LOCKED)
{
Status = SD_LOCK_UNLOCK_FAILED;
return(Status);
}
/* SDHC card the blocksize is fixed in 512B */
if (CardType == SDIO_HIGH_CAPACITY_SD_CARD)
{
BlockSize = 512;
addr /= 512;
}
/* Set the block size, both on controller and card */
if ((BlockSize > 0) && (BlockSize <= 2048) && ((BlockSize & (BlockSize - 1)) == 0))
{
power = Bytes_To_PowerTwo(BlockSize);
/* CMD16 Set Block Size for Card */
SDIO_CmdInitStructure.SDIO_CMDParameter = (uint32_t) BlockSize;
SDIO_CmdInitStructure.SDIO_CMDIndex = SDIO_SET_BLOCKLEN;
SDIO_CmdInitStructure.SDIO_ResponseType = SDIO_RESPONSETYPE_SHORT;
SDIO_CmdInitStructure.SDIO_WaitINTState = SDIO_WAITINTSTATE_NO;
SDIO_CmdInitStructure.SDIO_CSMState = SDIO_CSMSTATE_ENABLE;
SDIO_SendCMD(&SDIO_CmdInitStructure);
/* Check CMD errors */
Status = Check_Err_R1(SDIO_SET_BLOCKLEN);
if (Status != SD_OK)
{
return(Status);
}
}
else
{
Status = SD_INVALID_PARAMETER;
return(Status);
}
/* Wait till card is ready for writing data */
SDIO_CmdInitStructure.SDIO_CMDParameter = (uint32_t) (RCA << 16);
SDIO_CmdInitStructure.SDIO_CMDIndex = SDIO_SEND_STATUS;
SDIO_CmdInitStructure.SDIO_ResponseType = SDIO_RESPONSETYPE_SHORT;
SDIO_CmdInitStructure.SDIO_WaitINTState = SDIO_WAITINTSTATE_NO;
SDIO_CmdInitStructure.SDIO_CSMState = SDIO_CSMSTATE_ENABLE;
SDIO_SendCMD(&SDIO_CmdInitStructure);
/* Check CMD errors */
Status = Check_Err_R1(SDIO_SEND_STATUS);
if (Status != SD_OK)
{
return(Status);
}
cardstatus = SDIO_GetResponse(SDIO_RESP1);
timeout = 10000;
while (((cardstatus & 0x00000100) == 0) && (timeout > 0))
{
/* Card is busy, continue to send CMD13 to polling the state of the card */
timeout--;
SDIO_CmdInitStructure.SDIO_CMDParameter = (uint32_t) (RCA << 16);
SDIO_CmdInitStructure.SDIO_CMDIndex = SDIO_SEND_STATUS;
SDIO_CmdInitStructure.SDIO_ResponseType = SDIO_RESPONSETYPE_SHORT;
SDIO_CmdInitStructure.SDIO_WaitINTState = SDIO_WAITINTSTATE_NO;
SDIO_CmdInitStructure.SDIO_CSMState = SDIO_CSMSTATE_ENABLE;
SDIO_SendCMD(&SDIO_CmdInitStructure);
/* Check CMD errors */
Status = Check_Err_R1(SDIO_SEND_STATUS);
if (Status != SD_OK)
{
return(Status);
}
cardstatus = SDIO_GetResponse(SDIO_RESP1);
}
/* Polling timeout */
if (timeout == 0)
{
return(SD_ERROR);
}
/* Send CMD24 WRITE_SINGLE_BLOCK */
SDIO_CmdInitStructure.SDIO_CMDParameter = addr;
SDIO_CmdInitStructure.SDIO_CMDIndex = SDIO_WRITE_SINGLE_BLOCK;
SDIO_CmdInitStructure.SDIO_ResponseType = SDIO_RESPONSETYPE_SHORT;
SDIO_CmdInitStructure.SDIO_WaitINTState = SDIO_WAITINTSTATE_NO;
SDIO_CmdInitStructure.SDIO_CSMState = SDIO_CSMSTATE_ENABLE;
SDIO_SendCMD(&SDIO_CmdInitStructure);
/* Check CMD errors */
Status = Check_Err_R1(SDIO_WRITE_SINGLE_BLOCK);
if (Status != SD_OK)
{
return(Status);
}
TotalNumberOfBytes = BlockSize;
StopCondition = 0;
SrcBuffer = writebuff;
/* SDIO data transmisson config */
SDIO_DataInitStructure.SDIO_DataTimeOut = SD_DATATIMEOUT;
SDIO_DataInitStructure.SDIO_DataLength = BlockSize;
SDIO_DataInitStructure.SDIO_DataBlockSize = (uint32_t) power << 4;
SDIO_DataInitStructure.SDIO_TransDirection = SDIO_TRANSDIRECTION_TOCARD;
SDIO_DataInitStructure.SDIO_TransMode = SDIO_TRANSMODE_BLOCK;
SDIO_DataInitStructure.SDIO_DSMState = SDIO_DSMSTATE_ENABLE;
SDIO_DataConfig(&SDIO_DataInitStructure);
/* In case of single data block transfer no need of stop command at all */
if (TransmissionMode == SD_POLLING_MODE)
{
/* Polling mode */
while (!(SDIO->STR & (SDIO_FLAG_DTBLKEND | SDIO_FLAG_TXURE | SDIO_FLAG_DTCRCFAIL | SDIO_FLAG_DTTMOUT | SDIO_FLAG_STBITE)))
{
if (SDIO_GetBitState(SDIO_FLAG_TXFIFOHE) != RESET)
{
if ((TotalNumberOfBytes - bytestransferred) < 32)
{
restwords = ((TotalNumberOfBytes - bytestransferred) % 4 == 0) ? ((TotalNumberOfBytes - bytestransferred) / 4) : (( TotalNumberOfBytes - bytestransferred) / 4 + 1);
for (count = 0; count < restwords; count++, tempbuff++, bytestransferred += 4)
{
SDIO_WriteData(*tempbuff);
}
}
else
{
for (count = 0; count < 8; count++)
{
SDIO_WriteData(*(tempbuff + count));
}
tempbuff += 8;
bytestransferred += 32;
}
}
}
if (SDIO_GetBitState(SDIO_FLAG_DTTMOUT) != RESET)
{
SDIO_ClearBitState(SDIO_FLAG_DTTMOUT);
Status = SD_DATA_TIMEOUT;
return(Status);
}
else if (SDIO_GetBitState(SDIO_FLAG_DTCRCFAIL) != RESET)
{
SDIO_ClearBitState(SDIO_FLAG_DTCRCFAIL);
Status = SD_DATA_CRC_FAIL;
return(Status);
}
else if (SDIO_GetBitState(SDIO_FLAG_TXURE) != RESET)
{
SDIO_ClearBitState(SDIO_FLAG_TXURE);
Status = SD_TX_UNDERRUN;
return(Status);
}
else if (SDIO_GetBitState(SDIO_FLAG_STBITE) != RESET)
{
SDIO_ClearBitState(SDIO_FLAG_STBITE);
Status = SD_START_BIT_ERR;
return(Status);
}
}
else if (TransmissionMode == SD_DMA_MODE)
{
/* DMA mode */
/* Enable SDIO corresponding interrupts */
SDIO_INTConfig(SDIO_INT_DTCRCFAIL | SDIO_INT_DTTMOUT | SDIO_INT_DTEND | SDIO_INT_TXURE | SDIO_INT_STBITE, ENABLE);
DMA_TxConfiguration(writebuff, BlockSize);
/* Enable the DMA of SDIO */
SDIO_DMA_Enable(ENABLE);
while (DMA_GetBitState(DMA2_FLAG_TC4) == RESET)
{}
while ((TransferEnd == 0) && (TransferError == SD_OK))
{}
if (TransferError != SD_OK)
{
return(TransferError);
}
}
/* Clear all the static flags */
SDIO_ClearBitState(SDIO_STATIC_FLAGS);
/* Wait till the card is in programming state */
Status = IsCardProgramming(&cardstate);
while ((Status == SD_OK) && ((cardstate == SD_CARD_PROGRAMMING) || (cardstate == SD_CARD_RECEIVING)))
{
Status = IsCardProgramming(&cardstate);
}
return(Status);
}
|