📄 sd_controller.c
字号:
/*****************************************************************************
* Function: sd_close_wrapper
*
* Purpose: We use this wrapper as the callback function from the
* HAL "close()" system call. Since that API uses file
* descriptor pointers instead of integer file descriptors,
* we need to retrieve our integer file descriptor from
* the fd->priv pointer. We call the FAT function
* rb_fat_close() to close the file.
*
* Returns: value returned from rb_fat_close (should be 0)
*
*****************************************************************************/
int sd_close_wrapper( alt_fd* fd )
{
int ret_code;
int temp_fd = *((int*)(fd->priv));
ret_code = rb_fat_close( temp_fd );
free( fd->priv );
return( ret_code );
}
/*****************************************************************************
* Function: sd_close_wrapper
*
* Purpose: We use this wrapper as the callback function from the
* HAL "write()" system call. Since that API uses file
* descriptor pointers instead of integer file descriptors,
* we need to retrieve our integer file descriptor from
* the fd->priv pointer. We call the FAT function
* rb_fat_write() to close the file.
*
* Returns: Value returned from rb_fat_write (should be number of
* bytes written)
*
*****************************************************************************/
ssize_t sd_write_wrapper( alt_fd* fd, const void* buf, size_t count )
{
int ret_code;
int temp_fd = *((int*)(fd->priv));
ret_code = rb_fat_write( temp_fd, buf, count );
return( ret_code );
}
/*****************************************************************************
* Function: sd_read_wrapper
*
* Purpose: We use this wrapper as the callback function from the
* HAL "read()" system call. Since that API uses file
* descriptor pointers instead of integer file descriptors,
* we need to retrieve our integer file descriptor from
* the fd->priv pointer. We call the FAT function
* rb_fat_read() to close the file.
*
* Returns: Value returned from rb_fat_read (should be number of
* bytes read)
*
*****************************************************************************/
ssize_t sd_read_wrapper( alt_fd* fd, void* buf, size_t count)
{
int temp_fd = *((int*)(fd->priv));
return( rb_fat_read( temp_fd, buf, count ));
}
/*****************************************************************************
* Function: sd_lseek_wrapper
*
* Purpose: We use this wrapper as the callback function from the
* HAL "lseek()" system call. Since that API uses file
* descriptor pointers instead of integer file descriptors,
* we need to retrieve our integer file descriptor from
* the fd->priv pointer. We call the FAT function
* rb_fat_lseek() to close the file.
*
* Returns: Value returned by rb_fat_lseek (should be current file
* position after the seek)
*
*****************************************************************************/
off_t sd_lseek_wrapper( alt_fd* fd, off_t offset, int whence )
{
int temp_fd = *((int*)(fd->priv));
return( rb_fat_lseek( temp_fd, offset, whence ));
}
/*****************************************************************************
* Function: sd_fstat_wrapper
*
* Purpose: We use this wrapper as the callback function from the
* HAL "fstat()" system call. Since that API uses file
* descriptor pointers instead of integer file descriptors,
* we need to retrieve our integer file descriptor from
* the fd->priv pointer. We call the FAT function
* rb_fat_fstat() to close the file.
*
* Returns: Value returned by rb_fat_fstat (should be
* 0 - success, non-0 - failure.)
*
*****************************************************************************/
int sd_fstat_wrapper( alt_fd* fd, struct stat *st )
{
int temp_fd = *((int*)(fd->priv));
return( rb_fat_fstat( temp_fd, st ));
}
/*****************************************************************************
* Function: sd_read_data_block
*
* Purpose: Reads one block of data from the SD Card and returns it
* in the pointer "data_buffer".
*
* Returns: Value returned by SD_SendRecieveSPI (should be
* 0 - success, non-0 - failure.)
*
*****************************************************************************/
int sd_read_data_block( sd_card_info_struct* sd_card, char* data_buffer, alt_u32 read_address )
{
int ret_code = 0;
// alt_u32 card_status_reg, card_idle;
ret_code |= sd_sendreceive_spi( sd_card_global, READ_SINGLE_BLOCK, read_address );
if( !ret_code )
memcpy( data_buffer, (void*)(sd_card->data_buff_base_addr), sd_card->read_block_length );
/*
// Issue SEND_STATUS command
// Make sure the card's not still busy before we leave.
if( !ret_code )
{
do
{
ret_code |= sd_sendreceive_spi( sd_card_global, SEND_STATUS, SD_NO_ARG );
card_status_reg = IORD_32DIRECT( sd_card->base_addr, SD_COMMAND_RESP0_OFFSET );
card_idle = ( card_status_reg >> 8 ) & 0x1;
} while( !card_idle );
}
*/
return( ret_code );
}
/*****************************************************************************
* Function: sd_write_data_block
*
* Purpose: Writes one block of data to the SD Card. Data is passed
* in by the pointer "data_buffer".
*
* Returns: Value returned by SD_SendRecieveSPI (should be
* 0 - success, non-0 - failure.)
*
*****************************************************************************/
int sd_write_data_block( sd_card_info_struct* sd_card, char* data_buffer, alt_u32 write_address )
{
int ret_code = 0;
memcpy((alt_u8*)sd_card->data_buff_base_addr, data_buffer, sd_card->read_block_length );
ret_code |= sd_sendreceive_spi( sd_card_global, WRITE_BLOCK, write_address );
return( ret_code );
}
/*****************************************************************************
* Function: rb_fat_read_sectors
*
* Purpose: Entry point into SD Card-specific code from FAT code.
* Reads one block of data from the SD Card. Data is passed
* in by the pointer "data_buffer".
*
* Returns: Value returned by sd_read_data_block (should be
* 0 - success, non-0 - failure.)
*
*****************************************************************************/
int rb_fat_read_sectors( unsigned long start,
int incount,
void* inbuf )
{
int ret_code = 0;
int errors = 0;
int i;
for( i = 0; i < incount; i++ )
{
ret_code = sd_read_data_block( sd_card_global, (char*) inbuf, (( start + i ) << 9 ));
if( ret_code )
errors++;
inbuf += 512;
}
if( errors )
return ( -1 );
else
return( 0 );
}
/*****************************************************************************
* Function: rb_fat_write_sectors
*
* Purpose: Entry point into SD Card-specific code from FAT code.
* Writes one block of data to the SD Card. Data is passed
* in by the pointer "data_buffer".
*
* Returns: Value returned by sd_write_data_block (should be
* 0 - success, non-0 - failure.)
*
*****************************************************************************/
int rb_fat_write_sectors( unsigned long start,
int count,
void* buf)
{
int ret_code = 0;
int i;
for( i = 0; i < count; i++ )
{
ret_code |= sd_write_data_block( sd_card_global, (char*) buf, ( ( start + i ) << 9 ));
buf += sd_card_global->read_block_length;
}
if( ret_code )
return ( -1 );
else
return( 0 );
}
/*****************************************************************************
* Function: sd_sendreceive_spi
*
* Purpose: Sends an SD card command over SPI, and retrieves
* a response
*
* Returns: 0 - success
* non-0 - failure
*
*****************************************************************************/
int sd_sendreceive_spi( sd_card_info_struct* sd_card,
alt_u8 command,
alt_u32 command_argument )
{
int ret_code = 0;
volatile alt_u16 crc_calc, crc_rec;
volatile alt_u8 card_status, controller_status;
volatile alt_u32 cmd_attempts;
volatile alt_u32 polls, max_polls;
volatile alt_u8 ready, error;
volatile alt_u8 data_response;
// Wait for controller ready bit before we issue the command
for( cmd_attempts = 0; cmd_attempts < MAX_COMMAND_ATTEMPTS; cmd_attempts++ )
{
ready = IORD_8DIRECT( sd_card->base_addr, SD_CONTROL_STATUS_OFFSET ) & SD_READY_BIT_MASK;
if ( ready )
break;
if( cmd_attempts == MAX_COMMAND_ATTEMPTS )
ret_code |= CONTROLLER_NOT_READY;
}
// We repeatedly send the command until we get the expected status
// response from the SD card. If we exceed MAX_COMMAND_ATTEMPTS,
// we exit with an error code. The controller's command register
// shifts itself out every time, so we need to reload it for each
// command attempt.
for( cmd_attempts = 0; cmd_attempts < MAX_COMMAND_ATTEMPTS; cmd_attempts++ )
{
// Write command ID
IOWR_8DIRECT( sd_card->base_addr, SD_COMMAND_ID_OFFSET, sd_cmd[command].command_id );
// Write command argument
IOWR_32DIRECT( sd_card->base_addr, SD_COMMAND_ARG_OFFSET, command_argument );
// Write command CRC (only needed for CMD0)
if( command == GO_IDLE_STATE )
IOWR_8DIRECT( sd_card->base_addr, SD_COMMAND_CRC_OFFSET, 0x95 );
else
IOWR_8DIRECT( sd_card->base_addr, SD_COMMAND_CRC_OFFSET, 0x00 );
// Write expected response length (in bits)
IOWR_8DIRECT( sd_card->base_addr, SD_RESP_LENGTH_OFFSET, sd_cmd[command].response_length );
//Write data response length expected from the command (in 32-bit words)
IOWR_8DIRECT( sd_card->base_addr, SD_DATA_LENGTH_OFFSET, sd_cmd[command].data_words );
// Write the data CRC (only for WRITE_BLOCK command)
if( command == WRITE_BLOCK )
{
crc_calc = calc_crc16( (alt_u8*)(sd_card->data_buff_base_addr), ( sd_cmd[command].data_words << 2 ));
IOWR_16DIRECT( sd_card->base_addr, SD_DATA_CRC_OFFSET, crc_calc );
}
// Set the controller go_bit to start command execution
controller_status = IORD_8DIRECT( sd_card->base_addr, SD_CONTROL_STATUS_OFFSET );
IOWR_8DIRECT( sd_card->base_addr, SD_CONTROL_STATUS_OFFSET, ( controller_status | SD_GO_BIT_MASK ));
// Write commands can take some time. So we wait longer for them
if( command == WRITE_BLOCK )
max_polls = SD_MAX_POLLS_WRITE_BLOCK;
else
max_polls = SD_MAX_POLLS;
// Poll the ready_bit until the command is finished
// This loop times out to prevent getting caught in an endless
// loop waiting for data from an unresponsive SD Card
for( polls = 0; polls < max_polls; polls++ )
{
ready = ( IORD_8DIRECT( sd_card->base_addr, SD_CONTROL_STATUS_OFFSET ) & SD_READY_BIT_MASK );
if( ready )
break;
}
if( polls == max_polls )
{
// Reset the controller because we're stuck
IOWR_32DIRECT( sd_card->base_addr, SD_CONTROL_STATUS_OFFSET, SD_SYNC_RESET_BIT_MASK );
ret_code |= NO_RESPONSE;
break;
}
// Check the error bit in the controller
error = IORD_8DIRECT( sd_card->base_addr, SD_CONTROL_STATUS_OFFSET ) & SD_ERROR_BIT_MASK;
if( error )
{
ret_code |= CONTROLLER_ERROR;
break;
}
// Check the data response for error flags
// 0x5 - WRITE ACCEPTED
// 0xB - CRC ERROR
// 0xD - WRITE_ERROR
if( !ret_code && ( command == WRITE_BLOCK ))
{
data_response = IORD_8DIRECT( sd_card->base_addr, SD_DATA_RESP_OFFSET );
if(( data_response & 0x1F ) == 0xB )
ret_code |= CRC_MISMATCH;
else if(( data_response & 0x1F ) == 0xD )
ret_code |= WRITE_ERROR;
else if(( data_response & 0x1F ) != 0x5 )
ret_code |= MISC_ERROR;
else
ret_code |= SUCCESS;
}
// Get the R1 portion of the response from the card. This is the status
// of the card after the command. (where this portion will be in the
// response depends on the response type oo)
if( sd_cmd[command].response_type == SD_R1 )
card_status = IORD_32DIRECT( sd_card->base_addr, SD_COMMAND_RESP0_OFFSET ) & 0xFF;
else if( sd_cmd[command].response_type == SD_R2 )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -