📄 sd_controller.c
字号:
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 + -