316 lines
9.8 KiB
C
316 lines
9.8 KiB
C
/*
|
|
* Copyright (c) 2015, Freescale Semiconductor, Inc.
|
|
* Copyright 2016-2017 NXP
|
|
* All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include "fsl_debug_console.h"
|
|
#include "pin_mux.h"
|
|
#include "board.h"
|
|
#include "fsl_sd.h"
|
|
#include "sdmmc_config.h"
|
|
#include <stdbool.h>
|
|
#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);
|
|
/*!
|
|
* @brief call back function for SD card detect.
|
|
*
|
|
* @param isInserted true, indicate the card is insert.
|
|
* false, indicate the card is remove.
|
|
* @param userData
|
|
*/
|
|
static void SDCARD_DetectCallBack(bool isInserted, void *userData);
|
|
|
|
/*******************************************************************************
|
|
* 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);
|
|
|
|
/*! @brief SD card detect flag */
|
|
static volatile bool s_cardInserted = false;
|
|
/*******************************************************************************
|
|
* Code
|
|
******************************************************************************/
|
|
|
|
/*******************************************************************************
|
|
* Code
|
|
******************************************************************************/
|
|
static void SDCARD_DetectCallBack(bool isInserted, void *userData)
|
|
{
|
|
s_cardInserted = isInserted;
|
|
}
|
|
|
|
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, SDCARD_DetectCallBack, BOARD_SDMMC_SD_HOST_IRQ_PRIORITY, NULL);
|
|
|
|
PRINTF("\r\nSDCARD interrupt 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 */
|
|
while (!s_cardInserted)
|
|
{
|
|
}
|
|
/* 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);
|
|
s_cardInserted = false;
|
|
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);
|
|
}
|