889 lines
26 KiB
C
889 lines
26 KiB
C
/*
|
|
******************************************************************************
|
|
* @file driver_sd_card.c
|
|
* @author FreqChip Firmware Team
|
|
* @version V1.0.0
|
|
* @date 2022
|
|
* @brief SD card application HAL module driver.
|
|
******************************************************************************
|
|
* @attention
|
|
*
|
|
* Copyright (c) 2022 FreqChip.
|
|
* All rights reserved.
|
|
******************************************************************************
|
|
*/
|
|
#include "fr30xx.h"
|
|
|
|
/* Private function prototypes -----------------------------------------------*/
|
|
static uint32_t __SDCard_PowerON(SD_HandleTypeDef *hsd);
|
|
static uint32_t __SDCard_InitCard(SD_HandleTypeDef *hsd);
|
|
static void __SDCard_GetCardCSD(SD_HandleTypeDef *hsd);
|
|
static void __SDCard_GetCardCID(SD_HandleTypeDef *hsd);
|
|
|
|
/************************************************************************************
|
|
* @fn SDCard_IRQHandler
|
|
*
|
|
* @brief SDCard interrupt handler.
|
|
*
|
|
* @param hsd: Pointer to SD handle
|
|
*/
|
|
void SDCard_IRQHandler(SD_HandleTypeDef *hsd)
|
|
{
|
|
switch (hsd->CardStatus)
|
|
{
|
|
/* card read, write */
|
|
case CARD_STATUS_READ_BUSY:
|
|
case CARD_STATUS_WIRTE_BUSY:
|
|
{
|
|
/* DMA interrupt */
|
|
if (__SD_GET_INT_STATUS(hsd->SDx) & INT_DMA_INT)
|
|
{
|
|
__SD_CLR_INT_STATUS(hsd->SDx, INT_DMA_INT);
|
|
|
|
/* SDMA system Address alignment increases */
|
|
hsd->AddrAlign += SDMA_ADDR_UNIT;
|
|
|
|
/* Update SDMA system Address */
|
|
__SD_SET_SDMA_SYSTEM_ADDR(hsd->SDx, (uint32_t)hsd->AddrAlign);
|
|
}
|
|
|
|
/* error */
|
|
if (__SD_GET_INT_STATUS(hsd->SDx) & INT_ERR_MASK)
|
|
{
|
|
/* clear interrupt status */
|
|
__SD_CLR_ALL_INT_STATUS(hsd->SDx);
|
|
|
|
hsd->CardStatus = CARD_STATUS_ERR;
|
|
}
|
|
|
|
/* transfer complete */
|
|
if (__SD_GET_INT_STATUS(hsd->SDx) & INT_TRANSFER_COMPLETE)
|
|
{
|
|
/* clear transfer complete statsu */
|
|
__SD_CLR_INT_STATUS(hsd->SDx, INT_TRANSFER_COMPLETE);
|
|
|
|
hsd->CardStatus = CARD_STATUS_IDLE;
|
|
}
|
|
}break;
|
|
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
/************************************************************************************
|
|
* @fn SDCard_Init
|
|
*
|
|
* @brief Initializes the SD Card.
|
|
*
|
|
* @param hsd: Pointer to SD handle
|
|
*/
|
|
uint32_t SDCard_Init(SD_HandleTypeDef *hsd)
|
|
{
|
|
uint32_t lu32_ErrState = INT_NO_ERR;
|
|
|
|
/* SD Crad class initialization */
|
|
SD_SDCardClass_Init(hsd->SDx);
|
|
|
|
for(volatile uint32_t i=0; i<10000; i++);
|
|
|
|
/* Identify card operating voltage */
|
|
lu32_ErrState = __SDCard_PowerON(hsd);
|
|
if (lu32_ErrState)
|
|
{
|
|
return lu32_ErrState;
|
|
}
|
|
|
|
/* Card initialization */
|
|
lu32_ErrState = __SDCard_InitCard(hsd);
|
|
if (lu32_ErrState)
|
|
{
|
|
return lu32_ErrState;
|
|
}
|
|
|
|
/* Get the card information from the CID register */
|
|
__SDCard_GetCardCID(hsd);
|
|
/* Get the card information from the CSD register */
|
|
__SDCard_GetCardCSD(hsd);
|
|
|
|
return lu32_ErrState;
|
|
}
|
|
|
|
/************************************************************************************
|
|
* @fn SDCard_BusWidth_Select
|
|
*
|
|
* @brief SDCard 1bit/4bit bus width select.
|
|
*
|
|
* @param hsd: Pointer to SD handle.
|
|
* fu32_BusWidth: bus width. can select SDIO_BUS_WIDTH_1BIT.
|
|
* SDIO_BUS_WIDTH_4BIT.
|
|
*/
|
|
uint32_t SDCard_BusWidth_Select(SD_HandleTypeDef *hsd, uint32_t fu32_BusWidth)
|
|
{
|
|
uint32_t lu32_ErrState = INT_NO_ERR;
|
|
|
|
/* SEND CMD55 APP_CMD with RCA as 0 */
|
|
lu32_ErrState = SD_CMD_AppCommand(hsd->SDx, hsd->RCA);
|
|
if (lu32_ErrState)
|
|
{
|
|
return lu32_ErrState;
|
|
}
|
|
|
|
/* Send ACMD6 SET_BUS_WIDTH */
|
|
lu32_ErrState = SD_ACMD_SetBusWidth(hsd->SDx, fu32_BusWidth);
|
|
if (lu32_ErrState)
|
|
{
|
|
return lu32_ErrState;
|
|
}
|
|
else
|
|
{
|
|
if (fu32_BusWidth)
|
|
__SD_DATA_WIDTH_4BIT(hsd->SDx);
|
|
else
|
|
__SD_DATA_WIDTH_1BIT(hsd->SDx);
|
|
}
|
|
|
|
return lu32_ErrState;
|
|
}
|
|
|
|
/************************************************************************************
|
|
* @fn SDCard_ReadBolcks
|
|
*
|
|
* @brief Reads block(s) from a specified address in a card.
|
|
* The Data transfer by polling mode.
|
|
*
|
|
* @param hsd: Pointer to SD handle.
|
|
* fp_Data: pointer to the received dat buffer.
|
|
* fu32_BlockAddr: Block Start Address.
|
|
* fu16_BlockNum: Number of SD blocks to read.
|
|
*/
|
|
uint32_t SDCard_ReadBolcks(SD_HandleTypeDef *hsd, uint32_t *fp_Data, uint32_t fu32_BlockAddr, uint16_t fu16_BlockNum)
|
|
{
|
|
int i;
|
|
uint32_t lu32_ErrState = INT_NO_ERR;
|
|
|
|
if (fu16_BlockNum == 0)
|
|
return E1_NUM_ERR;
|
|
|
|
if (fu16_BlockNum == 1)
|
|
{
|
|
/* SEND CMD17 READ_SINGLI_BLOCK */
|
|
lu32_ErrState = SD_CMD_ReadSingleBlock(hsd->SDx, fu32_BlockAddr);
|
|
if (lu32_ErrState)
|
|
return lu32_ErrState;
|
|
|
|
/* Wait for Buffer Read Ready Int */
|
|
while(!(__SD_GET_INT_STATUS(hsd->SDx) & INT_BUFFER_READ_READY));
|
|
/* Clear Buffer_Read_Ready */
|
|
__SD_CLR_INT_STATUS(hsd->SDx, INT_BUFFER_READ_READY);
|
|
/* Read one block */
|
|
for (i = 0; i < BLOCKSIZE / 4; i++)
|
|
{
|
|
*fp_Data++ = __SD_GET_BUFFERDATA(hsd->SDx);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* SEND CMD23 SET_BLOCK_COUNT */
|
|
lu32_ErrState = SD_CMD_SetBlockCount(hsd->SDx, fu16_BlockNum);
|
|
if (lu32_ErrState)
|
|
return lu32_ErrState;
|
|
|
|
/* Set block count */
|
|
__SD_SET_BLOCK_COUNT(hsd->SDx, fu16_BlockNum);
|
|
|
|
/* SEND CMD18 READ_MULTIPLE_BLOCK */
|
|
lu32_ErrState = SD_CMD_ReadMultiBlock(hsd->SDx, fu32_BlockAddr);
|
|
if (lu32_ErrState)
|
|
return lu32_ErrState;
|
|
|
|
while (fu16_BlockNum--)
|
|
{
|
|
/* Wait for Buffer_Read_Ready */
|
|
while(!(__SD_GET_INT_STATUS(hsd->SDx) & INT_BUFFER_READ_READY));
|
|
/* Clear Buffer_Read_Ready */
|
|
__SD_CLR_INT_STATUS(hsd->SDx, INT_BUFFER_READ_READY);
|
|
/* Read one block */
|
|
for (i = 0; i < BLOCKSIZE / 4; i++)
|
|
{
|
|
*fp_Data++ = __SD_GET_BUFFERDATA(hsd->SDx);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* wait for transfer complete or any errors occur */
|
|
while(!(__SD_GET_INT_STATUS(hsd->SDx) & (INT_TRANSFER_COMPLETE | INT_ERR_MASK)));
|
|
|
|
/* Any errors occur */
|
|
if (__SD_GET_INT_STATUS(hsd->SDx) & INT_ERR_MASK)
|
|
{
|
|
lu32_ErrState = __SD_GET_INT_STATUS(hsd->SDx) & INT_ERR_MASK;
|
|
}
|
|
/* clear interrupt status */
|
|
__SD_CLR_ALL_INT_STATUS(hsd->SDx);
|
|
|
|
return lu32_ErrState;
|
|
}
|
|
|
|
/************************************************************************************
|
|
* @fn SDCard_WriteBolcks
|
|
*
|
|
* @brief Write block(s) from a specified address in a card.
|
|
* The Data transfer by polling mode.
|
|
*
|
|
* @param hsd: Pointer to SD handle.
|
|
* fp_Data: pointer to the received dat buffer.
|
|
* fu32_BlockAddr: Block Address.
|
|
* fu16_BlockNum: Number of SD blocks to write.
|
|
*/
|
|
uint32_t SDCard_WriteBolcks(SD_HandleTypeDef *hsd, uint32_t *fp_Data, uint32_t fu32_BlockAddr, uint16_t fu16_BlockNum)
|
|
{
|
|
int i;
|
|
uint32_t lu32_ErrState = INT_NO_ERR;
|
|
|
|
if (fu16_BlockNum == 0)
|
|
return E1_NUM_ERR;
|
|
|
|
if (fu16_BlockNum == 1)
|
|
{
|
|
/* SEND CMD24 WRITE_BLOCK */
|
|
lu32_ErrState = SD_CMD_WriteSingleBlock(hsd->SDx, fu32_BlockAddr);
|
|
if (lu32_ErrState)
|
|
return lu32_ErrState;
|
|
|
|
/* Wait for buffer write enable Int */
|
|
while(!(__SD_GET_PRESENT_STATE(hsd->SDx) & PreState_BUFFER_WRITE_EN_MASK));
|
|
/* write one block */
|
|
for (i = 0; i < BLOCKSIZE / 4; i++)
|
|
{
|
|
__SD_SET_BUFFERDATA(hsd->SDx, *fp_Data++);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* SEND CMD23 SET_BLOCK_COUNT */
|
|
lu32_ErrState = SD_CMD_SetBlockCount(hsd->SDx, fu16_BlockNum);
|
|
if (lu32_ErrState)
|
|
return lu32_ErrState;
|
|
|
|
/* Set block count */
|
|
__SD_SET_BLOCK_COUNT(hsd->SDx, fu16_BlockNum);
|
|
|
|
/* SEND CMD25 WRITE_MULTIPLE_BLOCK */
|
|
lu32_ErrState = SD_CMD_WriteMultiBlock(hsd->SDx, fu32_BlockAddr);
|
|
if (lu32_ErrState)
|
|
return lu32_ErrState;
|
|
|
|
/* First block transfer check the PresentState register */
|
|
/* Wait for Buffer_Write_Enable */
|
|
while(!(__SD_GET_PRESENT_STATE(hsd->SDx) & PreState_BUFFER_WRITE_EN_MASK));
|
|
/* write one block */
|
|
for (i = 0; i < BLOCKSIZE / 4; i++)
|
|
{
|
|
__SD_SET_BUFFERDATA(hsd->SDx, *fp_Data++);
|
|
}
|
|
fu16_BlockNum--;
|
|
/* Other block transfer check the StatusInt register */
|
|
while(fu16_BlockNum--)
|
|
{
|
|
/* Wait for Buffer_Write_Ready */
|
|
while(!(__SD_GET_INT_STATUS(hsd->SDx) & INT_BUFFER_WRITE_READY));
|
|
/* Clear Buffer_Write_Ready */
|
|
__SD_CLR_INT_STATUS(hsd->SDx, INT_BUFFER_WRITE_READY);
|
|
/* write one block */
|
|
for (i = 0; i < BLOCKSIZE / 4; i++)
|
|
{
|
|
__SD_SET_BUFFERDATA(hsd->SDx, *fp_Data++);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* wait for transfer complete or any errors occur */
|
|
while(!(__SD_GET_INT_STATUS(hsd->SDx) & (INT_TRANSFER_COMPLETE | INT_ERR_MASK)));
|
|
|
|
/* Any errors occur */
|
|
if (__SD_GET_INT_STATUS(hsd->SDx) & INT_ERR_MASK)
|
|
{
|
|
lu32_ErrState = __SD_GET_INT_STATUS(hsd->SDx) & INT_ERR_MASK;
|
|
}
|
|
/* clear interrupt status */
|
|
__SD_CLR_ALL_INT_STATUS(hsd->SDx);
|
|
|
|
return lu32_ErrState;
|
|
}
|
|
|
|
/************************************************************************************
|
|
* @fn SDCard_ReadBolcks_SDMA
|
|
*
|
|
* @brief Reads block(s) from a specified address in a card.
|
|
* The Data transfer by SDMA(Simple DMA) mode.
|
|
*
|
|
* @param hsd: Pointer to SD handle.
|
|
* fp_Data: pointer to the received dat buffer.
|
|
* fu32_BlockAddr: Block Start Address.
|
|
* fu16_BlockNum: Number of SD blocks to read.
|
|
*/
|
|
uint32_t SDCard_ReadBolcks_SDMA(SD_HandleTypeDef *hsd, uint32_t *fp_Data, uint32_t fu32_BlockAddr, uint16_t fu16_BlockNum)
|
|
{
|
|
int i;
|
|
uint32_t lu32_ErrState = INT_NO_ERR;
|
|
|
|
bool lb_TrfComplete = true;
|
|
uint32_t lu32_Addr = (uint32_t)fp_Data;
|
|
|
|
if (fu16_BlockNum == 0)
|
|
return E1_NUM_ERR;
|
|
|
|
/* SEND CMD23 SET_BLOCK_COUNT */
|
|
lu32_ErrState = SD_CMD_SetBlockCount(hsd->SDx, fu16_BlockNum);
|
|
if (lu32_ErrState)
|
|
return lu32_ErrState;
|
|
|
|
/* set SDMA system Address */
|
|
__SD_SET_SDMA_SYSTEM_ADDR(hsd->SDx, (uint32_t)fp_Data);
|
|
/* Set block count */
|
|
__SD_SET_BLOCK_COUNT(hsd->SDx, fu16_BlockNum);
|
|
|
|
/* SEND CMD18 READ_MULTIPLE_BLOCK */
|
|
lu32_ErrState = SD_CMD_ReadBlock_SDMA(hsd->SDx, fu32_BlockAddr);
|
|
if (lu32_ErrState)
|
|
return lu32_ErrState;
|
|
|
|
/* Address alignment */
|
|
lu32_Addr &= SDMA_ADDR_ALIGN_MASK;
|
|
|
|
/* wait for transfer complete or any errors occur */
|
|
while (lb_TrfComplete)
|
|
{
|
|
if (__SD_GET_INT_STATUS(hsd->SDx) & (INT_TRANSFER_COMPLETE | INT_ERR_MASK))
|
|
{
|
|
lb_TrfComplete = false;
|
|
}
|
|
|
|
if (__SD_GET_INT_STATUS(hsd->SDx) & INT_DMA_INT)
|
|
{
|
|
__SD_CLR_INT_STATUS(hsd->SDx, INT_DMA_INT);
|
|
|
|
/* SDMA system Address alignment increases */
|
|
lu32_Addr += SDMA_ADDR_UNIT;
|
|
|
|
/* Update SDMA system Address */
|
|
__SD_SET_SDMA_SYSTEM_ADDR(hsd->SDx, (uint32_t)lu32_Addr);
|
|
}
|
|
}
|
|
|
|
/* Any errors occur */
|
|
if (__SD_GET_INT_STATUS(hsd->SDx) & INT_ERR_MASK)
|
|
{
|
|
lu32_ErrState = __SD_GET_INT_STATUS(hsd->SDx) & INT_ERR_MASK;
|
|
}
|
|
/* clear interrupt status */
|
|
__SD_CLR_ALL_INT_STATUS(hsd->SDx);
|
|
|
|
return lu32_ErrState;
|
|
}
|
|
|
|
/************************************************************************************
|
|
* @fn SDCard_WriteBolcks_SDMA
|
|
*
|
|
* @brief Write block(s) from a specified address in a card.
|
|
* The Data transfer by SDMA(Simple DMA) mode.
|
|
*
|
|
* @param hsd: Pointer to SD handle.
|
|
* fp_Data: pointer to the received dat buffer.
|
|
* fu32_BlockAddr: Block Address.
|
|
* fu16_BlockNum: Number of SD blocks to write.
|
|
*/
|
|
uint32_t SDCard_WriteBolcks_SDMA(SD_HandleTypeDef *hsd, uint32_t *fp_Data, uint32_t fu32_BlockAddr, uint16_t fu16_BlockNum)
|
|
{
|
|
int i;
|
|
uint32_t lu32_ErrState = INT_NO_ERR;
|
|
|
|
bool lb_TrfComplete = true;
|
|
uint32_t lu32_Addr = (uint32_t)fp_Data;
|
|
|
|
if (fu16_BlockNum == 0)
|
|
return E1_NUM_ERR;
|
|
|
|
/* SEND CMD23 SET_BLOCK_COUNT */
|
|
lu32_ErrState = SD_CMD_SetBlockCount(hsd->SDx, fu16_BlockNum);
|
|
if (lu32_ErrState)
|
|
return lu32_ErrState;
|
|
|
|
/* set SDMA system Address */
|
|
__SD_SET_SDMA_SYSTEM_ADDR(hsd->SDx, (uint32_t)fp_Data);
|
|
/* Set block count */
|
|
__SD_SET_BLOCK_COUNT(hsd->SDx, fu16_BlockNum);
|
|
|
|
/* SEND CMD25 WRITE_MULTIPLE_BLOCK */
|
|
lu32_ErrState = SD_CMD_WriteBlock_SDMA(hsd->SDx, fu32_BlockAddr);
|
|
if (lu32_ErrState)
|
|
return lu32_ErrState;
|
|
|
|
/* Address alignment */
|
|
lu32_Addr &= SDMA_ADDR_ALIGN_MASK;
|
|
|
|
/* wait for transfer complete or any errors occur */
|
|
while (lb_TrfComplete)
|
|
{
|
|
if (__SD_GET_INT_STATUS(hsd->SDx) & (INT_TRANSFER_COMPLETE | INT_ERR_MASK))
|
|
{
|
|
lb_TrfComplete = false;
|
|
}
|
|
|
|
if (__SD_GET_INT_STATUS(hsd->SDx) & INT_DMA_INT)
|
|
{
|
|
__SD_CLR_INT_STATUS(hsd->SDx, INT_DMA_INT);
|
|
|
|
/* SDMA system Address alignment increases */
|
|
lu32_Addr += SDMA_ADDR_UNIT;
|
|
|
|
/* Update SDMA system Address */
|
|
__SD_SET_SDMA_SYSTEM_ADDR(hsd->SDx, (uint32_t)lu32_Addr);
|
|
}
|
|
}
|
|
|
|
/* Any errors occur */
|
|
if (__SD_GET_INT_STATUS(hsd->SDx) & INT_ERR_MASK)
|
|
{
|
|
lu32_ErrState = __SD_GET_INT_STATUS(hsd->SDx) & INT_ERR_MASK;
|
|
}
|
|
/* clear interrupt status */
|
|
__SD_CLR_ALL_INT_STATUS(hsd->SDx);
|
|
|
|
return lu32_ErrState;
|
|
}
|
|
|
|
/************************************************************************************
|
|
* @fn SDCard_ReadBolcks_SDMA_IT
|
|
*
|
|
* @brief Reads block(s) from a specified address in a card.
|
|
* The Data transfer by SDMA(Simple DMA) mode with interrupt.
|
|
*
|
|
* @param hsd: Pointer to SD handle.
|
|
* fp_Data: pointer to the received dat buffer.
|
|
* fu32_BlockAddr: Block Start Address.
|
|
* fu16_BlockNum: Number of SD blocks to read.
|
|
*/
|
|
uint32_t SDCard_ReadBolcks_SDMA_IT(SD_HandleTypeDef *hsd, uint32_t *fp_Data, uint32_t fu32_BlockAddr, uint16_t fu16_BlockNum)
|
|
{
|
|
int i;
|
|
uint32_t lu32_ErrState = INT_NO_ERR;
|
|
|
|
if (hsd->CardStatus != CARD_STATUS_IDLE)
|
|
return E4_CARD_BUSY;
|
|
|
|
if (fu16_BlockNum == 0)
|
|
return E1_NUM_ERR;
|
|
|
|
/* SEND CMD23 SET_BLOCK_COUNT */
|
|
lu32_ErrState = SD_CMD_SetBlockCount(hsd->SDx, fu16_BlockNum);
|
|
if (lu32_ErrState)
|
|
return lu32_ErrState;
|
|
|
|
/* set SDMA system Address */
|
|
__SD_SET_SDMA_SYSTEM_ADDR(hsd->SDx, (uint32_t)fp_Data);
|
|
/* Set block count */
|
|
__SD_SET_BLOCK_COUNT(hsd->SDx, fu16_BlockNum);
|
|
|
|
/* Address alignment */
|
|
hsd->AddrAlign = (uint32_t)fp_Data & SDMA_ADDR_ALIGN_MASK;
|
|
|
|
/* Enable error/transfer complete/dma */
|
|
__SD_INT_ENABLE(hsd->SDx, INT_DMA_INT | INT_TRANSFER_COMPLETE | INT_ERR_MASK);
|
|
|
|
/* SEND CMD18 READ_MULTIPLE_BLOCK */
|
|
lu32_ErrState = SD_CMD_ReadBlock_SDMA(hsd->SDx, fu32_BlockAddr);
|
|
if (lu32_ErrState)
|
|
return lu32_ErrState;
|
|
else
|
|
hsd->CardStatus = CARD_STATUS_READ_BUSY;
|
|
|
|
return lu32_ErrState;
|
|
}
|
|
|
|
/************************************************************************************
|
|
* @fn SDCard_WriteBolcks_SDMA_IT
|
|
*
|
|
* @brief Write block(s) from a specified address in a card.
|
|
* The Data transfer by SDMA(Simple DMA) mode with interrupt.
|
|
*
|
|
* @param hsd: Pointer to SD handle.
|
|
* fp_Data: pointer to the received dat buffer.
|
|
* fu32_BlockAddr: Block Address.
|
|
* fu16_BlockNum: Number of SD blocks to write.
|
|
*/
|
|
uint32_t SDCard_WriteBolcks_SDMA_IT(SD_HandleTypeDef *hsd, uint32_t *fp_Data, uint32_t fu32_BlockAddr, uint16_t fu16_BlockNum)
|
|
{
|
|
int i;
|
|
uint32_t lu32_ErrState = INT_NO_ERR;
|
|
|
|
if (hsd->CardStatus != CARD_STATUS_IDLE)
|
|
return E4_CARD_BUSY;
|
|
|
|
if (fu16_BlockNum == 0)
|
|
return E1_NUM_ERR;
|
|
|
|
/* SEND CMD23 SET_BLOCK_COUNT */
|
|
lu32_ErrState = SD_CMD_SetBlockCount(hsd->SDx, fu16_BlockNum);
|
|
if (lu32_ErrState)
|
|
return lu32_ErrState;
|
|
|
|
/* set SDMA system Address */
|
|
__SD_SET_SDMA_SYSTEM_ADDR(hsd->SDx, (uint32_t)fp_Data);
|
|
/* Set block count */
|
|
__SD_SET_BLOCK_COUNT(hsd->SDx, fu16_BlockNum);
|
|
|
|
/* Address alignment */
|
|
hsd->AddrAlign = (uint32_t)fp_Data & SDMA_ADDR_ALIGN_MASK;
|
|
|
|
/* Enable error/transfer complete/dma */
|
|
__SD_INT_ENABLE(hsd->SDx, INT_DMA_INT | INT_TRANSFER_COMPLETE | INT_ERR_MASK);
|
|
|
|
/* SEND CMD25 WRITE_MULTIPLE_BLOCK */
|
|
lu32_ErrState = SD_CMD_WriteBlock_SDMA(hsd->SDx, fu32_BlockAddr);
|
|
if (lu32_ErrState)
|
|
return lu32_ErrState;
|
|
else
|
|
hsd->CardStatus = CARD_STATUS_WIRTE_BUSY;
|
|
|
|
return lu32_ErrState;
|
|
}
|
|
|
|
/************************************************************************************
|
|
* @fn SDCard_Erase
|
|
*
|
|
* @brief Write block(s) from a specified address in a card.
|
|
* The Data transfer by polling mode.
|
|
*
|
|
* @param hsd: Pointer to SD handle.
|
|
* BlockStartAdd: Start Block address
|
|
* BlockEndAdd: End Block address
|
|
*/
|
|
uint32_t SDCard_Erase(SD_HandleTypeDef *hsd, uint32_t BlockStartAddr, uint32_t BlockEndAddr)
|
|
{
|
|
uint32_t lu32_ErrState = INT_NO_ERR;
|
|
|
|
/* CMD32: ERASE_WR_BLK_START */
|
|
lu32_ErrState = SD_CMD_EraseStartAddr(hsd->SDx, BlockStartAddr);
|
|
if (lu32_ErrState)
|
|
{
|
|
return lu32_ErrState;
|
|
}
|
|
|
|
/* CMD33: ERASE_WR_BLK_END */
|
|
lu32_ErrState = SD_CMD_EraseEndAddr(hsd->SDx, BlockEndAddr);
|
|
if (lu32_ErrState)
|
|
{
|
|
return lu32_ErrState;
|
|
}
|
|
|
|
/* CMD38: ERASE */
|
|
lu32_ErrState = SD_CMD_Erase(hsd->SDx);
|
|
if (lu32_ErrState)
|
|
{
|
|
return lu32_ErrState;
|
|
}
|
|
|
|
return lu32_ErrState;
|
|
}
|
|
|
|
/************************************************************************************
|
|
* @fn SDCard_Get_Block_count
|
|
*
|
|
* @brief Get block counter of mounted SD Card.
|
|
*
|
|
* @param hsd: Pointer to SD handle.
|
|
*
|
|
* @return Block count.
|
|
*/
|
|
uint32_t SDCard_Get_Block_count(SD_HandleTypeDef *hsd)
|
|
{
|
|
if (hsd) {
|
|
return hsd->CardInfo.MemoryCapacity / 512;
|
|
}
|
|
else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/************************************************************************************
|
|
* @fn SDCard_GetCardCSD
|
|
*
|
|
* @brief Get the card information from the CSD register.
|
|
*/
|
|
static void __SDCard_GetCardCSD(SD_HandleTypeDef *hsd)
|
|
{
|
|
hsd->CSDInfo = (SD_CardCSDTypeDef *)hsd->CSD;
|
|
|
|
/* Card memory capacity, unit KByte */
|
|
hsd->CardInfo.MemoryCapacity = (hsd->CSDInfo->C_SIZE + 1) * 512;
|
|
/* Card command class */
|
|
hsd->CardInfo.Class = hsd->CSDInfo->CCC;
|
|
}
|
|
|
|
/************************************************************************************
|
|
* @fn SDCard_GetCardCID
|
|
*
|
|
* @brief Get the card information from the CID register.
|
|
*/
|
|
static void __SDCard_GetCardCID(SD_HandleTypeDef *hsd)
|
|
{
|
|
hsd->CIDInfo = (SD_CardCIDTypeDef *)hsd->CID;
|
|
}
|
|
|
|
/************************************************************************************
|
|
* @fn SD_PowerON
|
|
*
|
|
* @brief Enquires cards about their operating voltage and configures clock ontrols.
|
|
*/
|
|
static uint32_t __SDCard_PowerON(SD_HandleTypeDef *hsd)
|
|
{
|
|
uint32_t lu32_ErrState = INT_NO_ERR;
|
|
uint32_t lu32_Response;
|
|
bool lb_BusyStatus = false;
|
|
|
|
/* CMD0: GO_IDLE_STATE */
|
|
lu32_ErrState = SD_CMD_GoIdleState(hsd->SDx);
|
|
if (lu32_ErrState)
|
|
{
|
|
return lu32_ErrState;
|
|
}
|
|
|
|
/* CMD8: SEND_IF_COND: Command available only on V2.0 cards */
|
|
lu32_ErrState = SD_CMD_SendInterfaceCondition(hsd->SDx);
|
|
if (lu32_ErrState)
|
|
{
|
|
hsd->CardInfo.CardVersion = CARD_VER_1_X;
|
|
|
|
return lu32_ErrState;
|
|
}
|
|
else
|
|
{
|
|
hsd->CardInfo.CardVersion = CARD_VER_2_X;
|
|
|
|
/* signaling 3.3V */
|
|
if (hsd->Init.SpeedMode & SIGNALING_3_3V_MASK)
|
|
{
|
|
while (lb_BusyStatus == false)
|
|
{
|
|
/* Send CMD55 APP_CMD with RCA as 0 */
|
|
lu32_ErrState = SD_CMD_AppCommand(hsd->SDx, 0);
|
|
if (lu32_ErrState)
|
|
{
|
|
return lu32_ErrState;
|
|
}
|
|
|
|
/* Send ACMD41 SD_SEND_OP_COND */
|
|
lu32_ErrState = SD_ACMD_SendOperCondition(hsd->SDx, ACMD41_ARG_HCS|ACMD41_ARG_VOLTAGE_WINDOW_32_33, &hsd->OCR);
|
|
if (lu32_ErrState)
|
|
{
|
|
return lu32_ErrState;
|
|
}
|
|
|
|
lb_BusyStatus = hsd->OCR & OCR_BUSY ? true : false;
|
|
}
|
|
|
|
if (hsd->OCR & OCR_CCS)
|
|
{
|
|
hsd->CardInfo.CardType = CARD_TYPE_SDHC_SDXC;
|
|
}
|
|
else
|
|
{
|
|
hsd->CardInfo.CardType = CARD_TYPE_SDSC;
|
|
}
|
|
}
|
|
/* signaling 1.8V */
|
|
else
|
|
{
|
|
while (lb_BusyStatus == false)
|
|
{
|
|
/* SEND CMD55 APP_CMD with RCA as 0 */
|
|
lu32_ErrState = SD_CMD_AppCommand(hsd->SDx, 0);
|
|
if (lu32_ErrState)
|
|
{
|
|
return lu32_ErrState;
|
|
}
|
|
|
|
/* Send ACMD41 SD_SEND_OP_COND */
|
|
lu32_ErrState = SD_ACMD_SendOperCondition(hsd->SDx, ACMD41_ARG_HCS|ACMD41_ARG_S18R|ACMD41_ARG_VOLTAGE_WINDOW_32_33, &hsd->OCR);
|
|
if (lu32_ErrState)
|
|
{
|
|
return lu32_ErrState;
|
|
}
|
|
|
|
lb_BusyStatus = hsd->OCR & OCR_BUSY ? true : false;
|
|
}
|
|
|
|
/* Card Capacity Status */
|
|
if (hsd->OCR & OCR_CCS)
|
|
{
|
|
hsd->CardInfo.CardType = CARD_TYPE_SDHC_SDXC;
|
|
}
|
|
else
|
|
{
|
|
hsd->CardInfo.CardType = CARD_TYPE_SDSC;
|
|
}
|
|
|
|
/* switching to 1.8V Accepted */
|
|
if (hsd->OCR & OCR_S18A)
|
|
{
|
|
/* SEND CMD11 VOLTAGE_SWITCH */
|
|
lu32_ErrState = SD_CMD_VoltageSwitch(hsd->SDx);
|
|
|
|
if (lu32_ErrState == INT_NO_ERR)
|
|
{
|
|
/* Data line is in use */
|
|
while(!(__SD_GET_PRESENT_STATE(hsd->SDx) & PreState_DAT0_SIGNAL_MASK));
|
|
|
|
/* Host switch 1.8V */
|
|
__SD_1_8V_ENABLE(hsd->SDx, 1);
|
|
/* Host default select SDR12 */
|
|
__SD_SDCLK_DISABLE(hsd->SDx);
|
|
__SD_UHS_MODE(hsd->SDx, 0);
|
|
__SD_SDCLK_ENABLE(hsd->SDx);
|
|
|
|
|
|
/* Wait to Card ready */
|
|
uint32_t lu32_Timeout = 100;
|
|
|
|
while (lu32_Timeout--)
|
|
{
|
|
if (!SD_CMD_SendStatus(hsd->SDx, hsd->RCA, &lu32_Response))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lu32_ErrState = E2_1_8V_ERR;
|
|
}
|
|
}
|
|
}
|
|
|
|
return lu32_ErrState;
|
|
}
|
|
|
|
/************************************************************************************
|
|
* @fn __SDCard_InitCard
|
|
*
|
|
* @brief Initializes the sd card.
|
|
*/
|
|
static uint32_t __SDCard_InitCard(SD_HandleTypeDef *hsd)
|
|
{
|
|
uint32_t lu32_ErrState = INT_NO_ERR;
|
|
uint32_t lu32_Response;
|
|
uint32_t CMD6_Data[16];
|
|
|
|
/* CMD2: ALL_SEND_CID */
|
|
lu32_ErrState = SD_CMD_AllSendCID(hsd->SDx, hsd->CID);
|
|
if (lu32_ErrState)
|
|
{
|
|
return lu32_ErrState;
|
|
}
|
|
|
|
/* CMD3: SEND_RELATIVE_ADDR */
|
|
lu32_ErrState = SD_CMD_SendRelAddr(hsd->SDx, &hsd->RCA);
|
|
if (lu32_ErrState)
|
|
{
|
|
return lu32_ErrState;
|
|
}
|
|
|
|
/* CMD9: SEND_CSD */
|
|
lu32_ErrState = SD_CMD_SendCSD(hsd->SDx, hsd->RCA, hsd->CSD);
|
|
if (lu32_ErrState)
|
|
{
|
|
return lu32_ErrState;
|
|
}
|
|
|
|
/* CMD7: SEL_DESEL_CARD */
|
|
lu32_ErrState = SD_CMD_SelectCard(hsd->SDx, hsd->RCA);
|
|
if (lu32_ErrState)
|
|
{
|
|
return lu32_ErrState;
|
|
}
|
|
|
|
/* Wait to enter transfer state */
|
|
uint32_t lu32_Timeout = 100;
|
|
|
|
while (lu32_Timeout--)
|
|
{
|
|
/* CMD13: SEND_STATUS */
|
|
lu32_ErrState = SD_CMD_SendStatus(hsd->SDx, hsd->RCA, &lu32_Response);
|
|
if (lu32_ErrState)
|
|
{
|
|
return lu32_ErrState;
|
|
}
|
|
if (lu32_Response & CARD_CURRENT_STATE_TRAN)
|
|
break;
|
|
}
|
|
|
|
/* Switch card function */
|
|
if (hsd->Init.SpeedMode != SPEED_DS)
|
|
{
|
|
/* CMD6: SWITCH_FUNC */
|
|
lu32_ErrState = SD_CMD_SwitchFunc(hsd->SDx, 0x80FFFFF0 | hsd->Init.SpeedMode);
|
|
if (lu32_ErrState)
|
|
{
|
|
return lu32_ErrState;
|
|
}
|
|
|
|
if (lu32_ErrState == INT_NO_ERR)
|
|
{
|
|
/* Wait for Buffer Read Ready Int */
|
|
while(!(__SD_GET_INT_STATUS(hsd->SDx) & INT_BUFFER_READ_READY));
|
|
/* Clear Buffer_Read_Ready */
|
|
__SD_CLR_INT_STATUS(hsd->SDx, INT_BUFFER_READ_READY);
|
|
/* Read one block */
|
|
for (int i = 0; i < 16; i++)
|
|
{
|
|
CMD6_Data[i] = __SD_GET_BUFFERDATA(hsd->SDx);
|
|
}
|
|
|
|
/* wait for transfer complete or any errors occur */
|
|
while(!(__SD_GET_INT_STATUS(hsd->SDx) & (INT_TRANSFER_COMPLETE | INT_ERR_MASK)));
|
|
/* Any errors occur */
|
|
if (__SD_GET_INT_STATUS(hsd->SDx) & INT_ERR_MASK)
|
|
{
|
|
return (__SD_GET_INT_STATUS(hsd->SDx) & INT_ERR_MASK);
|
|
}
|
|
/* clear interrupt status */
|
|
__SD_CLR_ALL_INT_STATUS(hsd->SDx);
|
|
|
|
|
|
/* Check Card */
|
|
/* Card Not support selected Speed */
|
|
if ((CMD6_Data[4] & 0xF) == 0xF)
|
|
{
|
|
lu32_ErrState = E3_SPEED_ERR;
|
|
|
|
return lu32_ErrState;
|
|
}
|
|
/* Update Speed mode */
|
|
else
|
|
{
|
|
if (hsd->Init.SpeedMode == SPEED_HS)
|
|
{
|
|
/* HIGH Speed mode */
|
|
__SD_SPEED_MODE(hsd->SDx, 1);
|
|
}
|
|
else
|
|
{
|
|
/* SDR25/SDR50/SDR104/DDR50 */
|
|
__SD_SDCLK_DISABLE(hsd->SDx);
|
|
__SD_UHS_MODE(hsd->SDx, (hsd->Init.SpeedMode & 0xF));
|
|
__SD_SDCLK_ENABLE(hsd->SDx);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Update bus clock speed */
|
|
__SD_CLOCK_DIV_LOW_8BIT(hsd->SDx, (hsd->Init.ClockDiv / 2));
|
|
/* Fixed Block Size 512 Byte */
|
|
__SD_SET_BLOCK_SIZE(hsd->SDx, 512);
|
|
|
|
return lu32_ErrState;
|
|
}
|