/** * @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.
* * 2016-02-08: * - Help Doc updated.
* - Bug fixes done.
* * 2016-04-05 * - Bug fixes for public release, April, 2016
* - MISRA fixes
* - Add timeout for erase()
* - Check write protection in write/erase conditions
* - Remove mode_init_flag check for functions invoked in IOCTL
* * 2016-07-20: * - lReadResponse(): Fixes in handling XMC_SDMMC_RESPONSE_TYPE_R2
* * 2016-08-24: * - Introduce timeout mechanism in SDMMC_BLOCK_SD_lCheckDataCommandLines()
* * 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 */