📄 sd.c
字号:
/*C**************************************************************************
* NAME: sd.c
*----------------------------------------------------------------------------
* Copyright (c) 2002 Atmel.
*----------------------------------------------------------------------------
* RELEASE: snd1c-demo-df-sd-3_0_0
* REVISION: 1.2
*----------------------------------------------------------------------------
* PURPOSE:
* This file contains the high level SD routines
*
* NOTES:
* Global Variables:
* - gl_ptr_mem: long in data space
*
* - Only SD or MMC card with block size = 512 bytes are accepted
*****************************************************************************/
/*_____ I N C L U D E S ____________________________________________________*/
#include "config.h" /* system configuration */
#include "lib_mcu\usb\usb_drv.h" /* usb driver definition */
#include "sd.h" /* SD definition */
/*_____ M A C R O S ________________________________________________________*/
/*_____ D E F I N I T I O N ________________________________________________*/
extern pdata Byte gl_buffer[];
extern data Uint32 gl_ptr_mem; /* memory data pointer */
extern data Byte gl_mem_tick; /* memory tick counter */
extern bdata bit gl_mem_failure; /* memory hardware failure */
static bdata bit sd_flag; /* memory flag (sd or mmc?) */
static idata Uint32 sd_rca; /* memory card relative address*/
static Byte sd_state;
static bit sd_mem_busy; /* memory in busy state */
idata Uint32 sd_mem_size; /* memory disk size in pages */
/*_____ D E C L A R A T I O N ______________________________________________*/
/*F**************************************************************************
* NAME: sd_init
*----------------------------------------------------------------------------
* PARAMS:
*
* return:
*----------------------------------------------------------------------------
* PURPOSE:
* SD/MMC initialisation
*----------------------------------------------------------------------------
* EXAMPLE:
*----------------------------------------------------------------------------
* NOTE:
*----------------------------------------------------------------------------
* REQUIREMENTS:
*****************************************************************************/
bit sd_init (void)
{
gl_mem_failure = FALSE;
sd_state = SD_INIT;
sd_mem_busy = FALSE; /* memory ready */
sd_flag = SD; /* Hyp: card is SD */
return OK;
}
/*F**************************************************************************
* NAME: sd_install
*----------------------------------------------------------------------------
* PARAMS:
*
* return:
*----------------------------------------------------------------------------
* PURPOSE:
* SD/MMC installation routine
*----------------------------------------------------------------------------
* EXAMPLE:
*----------------------------------------------------------------------------
* NOTE:
*----------------------------------------------------------------------------
* REQUIREMENTS:
*****************************************************************************/
Byte sd_install (void)
{
Byte func_state;
switch (sd_state & MMC_MSK_STATE)
{
case SD_INIT:
{
/* reset card stack */
sd_init_card();
sd_state = SD_ACQ;
gl_mem_tick = SD_FUNCT_TIME; /* init delay timer */
break;
}
case SD_ACQ:
{
if (gl_mem_tick >= SD_DELAY_TIME)
{
/* send operating conditions */
func_state = sd_acq_card();
if (func_state == SD_ERROR)
{
sd_state = SD_INIT;
return SD_ERROR;
}
else
{
if (func_state == SD_END) /* end of execution */
{ /* MMC1/2 or SD CSD is available now */
if (!sd_init_csd()) /* init & check card validity */
{
sd_state = SD_INIT;
return SD_ERROR;
}
else
{
sd_state = SD_SETUP;
}
}
gl_mem_tick = SD_FUNCT_TIME; /* init delay timer */
}
}
break;
}
case SD_SETUP:
{
if (gl_mem_tick >= SD_DELAY_TIME)
{ /* go to transfer state */
func_state = sd_setup_card();
if (func_state == SD_ERROR)
{
sd_state = SD_INIT;
return SD_ERROR;
}
else
{
if (func_state == SD_END) /* end of execution */
{
gl_mem_failure = FALSE;
sd_mem_busy = FALSE; /* memory ready */
sd_state = SD_INIT;
return SD_END; /* install done */
}
gl_mem_tick = SD_FUNCT_TIME; /* init delay timer */
}
}
break;
}
default:
{
sd_state = SD_INIT;
return SD_ERROR;
}
}
return SD_BUSY;
}
/*F**************************************************************************
* NAME: sd_init_csd
*----------------------------------------------------------------------------
* PARAMS:
*
* return:
* check status - OK: card supported by software
* - KO: card not supported by software
*----------------------------------------------------------------------------
* PURPOSE:
* Card validity checking, memory variable initialisation and
* controller data transfer mode initialisation
*----------------------------------------------------------------------------
* EXAMPLE:
*----------------------------------------------------------------------------
* NOTE:
* Card with block size != 512 are rejected
*----------------------------------------------------------------------------
* REQUIREMENTS:
*****************************************************************************/
bit sd_init_csd (void)
{
Byte tmp;
ACC = Mmc_rd_cmd(); /* dummy read of header */
ACC = Mmc_rd_cmd(); /* dummy read of CSD[0] */
ACC = Mmc_rd_cmd(); /* dummy read */
ACC = Mmc_rd_cmd(); /* dummy read */
ACC = Mmc_rd_cmd(); /* dummy read */
ACC = Mmc_rd_cmd(); /* dummy read */
if ((Mmc_rd_cmd() & CSD_MSK_RBL) != CSD_BLEN_512) /* check block length */
{ /* block size != 512 bytes not supported by firmware */
Mmc_reset_cmd_fifos(); /* reset pointers */
return KO;
}
else
{
Mmc_set_block_size(CSD_BLEN_512); /* init controller */
}
/* compute card size in number of block (block size = 512) */
/* read C_SIZE */
((Byte*)&sd_mem_size)[0] = 0;
((Byte*)&sd_mem_size)[1] = 0;
((Byte*)&sd_mem_size)[2] = Mmc_rd_cmd() & CSD_MSK_CSH;
((Byte*)&sd_mem_size)[3] = Mmc_rd_cmd();
sd_mem_size = sd_mem_size << 2;
((Byte*)&sd_mem_size)[3] |= ((Mmc_rd_cmd() & CSD_MSK_CSL) >> 6);
/* read C_SIZE_MULT */
tmp = Mmc_rd_cmd() << 1;
tmp = (tmp | (Mmc_rd_cmd() >> 7)) & CSD_MSK_CSM;
sd_mem_size = ((sd_mem_size + 1) << (tmp + 2));
sd_mem_size--;
Mmc_set_multi_block(); /* multi block mode transfer */
Mmc_enable_flow_ctrl(); /* start flow control */
Mmc_reset_cmd_fifos(); /* reset pointers */
return OK;
}
/*F**************************************************************************
* NAME: sd_init_card
*----------------------------------------------------------------------------
* PARAMS:
*
* return:
*----------------------------------------------------------------------------
* PURPOSE:
* Initialize MMC controller and reset card to idle state
*----------------------------------------------------------------------------
* EXAMPLE:
*----------------------------------------------------------------------------
* NOTE:
* This function is called when initializing stack for first time
*----------------------------------------------------------------------------
* REQUIREMENTS:
*****************************************************************************/
void sd_init_card (void)
{
gl_mem_failure = FALSE;
Mmc_set_read(); /* dir from card to uc */
Mmc_set_clock(SD_CLK_INIT); /* set SD/MMC clock to 400 KHz */
Mmc_enable();
Mmc_reset();
Mmc_reset_cmd_fifos();
Mmc_reset_data_fifos();
mmc_send_scmd(MMC_GO_IDLE_STATE, MMC_NO_RESP);
}
/*F**************************************************************************
* NAME: sd_acq_card
*----------------------------------------------------------------------------
* PARAMS:
*
* return:
* SD_BUSY: busy state
* SD_ERROR: state result KO
* SD_END: end of card acquisition
*----------------------------------------------------------------------------
* PURPOSE:
* Card acquisition
*----------------------------------------------------------------------------
* EXAMPLE:
*----------------------------------------------------------------------------
* NOTE:
* - This function must be called 5 or 6 times for completion depending on
* the busy card
* - Each call must be delayed enough to leave time for command
* transmission and response reception
* - By default, the memory card is a sd card. It checks the response to the
* CMD55 in idle state to determine wich card it is.
* - It does not take care of the DSR
* - At the end of this function CSD is in buffer
*
* STATES: SD_SINGLE_OP_COND send CMD55 for sd card by default
* SD_SIGNLE_OP_COND_2 send operating condition for sd or mmc
* SD_SINGLE_CID check busy and send CID or op cond again
* SD_SINGLE_SRA check CID response and set or send
* relative adress (mmc or sd)
* SD_SINGLE_CSD send CSD request
* SD_SINGLE_END check CSD reception
*----------------------------------------------------------------------------
* REQUIREMENTS:
*****************************************************************************/
Byte sd_acq_card (void)
{
Uint32 response;
switch (sd_state)
{
case SD_SINGLE_OP_COND: /* Card is SD Card by default */
{
mmc_send_cmd(MMC_APP_CMD, SD_RCA_DEFAULT, MMC_RESP_R1);
sd_state = SD_SINGLE_OP_COND_2;
return (SD_BUSY);
}
case SD_SINGLE_OP_COND_2: /* check if the card is SD */
{
if (mmc_check_response() == MMC_ERR_RESP) /* the card may be MMC */
{ /* sending MMC operation condition */
mmc_send_cmd(MMC_SEND_OP_COND, MMC_OCR_INIT, MMC_RESP_R3);
sd_state = SD_SINGLE_CID;
sd_flag = MMC;
return (SD_BUSY);
}
else
{
response = mmc_read_response(); /* the card is SD, next step for
sending SD operation condition */
mmc_send_cmd(SD_APP_OP_COND, MMC_OCR_INIT, MMC_RESP_R3);
sd_state = SD_SINGLE_CID;
sd_flag = SD;
return (SD_BUSY);
}
}
case SD_SINGLE_CID:
{
if (mmc_check_response() == MMC_ERR_RESP)
{
return (SD_ERROR); /* no response */
}
else
{
response = mmc_read_response();
if ((((Byte*)&response)[0] & MMC_BUSY_OCR) != MMC_BUSY_OCR)
{ /* at least one card is busy */
if (sd_flag == SD) /* connected card is sd */
{
mmc_send_cmd(MMC_APP_CMD, SD_RCA_DEFAULT, MMC_RESP_R1);
sd_state = SD_SINGLE_OP_COND_2;
}
else
{ /* connected card is mmc */
mmc_send_cmd(MMC_SEND_OP_COND, MMC_OCR_INIT, MMC_RESP_R3);
}
}
else
{
mmc_send_scmd(MMC_ALL_SEND_CID, MMC_RESP_R2);
sd_state = SD_SINGLE_SRA;
}
return (SD_BUSY);
}
}
case SD_SINGLE_SRA:
{
if (mmc_check_response() == MMC_ERR_RESP)
{
return (SD_ERROR); /* no response */
}
else
{
if (sd_flag == SD) /* connected card is sd */
{
mmc_send_scmd(SD_SEND_RELATIVE_ADDRESS, SD_RESP_R6);
}
else /* connected card is mmc */
{
mmc_send_cmd(MMC_SET_RELATIVE_ADDRESS, MMC_RCA, MMC_RESP_R1);
}
sd_state = SD_SINGLE_CSD;
return (SD_BUSY);
}
}
case SD_SINGLE_CSD:
{
if (mmc_check_response() == MMC_ERR_RESP)
{
return (SD_ERROR); /* no response */
}
else
{
if (sd_flag == SD) /* connected card is sd */
{
response = mmc_read_response();
sd_rca = response >> 16;
sd_rca = sd_rca << 16;
sd_rca = sd_rca | 0x0000FFFF;
mmc_send_cmd(MMC_SEND_CSD, sd_rca, MMC_RESP_R2);
}
else /* connected card is mmc */
{
mmc_send_cmd(MMC_SEND_CSD, MMC_RCA, MMC_RESP_R2);
}
sd_state = SD_SINGLE_END;
return (SD_BUSY);
}
}
case SD_SINGLE_END:
{
if (mmc_check_response() == MMC_ERR_RESP)
{
return (SD_ERROR); /* no response */
}
else
{
Mmc_set_clock(SD_CLK_TRANS); /* set SD clock to transfer */
Mmc_set_multi_block(); /* multi block transfer */
return (SD_END);
}
}
}
}
/*F**************************************************************************
* NAME: sd_setup_card
*----------------------------------------------------------------------------
* PARAMS:
*
* return:
* SD_BUSY: busy state
* SD_ERROR: state result KO
* SD_END: end of setup execution
*----------------------------------------------------------------------------
* PURPOSE:
* Select the corresponding card
*----------------------------------------------------------------------------
* EXAMPLE:
*----------------------------------------------------------------------------
* NOTE:
* - This function must be called at least 2 times for completion
* - Each call must be delayed enough to leave time for command
* transmission and response reception
* - Contrary to what is written in MMC spec, the request CSD can
* not be done in transfer state
*
* STATES: SD_SETUP_SELECT select card
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -