?? sdmmc.c
字號:
/* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support - ROUSSET -
* ----------------------------------------------------------------------------
* Copyright (c) 2006, Atmel Corporation
* 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 disclaimer below.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the disclaimer below in the documentation and/or
* other materials provided with the distribution.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL 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.
* ----------------------------------------------------------------------------
*/
//------------------------------------------------------------------------------
// Headers
//------------------------------------------------------------------------------
#include "sdmmc.h"
#include <board.h>
#include <utility/assert.h>
#include <utility/trace.h>
#include <string.h>
//------------------------------------------------------------------------------
// Local constants
//------------------------------------------------------------------------------
// SD card operation states
#define SD_STATE_STBY 0
#define SD_STATE_DATA 1
#define SD_STATE_RCV 2
// Card type
#define UNKNOWN_CARD 0
#define CARD_SD 1
#define CARD_SDHC 2
#define CARD_MMC 3
// Delay between sending MMC commands
#define MMC_DELAY 0x4ff
#define SD_ADDRESS(pSd, address) (((pSd)->cardType == CARD_SDHC) ? \
(address):((address) << SD_BLOCK_SIZE_BIT))
// Status register constants
#define STATUS_READY_FOR_DATA (1 << 8)
#define STATUS_IDLE (0 << 9)
#define STATUS_READY (1 << 9)
#define STATUS_IDENT (2 << 9)
#define STATUS_STBY (3 << 9)
#define STATUS_TRAN (4 << 9)
#define STATUS_DATA (5 << 9)
#define STATUS_RCV (6 << 9)
#define STATUS_PRG (7 << 9)
#define STATUS_DIS (8 << 9)
#define STATUS_STATE (0xF << 9)
////////////////////////////////////////////////////////////////////////////////////////////////////
// OCR Register
////////////////////////////////////////////////////////////////////////////////////////////////////
#define AT91C_VDD_16_17 (1UL << 4)
#define AT91C_VDD_17_18 (1UL << 5)
#define AT91C_VDD_18_19 (1UL << 6)
#define AT91C_VDD_19_20 (1UL << 7)
#define AT91C_VDD_20_21 (1UL << 8)
#define AT91C_VDD_21_22 (1UL << 9)
#define AT91C_VDD_22_23 (1UL << 10)
#define AT91C_VDD_23_24 (1UL << 11)
#define AT91C_VDD_24_25 (1UL << 12)
#define AT91C_VDD_25_26 (1UL << 13)
#define AT91C_VDD_26_27 (1UL << 14)
#define AT91C_VDD_27_28 (1UL << 15)
#define AT91C_VDD_28_29 (1UL << 16)
#define AT91C_VDD_29_30 (1UL << 17)
#define AT91C_VDD_30_31 (1UL << 18)
#define AT91C_VDD_31_32 (1UL << 19)
#define AT91C_VDD_32_33 (1UL << 20)
#define AT91C_VDD_33_34 (1UL << 21)
#define AT91C_VDD_34_35 (1UL << 22)
#define AT91C_VDD_35_36 (1UL << 23)
#define AT91C_CARD_POWER_UP_BUSY (1UL << 31)
#define AT91C_MMC_HOST_VOLTAGE_RANGE (AT91C_VDD_27_28 +\
AT91C_VDD_28_29 +\
AT91C_VDD_29_30 +\
AT91C_VDD_30_31 +\
AT91C_VDD_31_32 +\
AT91C_VDD_32_33)
#define AT91C_CCS (1UL << 30)
#define AT91C_NO_ARGUMENT 0x0
/////////////////////////////////////////////////////////////////////////////////////////////////////
// MCI_CMD Register Value
/////////////////////////////////////////////////////////////////////////////////////////////////////
#define AT91C_POWER_ON_INIT (0 | AT91C_MCI_TRCMD_NO | AT91C_MCI_SPCMD_INIT | AT91C_MCI_OPDCMD)
/////////////////////////////////////////////////////////////////
// Class 0 & 1 commands: Basic commands and Read Stream commands
/////////////////////////////////////////////////////////////////
#define AT91C_GO_IDLE_STATE_CMD (0 | AT91C_MCI_TRCMD_NO | AT91C_MCI_SPCMD_NONE )
#define AT91C_MMC_GO_IDLE_STATE_CMD (0 | AT91C_MCI_TRCMD_NO | AT91C_MCI_SPCMD_NONE | AT91C_MCI_OPDCMD)
#define AT91C_MMC_SEND_OP_COND_CMD (1 | AT91C_MCI_TRCMD_NO | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_OPDCMD)
#define AT91C_ALL_SEND_CID_CMD (2 | AT91C_MCI_TRCMD_NO | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_136 )
#define AT91C_MMC_ALL_SEND_CID_CMD (2 | AT91C_MCI_TRCMD_NO | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_136 | AT91C_MCI_OPDCMD)
#define AT91C_SET_RELATIVE_ADDR_CMD (3 | AT91C_MCI_TRCMD_NO | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_MAXLAT )
#define AT91C_MMC_SET_RELATIVE_ADDR_CMD (3 | AT91C_MCI_TRCMD_NO | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_MAXLAT | AT91C_MCI_OPDCMD)
#define AT91C_SET_DSR_CMD (4 | AT91C_MCI_TRCMD_NO | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_NO | AT91C_MCI_MAXLAT ) // not tested
#define AT91C_SEL_DESEL_CARD_CMD (7 | AT91C_MCI_TRCMD_NO | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_MAXLAT )
#define AT91C_SEND_IF_COND (8 | AT91C_MCI_TRCMD_NO | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_MAXLAT)
#define AT91C_SEND_CSD_CMD (9 | AT91C_MCI_TRCMD_NO | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_136 | AT91C_MCI_MAXLAT )
#define AT91C_SEND_CID_CMD (10 | AT91C_MCI_TRCMD_NO | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_136 | AT91C_MCI_MAXLAT )
#define AT91C_MMC_READ_DAT_UNTIL_STOP_CMD (11 | AT91C_MCI_TRTYP_STREAM| AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRDIR | AT91C_MCI_TRCMD_START | AT91C_MCI_MAXLAT )
#define AT91C_STOP_TRANSMISSION_CMD (12 | AT91C_MCI_TRCMD_STOP | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_MAXLAT )
#define AT91C_STOP_TRANSMISSION_SYNC_CMD (12 | AT91C_MCI_TRCMD_STOP | AT91C_MCI_SPCMD_SYNC | AT91C_MCI_RSPTYP_48 | AT91C_MCI_MAXLAT )
#define AT91C_SEND_STATUS_CMD (13 | AT91C_MCI_TRCMD_NO | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_MAXLAT )
#define AT91C_GO_INACTIVE_STATE_CMD (15 | AT91C_MCI_RSPTYP_NO )
//*------------------------------------------------
//* Class 2 commands: Block oriented Read commands
//*------------------------------------------------
#define AT91C_SET_BLOCKLEN_CMD (16 | AT91C_MCI_TRCMD_NO | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_MAXLAT )
#define AT91C_READ_SINGLE_BLOCK_CMD (17 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRCMD_START | AT91C_MCI_TRTYP_BLOCK | AT91C_MCI_TRDIR | AT91C_MCI_MAXLAT)
#define AT91C_READ_MULTIPLE_BLOCK_CMD (18 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRCMD_START | AT91C_MCI_TRTYP_MULTIPLE | AT91C_MCI_TRDIR | AT91C_MCI_MAXLAT)
//*--------------------------------------------
//* Class 3 commands: Sequential write commands
//*--------------------------------------------
#define AT91C_MMC_WRITE_DAT_UNTIL_STOP_CMD (20 | AT91C_MCI_TRTYP_STREAM| AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 & ~(AT91C_MCI_TRDIR) | AT91C_MCI_TRCMD_START | AT91C_MCI_MAXLAT ) // MMC
//*------------------------------------------------
//* Class 4 commands: Block oriented write commands
//*------------------------------------------------
#define AT91C_WRITE_BLOCK_CMD (24 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRCMD_START | (AT91C_MCI_TRTYP_BLOCK & ~(AT91C_MCI_TRDIR)) | AT91C_MCI_MAXLAT)
#define AT91C_WRITE_MULTIPLE_BLOCK_CMD (25 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRCMD_START | (AT91C_MCI_TRTYP_MULTIPLE & ~(AT91C_MCI_TRDIR)) | AT91C_MCI_MAXLAT)
#define AT91C_PROGRAM_CSD_CMD (27 | AT91C_MCI_RSPTYP_48 )
//*----------------------------------------
//* Class 6 commands: Group Write protect
//*----------------------------------------
#define AT91C_SET_WRITE_PROT_CMD (28 | AT91C_MCI_RSPTYP_48 )
#define AT91C_CLR_WRITE_PROT_CMD (29 | AT91C_MCI_RSPTYP_48 )
#define AT91C_SEND_WRITE_PROT_CMD (30 | AT91C_MCI_RSPTYP_48 )
//*----------------------------------------
//* Class 5 commands: Erase commands
//*----------------------------------------
#define AT91C_TAG_SECTOR_START_CMD (32 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRCMD_NO | AT91C_MCI_MAXLAT)
#define AT91C_TAG_SECTOR_END_CMD (33 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRCMD_NO | AT91C_MCI_MAXLAT)
#define AT91C_MMC_UNTAG_SECTOR_CMD (34 | AT91C_MCI_RSPTYP_48 )
#define AT91C_MMC_TAG_ERASE_GROUP_START_CMD (35 | AT91C_MCI_RSPTYP_48 )
#define AT91C_MMC_TAG_ERASE_GROUP_END_CMD (36 | AT91C_MCI_RSPTYP_48 )
#define AT91C_MMC_UNTAG_ERASE_GROUP_CMD (37 | AT91C_MCI_RSPTYP_48 )
#define AT91C_ERASE_CMD (38 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRCMD_NO | AT91C_MCI_MAXLAT )
//*----------------------------------------
//* Class 7 commands: Lock commands
//*----------------------------------------
#define AT91C_LOCK_UNLOCK (42 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRCMD_NO | AT91C_MCI_MAXLAT) // not tested
//*-----------------------------------------------
// Class 8 commands: Application specific commands
//*-----------------------------------------------
#define AT91C_APP_CMD (55 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRCMD_NO | AT91C_MCI_MAXLAT)
#define AT91C_GEN_CMD (56 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRCMD_NO | AT91C_MCI_MAXLAT) // not tested
#define AT91C_SDCARD_SET_BUS_WIDTH_CMD (6 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRCMD_NO | AT91C_MCI_MAXLAT)
#define AT91C_SDCARD_STATUS_CMD (13 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRCMD_START | AT91C_MCI_TRTYP_BLOCK | AT91C_MCI_TRDIR | AT91C_MCI_MAXLAT)
#define AT91C_SDCARD_SEND_NUM_WR_BLOCKS_CMD (22 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRCMD_NO | AT91C_MCI_MAXLAT)
#define AT91C_SDCARD_SET_WR_BLK_ERASE_COUNT_CMD (23 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRCMD_NO | AT91C_MCI_MAXLAT)
#define AT91C_SDCARD_APP_OP_COND_CMD (41 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRCMD_NO )
#define AT91C_SDCARD_SET_CLR_CARD_DETECT_CMD (42 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRCMD_NO | AT91C_MCI_MAXLAT)
#define AT91C_SDCARD_SEND_SCR_CMD (51 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRCMD_NO | AT91C_MCI_MAXLAT)
#define AT91C_SDCARD_APP_ALL_CMD (AT91C_SDCARD_SET_BUS_WIDTH_CMD +\
AT91C_SDCARD_STATUS_CMD +\
AT91C_SDCARD_SEND_NUM_WR_BLOCKS_CMD +\
AT91C_SDCARD_SET_WR_BLK_ERASE_COUNT_CMD +\
AT91C_SDCARD_APP_OP_COND_CMD +\
AT91C_SDCARD_SET_CLR_CARD_DETECT_CMD +\
AT91C_SDCARD_SEND_SCR_CMD)
//*----------------------------------------
//* Class 9 commands: IO Mode commands
//*----------------------------------------
#define AT91C_MMC_FAST_IO_CMD (39 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_MAXLAT)
#define AT91C_MMC_GO_IRQ_STATE_CMD (40 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRCMD_NO | AT91C_MCI_MAXLAT)
//------------------------------------------------------------------------------
// Local functions
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
/// Sends the current SD card driver command to the card.
/// Returns 0 if successful; Otherwise, returns the transfer status code or
/// SD_ERROR_MCI if there was a problem with the MCI transfer.
/// \param pSd Pointer to a SdCard driver instance.
//------------------------------------------------------------------------------
static unsigned char SendCommand(SdCard *pSd)
{
MciCmd *pCommand = &(pSd->command);
unsigned char error;
// Send command
error = MCI_SendCommand(pSd->pMci, pCommand);
if (error) {
trace_LOG(trace_ERROR, "-E- SendCommand: Failed to send command (%d)\n\r", error);
return SD_ERROR_MCI;
}
// Wait for command to complete
while (!MCI_IsTxComplete(pCommand));
if(pCommand->cmd == AT91C_STOP_TRANSMISSION_CMD) {
while (MCI_CheckBusy(pSd->pMci) != 0);
}
// Delay between sending commands, only for MMC card test.
if((pSd->cardType == CARD_MMC)||(pSd->cardType == UNKNOWN_CARD)) {
int i;
for(i=0; i < MMC_DELAY; i++);
}
return pCommand->status;
}
//------------------------------------------------------------------------------
/// Initialization delay: The maximum of 1 msec, 74 clock cycles and supply ramp
/// up time.
/// Returns the command transfer result (see SendCommand).
/// \param pSd Pointer to a SdCard driver instance.
//------------------------------------------------------------------------------
static unsigned char Pon(SdCard *pSd)
{
MciCmd *pCommand = &(pSd->command);
memset(pCommand, 0, sizeof(MciCmd));
// Fill command information
pCommand->cmd = AT91C_POWER_ON_INIT;
// Set SD command state
pSd->state = SD_STATE_STBY;
// Send command
return SendCommand(pSd);
}
//------------------------------------------------------------------------------
/// Resets all cards to idle state.
/// Returns the command transfer result (see SendCommand).
/// \param pSd Pointer to a SdCard driver instance.
//------------------------------------------------------------------------------
static unsigned char Cmd0(SdCard *pSd)
{
MciCmd *pCommand = &(pSd->command);
memset(pCommand, 0, sizeof(MciCmd));
// Fill command information
pCommand->cmd = AT91C_GO_IDLE_STATE_CMD;
// Set SD command state
pSd->state = SD_STATE_STBY;
// send command
return SendCommand(pSd);
}
//------------------------------------------------------------------------------
/// MMC send operation condition command.
/// Returns the command transfer result (see SendCommand).
/// \param pSd Pointer to a SdCard driver instance.
//------------------------------------------------------------------------------
static unsigned char Cmd1(SdCard *pSd)
{
MciCmd *pCommand = &(pSd->command);
unsigned char error;
unsigned int response;
memset(pCommand, 0, sizeof(MciCmd));
// Fill command information
pCommand->cmd = AT91C_MMC_SEND_OP_COND_CMD;
pCommand->arg = AT91C_MMC_HOST_VOLTAGE_RANGE;
pCommand->resSize = 1;
pCommand->pResp = &response;
// Set SD command state
pSd->state = SD_STATE_STBY;
// send command
error = SendCommand(pSd);
if (error) {
return error;
}
if ((response & AT91C_CARD_POWER_UP_BUSY) == AT91C_CARD_POWER_UP_BUSY) {
return 0;
}
else {
return SD_ERROR_MCI;
}
}
//------------------------------------------------------------------------------
/// Asks to all cards to send the CID numbers.
/// Returns the command transfer result (see SendCommand).
/// \param pSd Pointer to a SD card driver instance.
/// \param pCid Buffer for storing the CID numbers.
//------------------------------------------------------------------------------
static unsigned char Cmd2(SdCard *pSd, unsigned int *pCid)
{
MciCmd *pCommand = &(pSd->command);
memset(pCommand, 0, sizeof(MciCmd));
// Fill the command information
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -