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

📄 sd_controller.c

📁 在开发FPGA上比较有用
💻 C
📖 第 1 页 / 共 3 页
字号:
      card_status = ( IORD_32DIRECT( sd_card->base_addr, SD_COMMAND_RESP0_OFFSET ) >> 8 ) & 0xFF;
    else // SD_R3
      card_status = IORD_32DIRECT( sd_card->base_addr, SD_COMMAND_RESP1_OFFSET ) & 0xFF;
      
    // If the SD card status is what we expect, we're done.  If not, we re-issue
    // the command until either we get the expected response, or we time out
    if( card_status == sd_cmd[command].status_expected )
      break;
  }

  if( cmd_attempts == MAX_COMMAND_ATTEMPTS )
    ret_code |= COMMAND_TIMEOUT;
  
    // If we received data, check the CRC.
  if(( !ret_code ) && ( sd_cmd[command].receives_data ))
  {
    crc_rec = IORD_16DIRECT( sd_card->base_addr, SD_DATA_CRC_OFFSET );
    crc_calc = calc_crc16( (alt_u8*)(sd_card->data_buff_base_addr), ( sd_cmd[command].data_words << 2 ));
    if( crc_calc != crc_rec )
      ret_code |= CRC_MISMATCH;
  }  
 
  return( ret_code );
}

/*****************************************************************************
*  Function: sd_init_command_struct
*
*  Purpose: Initializes the structure we use to store SD Card commands.  These
*           commands are used anytime we interface directly with the SD Card.
*
*  Returns: void
*   
*****************************************************************************/
void sd_init_command_struct( void )
{
  //  GO_IDLE_STATE
  sd_cmd[GO_IDLE_STATE].command_id = SD_CMD0_ID;
  sd_cmd[GO_IDLE_STATE].response_type = SD_R1;
  sd_cmd[GO_IDLE_STATE].response_length = R1_LENGTH;
  sd_cmd[GO_IDLE_STATE].data_words = 0;
  sd_cmd[GO_IDLE_STATE].status_expected = 0x01;
  sd_cmd[GO_IDLE_STATE].receives_data = 0;  
  sd_cmd[GO_IDLE_STATE].sends_data = 0;  
  
  //  OP_COND
  sd_cmd[OP_COND].command_id = SD_CMD1_ID;
  sd_cmd[OP_COND].response_type = SD_R1;
  sd_cmd[OP_COND].response_length = R1_LENGTH;
  sd_cmd[OP_COND].data_words = 0;
  sd_cmd[OP_COND].status_expected = 0x00;
  sd_cmd[OP_COND].receives_data = 0;  
  sd_cmd[OP_COND].sends_data = 0;  
  
  //  SEND_CSD
  sd_cmd[SEND_CSD].command_id = SD_CMD9_ID;
  sd_cmd[SEND_CSD].response_type = SD_R1;
  sd_cmd[SEND_CSD].response_length = R1_LENGTH;
  sd_cmd[SEND_CSD].data_words = CSD_REG_LENGTH;
  sd_cmd[SEND_CSD].status_expected = 0x00;
  sd_cmd[SEND_CSD].receives_data = 1;  
  sd_cmd[SEND_CSD].sends_data = 0;  

  //  SEND_CID
  sd_cmd[SEND_CID].command_id = SD_CMD10_ID;
  sd_cmd[SEND_CID].response_type = SD_R1;
  sd_cmd[SEND_CID].response_length = R1_LENGTH;
  sd_cmd[SEND_CID].data_words = CID_REG_LENGTH;
  sd_cmd[SEND_CID].status_expected = 0x00;
  sd_cmd[SEND_CID].receives_data = 1;  
  sd_cmd[SEND_CID].sends_data = 0;  
  
  //  SEND_STATUS
  sd_cmd[SEND_STATUS].command_id = SD_CMD13_ID;
  sd_cmd[SEND_STATUS].response_type = SD_R2;
  sd_cmd[SEND_STATUS].response_length = R2_LENGTH;
  sd_cmd[SEND_STATUS].data_words = 0;
  sd_cmd[SEND_STATUS].status_expected = 0x00;
  sd_cmd[SEND_STATUS].receives_data = 0;  
  sd_cmd[SEND_STATUS].sends_data = 0;  

  //  SET_BLOCKLEN
  sd_cmd[SET_BLOCKLEN].command_id = SD_CMD16_ID;
  sd_cmd[SET_BLOCKLEN].response_type = SD_R1;
  sd_cmd[SET_BLOCKLEN].response_length = R1_LENGTH;
  sd_cmd[SET_BLOCKLEN].data_words = 0;
  sd_cmd[SET_BLOCKLEN].status_expected = 0x00;
  sd_cmd[SET_BLOCKLEN].receives_data = 0;  
  sd_cmd[SET_BLOCKLEN].sends_data = 0;  

  //  READ_SINGLE_BLOCK
  sd_cmd[READ_SINGLE_BLOCK].command_id = SD_CMD17_ID;
  sd_cmd[READ_SINGLE_BLOCK].response_type = SD_R1;
  sd_cmd[READ_SINGLE_BLOCK].response_length = R1_LENGTH;
  sd_cmd[READ_SINGLE_BLOCK].data_words = SD_DEFAULT_BLOCK_LENGTH / 4;
  sd_cmd[READ_SINGLE_BLOCK].status_expected = 0x00;
  sd_cmd[READ_SINGLE_BLOCK].receives_data = 1;  
  sd_cmd[READ_SINGLE_BLOCK].sends_data = 0;  
  
  //  WRITE_BLOCK
  sd_cmd[WRITE_BLOCK].command_id = SD_CMD24_ID;
  sd_cmd[WRITE_BLOCK].response_type = SD_R1;
  sd_cmd[WRITE_BLOCK].response_length = R1_LENGTH;
  sd_cmd[WRITE_BLOCK].data_words = SD_DEFAULT_BLOCK_LENGTH / 4;
  sd_cmd[WRITE_BLOCK].status_expected = 0x00;
  sd_cmd[WRITE_BLOCK].receives_data = 0;  
  sd_cmd[WRITE_BLOCK].sends_data = 1;  
  
  //  READ_OCR
  sd_cmd[READ_OCR].command_id = SD_CMD58_ID;
  sd_cmd[READ_OCR].response_type = SD_R3;
  sd_cmd[READ_OCR].response_length = R3_LENGTH;
  sd_cmd[READ_OCR].data_words = 0;
  sd_cmd[READ_OCR].status_expected = 0x00;
  sd_cmd[READ_OCR].receives_data = 0;  
  sd_cmd[READ_OCR].sends_data = 0;  
}  


/*****************************************************************************
*  Function: sd_parse_cid_register
*
*  Purpose: Parses through a response to the SEND_CID command, pulls out the
*           relevant info and inserts it into the sd_card structure.
*
*  Returns: 0
*   
*****************************************************************************/
int sd_parse_cid_register( sd_card_info_struct* sd_card, alt_u8* buff )
{
  int i, j;
  
  sd_card->mfg_id = buff[0];
  
  for( i = 0, j = 1; i < 2; i++, j++ )
    sd_card->oem_id[i] = buff[j];
  sd_card->oem_id[2] = '\0';

  for( i = 0, j = 3; i < 5; i++, j++ )
    sd_card->product_name[i] = buff[j];
  sd_card->product_name[5] = '\0';
  
  sd_card->product_revision = buff[8];

  sd_card->serial_num = buff[9] << 24 |
                        buff[10] << 16 |
                        buff[11] << 8  |
                        buff[12] << 0  ;
                        
  sd_card->mfg_date_code = buff[13] << 8 |
                           buff[14] << 0 ;
    
  return 0;
}  

/*****************************************************************************
*  Function: sd_parse_csd_register
*
*  Purpose: Parses through a response to the SEND_CSD command, pulls out the
*           relevant info and inserts it into the sd_card structure.
*
*  Returns: 0 -     success
*           non-0 - failure
*   
*****************************************************************************/
int sd_parse_csd_register( sd_card_info_struct* sd_card, alt_u8* buff )
{
  alt_u8 csd_read_bl_len, csd_tran_speed, i;
  alt_u32 csd_c_size, csd_c_size_mult, mult;
  int ret_code = 0;
  
  // Get the read block size
  csd_read_bl_len = buff[5] & 0x0F;

  // Block size is 2 ^ block_size_code
  sd_card->read_block_length = 1;
  for( i = 0; i < csd_read_bl_len; i++ )
    sd_card->read_block_length *= 2;
  
  // Get the capacity of the card
  csd_c_size = buff[6] << 16 |
               buff[7] << 8  |
               buff[8] << 0  ;
  csd_c_size = (( csd_c_size >> 6 ) & 0xFFF );        
  
  csd_c_size_mult = buff[9] << 8 |
                    buff[10] << 0 ;
  csd_c_size_mult = (( csd_c_size_mult >> 7 ) & 0x7 );
  
  // mult is 2 ^ (csd_c_size_mult + 2)
  for( i = 0, mult = 1; i < ( csd_c_size_mult + 2 ); i++ )
    mult *= 2;
  
  sd_card->capacity = (( csd_c_size + 1 ) * mult * sd_card->read_block_length );
  
  // Get max clock rate
  csd_tran_speed = buff[3];
  mult = csd_tran_speed & 0x7;
  csd_tran_speed >>= 3;
 
// mult: 0=100kbit/s, 1=1Mbit/s, 2=10Mbit/s, 3=100Mbit/s 
  // To avoid using floats in the next step, we divide all these by 10
  switch ( mult )
  {
    case 0: mult = 10000;     // 100000 / 10
      break;
    case 1: mult = 100000;    // 1000000 / 10
      break;
    case 2: mult = 1000000;   // 10000000 / 10
      break;
    case 3: mult = 10000000;  // 100000000 / 10
      break;
    default: ret_code |= BAD_MAX_CLK;
  }
    
  // 1=1.0, 2=1.2, 3=1.3, 4=1.5, 5=2.0, 6=2.5, 7=3.0,
  // 8=3.5, 9=4.0, A=4.5, B=5.0, C=5.5, D=6.0, E=7.0, F=8.0
  // To avoid floats, our mult has been divided by 10, so we can 
  // multiply our decimal values here by 10
  switch ( csd_tran_speed )
  {
    case 0x1: sd_card->max_clk_rate = ( 10 * mult ); // 1.0
      break;
    case 0x2: sd_card->max_clk_rate = ( 12 * mult ); // 1.2
      break;
    case 0x3: sd_card->max_clk_rate = ( 13 * mult ); // 1.3
      break;
    case 0x4: sd_card->max_clk_rate = ( 15 * mult ); // 1.5
      break;
    case 0x5: sd_card->max_clk_rate = ( 20 * mult ); // 2.0
      break;
    case 0x6: sd_card->max_clk_rate = ( 25 * mult ); // 2.5
      break;
    case 0x7: sd_card->max_clk_rate = ( 30 * mult ); // 3.0
      break;
    case 0x8: sd_card->max_clk_rate = ( 35 * mult ); // 3.5
      break;
    case 0x9: sd_card->max_clk_rate = ( 40 * mult ); // 4.0
      break;
    case 0xA: sd_card->max_clk_rate = ( 45 * mult ); // 4.5
      break;
    case 0xB: sd_card->max_clk_rate = ( 50 * mult ); // 5.0
      break;
    case 0xC: sd_card->max_clk_rate = ( 55 * mult ); // 5.5
      break;
    case 0xD: sd_card->max_clk_rate = ( 60 * mult ); // 6.0
      break;
    case 0xE: sd_card->max_clk_rate = ( 70 * mult ); // 7.0
      break;
    case 0xF: sd_card->max_clk_rate = ( 80 * mult ); // 8.0
      break;
    default: ret_code |= BAD_MAX_CLK;
  }
    
  return( ret_code );
}


/*****************************************************************************
*  Function: sd_print_card_info
*
*  Purpose: Prints all the SD Card info gathered from the SEND_CID and 
*           SEND_CSD commands
*
*  Returns: void
*   
*****************************************************************************/
void sd_print_card_info( sd_card_info_struct* sd_card )
{
  int month, year;
  printf("\n+-------------------- SD Card Info --------------------+\n" );
  printf("|                                                      |\n" );
  printf("|     Manufacturer ID:   %2.2X                            |\n", sd_card->mfg_id );
  printf("|     OEM ID:            %s                            |\n", sd_card->oem_id );
  printf("|     Product Name:      %s                         |\n", sd_card->product_name );
  printf("|     Product Revision:  0x%2.2X                          |\n", sd_card->product_revision );
  printf("|     Serial Number:     %8.8X                      |\n", (int)(sd_card->serial_num) );
  month = sd_card->mfg_date_code & 0x000F;
  year = 2000 + ( sd_card->mfg_date_code >> 4 );
  printf("|     Manufacture Date:  %d-%d                       |\n", month, year);
//  printf("|     RCA:               0x%8.8X                    |\n", sd_card->rca );  // Not used in SPI mode.
  printf("|     Max Clock Rate:    %2d MHz                        |\n", (int)(sd_card->max_clk_rate) / 1000000 );
  printf("|     Capacity:          %10d bytes              |\n", (int)(sd_card->capacity) );
  printf("|     Read Block Length: %d bytes                     |\n", (int)(sd_card->read_block_length) );
  printf("+------------------------------------------------------+\n" );
  
}

/*****************************************************************************
*  Function: calc_crc16
*
*  Purpose: Calculates a CRC16 value from a block of data.
*
*  Returns: CRC16 value
*   
*****************************************************************************/
alt_u16 calc_crc16( alt_u8* data, alt_u32 length )
{
  alt_u8 xor_flag;
  alt_u16 crc = 0;
  alt_u16 data_byte;
  int bit_index, byte_index;

  for( byte_index = 0; byte_index < length; byte_index++ )
  {
    data_byte = (alt_u16)data[byte_index];
    data_byte <<= 8;
    for ( bit_index = 0; bit_index < 8; bit_index++ )
    {
      if ((crc ^ data_byte) & 0x8000)
      {
        xor_flag = 1;
      }
      else
      {
        xor_flag = 0;
      }
      crc = crc << 1;
      if (xor_flag)
      {
        crc = crc ^ 0x1021; 
      }
      data_byte = data_byte << 1;
    }
  }
  return( crc );
}


/*****************************************************************************
*  Function: calc_crc7
*
*  Purpose: Calculates a CRC7 value from a block of data.
*
*  Returns: CRC7 value
*   
*****************************************************************************/
alt_u8 calc_crc7( alt_u8* data, alt_u32 length )
{
  int bit_index, byte_index;
  alt_u8 data_byte;
  alt_u8 crc = 0;
  
  for( byte_index = 0; byte_index < length; byte_index++ )
  {
    data_byte = data[byte_index];
    for( bit_index = 0; bit_index < 8; bit_index++ )
    {
      crc = crc << 1;
      if(( crc ^ data_byte ) & 0x80 )
        crc = crc ^ 0x09;
      data_byte <<= 1;
    }
    // Mask off the MSB of the 7-bit crc
    crc = crc & 0x7f; 
  }
  
  return( crc );
}

                          

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -