📄 mmc_sd.c
字号:
//! @file mmc_sd.c,v
//!
//! Copyright (c) 2004 Atmel.
//!
//! Please read file license.txt for copyright notice.
//!
//! @brief This file contains the MMC SD driver routines
//!
//! @version 1.25 snd3-refd1-1_9_5 $Id: mmc_sd.c,v 1.25 2007/10/29 15:36:21 sguyon Exp $
//!
//! @todo
//! @bug
//_____ I N C L U D E S ___________________________________________________
#include "config.h"
#include "mmc_sd.h"
#include "conf\conf_access.h"
#include "lib_mcu\timer\timer_drv.h"
#include "lib_system\timer_soft\timer_soft.h"
#if ( MEM_MMC != DISABLED )
//_____ M A C R O S ________________________________________________________
//#define READ_EXT_CSD
#ifndef MMC_CARD_SECU_FUNC
#error MMC_CARD_SECU_FUNC must be defined in conf_mmc.h
#define MMC_CARD_SECU_FUNC (DISABLE)
#endif
//_____ D E C L A R A T I O N ______________________________________________
// Variable to manage the specification of the card
Bool b_card_ready = CARD_UNINSTALLED;
Bool b_card_access_run;
Bool b_flag_change_detected = FALSE;
_MEM_TYPE_SLOW_ U8 g_u8_card_type;
_MEM_TYPE_SLOW_ U32 g_u32_card_rca;
_MEM_TYPE_SLOW_ U32 g_u32_card_size;
_MEM_TYPE_SLOW_ U16 g_u16_card_freq;
// Variables to manage a standby/restart access
_MEM_TYPE_SLOW_ U32 g_u32_save_addr;
_MEM_TYPE_SLOW_ U16 g_u16_save_nb_sector;
_MEM_TYPE_SLOW_ U16 g_u16_nb_sector;
_MEM_TYPE_SLOW_ U32 g_u32_addr;
Bool mmcsd_read_csd ( void );
Bool mmc_read_ext_csd ( void );
Bool mmc_state_change_check( void );
Ctrl_status mmc_dfc_state ( void );
Ctrl_status mmc_dfc_stop ( void );
Ctrl_status mmc_open_read ( U32 adr, U16 nb_sector );
Ctrl_status mmc_open_write ( U32 adr, U16 nb_sector );
Bool mmc_set_block_len ( U16 length );
Bool mmc_cmd_send_status ( void );
//! This function initialises the card
//!
//! @return Ctrl_status
//!
//! an error occure -> CTRL_FAIL
//! init in progress -> CTRL_NO_PRESENT
//! last step -> CTRL_BUSY
//! init finished -> CTRL_GOOD
//!
Ctrl_status mmc_sd_install_card( void )
{
U32 u32_response;
if( CARD_UNINSTALLED != b_card_ready )
return CTRL_GOOD;
//*** So install the card (MMC, SD, SD HC) ****
g_u8_card_type = 0;
b_card_access_run = FALSE;
// init mmc controler
mmc_drv_on();
// apply clock in case of a previous command is always running on card
Mmc_force_clk();
{
_MEM_TYPE_SLOW_ U32 timer = Timer_set_timer( TIMER_MS( 50 ));
while( !Timer_is_timeout( timer ));
}
Mmc_unforce_clk();
//** (CMD0)
// Set card in idle state
mmc_drv_send_cmd( MMC_GO_IDLE_STATE, 0xFFFFFFFF, MMC_NO_RESP );
mmc_sd_init_step1:
//** (CMD1)
// To send its Operating Conditions Register contents command only supported by MMC card
if( mmc_drv_send_cmd( MMC_SEND_OP_COND, OCR_MSK_VOLTAGE_ALL, MMC_RESP_R3 ))
{
// MMC cards always respond to MMC_SEND_OP_COND
g_u8_card_type = CARD_MMC;
if( !( mmc_drv_read_response()& OCR_MSK_BUSY ))
{
// here card busy, it did not completed its initialization process
// resend command MMC_SEND_OP_COND
goto mmc_sd_init_step1; // loop until it is ready
}
}
else
{
// SD cards do not respond to MMC_SEND_OP_COND
g_u8_card_type = CARD_SD;
// Reset MMC data fifo
//** (CMD8)
// enables to expand new functionality to some existing commands supported only by SD HC card
if( mmc_drv_send_cmd( SD_SEND_IF_COND, 0x000001AA, MMC_RESP_R1 ))
{
// It is a SD HC
if( 0x000001AA == mmc_drv_read_response())
{
g_u8_card_type |= CARD_SD_V2;
}
}
// Reset MMC data fifo
mmc_sd_init_step2:
//** (CMD55)
// Indicates to the card that the next command is an application specific command rather than a standard command
// CMD55 shall always precede ACMD41
if( !mmc_drv_send_cmd( MMC_APP_CMD, 0, MMC_RESP_R1 ))
return CTRL_FAIL;
//** (ACMD41)
// Sends host OCR register
if( CARD_SD_V2 & g_u8_card_type )
{
// Sends host capacity support information (HCS)
if( !mmc_drv_send_cmd( SD_APP_OP_COND, OCR_MSK_BUSY | OCR_MSK_VOLTAGE_3_2V_3_3V | OCR_MSK_HC, MMC_RESP_R3 ))
return CTRL_FAIL;
}
else
{
if( !mmc_drv_send_cmd( SD_APP_OP_COND, OCR_MSK_BUSY | OCR_MSK_VOLTAGE_3_2V_3_3V, MMC_RESP_R3 ))
return CTRL_FAIL;
}
u32_response = mmc_drv_read_response();
if( !( u32_response & OCR_MSK_BUSY ))
{
// Card Busy, resend ACMD41 precede of CMD55
goto mmc_sd_init_step2;
}
// Card read then check HC type
if( u32_response & OCR_MSK_HC )
g_u8_card_type |= CARD_SD_HC; // Card SD High Capacity
}
// Here card ready and type (MMC, SD V1, SD V2 HC) detected
//** (CMD2)
// Send CID
if( !mmc_drv_send_cmd( MMC_ALL_SEND_CID, 0 , MMC_RESP_R2 ))
return CTRL_FAIL;
//** (CMD3)
// Set relative address
if( CARD_MMC & g_u8_card_type )
{
// For MMC card, you send a address to card
g_u32_card_rca = RCA_DEFAULT_ADR;
if( !mmc_drv_send_cmd( MMC_SET_RELATIVE_ADDRESS, RCA_DEFAULT_ADR, MMC_RESP_R1 ))
return CTRL_FAIL;
}
else
{
// For SD card, you ask a address to card
if( !mmc_drv_send_cmd( MMC_SET_RELATIVE_ADDRESS, RCA_RESERVE_ADR, MMC_RESP_R1 ))
return CTRL_FAIL;
}
if( CARD_SD & g_u8_card_type )
{
// For SD card, you receiv address of card
g_u32_card_rca = mmc_drv_read_response() & RCA_MSK_ADR ;
}
//** (CMD9)
// Read & analyse CSD register
if( !mmcsd_read_csd())
return CTRL_FAIL;
//** (CMD7)
// select card
if( !mmc_drv_send_cmd( MMC_SELECT_CARD, g_u32_card_rca, MMC_RESP_R1 ))
return CTRL_FAIL;
// Wait end of busy
mmc_wait_busy_signal();
// Get clock by checking the extended CSD register
if( CARD_MMC_V4 & g_u8_card_type )
{
// only for MMC and appeared from V4.0 specification ??
#ifdef READ_EXT_CSD
//** (CMD8)
if( !mmc_read_ext_csd())
return FALSE;
#else
g_u16_card_freq = MMC_CLK_26M; // default frequency for V4.0 cards
#endif //READ_EXT_CSD
}
#if( SD_4_BIT == ENABLE )
// set bus size
if( CARD_SD & g_u8_card_type )
{
// set 4-bit bus for SD Card
//** (CMD55)
if( !mmc_drv_send_cmd( MMC_APP_CMD, g_u32_card_rca, MMC_RESP_R1 ))
return CTRL_FAIL;
//** (CMD6)
if( !mmc_drv_send_cmd( SD_APP_SET_BUS_WIDTH, SD_BUS_4_BIT, MMC_RESP_R1 ))
return CTRL_FAIL;
Mmc_set_bus_size(MMC_BUS_SIZE_4_BIT);
}
else
{
// set 4-bit bus for MMC Card
if( CARD_MMC_V4 & g_u8_card_type )
{
//** (CMD6)
// set 4-bit bus width (appeared from V4.0 specification)
if( !mmc_drv_send_cmd( MMC_SWITCH,
((U32)MMC_SWITCH_WRITE <<24)|
((U32)MMC_SWITCH_BUS_WIDTH<<16)|
((U32)MMC_SWITCH_VAL_4BIT << 8)|
((U32)MMC_SWITCH_CMD_SET ),
MMC_RESP_R1 ))
{
return CTRL_FAIL;
}
mmc_wait_busy_signal();
Mmc_set_bus_size( MMC_BUS_SIZE_4_BIT );
//** (CMD6)
// set high speed interface timing
if( !mmc_drv_send_cmd( MMC_SWITCH,
((U32)MMC_SWITCH_WRITE <<24)|
((U32)MMC_SWITCH_HIGH_SPEED<<16)|
((U32)MMC_SWITCH_VAL_HS << 8)|
((U32)MMC_SWITCH_CMD_SET ),
MMC_RESP_R1 ))
{
return CTRL_FAIL;
}
mmc_wait_busy_signal(); // read busy state on DAT0
}
}
#endif
// Set clock
clk_mmc_set_freq( g_u16_card_freq );
//** (CMD13)
// Check if card is ready, the card must be in TRAN state
if( !mmc_cmd_send_status())
return CTRL_FAIL;
if (( mmc_drv_read_response() & MMC_TRAN_STATE_MSK) != MMC_TRAN_STATE)
return CTRL_FAIL;
//** (CMD16)
// Set the card block length to 512B
if( !mmc_set_block_len( MMC_BLOCK_LENGTH_512B ))
return CTRL_FAIL;
// USB Unit Attention requires a control busy
// otherwise never report card change
b_card_ready = CARD_INSTALLED;
return CTRL_BUSY;
}
//! This function reads the CSD V1 & V2 and extract some information
//!
//! PURPOSE:
//! - Card validity checking,
//! - memory variable initialisation
//!
//! @return g_u16_card_freq
//! g_u32_card_size
//!
//! @return FALSE, card not supported
//! @return TRUE, card supported
//!
Bool mmcsd_read_csd( void )
{
_MEM_TYPE_SLOW_ U8 csd[ CSD_REG_SIZE ];
U8 tmp;
code U16 freq_unit[ 4 ] = { 10, 100, 1000, 10000 };
code U8 mult_fact[ 16 ] = { 0, 10, 12, 13, 15, 20, 26, 30, 35, 40, 45, 52, 55, 60, 70, 80 };
// code U8 mult_fact_sd[ 16 ] = { 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 };
//** (CMD9)
if( !mmc_drv_send_cmd( MMC_SEND_CSD, g_u32_card_rca , MMC_RESP_R2 ))
return FALSE;
//** Fill table CSD
for( tmp = 0; tmp < CSD_REG_SIZE ; tmp++ )
{
csd[ tmp ] = XBYTE[ SDCIF_REGBASE + 0x20 + tmp ];
}
//** Read "System specification version", only available on MMC card
// field: SPEC_VERS (only on MMC)
if( CARD_MMC & g_u8_card_type )
{
if( CSD_SPEC_VER_4_0 == ( csd[0] & CSD_MSK_SPEC_VER ))
{
g_u8_card_type |= CARD_MMC_V4;
}
}
//** Compute MMC/SD speed
// field: TRAN_SPEED (CSD V1 & V2 are the same)
g_u16_card_freq = mult_fact[(( csd[3] & 0x78) >> 3) ]; // Get Multiplier factor
if( CARD_SD & g_u8_card_type )
{
// SD card don't have same frequency that MMC card
if( 26 == g_u16_card_freq )
g_u16_card_freq = 25;
if( 52 == g_u16_card_freq )
g_u16_card_freq = 50;
}
g_u16_card_freq *= freq_unit[ csd[ 3 ]& 0x07 ]; // Get transfer rate unit
//** Compute card size in number of block
// field: WRITE_BL_LEN, READ_BL_LEN, C_SIZE (CSD V1 & V2 are not the same)
if( CARD_SD_HC & g_u8_card_type )
{
// Block size is fixed at 512B
// As the maximum capacity of the Physical Layer Specification Version 2.00 is 32 GB, the upper 6 bits of C_SIZE shall be set to 0.
// memory capacity = (C_SIZE+1) * 512K byte
MSB0( g_u32_card_size ) = 0;
MSB1( g_u32_card_size ) = 0;
MSB2( g_u32_card_size ) = csd[ 8 ];
MSB3( g_u32_card_size ) = csd[ 9 ];
// memory capacity = (C_SIZE+1) * 1K sector
g_u32_card_size = ( g_u32_card_size + 1 ) << 10; // unit 512B
}
else
{
// Check block size
tmp = (( csd[ 12 ]& CSD_MSK_WBL )<< 2 )|( csd[ 13 ]>> 6 ); // WRITE_BL_LEN
if( tmp < CSD_BLEN_512 )
return FALSE; // block size < 512B not supported by firmware
tmp = ( csd[ 5 ] & CSD_MSK_RBL ); // READ_BL_LEN
if( tmp < CSD_BLEN_512 )
return FALSE; // block size < 512B not supported by firmware
// Compute card size
MSB0( g_u32_card_size ) = 0;
MSB1( g_u32_card_size ) = csd[ 6 ] & CSD_MSK_CSH;
MSB2( g_u32_card_size ) = csd[ 7 ];
MSB3( g_u32_card_size ) = csd[ 8 ] & CSD_MSK_CSL;
g_u32_card_size = g_u32_card_size >> 6;
tmp -= CSD_BLEN_512;
tmp += ( csd[ 9 ]& CSD_MSK_CSMH ) * 2;
tmp += ( csd[ 10 ] >> 7 ); // get C_SIZE_MULT
g_u32_card_size = (( g_u32_card_size + 1 ) << ( tmp + 2 ));
}
return TRUE;
}
//! This function reads the extended CSD and extracts some information
//!
//! PURPOSE:
//! - Card type
//!
//! @return g_u16_card_freq
//!
#ifdef READ_EXT_CSD
Bool mmc_read_ext_csd( void )
{
U8 i;
Mmc_set_block_size(MMC_BLOCK_LENGTH_512B); // Ext CSD = 512B size
Mmc_set_read(); // set data dir in reception
Mmc_enable_data(); // enable data reception after response has been received
Mmc_set_single_block(); // enable single block data format
Mmc_reset_data_fifos();
//** (CMD8)
// read the extended CSD
if( !mmc_drv_send_cmd( MMC_SEND_EXT_CSD, 0 , MMC_RESP_R1 ))
return FALSE;
// READ_EXT_CSD // discard the 195 first bytes
for (i = (512L/8); i!=0; i--)
{
while (Mmc_fifo_8bytes_not_available()); // non blocking while
ACC = Mmc_rd_byte();
ACC = Mmc_rd_byte();
ACC = Mmc_rd_byte();
if( (64-24) == i )
{ // Read byte at offset 196
if( Mmc_rd_byte() & 0x02 )
g_u16_card_freq = MMC_CLK_52M;
else
g_u16_card_freq = MMC_CLK_26M;
}else{
ACC = Mmc_rd_byte();
}
ACC = Mmc_rd_byte();
ACC = Mmc_rd_byte();
ACC = Mmc_rd_byte();
ACC = Mmc_rd_byte();
}
return TRUE;
}
#endif //READ_EXT_CSD
//! This function tests the state of memory, and start the initialisation of the memory
//!
//! @return Ctrl_status
//! It is ready -> CTRL_GOOD
//! Memory unplug -> CTRL_NO_PRESENT
//! Not initialize or change -> CTRL_BUSY
//! A error occur -> CTRL_FAIL
//!
Ctrl_status mmc_test_unit_ready(void)
{
//if( mmc_state_change_check())
//return CTRL_NO_PRESENT; // card has been removed or inserted, then uninstall previous card
if( Mmc_card_not_present())
{
// card has been removed, then uninstall previous card
b_card_ready = CARD_UNINSTALLED;
mmc_drv_off();
return CTRL_NO_PRESENT;
}
// card is present
if( CARD_INSTALLED == b_card_ready )
return CTRL_GOOD; // install done
// if install is not done, then do it
return mmc_sd_install_card();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -