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

📄 sd_controller.c

📁 在开发FPGA上比较有用
💻 C
📖 第 1 页 / 共 3 页
字号:

/*****************************************************************************
*  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 + -