openblt/Target/Demo/ARMCM4_XMC4_XMC4700_Relax_K.../Boot/lib/FatFS/SDMMC_BLOCK/sdmmc_block_private_sd.c

2912 lines
109 KiB
C

/**
* @file sdmmc_block_private_sd.c
* @date 2017-06-08
*
* NOTE:
* This file is generated by DAVE. Any manual modification done to this file will be lost when the code is regenerated.
*
* @cond
***********************************************************************************************************************
* SDMMC_BLOCK v4.0.22 - Configures the SD host to interface with the SDMMC card.
*
* Copyright (c) 2016-2017, Infineon Technologies AG
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,are permitted provided that the
* following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following
* disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
*
* Neither the name of the copyright holders nor the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY,OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* To improve the quality of the software, users are encouraged to share modifications, enhancements or bug fixes
* with Infineon Technologies AG (dave@infineon.com).
***********************************************************************************************************************
*
* Change History
* --------------
*
* 2016-01-20:
* - Initial version. <br>
*
* 2016-02-08:
* - Help Doc updated. <br>
* - Bug fixes done.<br>
*
* 2016-04-05
* - Bug fixes for public release, April, 2016 <br>
* - MISRA fixes <br>
* - Add timeout for erase() <br>
* - Check write protection in write/erase conditions <br>
* - Remove mode_init_flag check for functions invoked in IOCTL <br>
*
* 2016-07-20:
* - lReadResponse(): Fixes in handling XMC_SDMMC_RESPONSE_TYPE_R2 <br>
*
* 2016-08-24:
* - Introduce timeout mechanism in SDMMC_BLOCK_SD_lCheckDataCommandLines() <br>
*
* 2017-06-08
* - Fix SDMMC_BLOCK_SD_GetSectorCount() for Standard Capacity cards
*
* @endcond
*
*/
#include "sdmmc_block_private_sd.h"
#include "boot.h"
#ifdef SDMMC_BLOCK_SD
/***********************************************************************************************************************
* EXTERNAL ROUTINES
**********************************************************************************************************************/
extern void SDMMC0_0_IRQHandler(void);
/***********************************************************************************************************************
* LOCAL ROUTINES
**********************************************************************************************************************/
static SDMMC_BLOCK_MODE_STATUS_t
SDMMC_BLOCK_SD_lReset(SDMMC_BLOCK_t *const obj, uint32_t reset);
static void
SDMMC_BLOCK_SD_lCardCleanUp(SDMMC_BLOCK_t *const obj);
static uint32_t
SDMMC_BLOCK_SD_lCheckDataCommandLines(SDMMC_BLOCK_t *const obj,
const XMC_SDMMC_COMMAND_t *cmd);
static void
SDMMC_BLOCK_SD_lCheckArgumentError(const uint32_t *card_status, uint8_t *err);
static void
SDMMC_BLOCK_SD_lCheckEraseError(const uint32_t *card_status, uint8_t *err);
static void
SDMMC_BLOCK_SD_lCheckCardError(const uint32_t *card_status, uint8_t *err);
static SDMMC_BLOCK_MODE_STATUS_t
SDMMC_BLOCK_SD_lCheckErrorInResponse(const uint32_t *card_status);
static void
SDMMC_BLOCK_SD_lGetCardLockState(SDMMC_BLOCK_t *const obj, uint32_t card_status, uint16_t cmd_index);
static SDMMC_BLOCK_MODE_STATUS_t
SDMMC_BLOCK_SD_lTransferDelay(SDMMC_BLOCK_t *const obj, uint32_t delay);
static SDMMC_BLOCK_MODE_STATUS_t
SDMMC_BLOCK_SD_lReadResponse(SDMMC_BLOCK_t *const obj,
const XMC_SDMMC_COMMAND_t *cmd,
XMC_SDMMC_RESPONSE_TYPE_t resp_type,
void *resp);
static SDMMC_BLOCK_MODE_STATUS_t
SDMMC_BLOCK_SD_lSendCommand(SDMMC_BLOCK_t *const obj,
const XMC_SDMMC_COMMAND_t *cmd,
uint32_t arg,
XMC_SDMMC_RESPONSE_TYPE_t resp_type,
void *resp);
static SDMMC_BLOCK_MODE_STATUS_t
SDMMC_BLOCK_SD_lSetVoltageWindow(SDMMC_BLOCK_t *const obj);
static SDMMC_BLOCK_MODE_STATUS_t
SDMMC_BLOCK_SD_lQueryOperatingCondition(SDMMC_BLOCK_t *const obj);
static SDMMC_BLOCK_MODE_STATUS_t
SDMMC_BLOCK_SD_lQueryVoltage(SDMMC_BLOCK_t *const obj, uint32_t arg);
static SDMMC_BLOCK_MODE_STATUS_t
SDMMC_BLOCK_SD_lAfterCardInitialize(SDMMC_BLOCK_t *const obj);
static SDMMC_BLOCK_MODE_STATUS_t
SDMMC_BLOCK_SD_lInitializeCard(SDMMC_BLOCK_t *const obj);
static SDMMC_BLOCK_MODE_STATUS_t
SDMMC_BLOCK_SD_lGetWriteProtect(SDMMC_BLOCK_t *const obj);
static SDMMC_BLOCK_MODE_STATUS_t
SDMMC_BLOCK_SD_lConfigureSingleBlockTransfer(SDMMC_BLOCK_t *const obj,
const XMC_SDMMC_COMMAND_t *cmd,
uint32_t arg,
uint16_t block_size);
static SDMMC_BLOCK_MODE_STATUS_t
SDMMC_BLOCK_SD_lMultiBlockTransfer(SDMMC_BLOCK_t *const obj,
uint32_t *addr,
uint32_t num_blocks,
const XMC_SDMMC_COMMAND_t *cmd,
uint32_t *buf,
SDMMC_BLOCK_SD_DATA_TRANSFER_t transfer_mode);
static SDMMC_BLOCK_MODE_STATUS_t
SDMMC_BLOCK_SD_lCheckLockStatus(SDMMC_BLOCK_t *const obj, SDMMC_BLOCK_CARD_LOCK_STATUS_t mode);
#if SDMMC_BLOCK_SD_SUPPORT_4_BUS_WIDTH
static SDMMC_BLOCK_MODE_STATUS_t
SDMMC_BLOCK_SD_lSwitchBusWidth(SDMMC_BLOCK_t *const obj);
static SDMMC_BLOCK_MODE_STATUS_t
SDMMC_BLOCK_SD_lSwitchSpeed(SDMMC_BLOCK_t *const obj);
#endif
static SDMMC_BLOCK_MODE_STATUS_t
SDMMC_BLOCK_SD_lCommandDelay(SDMMC_BLOCK_t *const obj, uint32_t delay);
static SDMMC_BLOCK_MODE_STATUS_t
SDMMC_BLOCK_SD_lSwitchToTransferState(SDMMC_BLOCK_t *const obj);
static void
SDMMC_BLOCK_SD_lAcmdErrorRecovery(SDMMC_BLOCK_t *const obj);
static SDMMC_BLOCK_MODE_STATUS_t
SDMMC_BLOCK_SD_lCheckSectorBound(SDMMC_BLOCK_t *const obj,
uint32_t sector_num,
uint32_t sector_count);
static SDMMC_BLOCK_MODE_STATUS_t
SDMMC_BLOCK_SD_lLocalErase(SDMMC_BLOCK_t *const obj,
uint32_t start_addr,
uint32_t end_addr,
uint32_t timeout);
static SDMMC_BLOCK_MODE_STATUS_t
SDMMC_BLOCK_SD_lHostControllerInit(SDMMC_BLOCK_t *const obj);
static SDMMC_BLOCK_MODE_STATUS_t
SDMMC_BLOCK_SD_lHostControllerDeInit(SDMMC_BLOCK_t *const obj);
static SDMMC_BLOCK_MODE_STATUS_t
SDMMC_BLOCK_SD_lCardReadMultipleBlocks(SDMMC_BLOCK_t *const obj,
uint32_t *read_buf,
uint32_t read_addr,
uint32_t num_blocks);
static SDMMC_BLOCK_MODE_STATUS_t
SDMMC_BLOCK_SD_lCardReadSingleBlock(SDMMC_BLOCK_t *const obj,
uint32_t *read_buf,
uint32_t read_addr);
static SDMMC_BLOCK_MODE_STATUS_t
SDMMC_BLOCK_SD_lCardWriteMultipleBlocks(SDMMC_BLOCK_t *const obj,
const uint32_t *write_buf,
uint32_t write_addr,
uint32_t num_blocks);
static SDMMC_BLOCK_MODE_STATUS_t
SDMMC_BLOCK_SD_lCardWriteSingleBlock(SDMMC_BLOCK_t *const obj,
const uint32_t *write_buf,
uint32_t write_addr);
static SDMMC_BLOCK_MODE_STATUS_t
SDMMC_BLOCK_SD_lDelay(SDMMC_BLOCK_t *const obj, uint32_t delay);
static void
SDMMC_BLOCK_SD_lWriteCardType(SDMMC_BLOCK_t *const obj);
static SDMMC_BLOCK_MODE_STATUS_t
SDMMC_BLOCK_SD_lReadRca(SDMMC_BLOCK_t *const obj);
static SDMMC_BLOCK_MODE_STATUS_t
SDMMC_BLOCK_SD_lReadCardRegisters(SDMMC_BLOCK_t *const obj);
static SDMMC_BLOCK_MODE_STATUS_t
SDMMC_BLOCK_SD_lDataTransfer(SDMMC_BLOCK_t *const obj,
uint32_t *buf,
SDMMC_BLOCK_SD_DATA_TRANSFER_t transfer_mode,
uint32_t quad_bytes);
static SDMMC_BLOCK_MODE_STATUS_t
SDMMC_BLOCK_SD_lErrorInterruptRecovery(SDMMC_BLOCK_t *const obj);
static SDMMC_BLOCK_MODE_STATUS_t
SDMMC_BLOCK_SD_lSingleBlockTransfer(SDMMC_BLOCK_t *const obj,
const XMC_SDMMC_COMMAND_t *cmd,
uint32_t arg,
uint16_t block_size,
uint32_t *buf,
SDMMC_BLOCK_SD_DATA_TRANSFER_t transfer_mode);
SDMMC_BLOCK_MODE_STATUS_t
SDMMC_BLOCK_SD_Start(SDMMC_BLOCK_t *const obj);
SDMMC_BLOCK_MODE_STATUS_t
SDMMC_BLOCK_SD_NormalInterruptHandler(SDMMC_BLOCK_t *const obj, uint16_t int_status);
SDMMC_BLOCK_MODE_STATUS_t
SDMMC_BLOCK_SD_ErrorInterruptHandler(SDMMC_BLOCK_t *const obj, uint16_t int_status);
/***********************************************************************************************************************
* MACROS
**********************************************************************************************************************/
/***********************************************************************************************************************
* DATA STRUCTURES
**********************************************************************************************************************/
/* Command Structure defining SD, MMC and Application specific commands */
const XMC_SDMMC_COMMAND_t sdmmc_block_command[40] =
{
/* Start: SD card commands */
{{0U, 0U, 0U, 0U, 0U, SDMMC_BLOCK_GO_IDLE_STATE}}, /* 0 */
{{1U, 1U, 0U, 0U, 0U, SDMMC_BLOCK_ALL_SEND_CID}}, /* 1 */
{{2U, 1U, 1U, 0U, 0U, SDMMC_BLOCK_SEND_RELATIVE_ADDR}}, /* 2 */
{{0U, 0U, 0U, 0U, 0U, SDMMC_BLOCK_SET_DSR}}, /* 3 */
{{2U, 1U, 1U, 1U, 0U, SDMMC_BLOCK_SWITCH_FUNC}}, /* 4 */
{{3U, 1U, 1U, 0U, 0U, SDMMC_BLOCK_SELECT_DESELECT_CARD}}, /* 5 */
{{2U, 1U, 1U, 0U, 0U, SDMMC_BLOCK_SD_SEND_IF_COND}}, /* 6 */
{{1U, 1U, 0U, 0U, 0U, SDMMC_BLOCK_SEND_CSD}}, /* 7 */
{{1U, 1U, 0U, 0U, 0U, SDMMC_BLOCK_SEND_CID}}, /* 8 */
{{3U, 1U, 1U, 0U, 0U, SDMMC_BLOCK_STOP_TRANSMISSION}}, /* 9 */
{{2U, 1U, 1U, 0U, 0U, SDMMC_BLOCK_SEND_STATUS}}, /* 10 */
{{0U, 0U, 0U, 0U, 0U, SDMMC_BLOCK_GO_INACTIVE_STATE}}, /* 11 */
{{2U, 1U, 1U, 0U, 0U, SDMMC_BLOCK_SET_BLOCKLEN}}, /* 12 */
{{2U, 1U, 1U, 1U, 0U, SDMMC_BLOCK_READ_SINGLE_BLOCK}}, /* 13 */
{{2U, 1U, 1U, 1U, 0U, SDMMC_BLOCK_READ_MULTIPLE_BLOCK}}, /* 14 */
{{2U, 1U, 1U, 1U, 0U, SDMMC_BLOCK_WRITE_BLOCK}}, /* 15 */
{{2U, 1U, 1U, 1U, 0U, SDMMC_BLOCK_WRITE_MULTIPLE_BLOCK}}, /* 16 */
{{2U, 1U, 1U, 1U, 0U, SDMMC_BLOCK_PROGRAM_CSD}}, /* 17 */
{{2U, 1U, 1U, 0U, 0U, SDMMC_BLOCK_SET_WRITE_PROT}}, /* 18 */
{{2U, 1U, 1U, 0U, 0U, SDMMC_BLOCK_CLR_WRITE_PROT}}, /* 19 */
{{2U, 1U, 1U, 1U, 0U, SDMMC_BLOCK_SEND_WRITE_PROT}}, /* 20 */
{{2U, 1U, 1U, 0U, 0U, SDMMC_BLOCK_ERASE_WR_BLK_START}}, /* 21 */
{{2U, 1U, 1U, 0U, 0U, SDMMC_BLOCK_ERASE_WR_BLK_END}}, /* 22 */
{{3U, 1U, 1U, 0U, 0U, SDMMC_BLOCK_ERASE}}, /* 23 */
{{2U, 1U, 1U, 1U, 0U, SDMMC_BLOCK_LOCK_UNLOCK}}, /* 24 */
{{2U, 1U, 1U, 0U, 0U, SDMMC_BLOCK_APP_CMD}}, /* 25 */
{{2U, 1U, 1U, 1U, 0U, SDMMC_BLOCK_GEN_CMD}}, /* 26 */
/* Start: application specific commands */
{{2U, 1U, 1U, 0U, 0U, SDMMC_BLOCK_SET_BUS_WIDTH}}, /* 27 */
{{2U, 1U, 1U, 1U, 0U, SDMMC_BLOCK_SD_STATUS}}, /* 28 */
{{2U, 1U, 1U, 1U, 0U, SDMMC_BLOCK_SEND_NUM_WR_BLOCKS}}, /* 29 */
{{2U, 1U, 1U, 0U, 0U, SDMMC_BLOCK_SET_WR_BLK_ERASE_COUNT}}, /* 30 */
{{2U, 0U, 0U, 0U, 0U, SDMMC_BLOCK_SD_SEND_OP_COND}}, /* 31 */
{{2U, 1U, 1U, 0U, 0U, SDMMC_BLOCK_SET_CLR_CARD_DETECT}}, /* 32 */
{{2U, 1U, 1U, 1U, 0U, SDMMC_BLOCK_SEND_SCR}}, /* 33 */
/* Start of SDMMC_MMC Card specific commands */
{{2U, 0U, 1U, 0U, 0U, SDMMC_BLOCK_MMC_SEND_OP_COND}}, /* 34 */
{{3U, 1U, 1U, 0U, 0U, SDMMC_BLOCK_MMC_SLEEP_AWAKE}}, /* 35 */
{{3U, 1U, 1U, 0U, 0U, SDMMC_BLOCK_SWITCH_FUNC}}, /* 36 */
{{2U, 1U, 1U, 1U, 0U, SDMMC_BLOCK_MMC_SEND_EXT_CSD}}, /* 37 */
{{2U, 1U, 1U, 0U, 0U, SDMMC_BLOCK_ERASE_GROUP_START}}, /* 38 */
{{2U, 1U, 1U, 0U, 0U, SDMMC_BLOCK_ERASE_GROUP_END}} /* 39 */
};
/*
* SD card command index hash table
* It contains the index of the command structure
*
* Array index 0-57 is for general SD commands and array
* index 58-64 is for application specific commands.
*/
const uint8_t sdmmc_block_sd_hash_table[65] =
{
(uint8_t)0x00, (uint8_t)0xFF, (uint8_t)0x01, (uint8_t)0x02,
(uint8_t)0x03, (uint8_t)0xFF, (uint8_t)0x04, (uint8_t)0x05,
(uint8_t)0x06, (uint8_t)0x07, (uint8_t)0x08, (uint8_t)0xFF,
(uint8_t)0x09, (uint8_t)0x0A, (uint8_t)0xFF, (uint8_t)0x0B,
(uint8_t)0x0C, (uint8_t)0x0D, (uint8_t)0x0E, (uint8_t)0xFF,
(uint8_t)0xFF, (uint8_t)0xFF, (uint8_t)0xFF, (uint8_t)0xFF,
(uint8_t)0x0F, (uint8_t)0x10, (uint8_t)0xFF, (uint8_t)0x11,
(uint8_t)0x12, (uint8_t)0x13, (uint8_t)0x14, (uint8_t)0xFF,
(uint8_t)0x15, (uint8_t)0x16, (uint8_t)0xFF, (uint8_t)0xFF,
(uint8_t)0xFF, (uint8_t)0xFF, (uint8_t)0x17, (uint8_t)0xFF,
(uint8_t)0xFF, (uint8_t)0xFF, (uint8_t)0x18, (uint8_t)0xFF,
(uint8_t)0xFF, (uint8_t)0xFF, (uint8_t)0xFF, (uint8_t)0xFF,
(uint8_t)0xFF, (uint8_t)0xFF, (uint8_t)0xFF, (uint8_t)0xFF,
(uint8_t)0xFF, (uint8_t)0xFF, (uint8_t)0xFF, (uint8_t)0x19,
(uint8_t)0x1A, (uint8_t)0xFF, (uint8_t)0x1B, (uint8_t)0x1C,
(uint8_t)0x1D, (uint8_t)0x1E, (uint8_t)0x1F, (uint8_t)0x20,
(uint8_t)0x21
};
/***********************************************************************************************************************
* EXTERNAL REFERENCES
**********************************************************************************************************************/
/***********************************************************************************************************************
* API DEFINITIONS
**********************************************************************************************************************/
/* Resets the Host Controller's register */
static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_lReset(SDMMC_BLOCK_t *const obj, uint32_t reset)
{
SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_SUCCESS;
uint32_t timeoutTime;
XMC_SDMMC_SetSWReset(obj->sdmmc_sd->sdmmc, reset);
/* Set timeout time. */
timeoutTime = TimerGet() + (SDMMC_BLOCK_RESET_DELAY / 1000u) + 1u;
do
{
if (TimerGet() > timeoutTime)
{
status = SDMMC_BLOCK_MODE_STATUS_TIMEOUT_OCCURED;
break;
}
/* Service the watchdog. */
CopService();
}
while (((uint32_t)XMC_SDMMC_GetSWResetStatus(obj->sdmmc_sd->sdmmc)) & (reset));
return status;
}
/* Clears card specific structures and stops the SD clock */
static void SDMMC_BLOCK_SD_lCardCleanUp(SDMMC_BLOCK_t *const obj)
{
memset((void *)&obj->sdmmc_sd->card_info, 0, sizeof(SDMMC_BLOCK_SD_CARD_INFORMATION_t));
obj->card_type = (uint8_t)0;
obj->sdmmc_sd->f8 = (uint8_t)0;
obj->sdmmc_sd->cmd_int_err = SDMMC_BLOCK_MODE_STATUS_FAILURE;
obj->sdmmc_sd->data_int_err = SDMMC_BLOCK_MODE_STATUS_FAILURE;
obj->sdmmc_sd->err_recovery_stat = SDMMC_BLOCK_MODE_STATUS_FAILURE;
obj->sdmmc_sd->transfer_int_err = SDMMC_BLOCK_MODE_STATUS_FAILURE;
obj->card_state = (uint8_t)0U;
/* SD clock disable */
XMC_SDMMC_SDClockDisable(obj->sdmmc_sd->sdmmc);
}
/* Check if CMD and DAT lines are free before issuing a command */
static uint32_t SDMMC_BLOCK_SD_lCheckDataCommandLines(SDMMC_BLOCK_t *const obj, const XMC_SDMMC_COMMAND_t *cmd)
{
uint32_t status = (uint32_t)SDMMC_BLOCK_MODE_STATUS_CMD_LINE_BUSY;
uint32_t timeoutTime;
timeoutTime = TimerGet() + (SDMMC_BLOCK_DELAY_IN_COMMAND / 1000u) + 1u;
do
{
if (TimerGet() > timeoutTime)
{
status = SDMMC_BLOCK_MODE_STATUS_TIMEOUT_OCCURED;
break;
}
/* Service the watchdog. */
CopService();
} while ((XMC_SDMMC_IsDataLineBusy(obj->sdmmc_sd->sdmmc) ||
(XMC_SDMMC_IsCommandLineBusy(obj->sdmmc_sd->sdmmc))));
/* Check if command line is not busy; then proceed */
if (XMC_SDMMC_IsCommandLineBusy(obj->sdmmc_sd->sdmmc) == false)
{
status = (uint32_t)SDMMC_BLOCK_MODE_STATUS_SUCCESS;
if (((uint32_t)cmd->dat_present_sel == (uint32_t)1U) ||
((uint32_t)cmd->cmd_index == (uint32_t)SDMMC_BLOCK_SEND_STATUS) ||
((uint32_t)cmd->response_type_sel == (uint32_t)3U))
{
if (XMC_SDMMC_IsDataLineBusy(obj->sdmmc_sd->sdmmc) != false)
{
status = (uint32_t)SDMMC_BLOCK_MODE_STATUS_DATA_LINE_BUSY;
}
else
{
if (((uint32_t)cmd->dat_present_sel == (uint32_t)1U) || ((uint32_t)cmd->response_type_sel == (uint32_t)3U))
{
/* Update data line state to active */
obj->card_state |= (uint8_t)SDMMC_BLOCK_CARD_STATE_DATA_ACTIVE;
}
}
}
if (status == (uint32_t)SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Update command line state to active */
obj->card_state |= (uint8_t)SDMMC_BLOCK_CARD_STATE_CMD_ACTIVE;
}
}
return status;
}
/* Check response error types in command's arguments category */
static void SDMMC_BLOCK_SD_lCheckArgumentError(const uint32_t *card_status, uint8_t *err)
{
if ((*card_status & (uint32_t)SDMMC_BLOCK_SD_CSR_OUT_OF_RANGE_BITMASK) != (uint32_t)0U)
{
*err = (uint8_t)1U;
XMC_DEBUG("SDMMC_BLOCK_SD_CheckArgumentError: Out of range error");
}
if ((*card_status & (uint32_t)SDMMC_BLOCK_SD_CSR_ADDRESS_ERROR_BITMASK) != (uint32_t)0U)
{
*err = (uint8_t)1U;
XMC_DEBUG("SDMMC_BLOCK_SD_CheckArgumentError: Address error");
}
if ((*card_status & (uint32_t)SDMMC_BLOCK_SD_CSR_BLOCK_LEN_ERROR_BITMASK) != (uint32_t)0U)
{
*err = (uint8_t)1U;
XMC_DEBUG("SDMMC_BLOCK_SD_CheckArgumentError: Block length error");
}
if ((*card_status & (uint32_t)SDMMC_BLOCK_SD_CSR_WP_VIOLATION_BITMASK) != (uint32_t)0U)
{
*err = (uint8_t)1U;
XMC_DEBUG("SDMMC_BLOCK_SD_CheckArgumentError: Write protection violation error");
}
}
/* Checks response error types in erase category */
static void SDMMC_BLOCK_SD_lCheckEraseError(const uint32_t *card_status, uint8_t *err)
{
/* An error in the sequence of erase commands occurred.*/
if ((*card_status & (uint32_t)SDMMC_BLOCK_SD_CSR_ERASE_SEQ_ERROR_BITMASK) != (uint32_t)0)
{
*err = (uint8_t)1U;
XMC_DEBUG("SDMMC_BLOCK_SD_CheckEraseError: Sequential erase error");
}
/* An invalid selection of write-blocks for erase occurred */
if ((*card_status & (uint32_t)SDMMC_BLOCK_SD_CSR_ERASE_PARAM_BITMASK) != (uint32_t)0)
{
*err = (uint8_t)1U;
XMC_DEBUG("SDMMC_BLOCK_SD_CheckEraseError: Parameter erase error");
}
/*
* Set when only partial address space was erased due to existing
* write protected blocks OR the temporary/permanent write protected card
* was erased
*/
if ((*card_status & (uint32_t)SDMMC_BLOCK_SD_CSR_WP_ERASE_SKIP_BITMASK) != (uint32_t)0)
{
*err = (uint8_t)1U;
XMC_DEBUG("SDMMC_BLOCK_SD_CheckEraseError: Write protection erase skip error");
}
}
/* Check response error types in card's internal error category */
static void SDMMC_BLOCK_SD_lCheckCardError(const uint32_t *card_status, uint8_t *err)
{
/* Card internal ECC was applied but failed to correct the data */
if ((*card_status & (uint32_t)SDMMC_BLOCK_SD_CSR_CARD_ECC_FAILED_BITMASK) != (uint32_t)0U)
{
*err = (uint8_t)1U;
XMC_DEBUG("SDMMC_BLOCK_SD_CheckCardError: Card ECC error");
}
/* Internal card controller error */
if ((*card_status & (uint32_t)SDMMC_BLOCK_SD_CSR_CC_ERROR_BITMASK) != (uint32_t)0)
{
*err = (uint8_t)1U;
XMC_DEBUG("SDMMC_BLOCK_SD_CheckCardError: Internal card controller error");
}
/* A general or an unknown error occurred during the operation */
if ((*card_status & (uint32_t)SDMMC_BLOCK_SD_CSR_ERROR_BITMASK) != (uint32_t)0)
{
*err = (uint8_t)1U;
XMC_DEBUG("SDMMC_BLOCK_SD_CheckCardError: Unknown error");
}
}
/* Check for any error in the command's (received) response */
static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_lCheckErrorInResponse(const uint32_t *card_status)
{
SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_SUCCESS;
uint8_t err = (uint8_t)0; /* No error */
/* Check errors in arguments */
SDMMC_BLOCK_SD_lCheckArgumentError(card_status, &err);
/* Check errors specific to erase operation */
SDMMC_BLOCK_SD_lCheckEraseError(card_status, &err);
/* Check errors specific to the card */
SDMMC_BLOCK_SD_lCheckCardError(card_status, &err);
/*
* Set when a sequence or password error has been detected in
* lock/unlock card command
*/
if ((*card_status & (uint32_t)SDMMC_BLOCK_SD_CSR_LOCK_UNLOCK_FAILED_BITMASK) != (uint32_t)0)
{
err = (uint8_t)1;
XMC_DEBUG("SDMMC_BLOCK_SD_CheckErrorInResponse: Lock/unlock error");
}
/*
* Can be one of the following errors:
* 1) The read only section of the CSD does not match the card content
* 2) An attempt to reverse the copy or permanent WP bits was made
*/
if ((*card_status & (uint32_t)SDMMC_BLOCK_SD_CSR_CSD_OVERWRITE_BITMASK) != (uint32_t)0)
{
err = (uint8_t)1;
XMC_DEBUG("SDMMC_BLOCK_SD_CheckErrorInResponse: CSD overwrite error");
}
/* Error in the sequence of the authentication process */
if ((*card_status & (uint32_t)SDMMC_BLOCK_SD_CSR_ASK_SEQ_ERROR_BITMASK) != (uint32_t)0)
{
err = (uint8_t)1;
XMC_DEBUG("SDMMC_BLOCK_SD_CheckErrorInResponse: Authentication sequence error");
}
/* Some SD cards treat CMD55 as an illegal command */
if (err == 1U)
{
status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
}
return status;
}
/* Check for lock status of SD card */
static void SDMMC_BLOCK_SD_lGetCardLockState(SDMMC_BLOCK_t *const obj, uint32_t card_status, uint16_t cmd_index)
{
if (((card_status & (uint32_t)SDMMC_BLOCK_SD_CSR_CARD_IS_LOCKED_BITMASK) != (uint32_t)0) &&
(cmd_index != (uint32_t)SDMMC_BLOCK_SEND_RELATIVE_ADDR))
{
obj->card_state |= (uint8_t)SDMMC_BLOCK_CARD_STATE_LOCKED;
}
else
{
obj->card_state &= (uint8_t)~(uint8_t)SDMMC_BLOCK_CARD_STATE_LOCKED;
}
}
/* Provide transfer delay */
static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_lTransferDelay(SDMMC_BLOCK_t *const obj, uint32_t delay)
{
SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_SUCCESS;
uint32_t timeoutTime;
obj->sdmmc_sd->tmr_expire = (bool)1;
timeoutTime = TimerGet() + (delay / 1000u) + 1u;
do
{
#if (SDMMC_BLOCK_POLLING_MODE > 0U)
/* Poll for interrupt events. */
SDMMC0_0_IRQHandler();
#endif
if (TimerGet() > timeoutTime)
{
status = SDMMC_BLOCK_MODE_STATUS_TIMEOUT_OCCURED;
break;
}
/* Service the watchdog. */
CopService();
} while (obj->sdmmc_sd->isr_context.transfer_flag == (uint8_t)0U);
obj->sdmmc_sd->isr_context.transfer_flag = (uint8_t)0U;
if (obj->sdmmc_sd->transfer_int_err != SDMMC_BLOCK_MODE_STATUS_TRANSFER_COMPLETE)
{
status = (SDMMC_BLOCK_MODE_STATUS_t)obj->sdmmc_sd->data_int_err;
}
return status;
}
/* Read response received for the command issued */
static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_lReadResponse(SDMMC_BLOCK_t *const obj,
const XMC_SDMMC_COMMAND_t *cmd,
XMC_SDMMC_RESPONSE_TYPE_t resp_type,
void *resp)
{
uint32_t *ptr;
uint32_t card_status = 0U;
uint32_t err_status = 0U;
SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_SUCCESS;
/* To mask high byte from response register */
uint32_t resp_high_mask = 0;
/* Check for no-response type commands */
if (((uint16_t)cmd->cmd_index == (uint16_t)SDMMC_BLOCK_GO_IDLE_STATE) ||
((uint16_t)cmd->cmd_index == (uint16_t)SDMMC_BLOCK_GO_INACTIVE_STATE))
{
status = SDMMC_BLOCK_MODE_STATUS_SUCCESS;
}
else
{
ptr = (uint32_t *)resp;
card_status = (uint32_t)obj->sdmmc_sd->sdmmc->RESPONSE[0];
/* Check Lock Status */
SDMMC_BLOCK_SD_lGetCardLockState(obj, card_status, (uint16_t)cmd->cmd_index);
/* Check response type */
switch (resp_type)
{
/* Response R1 */
case XMC_SDMMC_RESPONSE_TYPE_R1:
/* check the error bits in the response */
*ptr = card_status;
status = SDMMC_BLOCK_SD_lCheckErrorInResponse(&card_status);
break;
/* Response R1b */
case XMC_SDMMC_RESPONSE_TYPE_R1b:
*ptr = card_status;
status = SDMMC_BLOCK_SD_lCheckErrorInResponse(&card_status);
if (status != SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Wait for transfer complete interrupt */
status = SDMMC_BLOCK_SD_lTransferDelay(obj, (uint32_t)SDMMC_BLOCK_DELAY_IN_TRANSFER);
if (status != SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
XMC_DEBUG("SDMMC_BLOCK_ReadResponse: For R1b, SDMMC_BLOCK_TransferDelay failed");
}
}
break;
/* Response R2: response register R0-R7 */
case XMC_SDMMC_RESPONSE_TYPE_R2:
*ptr = (uint32_t)((uint32_t)XMC_SDMMC->RESPONSE[0] << 8U); ptr++;
resp_high_mask = (uint32_t)(((uint32_t)XMC_SDMMC->RESPONSE[0] & 0xFF000000) >> 24U);
*ptr = (uint32_t)(((uint32_t)XMC_SDMMC->RESPONSE[1] << 8U) | resp_high_mask); ptr++;
resp_high_mask = (uint32_t)(((uint32_t)XMC_SDMMC->RESPONSE[1] & 0xFF000000) >> 24U);
*ptr = (uint32_t)(((uint32_t)XMC_SDMMC->RESPONSE[2] << 8U) | resp_high_mask);
resp_high_mask = (uint32_t)(((uint32_t)XMC_SDMMC->RESPONSE[2] & 0xFF000000) >> 24U);
*ptr = (uint32_t)(((uint32_t)XMC_SDMMC->RESPONSE[3] << 8U) | resp_high_mask);
break;
/* Responses R3 and R7 */
case XMC_SDMMC_RESPONSE_TYPE_R3:
*ptr = card_status;
break;
case XMC_SDMMC_RESPONSE_TYPE_R7:
*ptr = card_status;
break;
/* Response R6 */
case XMC_SDMMC_RESPONSE_TYPE_R6:
err_status = card_status & (uint32_t)SDMMC_RESPONSE0_RESPONSE0_Msk;
status = SDMMC_BLOCK_SD_lCheckErrorInResponse(&err_status);
/* Read 16-bit RCA received in response R1 register */
*ptr = ((uint32_t)(card_status & (uint32_t)SDMMC_RESPONSE0_RESPONSE1_Msk) >> SDMMC_BLOCK_HC_RESPONSE1_BITPOS);
break;
/* No response */
case XMC_SDMMC_RESPONSE_TYPE_NO_RESPONSE:
status = SDMMC_BLOCK_MODE_STATUS_SUCCESS;
break;
default:
status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
break;
}
}
return status;
}
/* Send command */
static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_lSendCommand(SDMMC_BLOCK_t *const obj,
const XMC_SDMMC_COMMAND_t *cmd,
uint32_t arg,
XMC_SDMMC_RESPONSE_TYPE_t resp_type,
void *resp)
{
SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
uint32_t timeoutTime;
obj->sdmmc_sd->issue_abort = (uint8_t)0U;
obj->sdmmc_sd->cmd_int_err = SDMMC_BLOCK_MODE_STATUS_FAILURE;
obj->sdmmc_sd->data_int_err = SDMMC_BLOCK_MODE_STATUS_FAILURE;
/* Data or command line free? */
status = (SDMMC_BLOCK_MODE_STATUS_t)SDMMC_BLOCK_SD_lCheckDataCommandLines(obj, cmd);
if (!((status == SDMMC_BLOCK_MODE_STATUS_DATA_LINE_BUSY) ||
(status == SDMMC_BLOCK_MODE_STATUS_CMD_LINE_BUSY)))
{
/* Send command */
(void)XMC_SDMMC_SendCommand(obj->sdmmc_sd->sdmmc, cmd, arg);
/* Block until any of the bit in the interrupt status register gets set */
timeoutTime = TimerGet() + (SDMMC_BLOCK_DELAY_IN_COMMAND / 1000u) + 1u;
do
{
#if (SDMMC_BLOCK_POLLING_MODE > 0U)
/* Poll for interrupt events. */
SDMMC0_0_IRQHandler();
#endif
if (TimerGet() > timeoutTime)
{
XMC_DEBUG("SDMMC_BLOCK_SendCommand: Timeout occured");
break;
}
/* Service the watchdog. */
CopService();
} while ((uint8_t)obj->sdmmc_sd->isr_context.cmd_flag == (uint8_t)0U);
obj->sdmmc_sd->isr_context.cmd_flag = (uint8_t)0;
/* Check for possible errors */
if ((SDMMC_BLOCK_MODE_STATUS_t)obj->sdmmc_sd->cmd_int_err == SDMMC_BLOCK_MODE_STATUS_COMMAND_COMPLETE)
{
/* Read response received */
status = SDMMC_BLOCK_SD_lReadResponse(obj, cmd, resp_type, resp);
}
/* For cmd8, check for cmd timeout interrupt */
else if (((SDMMC_BLOCK_MODE_STATUS_t)obj->sdmmc_sd->cmd_int_err == SDMMC_BLOCK_MODE_STATUS_COMMAND_TIMEOUT_ERROR) &&
((uint16_t)cmd->cmd_index == (uint16_t)SDMMC_BLOCK_SD_SEND_IF_COND))
{
status = SDMMC_BLOCK_MODE_STATUS_COMMAND_TIMEOUT_ERROR;
}
else
{
if ((uint16_t)cmd->dat_present_sel == (uint16_t)1)
{
obj->sdmmc_sd->issue_abort = (uint8_t)1;
}
/* Error Recovery for the failed command */
status = SDMMC_BLOCK_SD_lErrorInterruptRecovery(obj);
}
}
return status;
}
/* Set voltage window in the OCR register */
static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_lSetVoltageWindow(SDMMC_BLOCK_t *const obj)
{
SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
uint32_t card_status = 0U;
uint32_t loop_count = 0U;
uint32_t arg = 0U;
if (obj->sdmmc_sd->f8 == (uint8_t)0U)
{
arg = SDMMC_BLOCK_SD_ACMD41_F80_ARG; /* Set HCS=0 for standard cards */
}
else
{
arg = SDMMC_BLOCK_SD_ACMD41_F81_ARG; /* Set HCS=1 for high capacity cards */
}
do
{
/* Send CMD55 for application specific commands (default RCA: 0) */
status = SDMMC_BLOCK_SD_lSendCommand(obj,
&(SDMMC_BLOCK_COMMON_COMMAND(55)),
SDMMC_BLOCK_ARGUMENT0,
XMC_SDMMC_RESPONSE_TYPE_R1,
&card_status);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Send ACMD41 to set card's voltage window */
status = SDMMC_BLOCK_SD_lSendCommand(obj,
&(SDMMC_BLOCK_SD_COMMAND(62)),
arg,
XMC_SDMMC_RESPONSE_TYPE_R3,
&(obj->sdmmc_sd->card_info.ocr));
if ((status != SDMMC_BLOCK_MODE_STATUS_SUCCESS) &&
(status != SDMMC_BLOCK_MODE_STATUS_ILLEGAL_COMMAND_ERROR))
{
break;
}
status = SDMMC_BLOCK_MODE_STATUS_SUCCESS;
/* Card takes some time to set power status bit. Card must respond in a second */
(void)SDMMC_BLOCK_SD_lDelay(obj, (uint32_t)SDMMC_BLOCK_CARD_POWER_DELAY);
}
else
{
loop_count = 100U;
}
} while (((loop_count++) < (uint32_t)50U) &&
(!(((uint32_t)obj->sdmmc_sd->card_info.ocr &
(uint32_t)SDMMC_BLOCK_OCR_POWER_STATUS_BITMASK)!= (uint32_t)0UL)));
return status;
}
/* Query voltage operating condition of the card */
static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_lQueryOperatingCondition(SDMMC_BLOCK_t *const obj)
{
uint32_t resp_data = 0U;
SDMMC_BLOCK_MODE_STATUS_t status;
/* Query voltage operating condition (cmd8) */
status = SDMMC_BLOCK_SD_lSendCommand(obj,
&(SDMMC_BLOCK_SD_COMMAND(8)),
SDMMC_BLOCK_SD_CMD8_ARG,
XMC_SDMMC_RESPONSE_TYPE_R7,
&resp_data);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Check if pattern matches in both the argument and response */
if (((resp_data >> SDMMC_BLOCK_SD_CMD8_CHECK_PATTERN_BITPOS) & SDMMC_BLOCK_SD_CMD8_CHECK_PATTERN_BITMASK) !=
(SDMMC_BLOCK_SD_CMD8_CHECK_PATTERN_VALUE))
{
status = SDMMC_BLOCK_MODE_STATUS_BAD_RESPONSE;
}
/* Check if input voltage accepted by the card in the response */
else if (((uint8_t)(resp_data >> SDMMC_BLOCK_SD_CMD8_VHS_BITPOS) & SDMMC_BLOCK_SD_CMD8_VHS_BITMASK) !=
(SDMMC_BLOCK_SD_VHS_PATTERN_2_7_3_6_VALUE))
{
status = SDMMC_BLOCK_MODE_STATUS_BAD_RESPONSE;
}
else
{
/* Set Flag f8 */
obj->sdmmc_sd->f8 = (uint8_t)1U;
}
}
/* Response received; High capacity cards */
else
{
/* No response is received for Standard Capacity SD cards or MMC card. */
if (obj->sdmmc_sd->cmd_int_err == SDMMC_BLOCK_MODE_STATUS_COMMAND_TIMEOUT_ERROR)
{
obj->sdmmc_sd->f8 = (uint8_t)0U;
status = SDMMC_BLOCK_MODE_STATUS_SUCCESS;
}
}
return status;
}
/* Query voltage supported from the card */
static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_lQueryVoltage(SDMMC_BLOCK_t *const obj, uint32_t arg)
{
uint32_t card_status = 0U;
SDMMC_BLOCK_MODE_STATUS_t status;
/* Send CMD55 for application specific commands with 0 as the default RCA */
status = SDMMC_BLOCK_SD_lSendCommand(obj,
&(SDMMC_BLOCK_COMMON_COMMAND(55)),
arg,
XMC_SDMMC_RESPONSE_TYPE_R1,
&card_status);
if (((obj->sdmmc_sd->f8 == (uint8_t)0U) && (status == SDMMC_BLOCK_MODE_STATUS_ILLEGAL_COMMAND_ERROR)) ||
(status == SDMMC_BLOCK_MODE_STATUS_SUCCESS))
{
/* Send ACMD41 to query the card's voltage window */
status = SDMMC_BLOCK_SD_lSendCommand(obj,
&(SDMMC_BLOCK_SD_COMMAND(62)),
arg,
XMC_SDMMC_RESPONSE_TYPE_R3,
&(obj->sdmmc_sd->card_info.ocr));
if ((status == SDMMC_BLOCK_MODE_STATUS_ILLEGAL_COMMAND_ERROR) ||
(status == SDMMC_BLOCK_MODE_STATUS_SUCCESS))
{
/* Send ACMD41 with voltage window argument set */
status = SDMMC_BLOCK_SD_lSetVoltageWindow(obj);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* SD Card Type */
SDMMC_BLOCK_SD_lWriteCardType(obj);
}
}
}
return status;
}
/* Read card registers after the card initialization */
static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_lAfterCardInitialize(SDMMC_BLOCK_t *const obj)
{
SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
uint8_t card_lock = (obj->card_state & (uint8_t)SDMMC_BLOCK_CARD_STATE_LOCKED);
uint32_t card_status;
/* Read CSD & SCR register & card write protection flags */
status = SDMMC_BLOCK_SD_lReadCardRegisters(obj);
/* Explicitly set block size as 512 */
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
status = SDMMC_BLOCK_SD_lSendCommand(obj,
&(SDMMC_BLOCK_COMMON_COMMAND(16)),
512U,
XMC_SDMMC_RESPONSE_TYPE_R1,
&card_status);
}
if ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) && (card_lock == (uint8_t)0U))
{
#if SDMMC_BLOCK_SD_SUPPORT_4_BUS_WIDTH
/* Switch to 4-bit bus width if supported */
status = SDMMC_BLOCK_SD_lSwitchBusWidth(obj);
if (status != SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Switch to default (1-bit) bus width */
XMC_SDMMC_SetDataTransferWidth(obj->sdmmc_sd->sdmmc, XMC_SDMMC_DATA_LINES_1);
}
/* Switch to high speed mode */
status = SDMMC_BLOCK_SD_lSwitchSpeed(obj);
if (status != SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Switch host controller to normal (default) speed mode */
XMC_SDMMC_DisableHighSpeed(obj->sdmmc_sd->sdmmc);
status = SDMMC_BLOCK_MODE_STATUS_SUCCESS;
}
#endif
}
return status;
}
/* Initialize the SD card */
static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_lInitializeCard(SDMMC_BLOCK_t *const obj)
{
SDMMC_BLOCK_MODE_STATUS_t status;
SDMMC_BLOCK_CARD_LOCK_STATUS_t lock_status;
uint8_t count = (uint8_t)0U;
/* Repeat the below steps 2 times if bad response is received */
do
{
/* Reset the card (CMD0) */
status = SDMMC_BLOCK_SD_lSendCommand(obj,
&(SDMMC_BLOCK_COMMON_COMMAND(0)),
SDMMC_BLOCK_ARGUMENT0,
XMC_SDMMC_RESPONSE_TYPE_NO_RESPONSE,
NULL);
if (status != SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
break;
}
/* Query card's operation condition */
status = SDMMC_BLOCK_SD_lQueryOperatingCondition(obj);
count++;
} while ((count < (uint8_t)SDMMC_BLOCK_NUM_CARD_RESET_RETRIES) &&
(status == SDMMC_BLOCK_MODE_STATUS_BAD_RESPONSE));
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Query and set voltage window */
status = SDMMC_BLOCK_SD_lQueryVoltage(obj, (uint32_t)obj->sdmmc_sd->card_info.rca);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Read CID */
status = SDMMC_BLOCK_SD_lSendCommand(obj,
&(SDMMC_BLOCK_COMMON_COMMAND(2)),
SDMMC_BLOCK_ARGUMENT0,
XMC_SDMMC_RESPONSE_TYPE_R2,
(void *)obj->sdmmc_sd->card_info.cid);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Read RCA */
status = SDMMC_BLOCK_SD_lReadRca(obj);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Check card lock/unlock status */
status = SDMMC_BLOCK_SD_GetLockStatus(obj, &lock_status);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
if (lock_status == SDMMC_BLOCK_CARD_LOCK_STATUS_LOCKED)
{
status = SDMMC_BLOCK_MODE_STATUS_INITIALIZED_BUT_LOCKED;
}
/* Update card initialization status */
obj->card_state &= (uint8_t)~((uint8_t)SDMMC_BLOCK_CARD_STATE_NOT_INITIALIZED |
(uint8_t)SDMMC_BLOCK_CARD_STATE_NO_CARD);
}
}
}
}
}
return status;
}
/* Get card type */
static void SDMMC_BLOCK_SD_lWriteCardType(SDMMC_BLOCK_t *const obj)
{
/* If F8=0; standard capacity v1 card */
if (obj->sdmmc_sd->f8 == (uint8_t)0U)
{
obj->card_type |= (uint8_t)SDMMC_BLOCK_CARD_TYPE_STANDARD_CAPACITY_V1X;
}
/* If F8=1; standard capacity v2 or high capacity card */
else
{
/* Check CCS bit in the OCR register; CCS=1 implies a high capacity card */
if (((uint32_t)obj->sdmmc_sd->card_info.ocr & (uint32_t)SDMMC_BLOCK_OCR_CCS_BITMASK) != (uint32_t)0U)
{
obj->card_type |= (uint8_t)((uint8_t)SDMMC_BLOCK_CARD_TYPE_HIGH_CAPACITY |
(uint8_t)SDMMC_BLOCK_CARD_TYPE_BLOCK_ADDRESSING);
}
else
{
/* CCS=0 implies standard capacity v2 */
obj->card_type |= (uint8_t)SDMMC_BLOCK_CARD_TYPE_STANDARD_CAPACITY_V2;
}
}
}
/* Check write protection status of card */
static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_lGetWriteProtect(SDMMC_BLOCK_t *const obj)
{
uint32_t sd_status[16] = {0U};
uint32_t write_protect;
SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
status = SDMMC_BLOCK_SD_GetSdStatus(obj, (void *)&(sd_status[0]));
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Bits 480:495 in the SD status provides write protection information */
write_protect = ((sd_status[0] & 0xFF000000U) >> 24U) | (((sd_status[0] & 0x00FF0000U) >> 16U) << 8U);
if ((write_protect & SDMMC_BLOCK_SD_CARD_TYPE_BITMASK) != 0U)
{
obj->card_state |= (uint8_t)SDMMC_BLOCK_CARD_STATE_WRITE_PROTECTED;
}
}
return status;
}
/* Reads RCA (relative card address) of the card */
static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_lReadRca(SDMMC_BLOCK_t *const obj)
{
SDMMC_BLOCK_MODE_STATUS_t status;
status = SDMMC_BLOCK_SD_lSendCommand(obj,
&(SDMMC_BLOCK_COMMON_COMMAND(3)),
SDMMC_BLOCK_ARGUMENT0,
XMC_SDMMC_RESPONSE_TYPE_R6,
&(obj->sdmmc_sd->card_info.rca));
return status;
}
/* Read the CSD, SCR and Write protection status of the card */
static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_lReadCardRegisters(SDMMC_BLOCK_t *const obj)
{
uint32_t arg = 0U;
uint32_t card_status = 0U;
SDMMC_BLOCK_MODE_STATUS_t status;
SDMMC_BLOCK_SCR_t scr_content = {0U};
uint8_t card_lock = (obj->card_state & (uint8_t)SDMMC_BLOCK_CARD_STATE_LOCKED);
/* Read CSD Register */
arg |= (uint32_t)((uint32_t)obj->sdmmc_sd->card_info.rca << (uint16_t)SDMMC_BLOCK_ARG_RCA_BITPOS);
status = SDMMC_BLOCK_SD_lSendCommand(obj,
&(SDMMC_BLOCK_COMMON_COMMAND(9)),
arg,
XMC_SDMMC_RESPONSE_TYPE_R2,
(void *)obj->sdmmc_sd->card_info.csd);
if ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) && (card_lock == (uint8_t)0U))
{
/* Set write protection flags */
status = SDMMC_BLOCK_SD_lGetWriteProtect(obj);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Read SCR register for SD card */
if (((uint8_t)obj->card_type & (uint8_t)SDMMC_BLOCK_CARD_TYPE_MMC) == 0U)
{
/* Switch to Transferring State. */
status = SDMMC_BLOCK_SD_lSwitchToTransferState(obj);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Send application specific command CMD55 */
arg |= (uint32_t)((uint32_t)obj->sdmmc_sd->card_info.rca << (uint32_t)SDMMC_BLOCK_ARG_RCA_BITPOS);
status = SDMMC_BLOCK_SD_lSendCommand(obj,
&(SDMMC_BLOCK_COMMON_COMMAND(55)),
arg,
XMC_SDMMC_RESPONSE_TYPE_R1,
&card_status);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Set direction select bit */
XMC_SDMMC_SetDataTransferDirection(obj->sdmmc_sd->sdmmc, XMC_SDMMC_DATA_TRANSFER_CARD_TO_HOST);
/* Read the transferred SCR data */
status = SDMMC_BLOCK_SD_lSingleBlockTransfer(obj,
&(SDMMC_BLOCK_SD_COMMAND(64)),
(uint32_t)SDMMC_BLOCK_ARGUMENT0,
(uint16_t)8U,
(uint32_t *)&scr_content,
SDMMC_BLOCK_SD_DATA_TRANSFER_READ_BUFFER);
obj->sdmmc_sd->card_info.scr = scr_content;
}
}
}
}
}
else
{
status = SDMMC_BLOCK_SD_lSwitchToTransferState(obj);
XMC_SDMMC_SetDataTransferDirection(obj->sdmmc_sd->sdmmc, XMC_SDMMC_DATA_TRANSFER_CARD_TO_HOST);
}
return status;
}
/* Configure the registers for a single block transfer */
static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_lConfigureSingleBlockTransfer(SDMMC_BLOCK_t *const obj,
const XMC_SDMMC_COMMAND_t *cmd,
uint32_t arg,
uint16_t block_size)
{
SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
uint32_t card_status = 0U;
XMC_SDMMC_TRANSFER_MODE_t response;
response.block_size = block_size;
response.type = XMC_SDMMC_TRANSFER_MODE_TYPE_SINGLE;
response.auto_cmd = XMC_SDMMC_TRANSFER_MODE_AUTO_CMD_DISABLED;
XMC_SDMMC_SetDataTransferMode(obj->sdmmc_sd->sdmmc, &response);
status = SDMMC_BLOCK_SD_lSendCommand(obj, cmd, arg, XMC_SDMMC_RESPONSE_TYPE_R1, &card_status);
return status;
}
/* Configure the registers for a multi-block transfer */
static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_lConfigureMultiBlockTransfer(SDMMC_BLOCK_t *const obj,
uint32_t *arg,
uint32_t num_blocks,
const XMC_SDMMC_COMMAND_t *cmd)
{
SDMMC_BLOCK_MODE_STATUS_t status;
uint32_t card_status = 0U;
XMC_SDMMC_TRANSFER_MODE_t response;
/* Block addressing */
if (((uint8_t)obj->card_type & (uint8_t)SDMMC_BLOCK_CARD_TYPE_BLOCK_ADDRESSING) == (uint8_t)0U)
{
*arg *= (uint32_t)512U;
}
response.block_size = SDMMC_BLOCK_TX_BLOCK_SIZE_VALUE;
response.num_blocks = num_blocks;
response.type = XMC_SDMMC_TRANSFER_MODE_TYPE_MULTIPLE;
response.auto_cmd = XMC_SDMMC_TRANSFER_MODE_AUTO_CMD_12;
XMC_SDMMC_SetDataTransferMode(obj->sdmmc_sd->sdmmc, &response);
/* Enable ACMD 12 interrupt signal */
XMC_SDMMC_EnableEvent(obj->sdmmc_sd->sdmmc, (uint32_t)XMC_SDMMC_ACMD_ERR);
/* Send multiple block transfer command */
status = SDMMC_BLOCK_SD_lSendCommand(obj, cmd, *arg, XMC_SDMMC_RESPONSE_TYPE_R1, &card_status);
return status;
}
/* Transfer multiple blocks of data */
static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_lMultiBlockTransfer(SDMMC_BLOCK_t *const obj,
uint32_t *addr,
uint32_t num_blocks,
const XMC_SDMMC_COMMAND_t *cmd,
uint32_t *buf,
SDMMC_BLOCK_SD_DATA_TRANSFER_t transfer_mode)
{
SDMMC_BLOCK_MODE_STATUS_t status;
obj->sdmmc_sd->transfer_int_err = SDMMC_BLOCK_MODE_STATUS_FAILURE;
/* Configure registers for Multi block transfer*/
status = SDMMC_BLOCK_SD_lConfigureMultiBlockTransfer(obj, addr, (uint32_t)num_blocks, cmd);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Read/write block data */
while ((uint32_t)num_blocks > 0U)
{
/* Perform Transfer */
status = SDMMC_BLOCK_SD_lDataTransfer(obj, buf, transfer_mode, SDMMC_BLOCK_NUM_QUADLETS_IN_BLOCK);
if (status != SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
break;
}
/* Decrement number of blocks */
num_blocks--;
/* Pointer pointing to the next block pointer */
buf += (uint32_t)SDMMC_BLOCK_NUM_QUADLETS_IN_BLOCK;
}
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Block on transfer complete interrupt */
/* Timeout: 5ms */
status = SDMMC_BLOCK_SD_lTransferDelay(obj, SDMMC_BLOCK_DELAY_IN_TRANSFER);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Check if transfer happened successfully; Check ACMD status */
if ((SDMMC_BLOCK_MODE_STATUS_t)obj->sdmmc_sd->acmd_int_err == SDMMC_BLOCK_MODE_STATUS_ACMD12_ERROR)
{
/* Call ACMD12 error recovery */
SDMMC_BLOCK_SD_lAcmdErrorRecovery(obj);
}
}
}
}
return status;
}
/* Performs single block transfer */
static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_lSingleBlockTransfer(SDMMC_BLOCK_t *const obj,
const XMC_SDMMC_COMMAND_t *cmd,
uint32_t arg,
uint16_t block_size,
uint32_t *buf,
SDMMC_BLOCK_SD_DATA_TRANSFER_t transfer_mode)
{
SDMMC_BLOCK_MODE_STATUS_t status;
uint32_t timeoutTime;
uint32_t qbytes = (uint32_t)(((((uint32_t)block_size + 3UL) >> 2U) << 2U) >> 2U);
status = SDMMC_BLOCK_SD_lConfigureSingleBlockTransfer(obj, cmd, arg, block_size);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Perform data transfer */
status = SDMMC_BLOCK_SD_lDataTransfer(obj, buf, transfer_mode, qbytes);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Block on transfer complete interrupt */
timeoutTime = TimerGet() + (SDMMC_BLOCK_DELAY_IN_TRANSFER / 1000u) + 1u;
do
{
#if (SDMMC_BLOCK_POLLING_MODE > 0U)
/* Poll for interrupt events. */
SDMMC0_0_IRQHandler();
#endif
if (TimerGet() > timeoutTime)
{
status = SDMMC_BLOCK_MODE_STATUS_TIMEOUT_OCCURED;
break;
}
/* Service the watchdog. */
CopService();
} while ((uint8_t)obj->sdmmc_sd->isr_context.transfer_flag == (uint8_t)0U);
obj->sdmmc_sd->isr_context.transfer_flag = (uint8_t)0U;
/* Check transfer complete status */
if ((SDMMC_BLOCK_MODE_STATUS_t)obj->sdmmc_sd->transfer_int_err == SDMMC_BLOCK_MODE_STATUS_TRANSFER_COMPLETE)
{
status = SDMMC_BLOCK_MODE_STATUS_SUCCESS;
}
else
{
obj->sdmmc_sd->issue_abort = (uint8_t)1U;
status = SDMMC_BLOCK_SD_lErrorInterruptRecovery(obj);
}
}
}
return status;
}
/* Check lock status */
static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_lCheckLockStatus(SDMMC_BLOCK_t *const obj,
SDMMC_BLOCK_CARD_LOCK_STATUS_t mode)
{
SDMMC_BLOCK_MODE_STATUS_t status;
SDMMC_BLOCK_CARD_LOCK_STATUS_t lock_status;
status = SDMMC_BLOCK_SD_GetLockStatus(obj, &lock_status);
/* For lock, card state must be "locked" */
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
if ((lock_status == SDMMC_BLOCK_CARD_LOCK_STATUS_LOCKED) && (mode == SDMMC_BLOCK_CARD_LOCK_STATUS_LOCKED))
{
status = SDMMC_BLOCK_MODE_STATUS_SUCCESS;
}
/* For unlock, card state must be "unlocked" */
else if ((lock_status == SDMMC_BLOCK_CARD_LOCK_STATUS_UNLOCKED) && (mode == SDMMC_BLOCK_CARD_LOCK_STATUS_UNLOCKED))
{
status = SDMMC_BLOCK_MODE_STATUS_SUCCESS;
}
else
{
status = SDMMC_BLOCK_MODE_STATUS_LOCK_UNLOCK_ERROR;
}
}
return status;
}
#if SDMMC_BLOCK_SD_SUPPORT_4_BUS_WIDTH
/* Switch bus width to 4-bit if supported */
static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_lSwitchBusWidth(SDMMC_BLOCK_t *const obj)
{
uint32_t arg = 0U;
SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
uint32_t card_status = 0U;
/* Switch to transfer state (CMD7) */
status = SDMMC_BLOCK_SD_lSwitchToTransferState(obj);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Disable card insertion interrupt */
XMC_SDMMC_DisableEvent(obj->sdmmc_sd->sdmmc, (uint32_t)XMC_SDMMC_CARD_INS);
/* Check data transfer width supported in SCR register */
if ((obj->sdmmc_sd->card_info.scr.sd_bus_width & SDMMC_BLOCK_SCR_BUS_WIDTH4_BITMASK))
{
/* Set the argument */
arg |= ((uint32_t)obj->sdmmc_sd->card_info.rca << (uint32_t)SDMMC_BLOCK_ARG_RCA_BITPOS);
/* Send application specific command */
status = SDMMC_BLOCK_SD_lSendCommand(obj,
&(SDMMC_BLOCK_COMMON_COMMAND(55)),
arg,
XMC_SDMMC_RESPONSE_TYPE_R1,
&card_status);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Send ACMD6 to switch the bus width */
status = SDMMC_BLOCK_SD_lSendCommand(obj,
&(SDMMC_BLOCK_SD_COMMAND(58)),
SDMMC_BLOCK_SD_4BUS_WIDTH_ARG,
XMC_SDMMC_RESPONSE_TYPE_R1,
&card_status);
}
}
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Set data transfer width */
XMC_SDMMC_SetDataTransferWidth(obj->sdmmc_sd->sdmmc, XMC_SDMMC_DATA_LINES_4);
}
}
return status;
}
/* Switch the card speed mode to high speed if supported */
static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_lSwitchSpeed(SDMMC_BLOCK_t *const obj)
{
uint32_t switch_status[16] = {0U};
SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
/* Check CMD6 support in SCR register */
if (obj->sdmmc_sd->card_info.scr.sd_spec != 0UL)
{
/* Switch to transfer state (CMD7) */
status = SDMMC_BLOCK_SD_lSwitchToTransferState(obj);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/*
* Send the Switch function command and read the transferred block of
* data from the card
*/
status = SDMMC_BLOCK_SD_lSingleBlockTransfer(obj,
&(SDMMC_BLOCK_SD_COMMAND(6)),
SDMMC_BLOCK_SD_HIGH_SPEED_ARG,
64U,
(uint32_t *)switch_status,
SDMMC_BLOCK_SD_DATA_TRANSFER_READ_BUFFER);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
if (((switch_status[4] & (uint32_t)SDMMC_BLOCK_SWITCH_FUNC_GRP1_STATUS_BITMASK) >>
(uint32_t)SDMMC_BLOCK_SWITCH_FUNC_GRP1_STATUS_BITPOS) != (uint32_t)1U)
{
status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
}
}
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Change speed mode (high speed) in the host controller */
XMC_SDMMC_EnableHighSpeed(obj->sdmmc_sd->sdmmc);
}
}
}
return status;
}
#endif
/* Provides delay in command execution */
static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_lCommandDelay(SDMMC_BLOCK_t *const obj, uint32_t delay)
{
SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_SUCCESS;
uint32_t timeoutTime;
obj->sdmmc_sd->tmr_expire = (bool)1U;
timeoutTime = TimerGet() + (delay / 1000u) + 1u;
do
{
#if (SDMMC_BLOCK_POLLING_MODE > 0U)
/* Poll for interrupt events. */
SDMMC0_0_IRQHandler();
#endif
if (TimerGet() > timeoutTime)
{
status = SDMMC_BLOCK_MODE_STATUS_TIMEOUT_OCCURED;
break;
}
/* Service the watchdog. */
CopService();
} while ((!((obj->sdmmc_sd->isr_context.cmd_flag == 1U) ||
(obj->sdmmc_sd->isr_context.data_flag == 1U))) &&
((XMC_SDMMC_GetEvent(obj->sdmmc_sd->sdmmc, XMC_SDMMC_CARD_ERR) != 0U)));
obj->sdmmc_sd->isr_context.cmd_flag = (uint8_t)0U;
obj->sdmmc_sd->isr_context.data_flag = (uint8_t)0U;
return status;
}
/* Recovery task for error interrupts */
static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_lErrorInterruptRecovery(SDMMC_BLOCK_t *const obj)
{
XMC_SDMMC_COMMAND_t *cmd = (XMC_SDMMC_COMMAND_t *)&(SDMMC_BLOCK_COMMON_COMMAND(12));
SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_NONRECOVERABLE_ERROR;
uint32_t normal_events = 0U;
uint32_t error_events = 0U;
error_events = ((uint32_t)XMC_SDMMC_CMD_TIMEOUT_ERR) |
((uint32_t)XMC_SDMMC_CMD_CRC_ERR) |
((uint32_t)XMC_SDMMC_CMD_END_BIT_ERR) |
((uint32_t)XMC_SDMMC_CMD_IND_ERR) |
((uint32_t)XMC_SDMMC_DATA_TIMEOUT_ERR) |
((uint32_t)XMC_SDMMC_DATA_CRC_ERR) |
((uint32_t)XMC_SDMMC_DATA_END_BIT_ERR) |
((uint32_t)XMC_SDMMC_CURRENT_LIMIT_ERR) |
((uint32_t)XMC_SDMMC_TARGET_RESP_ERR);
/* Disable all error events */
XMC_SDMMC_DisableEvent(obj->sdmmc_sd->sdmmc, error_events);
/* Check error interrupt status bits D0-D3 for CMD line errors */
if ((((uint32_t)obj->sdmmc_sd->isr_context.int_status_shadow &
(uint32_t)SDMMC_BLOCK_ERROR_CMD_STATUS_BITMASK) != (uint32_t)0U) ||
(XMC_SDMMC_IsCommandLineBusy(obj->sdmmc_sd->sdmmc) == true))
{
/* Set software reset for CMD line */
status = SDMMC_BLOCK_SD_lReset(obj, (uint32_t)XMC_SDMMC_SW_RST_CMD_LINE);
}
/* Check error interrupt status bits D4-D6 for data line errors */
if ((((uint32_t)obj->sdmmc_sd->isr_context.int_status_shadow &
(uint32_t)SDMMC_BLOCK_ERROR_DATA_STATUS_BITMASK) != (uint32_t)0U) ||
(XMC_SDMMC_IsDataLineBusy(obj->sdmmc_sd->sdmmc) == true))
{
/* Set software reset for data line */
status = SDMMC_BLOCK_SD_lReset(obj, (uint32_t)XMC_SDMMC_SW_RST_DAT_LINE);
}
error_events = ((uint32_t)XMC_SDMMC_CMD_TIMEOUT_ERR) |
((uint32_t)XMC_SDMMC_CMD_CRC_ERR) |
((uint32_t)XMC_SDMMC_CMD_END_BIT_ERR) |
((uint32_t)XMC_SDMMC_CMD_IND_ERR) |
((uint32_t)XMC_SDMMC_DATA_TIMEOUT_ERR) |
((uint32_t)XMC_SDMMC_DATA_CRC_ERR) |
((uint32_t)XMC_SDMMC_DATA_END_BIT_ERR) |
((uint32_t)XMC_SDMMC_CURRENT_LIMIT_ERR) |
((uint32_t)XMC_SDMMC_CARD_ERR);
XMC_SDMMC_ClearEvent(obj->sdmmc_sd->sdmmc, error_events);
if (obj->sdmmc_sd->issue_abort == (uint8_t)1U)
{
/* Issue abort command. Set argument register */
(void)XMC_SDMMC_SendCommand(obj->sdmmc_sd->sdmmc, cmd, SDMMC_BLOCK_ARGUMENT0);
/* Wait for any interrupt status bit to be set */
/* Timeout of 5ms */
status = SDMMC_BLOCK_SD_lCommandDelay(obj, (uint32_t)SDMMC_BLOCK_DELAY_IN_COMMAND);
if ((SDMMC_BLOCK_MODE_STATUS_t)status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* If error status bit is set in the status register */
if (XMC_SDMMC_IsAnyErrorEvent(obj->sdmmc_sd->sdmmc) == true)
{
status = SDMMC_BLOCK_MODE_STATUS_NONRECOVERABLE_ERROR;
XMC_SDMMC_ClearEvent(obj->sdmmc_sd->sdmmc, normal_events);
XMC_SDMMC_ClearEvent(obj->sdmmc_sd->sdmmc, error_events);
/* Set software reset for CMD line and data line */
(void)SDMMC_BLOCK_SD_lReset(obj, (uint32_t)((uint32_t)XMC_SDMMC_SW_RST_CMD_LINE |
(uint32_t)XMC_SDMMC_SW_RST_DAT_LINE));
}
}
/* Check Data lines status in present status register */
if (XMC_SDMMC_IsAnyErrorEvent(obj->sdmmc_sd->sdmmc) == false)
{
if (XMC_SDMMC_IsAllDataLinesHigh(obj->sdmmc_sd->sdmmc) == true)
{
status = SDMMC_BLOCK_MODE_STATUS_RECOVERABLE_ERROR;
}
else
{
status = SDMMC_BLOCK_MODE_STATUS_NONRECOVERABLE_ERROR;
}
}
}
else
{
if (XMC_SDMMC_IsAnyErrorEvent(obj->sdmmc_sd->sdmmc) == false)
{
if (XMC_SDMMC_IsAllDataLinesHigh(obj->sdmmc_sd->sdmmc) == true)
{
status = SDMMC_BLOCK_MODE_STATUS_RECOVERABLE_ERROR;
}
else
{
status = SDMMC_BLOCK_MODE_STATUS_NONRECOVERABLE_ERROR;
}
}
}
/* Enable the error interrupt signal */
error_events |= (uint32_t)XMC_SDMMC_TARGET_RESP_ERR;
XMC_SDMMC_EnableEvent(obj->sdmmc_sd->sdmmc, error_events);
/* Global error recovery variable */
obj->sdmmc_sd->err_recovery_stat = status;
return status;
}
/* Handles interrupts in normal interrupt status register */
SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_NormalInterruptHandler(SDMMC_BLOCK_t *const obj, uint16_t int_status)
{
SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_SUCCESS;
#if SDMMC_BLOCK_SD_CARD_DETECTION_SUPPORT
bool pstate;
/* Card removal interrupt */
if ((int_status & (uint32_t)XMC_SDMMC_CARD_REMOVAL) != 0U)
{
obj->sdmmc_sd->card_detect_state |= ((uint32_t)1U << SDMMC_BLOCK_SD_INTERRUPT_CARD_REMOVAL);
/* Clear the interrupt status bit */
XMC_SDMMC_ClearEvent(obj->sdmmc_sd->sdmmc, (uint32_t)XMC_SDMMC_CARD_REMOVAL);
}
/* Card insertion interrupt */
if ((int_status & (uint32_t)XMC_SDMMC_CARD_INS) != 0U)
{
obj->sdmmc_sd->card_detect_state |= ((uint32_t)1U << SDMMC_BLOCK_SD_INTERRUPT_CARD_INSERTION);
/* Clear the interrupt status bit */
XMC_SDMMC_ClearEvent(obj->sdmmc_sd->sdmmc, (uint32_t)XMC_SDMMC_CARD_INS);
}
/* Invoke a callback function if a user has registered one */
if ((obj->sdmmc_sd->callback != NULL) && (obj->sdmmc_sd->card_detect_state != 0U))
{
obj->sdmmc_sd->card_detect_state = 0U;
pstate = (bool)(SDMMC_BLOCK_0.sdmmc_sd->sdmmc->PRESENT_STATE & SDMMC_PRESENT_STATE_CARD_INSERTED_Msk);
obj->sdmmc_sd->callback((SDMMC_BLOCK_SD_INTERRUPT_t)pstate);
}
else
{
status = SDMMC_BLOCK_MODE_STATUS_NULL_POINTER;
}
#endif
/* Buffer read ready interrupt */
if (((uint32_t)int_status & (uint32_t)XMC_SDMMC_BUFFER_READ_READY) != (uint32_t)0)
{
obj->sdmmc_sd->data_int_err = SDMMC_BLOCK_MODE_STATUS_BUFFER_READY;
XMC_SDMMC_ClearEvent(obj->sdmmc_sd->sdmmc, (uint32_t)XMC_SDMMC_BUFFER_READ_READY);
obj->sdmmc_sd->isr_context.data_flag = (uint8_t)1U;
}
/* Buffer write ready interrupt */
if (((uint32_t)int_status & (uint32_t)XMC_SDMMC_BUFFER_WRITE_READY) != (uint32_t)0)
{
obj->sdmmc_sd->data_int_err = SDMMC_BLOCK_MODE_STATUS_BUFFER_READY;
XMC_SDMMC_ClearEvent(obj->sdmmc_sd->sdmmc, (uint32_t)XMC_SDMMC_BUFFER_WRITE_READY);
obj->sdmmc_sd->isr_context.data_flag = (uint8_t)1U;
}
/* Transfer complete interrupt */
if (((uint32_t)int_status & (uint32_t)XMC_SDMMC_TX_COMPLETE) != (uint32_t)0)
{
obj->sdmmc_sd->transfer_int_err = SDMMC_BLOCK_MODE_STATUS_TRANSFER_COMPLETE;
XMC_SDMMC_ClearEvent(obj->sdmmc_sd->sdmmc, (uint32_t)XMC_SDMMC_TX_COMPLETE);
obj->card_state &= (uint8_t)~(uint8_t)SDMMC_BLOCK_CARD_STATE_DATA_ACTIVE;
obj->sdmmc_sd->isr_context.transfer_flag = (uint8_t)1U;
}
/* Command complete interrupt */
if (((uint32_t)int_status & (uint32_t)XMC_SDMMC_CMD_COMPLETE) != (uint32_t)0)
{
obj->sdmmc_sd->cmd_int_err = SDMMC_BLOCK_MODE_STATUS_COMMAND_COMPLETE;
XMC_SDMMC_ClearEvent(obj->sdmmc_sd->sdmmc, (uint32_t)XMC_SDMMC_CMD_COMPLETE);
obj->card_state &= (uint8_t)~(uint8_t)SDMMC_BLOCK_CARD_STATE_CMD_ACTIVE;
obj->sdmmc_sd->isr_context.cmd_flag = (uint8_t)1;
}
return status;
}
/* Handles interrupt in error interrupt status register */
SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_ErrorInterruptHandler(SDMMC_BLOCK_t *const obj,
uint16_t int_status)
{
SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
obj->sdmmc_sd->isr_context.int_status_shadow = int_status;
/* Command timeout error interrupt */
if (((uint32_t)int_status & ((uint32_t)XMC_SDMMC_CMD_TIMEOUT_ERR >> 16U)) != (uint32_t)0)
{
obj->sdmmc_sd->cmd_int_err = SDMMC_BLOCK_MODE_STATUS_COMMAND_TIMEOUT_ERROR;
obj->card_state &= (uint8_t)~(uint8_t)SDMMC_BLOCK_CARD_STATE_CMD_ACTIVE;
XMC_SDMMC_ClearEvent(obj->sdmmc_sd->sdmmc, (uint32_t)XMC_SDMMC_CMD_TIMEOUT_ERR);
obj->sdmmc_sd->isr_context.cmd_flag = 1U;
}
/* Command CRC error interrupt */
if (((uint32_t)int_status & ((uint32_t)XMC_SDMMC_CMD_CRC_ERR >> 16U)) != (uint32_t)0)
{
obj->sdmmc_sd->cmd_int_err = SDMMC_BLOCK_MODE_STATUS_COMMAND_CRC_ERROR;
obj->card_state &= (uint8_t)~(uint8_t)SDMMC_BLOCK_CARD_STATE_CMD_ACTIVE;
XMC_SDMMC_ClearEvent(obj->sdmmc_sd->sdmmc, (uint32_t)XMC_SDMMC_CMD_CRC_ERR);
obj->sdmmc_sd->isr_context.cmd_flag = 1U;
}
/* Command end bit error interrupt */
if (((uint32_t)int_status & ((uint32_t)XMC_SDMMC_CMD_END_BIT_ERR >> 16U)) != (uint32_t)0)
{
obj->sdmmc_sd->cmd_int_err = SDMMC_BLOCK_MODE_STATUS_COMMAND_ENDBIT_ERROR;
obj->card_state &= (uint8_t)~(uint8_t)SDMMC_BLOCK_CARD_STATE_CMD_ACTIVE;
XMC_SDMMC_ClearEvent(obj->sdmmc_sd->sdmmc, (uint32_t)XMC_SDMMC_CMD_END_BIT_ERR);
obj->sdmmc_sd->isr_context.cmd_flag = 1U;
}
/* Command index error interrupt */
if (((uint32_t)int_status & ((uint32_t)XMC_SDMMC_CMD_IND_ERR >> 16U)) != (uint32_t)0)
{
obj->sdmmc_sd->cmd_int_err = SDMMC_BLOCK_MODE_STATUS_COMMAND_INDEX_ERROR;
obj->card_state &= (uint8_t)~(uint8_t)SDMMC_BLOCK_CARD_STATE_CMD_ACTIVE;
XMC_SDMMC_ClearEvent(obj->sdmmc_sd->sdmmc, (uint32_t)XMC_SDMMC_CMD_IND_ERR);
obj->sdmmc_sd->isr_context.cmd_flag = 1U;
}
/* Data timeout error interrupt */
if (((uint32_t)int_status & ((uint32_t)XMC_SDMMC_DATA_TIMEOUT_ERR >> 16U)) != (uint32_t)0)
{
obj->sdmmc_sd->data_int_err = SDMMC_BLOCK_MODE_STATUS_DATA_TIMEOUT_ERROR;
obj->card_state &= (uint8_t)~(uint8_t)SDMMC_BLOCK_CARD_STATE_DATA_ACTIVE;
XMC_SDMMC_ClearEvent(obj->sdmmc_sd->sdmmc, (uint32_t)XMC_SDMMC_DATA_TIMEOUT_ERR);
obj->sdmmc_sd->isr_context.data_flag = 1U;
}
/* Data CRC error interrupt */
if (((uint32_t)int_status & ((uint32_t)XMC_SDMMC_DATA_CRC_ERR >> 16U)) != (uint32_t)0)
{
obj->sdmmc_sd->data_int_err = SDMMC_BLOCK_MODE_STATUS_DATA_CRC_ERROR;
obj->card_state &= (uint8_t)~(uint8_t)SDMMC_BLOCK_CARD_STATE_DATA_ACTIVE;
XMC_SDMMC_ClearEvent(obj->sdmmc_sd->sdmmc, (uint32_t)XMC_SDMMC_DATA_CRC_ERR);
obj->sdmmc_sd->isr_context.data_flag = 1U;
}
/* Data end bit error interrupt */
if (((uint32_t)int_status & ((uint32_t)XMC_SDMMC_DATA_END_BIT_ERR >> 16U)) != (uint32_t)0)
{
obj->sdmmc_sd->data_int_err = SDMMC_BLOCK_MODE_STATUS_DATA_ENDBIT_ERROR;
obj->card_state &= (uint8_t)~(uint8_t)SDMMC_BLOCK_CARD_STATE_DATA_ACTIVE;
XMC_SDMMC_ClearEvent(obj->sdmmc_sd->sdmmc, (uint32_t)XMC_SDMMC_DATA_END_BIT_ERR);
obj->sdmmc_sd->isr_context.data_flag = 1U;
}
/* ACMD12 error interrupt */
if (((uint32_t)int_status & ((uint32_t)XMC_SDMMC_ACMD_ERR >> 16U)) != (uint32_t)0)
{
obj->sdmmc_sd->acmd_int_err = SDMMC_BLOCK_MODE_STATUS_ACMD12_ERROR;
obj->card_state &= (uint8_t)~(uint8_t)SDMMC_BLOCK_CARD_STATE_CMD_ACTIVE;
obj->card_state &= (uint8_t)~(uint8_t)SDMMC_BLOCK_CARD_STATE_DATA_ACTIVE;
XMC_SDMMC_ClearEvent(obj->sdmmc_sd->sdmmc, (uint32_t)XMC_SDMMC_ACMD_ERR);
obj->sdmmc_sd->isr_context.cmd_flag = 1U;
}
return status;
}
/* Switch the card state to transferring state if it isn't */
static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_lSwitchToTransferState(SDMMC_BLOCK_t *const obj)
{
SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
uint32_t arg = 0UL;
uint32_t card_status = 0U;
/* Check the current state of the card */
arg |= (uint32_t)((uint32_t)obj->sdmmc_sd->card_info.rca << (uint32_t)SDMMC_BLOCK_ARG_RCA_BITPOS);
/* Send CMD13 to read card status */
status = SDMMC_BLOCK_SD_lSendCommand(obj,
&(SDMMC_BLOCK_COMMON_COMMAND(13)),
arg,
XMC_SDMMC_RESPONSE_TYPE_R1,
&card_status);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Check if it is in transferring state */
if (((card_status & SDMMC_BLOCK_SD_CSR_CURRENT_STATE_BITMASK) >> SDMMC_BLOCK_SD_CSR_CURRENT_STATE_BITPOS) ==
SDMMC_BLOCK_SD_CSR_CURRENT_STATE_TRANS_VALUE)
{
status = SDMMC_BLOCK_MODE_STATUS_SUCCESS;
}
else
{
/* Switch to transfer state (CMD7) */
status = SDMMC_BLOCK_SD_lSendCommand(obj,
&(SDMMC_BLOCK_COMMON_COMMAND(7)),
arg,
XMC_SDMMC_RESPONSE_TYPE_R1b,
&card_status);
}
}
return status;
}
/* Do data transfer to OR from card */
static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_lDataTransfer(SDMMC_BLOCK_t *const obj,
uint32_t *buf,
SDMMC_BLOCK_SD_DATA_TRANSFER_t transfer_mode,
uint32_t quad_bytes)
{
SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
uint32_t timeoutTime;
uint32_t count = 0U;
/* Block on buffer read/write ready interrupt */
timeoutTime = TimerGet() + (SDMMC_BLOCK_RESET_IN_DATA_TRANSFER / 1000u) + 1u;
do
{
#if (SDMMC_BLOCK_POLLING_MODE > 0U)
/* Poll for interrupt events. */
SDMMC0_0_IRQHandler();
#endif
if (TimerGet() > timeoutTime)
{
status = SDMMC_BLOCK_MODE_STATUS_TIMEOUT_OCCURED;
break;
}
/* Service the watchdog. */
CopService();
} while (obj->sdmmc_sd->isr_context.data_flag == 0U);
obj->sdmmc_sd->isr_context.data_flag = (uint8_t)0U;
/* Check if buffer is ready */
if (obj->sdmmc_sd->data_int_err == SDMMC_BLOCK_MODE_STATUS_BUFFER_READY)
{
/* 4 bytes data transmission in each iteration */
for (count = 0U; count < quad_bytes; count++)
{
if (transfer_mode == SDMMC_BLOCK_SD_DATA_TRANSFER_READ_BUFFER)
{
*buf = (uint32_t)XMC_SDMMC_ReadFIFO(obj->sdmmc_sd->sdmmc);
}
if (transfer_mode == SDMMC_BLOCK_SD_DATA_TRANSFER_WRITE_BUFFER)
{
XMC_SDMMC_WriteFIFO(obj->sdmmc_sd->sdmmc, buf);
}
buf++;
}
status = SDMMC_BLOCK_MODE_STATUS_SUCCESS;
}
else
{
obj->sdmmc_sd->issue_abort = (uint8_t)1U;
status = SDMMC_BLOCK_SD_lErrorInterruptRecovery(obj);
}
return status;
}
/* Performs the ACMD error recovery */
static void SDMMC_BLOCK_SD_lAcmdErrorRecovery(SDMMC_BLOCK_t *const obj)
{
SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_SUCCESS;
uint32_t pcmd_flag = 0U;
uint32_t card_status = 0U;
/* Check ACMD12 "Not executed err" in Auto CMD12 error status register */
if (XMC_SDMMC_GetACMDErrStatus(obj->sdmmc_sd->sdmmc, XMC_SDMMC_ACMD12_NOT_EXEC_ERR) == true)
{
pcmd_flag = 1U;
/* Check Return Status of Recovery function of CMD_wo_DAT command */
if (obj->sdmmc_sd->err_recovery_stat == SDMMC_BLOCK_MODE_STATUS_RECOVERABLE_ERROR)
{
/* For recoverable error, issue CMD12 */
status = SDMMC_BLOCK_SD_lSendCommand(obj,
&(SDMMC_BLOCK_COMMON_COMMAND(12)),
SDMMC_BLOCK_ARGUMENT0,
XMC_SDMMC_RESPONSE_TYPE_R1,
&card_status);
}
if ((status != SDMMC_BLOCK_MODE_STATUS_SUCCESS) && (status != SDMMC_BLOCK_MODE_STATUS_NONRECOVERABLE_ERROR))
{
/* Set software reset for data line */
status = SDMMC_BLOCK_SD_lReset(obj, (uint32_t)XMC_SDMMC_SW_RST_DAT_LINE);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Check for XMC_SDMMC_CMD_NOT_ISSUED_BY_ACMD12_ERR */
if (XMC_SDMMC_GetACMDErrStatus(obj->sdmmc_sd->sdmmc, XMC_SDMMC_CMD_NOT_ISSUED_BY_ACMD12_ERR) == true)
{
XMC_DEBUG("SDMMC_BLOCK_ACMDErrorRecovery: SDMMC_BLOCK_ACMD_CMD_wo_DAT_NOT_ISSUED");
}
else
{
/*
* Check pcmd_flag. If 1, an error occurred in CMD_wo_DAT,
* and also in the SD memory transfer
*/
if (pcmd_flag == 1U)
{
XMC_DEBUG("SDMMC_BLOCK_CheckPCMDFlag: ACMD both error");
}
else
{
XMC_DEBUG("SDMMC_BLOCK_CheckPCMDFlag: ACMD SD transfer error");
}
}
}
}
}
else
{
/* Set software reset for CMD line */
status = SDMMC_BLOCK_SD_lReset(obj, (uint32_t)XMC_SDMMC_SW_RST_CMD_LINE);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Issue CMD12 */
status = SDMMC_BLOCK_SD_lSendCommand(obj,
&(SDMMC_BLOCK_COMMON_COMMAND(12)),
SDMMC_BLOCK_ARGUMENT0,
XMC_SDMMC_RESPONSE_TYPE_R1,
&card_status);
if (status != SDMMC_BLOCK_MODE_STATUS_NONRECOVERABLE_ERROR)
{
/*Set Software Reset for Data line*/
status = SDMMC_BLOCK_SD_lReset(obj, (uint32_t)XMC_SDMMC_SW_RST_DAT_LINE);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Check XMC_SDMMC_CMD_NOT_ISSUED_BY_ACMD12_ERR */
if (XMC_SDMMC_GetACMDErrStatus(obj->sdmmc_sd->sdmmc, XMC_SDMMC_CMD_NOT_ISSUED_BY_ACMD12_ERR) == true)
{
XMC_DEBUG("SDMMC_BLOCK_ACMDErrorRecovery: SDMMC_BLOCK_ACMD_CMD_wo_DAT_NOT_ISSUED");
}
else
{
/*
* Check PCMD flag. If 1, an error occurred in CMD_wo_DAT,
* and also in the SD memory transfer
*/
if (pcmd_flag == 1U)
{
XMC_DEBUG("SDMMC_BLOCK_CheckPCMDFlag: ACMD both error");
}
else
{
XMC_DEBUG("SDMMC_BLOCK_CheckPCMDFlag: ACMD SD transfer error");
}
}
}
}
}
}
}
/* Delay function */
static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_lDelay(SDMMC_BLOCK_t *const obj, uint32_t delay)
{
uint32_t timeoutTime;
SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_CREATE_TIMER_FAILED;
/* Set timeout time. */
timeoutTime = TimerGet() + (delay / 1000u) + 1u;
/* Wait for the timer to expire. */
while (TimerGet() < timeoutTime)
{
/* Service the watchdog. */
CopService();
}
/* Update the status. */
status = SDMMC_BLOCK_MODE_STATUS_SUCCESS;
/* Return the status. */
return status;
}
/*
* Perform host controller initialization and card initialization.
* Also, reading card registers
*/
SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_CardIdentificationProcess(SDMMC_BLOCK_t *const obj)
{
SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
uint32_t timeoutTime;
/* Wait until the internal clock is stable */
timeoutTime = TimerGet() + (SDMMC_BLOCK_CLOCK_STABLE_DELAY / 1000u) + 1u;
do
{
if (TimerGet() > timeoutTime)
{
status = SDMMC_BLOCK_MODE_STATUS_TIMEOUT_OCCURED;
break;
}
/* Service the watchdog. */
CopService();
} while ((XMC_SDMMC_GetClockStability(obj->sdmmc_sd->sdmmc) == false));
if (status != SDMMC_BLOCK_MODE_STATUS_TIMEOUT_OCCURED)
{
/* Enable the SD clock */
XMC_SDMMC_SDClockEnable(obj->sdmmc_sd->sdmmc);
/* Turn the bus power on */
XMC_SDMMC_BusPowerOn(obj->sdmmc_sd->sdmmc);
if (obj->sdmmc_sd->mode_init_flag == false)
{
status = SDMMC_BLOCK_SD_lInitializeCard(obj);
if ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) ||
(status == SDMMC_BLOCK_MODE_STATUS_INITIALIZED_BUT_LOCKED))
{
status = SDMMC_BLOCK_SD_lAfterCardInitialize(obj);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
obj->sdmmc_sd->mode_init_flag = 1U;
}
}
}
}
return status;
}
/* Check if the sector address is out of bound */
static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_lCheckSectorBound(SDMMC_BLOCK_t *const obj,
uint32_t sector_num,
uint32_t sector_count)
{
SDMMC_BLOCK_MODE_STATUS_t status;
uint32_t local_sector_count = 0U;
/* Get sector count function */
status = SDMMC_BLOCK_SD_GetSectorCount(obj, (void *)&local_sector_count);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Check the sector count limit */
if ((sector_num + sector_count) > local_sector_count)
{
status = SDMMC_BLOCK_MODE_STATUS_SECTOR_OUT_OF_BOUND;
}
}
return status;
}
/* Perform erase operation */
static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_lLocalErase(SDMMC_BLOCK_t *const obj,
uint32_t start_addr,
uint32_t end_addr,
uint32_t timeout)
{
/* Stores the response received */
uint32_t card_status = 0U;
uint32_t timeoutTime;
SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
if (((uint32_t)obj->card_type & (uint32_t)SDMMC_BLOCK_CARD_TYPE_BLOCK_ADDRESSING) == (uint32_t)0U)
{
start_addr *= (uint32_t)512U;
end_addr *= (uint32_t)512U;
}
/* SD erase start command */
status = SDMMC_BLOCK_SD_lSendCommand(obj,
&(SDMMC_BLOCK_SD_COMMAND(32)),
start_addr,
XMC_SDMMC_RESPONSE_TYPE_R1,
&card_status);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* SD Erase End Command */
status = SDMMC_BLOCK_SD_lSendCommand(obj,
&(SDMMC_BLOCK_SD_COMMAND(33)),
end_addr,
XMC_SDMMC_RESPONSE_TYPE_R1,
&card_status);
}
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
status = SDMMC_BLOCK_SD_lSendCommand(obj,
&(SDMMC_BLOCK_SD_COMMAND(38)),
SDMMC_BLOCK_ARGUMENT0,
XMC_SDMMC_RESPONSE_TYPE_R1b,
&card_status);
timeoutTime = TimerGet() + ((timeout * (uint32_t)1000U)) + 1u;
do
{
if (TimerGet() > timeoutTime)
{
status = SDMMC_BLOCK_MODE_STATUS_TIMEOUT_OCCURED;
break;
}
/* Service the watchdog. */
CopService();
} while ((XMC_SDMMC_IsDataLineBusy(obj->sdmmc_sd->sdmmc) ||
(XMC_SDMMC_IsCommandLineBusy(obj->sdmmc_sd->sdmmc))));
}
return status;
}
/*
* PUBLIC FUNCTIONS
*/
/* Initialize host controller */
static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_lHostControllerInit(SDMMC_BLOCK_t *const obj)
{
SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_HOST_CONTROLLER_INITIALIZED;
/* Check if host controller is initialized */
if (((uint32_t)obj->card_state & (uint32_t)SDMMC_BLOCK_CARD_STATE_HC_INITIALIZED) == (uint32_t)0U)
{
/* Reset the registers to default values */
status = SDMMC_BLOCK_SD_lReset(obj, (uint32_t)XMC_SDMMC_SW_RESET_ALL);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/*
* The internal clock should be disabled before
* updating frequency clock select (Please see
* section 2.2.14 -> Clock Control Register)
*/
XMC_SDMMC_Stop(obj->sdmmc_sd->sdmmc);
/* Select SD clock frequency */
XMC_SDMMC_SDClockFreqSelect(obj->sdmmc_sd->sdmmc, XMC_SDMMC_CLK_DIV_2);
/* Internal clock enable */
XMC_SDMMC_Start(obj->sdmmc_sd->sdmmc);
/*
* Enable all normal interrupt status bits except block-gap
* event, card interrupt event, DMA int., ADMA and auto cmd
* errors. Enable the status and the events themselves.
*/
obj->sdmmc_sd->sdmmc->EN_INT_STATUS_NORM = SDMMC_BLOCK_NORMAL_INT_STATUS_ENABLE;
obj->sdmmc_sd->sdmmc->EN_INT_STATUS_ERR = SDMMC_BLOCK_ERROR_INT_STATUS_ENABLE;
obj->sdmmc_sd->sdmmc->EN_INT_SIGNAL_NORM = SDMMC_BLOCK_NORMAL_INT_SIGNAL_ENABLE;
obj->sdmmc_sd->sdmmc->EN_INT_SIGNAL_ERR = SDMMC_BLOCK_ERROR_INT_SIGNAL_ENABLE;
#if SDMMC_BLOCK_SD_CARD_DETECTION_SUPPORT
XMC_SDMMC_EnableEvent(obj->sdmmc_sd->sdmmc, ((uint32_t)XMC_SDMMC_CARD_REMOVAL) |
((uint32_t)XMC_SDMMC_CARD_INS) |
((uint32_t)XMC_SDMMC_CARD_INT));
#endif
/* Set data-line timeout */
XMC_SDMMC_SetDataLineTimeout(obj->sdmmc_sd->sdmmc, XMC_SDMMC_DAT_TIMEOUT_COUNTER_2_POW_27);
/* Set bus voltage in the power control register: flattop 3.3 volts */
XMC_SDMMC_SetBusVoltage(obj->sdmmc_sd->sdmmc, XMC_SDMMC_BUS_VOLTAGE_3_3_VOLTS);
/* Update the state status to card initialized */
obj->card_state |= (uint8_t)((uint8_t)SDMMC_BLOCK_CARD_STATE_HC_INITIALIZED |
(uint8_t)SDMMC_BLOCK_CARD_STATE_NO_CARD |
(uint8_t)SDMMC_BLOCK_CARD_STATE_NOT_INITIALIZED);
/* A stub of delay for initialization */
for (volatile uint32_t i = 0; (uint32_t)i < (uint32_t)100000U; i++)
{
}
}
}
return status;
}
/* De-initialize the host controller */
static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_lHostControllerDeInit(SDMMC_BLOCK_t *const obj)
{
SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
/* Check if the host controller is initialized */
if (((uint32_t)obj->card_state & (uint32_t)SDMMC_BLOCK_CARD_STATE_HC_INITIALIZED) != (uint32_t)0U)
{
/* Cleanup the card */
SDMMC_BLOCK_SD_lCardCleanUp(obj);
/* Reset host controller's registers */
status = SDMMC_BLOCK_SD_lReset(obj, (uint32_t)XMC_SDMMC_SW_RESET_ALL);
}
return status;
}
/* Read multiple blocks of data from the card */
static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_lCardReadMultipleBlocks(SDMMC_BLOCK_t *const obj,
uint32_t *read_buf,
uint32_t read_addr,
uint32_t num_blocks)
{
SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_INIT_FAIL;
obj->sdmmc_sd->cmd_int_err = SDMMC_BLOCK_MODE_STATUS_FAILURE;
obj->sdmmc_sd->data_int_err = SDMMC_BLOCK_MODE_STATUS_FAILURE;
obj->sdmmc_sd->transfer_int_err = SDMMC_BLOCK_MODE_STATUS_FAILURE;
/* Check if initialization is successful */
if (obj->sdmmc_sd->mode_init_flag == true)
{
/* Ensure that sector number is not out of bound */
status = SDMMC_BLOCK_SD_lCheckSectorBound(obj, read_addr, num_blocks);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Set transfer direction select in the Transfer Mode Register */
XMC_SDMMC_SetDataTransferDirection(obj->sdmmc_sd->sdmmc, XMC_SDMMC_DATA_TRANSFER_CARD_TO_HOST);
/* Send Multiple Block Read Command i.e CMD18 */
status = SDMMC_BLOCK_SD_lMultiBlockTransfer(obj,
&read_addr,
num_blocks,
&(SDMMC_BLOCK_COMMON_COMMAND(18)),
read_buf,
SDMMC_BLOCK_SD_DATA_TRANSFER_READ_BUFFER);
}
}
return status;
}
/* Read single block of data from the card */
static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_lCardReadSingleBlock(SDMMC_BLOCK_t *const obj,
uint32_t *read_buf,
uint32_t read_addr)
{
SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_INIT_FAIL;
uint32_t sector_count = 1U;
/* Check if initialization successful */
if (obj->sdmmc_sd->mode_init_flag == true)
{
/* Ensure that the sector number is not out of bound */
status = SDMMC_BLOCK_SD_lCheckSectorBound(obj, read_addr, sector_count);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Block addressing or byte addressing */
if (((uint32_t)obj->card_type & (uint32_t)SDMMC_BLOCK_CARD_TYPE_BLOCK_ADDRESSING) == (uint32_t)0UL)
{
read_addr = (uint32_t)(read_addr * 512UL);
}
XMC_SDMMC_SetDataTransferDirection(obj->sdmmc_sd->sdmmc, XMC_SDMMC_DATA_TRANSFER_CARD_TO_HOST);
/* SDMMC->TRANSFER_MODE |= (uint16_t)((uint32_t)1U << (uint32_t)SDMMC_TRANSFER_MODE_TX_DIR_SELECT_Pos); */
/* Perform the Single block transfer operation */
status = SDMMC_BLOCK_SD_lSingleBlockTransfer(obj,
&(SDMMC_BLOCK_COMMON_COMMAND(17)),
read_addr,
(uint16_t)SDMMC_BLOCK_BLOCK_SIZE,
read_buf,
SDMMC_BLOCK_SD_DATA_TRANSFER_READ_BUFFER);
}
}
return status;
}
/* Write multiple blocks of data on the card */
static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_lCardWriteMultipleBlocks(SDMMC_BLOCK_t *const obj,
const uint32_t *write_buf,
uint32_t write_addr,
uint32_t num_blocks)
{
SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_INIT_FAIL;
obj->sdmmc_sd->cmd_int_err = SDMMC_BLOCK_MODE_STATUS_FAILURE;
obj->sdmmc_sd->data_int_err = SDMMC_BLOCK_MODE_STATUS_FAILURE;
obj->sdmmc_sd->transfer_int_err = SDMMC_BLOCK_MODE_STATUS_FAILURE;
/* Check if initialization is successful */
if (obj->sdmmc_sd->mode_init_flag == true)
{
/* Ensure sector number is not out of bound */
status = SDMMC_BLOCK_SD_lCheckSectorBound(obj, write_addr, num_blocks);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Clear transfer direction select in transfer mode register */
XMC_SDMMC_SetDataTransferDirection(obj->sdmmc_sd->sdmmc, XMC_SDMMC_DATA_TRANSFER_HOST_TO_CARD);
/* Send Multiple Block Write Command i.e CMD25 */
status = SDMMC_BLOCK_SD_lMultiBlockTransfer(obj,
&write_addr,
num_blocks,
&(SDMMC_BLOCK_COMMON_COMMAND(25)),
(uint32_t *)write_buf,
SDMMC_BLOCK_SD_DATA_TRANSFER_WRITE_BUFFER);
}
}
return status;
}
/* Write single block of data on the card */
static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_lCardWriteSingleBlock(SDMMC_BLOCK_t *const obj,
const uint32_t *write_buf,
uint32_t write_addr)
{
SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_INIT_FAIL;
uint32_t sector_count = 1U;
/* Check if initialization is successful */
if (obj->sdmmc_sd->mode_init_flag == true)
{
/* Check if sector number is not out of bound */
status = SDMMC_BLOCK_SD_lCheckSectorBound(obj, write_addr, sector_count);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* If not block addressing, then multiply by 512 bytes */
if (((uint32_t)obj->card_type & (uint32_t)SDMMC_BLOCK_CARD_TYPE_BLOCK_ADDRESSING) == (uint32_t)0U)
{
write_addr = (uint32_t)(write_addr * 512U);
}
/* Clear transfer direction select bit */
XMC_SDMMC_SetDataTransferDirection(obj->sdmmc_sd->sdmmc, XMC_SDMMC_DATA_TRANSFER_HOST_TO_CARD);
/* Single block transfer function */
status = SDMMC_BLOCK_SD_lSingleBlockTransfer(obj,
&(SDMMC_BLOCK_COMMON_COMMAND(24)),
write_addr,
(uint16_t)SDMMC_BLOCK_BLOCK_SIZE,
(uint32_t *)write_buf,
SDMMC_BLOCK_SD_DATA_TRANSFER_WRITE_BUFFER);
}
}
return status;
}
/* Erase data from the card */
SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_EraseBlock(SDMMC_BLOCK_t *const obj, uint32_t start_addr, uint32_t end_addr)
{
SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_INIT_FAIL;
uint32_t tmp_start_addr;
uint32_t num_sectors = 0U;
/* Allocation unit to no. of sectors in 1 AU table mapping */
uint32_t au_to_sectors[10] = {0U, 32U, 64U, 128U, 256U, 512U, 1024U, 2048U, 4096U, 8192U};
uint16_t erase_size = (uint16_t)0U;
uint8_t erase_offset = (uint8_t)0U;
uint8_t erase_timeout = (uint8_t)0U;
uint8_t au_size = (uint8_t)0U;
uint32_t sectors_in_au = 0U;
uint32_t sectors_in_erase_cluster = 0U;
/* Read SD status */
uint32_t sd_status[16] = {0U};
uint32_t erase_timeout_per_cluster = 0UL;
obj->sdmmc_sd->cmd_int_err = SDMMC_BLOCK_MODE_STATUS_FAILURE;
obj->sdmmc_sd->data_int_err = SDMMC_BLOCK_MODE_STATUS_FAILURE;
obj->sdmmc_sd->transfer_int_err = SDMMC_BLOCK_MODE_STATUS_FAILURE;
/* If the card is read only or write protected */
if ((obj->card_state & (uint8_t)SDMMC_BLOCK_CARD_STATE_WRITE_PROTECTED) != (uint8_t)0U)
{
status = SDMMC_BLOCK_MODE_STATUS_WP_VIOLATION_ERROR;
}
#ifdef SDMMC_BLOCK_CARD_WRITE_PROTECT_SIGNAL
else if ((obj->sdwc != NULL) && (XMC_GPIO_GetInput(obj->sdwc->port, obj->sdwc->pin)))
{
status = SDMMC_BLOCK_MODE_STATUS_WP_VIOLATION_ERROR;
}
#endif /* SDMMC_BLOCK_CARD_WRITE_PROTECT_SIGNAL */
/* Assume initialization is successful: This is invoked from IOCTL */
else
{
tmp_start_addr = start_addr;
num_sectors = (end_addr - tmp_start_addr) + 1U;
/* Check sector number is not out of bound */
status = SDMMC_BLOCK_SD_lCheckSectorBound(obj, tmp_start_addr, num_sectors);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Erase timeout calculation */
/* Get SD status */
status = SDMMC_BLOCK_SD_GetSdStatus(obj, (void*)&(sd_status[0]));
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Bits 400-401 in SD status: Erase offset */
erase_offset = (uint8_t)(((sd_status[3] & 0x00000300UL)) >> 8U);
/* Bits 402-407: Erase timeout */
erase_timeout = (uint8_t)(((sd_status[3] & 0x0000FC00UL)) >> 10UL);
/* Bits 408-423: Erase size */
erase_size = (uint16_t)((((sd_status[2] & 0xFF000000U) >> 24U) << 8U) | (sd_status[3] & 0x000000FFU));
/* Bits 428-431: Allocation unit size */
au_size = (uint8_t)((sd_status[2] & 0x00F00000U) >> 20);
/* Erase timeout calculations */
erase_timeout_per_cluster = ((uint32_t)erase_timeout / (uint32_t)erase_size) + (uint32_t)erase_offset;
/* Number of sectors in 1 AU */
sectors_in_au = au_to_sectors[au_size];
sectors_in_erase_cluster = sectors_in_au * erase_size;
while (num_sectors >= sectors_in_erase_cluster)
{
status = SDMMC_BLOCK_SD_lLocalErase(obj,
tmp_start_addr,
(tmp_start_addr + sectors_in_erase_cluster),
erase_timeout_per_cluster);
if (status != SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
break;
}
tmp_start_addr = tmp_start_addr + sectors_in_erase_cluster;
num_sectors = num_sectors - sectors_in_erase_cluster;
}
if (num_sectors != 0U)
{
status = SDMMC_BLOCK_SD_lLocalErase(obj, tmp_start_addr, end_addr, erase_timeout_per_cluster);
}
}
}
}
/* Wait for until the command OR data lines aren't busy */
while ((XMC_SDMMC_IsDataLineBusy(obj->sdmmc_sd->sdmmc)) || (XMC_SDMMC_IsCommandLineBusy(obj->sdmmc_sd->sdmmc)))
{
}
return status;
}
/* Set, clear password, lock/unlock card */
SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_LockUnlockCard(SDMMC_BLOCK_t *const obj,
SDMMC_BLOCK_LOCK_STRUCTURE_t *lock,
SDMMC_BLOCK_CARD_LOCK_STATUS_t operation_mode)
{
SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
uint32_t data_length = 0U;
uint32_t card_status;
/* Select the card before proceeding */
status = SDMMC_BLOCK_SD_lSwitchToTransferState(obj);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Send CMD42 and write the lock data structure */
/* Clear transfer direction select in transfer mode register */
XMC_SDMMC_SetDataTransferDirection(obj->sdmmc_sd->sdmmc, XMC_SDMMC_DATA_TRANSFER_HOST_TO_CARD);
/* Compute password length */
data_length = (uint32_t)((((uint32_t)lock->pwd_len + (uint32_t)1U) >> 1U) << 1U) + 2U;
/* Set block length */
status = SDMMC_BLOCK_SD_lSendCommand(obj,
&(SDMMC_BLOCK_COMMON_COMMAND(16)),
data_length,
XMC_SDMMC_RESPONSE_TYPE_R1,
&card_status);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
status = SDMMC_BLOCK_SD_lSingleBlockTransfer(obj,
&(SDMMC_BLOCK_COMMON_COMMAND(42)),
(uint32_t)SDMMC_BLOCK_ARGUMENT0,
(uint16_t)data_length,
(uint32_t *)lock,
SDMMC_BLOCK_SD_DATA_TRANSFER_WRITE_BUFFER);
while (XMC_SDMMC_IsDataLineBusy(obj->sdmmc_sd->sdmmc))
{
}
status = SDMMC_BLOCK_SD_lSendCommand(obj,
&(SDMMC_BLOCK_COMMON_COMMAND(16)),
512U,
XMC_SDMMC_RESPONSE_TYPE_R1,
&card_status);
/* Wait for until the command OR data lines aren't busy */
while ((XMC_SDMMC_IsDataLineBusy(obj->sdmmc_sd->sdmmc)) ||
(XMC_SDMMC_IsCommandLineBusy(obj->sdmmc_sd->sdmmc)))
{
}
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
status = SDMMC_BLOCK_SD_lCheckLockStatus(obj, operation_mode);
}
}
}
return status;
}
/* Get the lock status from card */
SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_GetLockStatus(SDMMC_BLOCK_t *const obj,
SDMMC_BLOCK_CARD_LOCK_STATUS_t *lock_status)
{
uint32_t card_status = 0UL;
uint32_t arg = 0UL;
SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
arg |= ((uint32_t)obj->sdmmc_sd->card_info.rca << SDMMC_BLOCK_ARG_RCA_BITPOS);
/* Send CMD13 to read card status */
status = SDMMC_BLOCK_SD_lSendCommand(obj,
&(SDMMC_BLOCK_COMMON_COMMAND(13)),
arg,
XMC_SDMMC_RESPONSE_TYPE_R1,
&card_status);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Lock/unlock status bit in the CSR register */
if (((uint32_t)card_status & (uint32_t)SDMMC_BLOCK_SD_CSR_CARD_IS_LOCKED_BITMASK) != (uint32_t)0)
{
*lock_status = SDMMC_BLOCK_CARD_LOCK_STATUS_LOCKED;
obj->card_state |= (uint8_t)SDMMC_BLOCK_CARD_STATE_LOCKED;
}
else
{
*lock_status = SDMMC_BLOCK_CARD_LOCK_STATUS_UNLOCKED;
obj->card_state &= (uint8_t)~(uint8_t)(SDMMC_BLOCK_CARD_STATE_LOCKED);
}
}
return status;
}
/* Get card's current state */
uint8_t SDMMC_BLOCK_SD_GetState(SDMMC_BLOCK_t *obj)
{
return (obj->card_state & 0xFU);
}
/* Get card type */
SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_GetCardType(SDMMC_BLOCK_t *const obj, uint32_t *card_type)
{
*card_type = obj->card_type;
return SDMMC_BLOCK_MODE_STATUS_SUCCESS;
}
/* Get CID register information of card */
SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_GetCid(SDMMC_BLOCK_t *const obj, void *buf)
{
SDMMC_BLOCK_CID_t *temp = (SDMMC_BLOCK_CID_t *)buf;
temp->manufacturing_date = (uint16_t)((obj->sdmmc_sd->card_info.cid[0]) & 0xFFFU);
temp->product_serial_num = (obj->sdmmc_sd->card_info.cid[1] << 16U) | (obj->sdmmc_sd->card_info.cid[0] >> 16U);
temp->product_rev = (uint8_t)((obj->sdmmc_sd->card_info.cid[1] >> 16U) & 0xFFU);
temp->product_name[0] = (uint8_t)((obj->sdmmc_sd->card_info.cid[2] >> 24U) & 0xFFU);
temp->product_name[1] = (uint8_t)((obj->sdmmc_sd->card_info.cid[2] >> 16U) & 0xFFU);
temp->product_name[2] = (uint8_t)((obj->sdmmc_sd->card_info.cid[2] >> 8U) & 0xFFU);
temp->product_name[3] = (uint8_t)((obj->sdmmc_sd->card_info.cid[2] >> 0U) & 0xFFU);
temp->product_name[4] = (uint8_t)((obj->sdmmc_sd->card_info.cid[1] >> 24U) & 0xFFU);
temp->app_oem_id[0] = (uint8_t)((obj->sdmmc_sd->card_info.cid[3] >> 8U) & 0xFFU);
temp->app_oem_id[1] = (uint8_t)((obj->sdmmc_sd->card_info.cid[3]) & 0xFFU);
temp->manufacturer_id = (uint8_t)((obj->sdmmc_sd->card_info.cid[3] >> 16U) & 0xFFU);
return SDMMC_BLOCK_MODE_STATUS_SUCCESS;
}
/* Get OCR information */
SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_GetOcr(SDMMC_BLOCK_t *const obj, void *buf)
{
*(uint32_t *)buf = obj->sdmmc_sd->card_info.ocr;
return SDMMC_BLOCK_MODE_STATUS_SUCCESS;
}
/* Get CSD information */
SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_GetCsd(SDMMC_BLOCK_t *const obj, void *buf)
{
/*
* CSD Structure includes 7-bit CRC and 1-bit fixed bit
* which is not sent by the card. So, skip 1 byte before
* copying into the structure.
*/
memcpy(((uint8_t *)buf + 1U), (void *)obj->sdmmc_sd->card_info.csd, 15U);
return SDMMC_BLOCK_MODE_STATUS_SUCCESS;
}
/* Get number of sectors present on the card */
SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_GetSectorCount(SDMMC_BLOCK_t *const obj, void *buf)
{
SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_SUCCESS;
uint32_t mult = 0U;
if (((uint32_t)obj->card_type & (uint32_t)SDMMC_BLOCK_CARD_TYPE_HIGH_CAPACITY) != (uint32_t)0U)
{
SDMMC_BLOCK_SDV2_CSD_t temp_csd_v2 = {0U};
/* Get CSD function */
status = SDMMC_BLOCK_SD_GetCsd(obj, (void *)&temp_csd_v2);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/*
* For High Capacity SD card, (C_SIZE field value + 1) * 1024
* gives the sector count
*/
*(uint32_t *)buf = (uint32_t)(((((uint32_t)temp_csd_v2.dev_size_high << (uint32_t)16UL) |
((uint32_t)temp_csd_v2.dev_size_low)) + (uint32_t)1UL) << (uint32_t)10UL);
}
}
/*
* For Standard SD (and MMC) cards:
* Sector Count = (Device Size + 1) * Mult, where Mult = 2 ^ C_SIZE_MULT
*/
else
{
SDMMC_BLOCK_SDV1_CSD_t temp_csd_v1 = {0U};
/* Get CSD function */
status = SDMMC_BLOCK_SD_GetCsd(obj, (void *)&temp_csd_v1);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Left shift evaluates 1 * 2 ^ (TmpMmcCsd.DeviceSizeMult + 2) */
mult = (uint32_t)((uint32_t)temp_csd_v1.dev_size_mult + 2U);
/* Sector Count = device_size * mult */
*(uint32_t *)buf = (uint32_t)((((uint32_t)temp_csd_v1.dev_size_high << (uint32_t)2UL) |
((uint32_t)temp_csd_v1.dev_size_low)) + (uint32_t)1UL) << mult;
}
}
return status;
}
/* Get sector size info from the card */
SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_GetSectorSize(SDMMC_BLOCK_t *const obj, void *buf)
{
/* Sector Size is fixed to 512 bytes */
*(uint16_t *)buf = (uint16_t)512U;
return SDMMC_BLOCK_MODE_STATUS_SUCCESS;
}
SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_GetBlockSize(SDMMC_BLOCK_t *const obj, void *buf)
{
SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_SUCCESS;
/* SD high capacity card (CSD V2) */
if (((uint32_t)obj->card_type & (uint32_t)SDMMC_BLOCK_CARD_TYPE_HIGH_CAPACITY) != (uint32_t)0)
{
SDMMC_BLOCK_SDV2_CSD_t temp_csd_v2 = {0U};
/* Get CSD function */
status = SDMMC_BLOCK_SD_GetCsd(obj, (void *)&temp_csd_v2);
*(uint32_t *)buf = (uint32_t)((uint32_t)temp_csd_v2.erase_sector_size + (uint32_t)1U);
}
/* SD standard capacity card (CSD V1) */
else
{
SDMMC_BLOCK_SDV2_CSD_t temp_csd_v1 = {0U};
/* Get CSD function */
status = SDMMC_BLOCK_SD_GetCsd(obj, (void *)&temp_csd_v1);
*(uint32_t *)buf = (uint32_t)((uint32_t)temp_csd_v1.erase_sector_size + (uint32_t)1U);
}
return status;
}
/* Get SD status information */
SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_GetSdStatus(SDMMC_BLOCK_t *const obj, void *buf)
{
uint32_t arg = 0U;
uint32_t card_status = 0U;
SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
/* Select the card (CMD7) */
status = SDMMC_BLOCK_SD_lSwitchToTransferState(obj);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Send CMD55 (application specific command) */
arg |= (uint32_t)((uint32_t)obj->sdmmc_sd->card_info.rca << (uint32_t)SDMMC_BLOCK_ARG_RCA_BITPOS);
status = SDMMC_BLOCK_SD_lSendCommand(obj,
&(SDMMC_BLOCK_COMMON_COMMAND(55)),
arg,
XMC_SDMMC_RESPONSE_TYPE_R1,
&card_status);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Set transfer mode */
XMC_SDMMC_SetDataTransferDirection(obj->sdmmc_sd->sdmmc, XMC_SDMMC_DATA_TRANSFER_CARD_TO_HOST);
/* Read the SD status from the data line */
status = SDMMC_BLOCK_SD_lSingleBlockTransfer(obj,
&(SDMMC_BLOCK_SD_COMMAND(59)),
(uint32_t)SDMMC_BLOCK_ARGUMENT0,
(uint16_t)64U,
(uint32_t *)buf,
SDMMC_BLOCK_SD_DATA_TRANSFER_READ_BUFFER);
}
}
return status;
}
/* Eject SD card */
SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_EjectCard(SDMMC_BLOCK_t *const obj)
{
SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
uint32_t arg = 0U;
if ((obj->card_state & (uint16_t)SDMMC_BLOCK_CARD_STATE_NO_CARD) == 0U)
{
/* Send CMD15 to deactivate the card */
arg |= (uint32_t)((uint32_t)obj->sdmmc_sd->card_info.rca << (uint32_t)SDMMC_BLOCK_ARG_RCA_BITPOS);
status = SDMMC_BLOCK_SD_lSendCommand(obj,
&(SDMMC_BLOCK_SD_COMMAND(15)),
(uint32_t)arg,
(XMC_SDMMC_RESPONSE_TYPE_t)XMC_SDMMC_RESPONSE_TYPE_NO_RESPONSE,
NULL);
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
/* Card Cleanup */
SDMMC_BLOCK_SD_lCardCleanUp(obj);
obj->sdmmc_sd->mode_init_flag = false;
}
}
return status;
}
/*
* Initialize low level drivers, host controller, the card
* and read card registers.
*/
SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_Start(SDMMC_BLOCK_t *const obj)
{
SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_HOST_CONTROLLER_INITIALIZED;
/* Check If host controller is already initialized */
if (((uint32_t)obj->card_state & (uint32_t)SDMMC_BLOCK_CARD_STATE_HC_INITIALIZED) == (uint32_t)0U)
{
#if (SDMMC_BLOCK_POLLING_MODE == 0U)
/* Enable Interrupt */
NVIC_SetPriority(SDMMC0_0_IRQn,
NVIC_EncodePriority(NVIC_GetPriorityGrouping(),
obj->sdmmc_sd->int_priority,
obj->sdmmc_sd->int_sub_priority));
NVIC_ClearPendingIRQ(SDMMC0_0_IRQn);
NVIC_EnableIRQ(SDMMC0_0_IRQn);
#endif
/* Host controller initialize */
status = SDMMC_BLOCK_SD_lHostControllerInit(obj);
}
return status;
}
/* De-assert the SDMMC peripheral */
SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SD_Init(SDMMC_BLOCK_t *const obj)
{
/* Enable SDMMC peripheral */
XMC_SDMMC_Enable(obj->sdmmc_sd->sdmmc);
/* Enable SCU clock for SDMMC */
XMC_SCU_CLOCK_EnableClock(XMC_SCU_CLOCK_MMC);
/* De-initialize host controller */
(void)SDMMC_BLOCK_SD_lHostControllerDeInit(obj);
/* Initialize LLD and host controller */
return SDMMC_BLOCK_SD_Start(obj);
}
/* Reads the data from the card */
SDMMC_BLOCK_STATUS_t SDMMC_BLOCK_SD_ReadBlock(SDMMC_BLOCK_t *const obj,
uint8_t *read_buf,
uint32_t sector_num,
uint8_t sector_count)
{
SDMMC_BLOCK_MODE_STATUS_t status;
uint8_t disk_status;
SDMMC_BLOCK_STATUS_t res;
/* Check the status before reading data */
disk_status = obj->card_state;
if ((disk_status & (uint8_t)SDMMC_BLOCK_CARD_STATE_NOT_INITIALIZED) != (uint8_t)0U)
{
res = SDMMC_BLOCK_STATUS_NOTRDY;
}
else if ((disk_status & (uint8_t)SDMMC_BLOCK_CARD_STATE_LOCKED) != (uint8_t)0U)
{
res = SDMMC_BLOCK_STATUS_LOCKED;
}
else
{
/* Check for single block read or multiple block read based on sector count */
if (sector_count == (uint8_t)1U)
{
status = SDMMC_BLOCK_SD_lCardReadSingleBlock(obj, (uint32_t *)read_buf, sector_num);
}
else
{
status = SDMMC_BLOCK_SD_lCardReadMultipleBlocks(obj, (uint32_t *)read_buf, sector_num, (uint32_t)sector_count);
}
if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
{
res = SDMMC_BLOCK_STATUS_SUCCESS;
}
else if (status == SDMMC_BLOCK_MODE_STATUS_SECTOR_OUT_OF_BOUND)
{
res = SDMMC_BLOCK_STATUS_PARERR;
}
else
{
res = SDMMC_BLOCK_STATUS_FAILURE;
}
}
/* Wait for until the command OR data lines aren't busy */
while ((XMC_SDMMC_IsDataLineBusy(obj->sdmmc_sd->sdmmc)) || (XMC_SDMMC_IsCommandLineBusy(obj->sdmmc_sd->sdmmc)))
{
}
return res;
}
/* Writes the data on the card */
SDMMC_BLOCK_STATUS_t SDMMC_BLOCK_SD_WriteBlock(SDMMC_BLOCK_t *const obj,
const uint8_t *write_buf,
uint32_t sector_num,
uint8_t sector_count)
{
SDMMC_BLOCK_MODE_STATUS_t status;
uint8_t disk_status;
SDMMC_BLOCK_STATUS_t res;
/* Get card state */
disk_status = obj->card_state;
/* If the card is not initialized */
if ((disk_status & (uint8_t)SDMMC_BLOCK_CARD_STATE_NOT_INITIALIZED) != (uint8_t)0U)
{
res = SDMMC_BLOCK_STATUS_NOTRDY;
}
else if ((disk_status & (uint8_t)SDMMC_BLOCK_CARD_STATE_LOCKED) != (uint8_t)0U)
{
res = SDMMC_BLOCK_STATUS_LOCKED;
}
/* If the card is read only or write protected */
else if ((disk_status & (uint8_t)SDMMC_BLOCK_CARD_STATE_WRITE_PROTECTED) != (uint8_t)0U)
{
res = SDMMC_BLOCK_STATUS_WRPRT;
}
#ifdef SDMMC_BLOCK_CARD_WRITE_PROTECT_SIGNAL
else if ((obj->sdwc != NULL) && (XMC_GPIO_GetInput(obj->sdwc->port, obj->sdwc->pin)))
{
res = SDMMC_BLOCK_STATUS_WRPRT;
}
#endif /* SDMMC_BLOCK_CARD_WRITE_PROTECT_SIGNAL */
else
{
/* Check for single block write or multiple block write */
if (sector_count == (uint8_t)1U)
{
status = SDMMC_BLOCK_SD_lCardWriteSingleBlock(obj, (const uint32_t *)write_buf, sector_num);
}
else
{
status = SDMMC_BLOCK_SD_lCardWriteMultipleBlocks(obj,
(const uint32_t *)write_buf,
sector_num,
(uint32_t)sector_count);
}
if ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) || (status == SDMMC_BLOCK_MODE_STATUS_BUFFER_READY))
{
res = SDMMC_BLOCK_STATUS_SUCCESS;
}
else if (status == SDMMC_BLOCK_MODE_STATUS_SECTOR_OUT_OF_BOUND)
{
res = SDMMC_BLOCK_STATUS_PARERR;
}
else
{
res = SDMMC_BLOCK_STATUS_FAILURE;
}
}
/* Wait for until the command OR data lines aren't busy */
while ((XMC_SDMMC_IsDataLineBusy(obj->sdmmc_sd->sdmmc)) || (XMC_SDMMC_IsCommandLineBusy(obj->sdmmc_sd->sdmmc)))
{
}
return res;
}
#endif /* SDMMC_BLOCK_SD */