/* * Copyright (c) 2015, Freescale Semiconductor, Inc. * Copyright 2016-2017 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include "fsl_debug_console.h" #include "pin_mux.h" #include "board.h" #include "fsl_sd.h" #include "sdmmc_config.h" #include #include "fsl_iocon.h" #include "fsl_power.h" /******************************************************************************* * Definitions ******************************************************************************/ /*! @brief Data block count accessed in card */ #define DATA_BLOCK_COUNT (5U) /*! @brief Start data block number accessed in card */ #define DATA_BLOCK_START (2U) /*! @brief Data buffer size. */ #define DATA_BUFFER_SIZE (FSL_SDMMC_DEFAULT_BLOCK_SIZE * DATA_BLOCK_COUNT) /******************************************************************************* * Prototypes ******************************************************************************/ /*! * @brief printf the card information log. * * @param card Card descriptor. */ static void CardInformationLog(sd_card_t *card); /******************************************************************************* * Variables ******************************************************************************/ /*! @brief Card descriptor. */ sd_card_t g_sd; /* @brief decription about the read/write buffer * The size of the read/write buffer should be a multiple of 512, since SDHC/SDXC card uses 512-byte fixed * block length and this driver example is enabled with a SDHC/SDXC card.If you are using a SDSC card, you * can define the block length by yourself if the card supports partial access. * The address of the read/write buffer should align to the specific DMA data buffer address align value if * DMA transfer is used, otherwise the buffer address is not important. * At the same time buffer address/size should be aligned to the cache line size if cache is supported. */ /*! @brief Data written to the card */ SDK_ALIGN(uint8_t g_dataWrite[DATA_BUFFER_SIZE], BOARD_SDMMC_DATA_BUFFER_ALIGN_SIZE); /*! @brief Data read from the card */ SDK_ALIGN(uint8_t g_dataRead[DATA_BUFFER_SIZE], BOARD_SDMMC_DATA_BUFFER_ALIGN_SIZE); /******************************************************************************* * Code ******************************************************************************/ /******************************************************************************* * Code ******************************************************************************/ static status_t AccessCard(sd_card_t *card, bool isReadOnly) { if (isReadOnly) { PRINTF("\r\nRead one data block......\r\n"); if (kStatus_Success != SD_ReadBlocks(card, g_dataRead, DATA_BLOCK_START, 1U)) { PRINTF("Read one data block failed.\r\n"); return kStatus_Fail; } PRINTF("Read multiple data blocks......\r\n"); if (kStatus_Success != SD_ReadBlocks(card, g_dataRead, DATA_BLOCK_START, DATA_BLOCK_COUNT)) { PRINTF("Read multiple data blocks failed.\r\n"); return kStatus_Fail; } } else { memset(g_dataWrite, 0x67U, sizeof(g_dataWrite)); PRINTF("\r\nWrite/read one data block......\r\n"); if (kStatus_Success != SD_WriteBlocks(card, g_dataWrite, DATA_BLOCK_START, 1U)) { PRINTF("Write one data block failed.\r\n"); return kStatus_Fail; } memset(g_dataRead, 0U, sizeof(g_dataRead)); if (kStatus_Success != SD_ReadBlocks(card, g_dataRead, DATA_BLOCK_START, 1U)) { PRINTF("Read one data block failed.\r\n"); return kStatus_Fail; } PRINTF("Compare the read/write content......\r\n"); if (memcmp(g_dataRead, g_dataWrite, FSL_SDMMC_DEFAULT_BLOCK_SIZE)) { PRINTF("The read/write content isn't consistent.\r\n"); return kStatus_Fail; } PRINTF("The read/write content is consistent.\r\n"); PRINTF("Write/read multiple data blocks......\r\n"); if (kStatus_Success != SD_WriteBlocks(card, g_dataWrite, DATA_BLOCK_START, DATA_BLOCK_COUNT)) { PRINTF("Write multiple data blocks failed.\r\n"); return kStatus_Fail; } memset(g_dataRead, 0U, sizeof(g_dataRead)); if (kStatus_Success != SD_ReadBlocks(card, g_dataRead, DATA_BLOCK_START, DATA_BLOCK_COUNT)) { PRINTF("Read multiple data blocks failed.\r\n"); return kStatus_Fail; } PRINTF("Compare the read/write content......\r\n"); if (memcmp(g_dataRead, g_dataWrite, FSL_SDMMC_DEFAULT_BLOCK_SIZE)) { PRINTF("The read/write content isn't consistent.\r\n"); return kStatus_Fail; } PRINTF("The read/write content is consistent.\r\n"); PRINTF("Erase multiple data blocks......\r\n"); if (kStatus_Success != SD_EraseBlocks(card, DATA_BLOCK_START, DATA_BLOCK_COUNT)) { PRINTF("Erase multiple data blocks failed.\r\n"); return kStatus_Fail; } } return kStatus_Success; } /*! * @brief Main function */ int main(void) { sd_card_t *card = &g_sd; char ch = '0'; bool isReadOnly; /* set BOD VBAT level to 1.65V */ POWER_SetBodVbatLevel(kPOWER_BodVbatLevel1650mv, kPOWER_BodHystLevel50mv, false); CLOCK_EnableClock(kCLOCK_InputMux); /* attach 12 MHz clock to FLEXCOMM0 (debug console) */ CLOCK_AttachClk(BOARD_DEBUG_UART_CLK_ATTACH); BOARD_InitPins(); BOARD_BootClockPLL150M(); BOARD_InitDebugConsole(); BOARD_SD_Config(card, NULL, BOARD_SDMMC_SD_HOST_IRQ_PRIORITY, NULL); PRINTF("\r\nSDCARD polling example.\r\n"); /* SD host init function */ if (SD_HostInit(card) != kStatus_Success) { PRINTF("\r\nSD host init fail\r\n"); return -1; } while (ch != 'q') { PRINTF("\r\nPlease insert a card into board.\r\n"); /* wait card insert */ SD_PollingCardInsert(card, kSD_Inserted); /* power off card */ SD_SetCardPower(card, false); /* power on the card */ SD_SetCardPower(card, true); PRINTF("\r\nCard inserted.\r\n"); /* Init card. */ if (SD_CardInit(card)) { PRINTF("\r\nSD card init failed.\r\n"); return -1; } /* card information log */ CardInformationLog(card); /* Check if card is readonly. */ isReadOnly = SD_CheckReadOnly(card); PRINTF("\r\nRead/Write/Erase the card continuously until encounter error......\r\n"); for (;;) { if (kStatus_Success != AccessCard(card, isReadOnly)) { /* access card fail, due to card remove. */ if (SD_IsCardPresent(card) == false) { SD_HostDoReset(card); PRINTF("\r\nCard removed\r\n"); PRINTF( "\r\nInput 'q' to quit read/write/erase process.\ \r\nInput other char to wait card re-insert.\r\n"); ch = GETCHAR(); PUTCHAR(ch); } /* access card fail, due to transfer error */ else { ch = 'q'; } break; } else { PRINTF( "\r\nInput 'q' to quit read/write/erase process.\ \r\nInput other char to read/write/erase data blocks again.\r\n"); ch = GETCHAR(); PUTCHAR(ch); if (ch == 'q') { break; } } } } PRINTF("\r\nThe example will not read/write data blocks again.\r\n"); SD_Deinit(card); while (true) { } } static void CardInformationLog(sd_card_t *card) { assert(card); PRINTF("\r\nCard size %d * %d bytes\r\n", card->blockCount, card->blockSize); PRINTF("\r\nWorking condition:\r\n"); if (card->operationVoltage == kSDMMC_OperationVoltage330V) { PRINTF("\r\n Voltage : 3.3V\r\n"); } else if (card->operationVoltage == kSDMMC_OperationVoltage180V) { PRINTF("\r\n Voltage : 1.8V\r\n"); } if (card->currentTiming == kSD_TimingSDR12DefaultMode) { if (card->operationVoltage == kSDMMC_OperationVoltage330V) { PRINTF("\r\n Timing mode: Default mode\r\n"); } else if (card->operationVoltage == kSDMMC_OperationVoltage180V) { PRINTF("\r\n Timing mode: SDR12 mode\r\n"); } } else if (card->currentTiming == kSD_TimingSDR25HighSpeedMode) { if (card->operationVoltage == kSDMMC_OperationVoltage180V) { PRINTF("\r\n Timing mode: SDR25\r\n"); } else { PRINTF("\r\n Timing mode: High Speed\r\n"); } } else if (card->currentTiming == kSD_TimingSDR50Mode) { PRINTF("\r\n Timing mode: SDR50\r\n"); } else if (card->currentTiming == kSD_TimingSDR104Mode) { PRINTF("\r\n Timing mode: SDR104\r\n"); } else if (card->currentTiming == kSD_TimingDDR50Mode) { PRINTF("\r\n Timing mode: DDR50\r\n"); } PRINTF("\r\n Freq : %d HZ\r\n", card->busClock_Hz); }