⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mmc_sd.c

📁 mp3播放器
💻 C
📖 第 1 页 / 共 2 页
字号:
//! @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 + -