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

📄 sdd_mem.c

📁 sd卡的高速读写程序 sd卡的高速读写程序
💻 C
📖 第 1 页 / 共 4 页
字号:
    SD_card_status_ptr = (SD_CARD_STATUS *)dram_cached(SD_CSTATUS_START);
    SD_status_ptr = (SD_STATUS *)dram_cached(SD_STATUS_START);
    SD_ocr_reg_ptr = (SD_OCR *)dram_cached(SD_OCR_START);
    SD_cid_reg_ptr = (SD_CID *)dram_cached(SD_CID_START);
    SD_csd_reg_ptr = (SD_CSD *)dram_cached(SD_CSD_START);
    SD_scr_reg_ptr = (SD_SCR *)dram_cached(SD_SCR_START);

    /* generate the crc table */ 
    SD_calc_crc16_table(sd_crc16_look_up_table); 
    SD_calc_crc7_table(sd_crc7_look_up_table); 

    SD_rca_reg = 0; /* initially '0' */
    SD_card_info.type = SD_UNKNOWN;
    sd_is_mmc = 0;
    SD_card_info.capacity = 0; /* used to check if CSD received */
    SD_xmit_info.com_state = SD_IDLE;
#if SD_CHECK_RECV_CRC
    SD_xmit_info.crc7_err_cnt = 0;
    SD_xmit_info.crc16_err_cnt = 0;
#endif

    SD_acmdq.cmd = SD_CMD_EMPTY;
    SET_SD_CMD; /* initially high */
    SD_DETECT_INPUT; 
}


/* 
  Function: Enable/disable SD eaux ports shared with ATAPI. This is
	    used to prevent ATAPI initialization problems.

  input:
	enable: 1 - enable SD IO ports.
		0 - disable SD IO ports.

  output:		      

  side-effects:
	(refer to sd_mem.h for specific eaux ports affected)
*/
void SD_enable_io(int enable)
{
#if defined(SD_MEMORY)
    /* shared with ATAPI..
     * there is known conflict with ATAPI-D7 (Busy pin) that cause
     * ATAPI initialization problem..tread lightly here.
     */
    if (enable){
	sd_io_status = 1;
	ENABLE_SD_GENERAL;
	ENABLE_SD_IO;
    } else if(sd_io_status){
	DISABLE_SD_GENERAL;
	DISABLE_SD_IO;
	sd_io_status = 0;
    }
#endif    
}


/* 
  Function: SD-memory/MMC card detection. Gets relative card  
	    address(RCA) from card if detected.

  input: (none)

  output:		      
	-2:	failed to get CSD register
	-1:	not voltage compatible
	 0:	no valid SD-mem or MMC card found
	 5:	if successful
*/
int SD_identify_device(void)
{
    int status, status1, cnt=0;    


    SD_enable_io(1);
    
    SD_init();

    SD_card_info.inserted = 1;

    /* Force SD card to idle-state to start initialization */
    SD_clk_restricted_cmd(SD_CMD_GO_IDLE_STATE, 0);

    /* send ACMD41 w/acceptable OCR.. 
     * and wait until SD card is ready.
     */
    SD_ocr_reg_ptr->card_ready = 0;
    do {
	status = SD_clk_restricted_cmd(SD_CMD_APP_CMD, 0);
	status1 = SD_clk_restricted_cmd(SD_ACMD_SD_SEND_OP_COND, 
					SD_ACCEPTABLE_OCR);
	if ((status == -1) && (status1 == -1)) { 
	    SD_clk_restricted_cmd(SD_CMD_GO_IDLE_STATE, 0);
	    cnt++;
	    if (cnt > SD_MAX_RETRIES) {
		/* timed out..no response */
		status = -3;
		break;
	    }
	}
    } while (!SD_ocr_reg_ptr->card_ready);

    sd_is_mmc = 0;
    /*
     * if no response: 1) SD card not voltage compatible
     *		       2) could be Multimedia card..verify
     *			  by sending CMD1 (MMC's ACMD41)
     */
    if (status == -3){
	/* check if MMC? */
	SD_clk_restricted_cmd(SD_CMD_GO_IDLE_STATE, 0);

	cnt=0;
	SD_ocr_reg_ptr->card_ready = 0;
	do {
	    status = SD_clk_restricted_cmd(SD_CMD_MMC_SEND_OP_COND, 
					   SD_ACCEPTABLE_OCR);
	    if (status == -1) {
		/* no response */
		cnt++;
		if (cnt > SD_MAX_RETRIES){
		    /* card not voltage compatible */
		    return (-1);
		}
	    }
	} while (!SD_ocr_reg_ptr->card_ready);

	SD_card_info.type = SD_MMC; /* MultiMedia Card */
	sd_is_mmc = 1;
    } else {
	SD_card_info.type = SD_MEM; /* SD Memory Card */
    }

    if(SD_card_info.type == SD_MMC){
	SD_rca_reg = 0x1;
    }
    else{
	SD_rca_reg = 0xffff; 
    }

    /* send CMD2 to get CID number */
    status = SD_clk_restricted_cmd(SD_CMD_ALL_SEND_CID, 0);

	
    /* send CMD3 to get RCA */
    if(SD_card_info.type == SD_MMC){
	status = SD_clk_restricted_cmd(SD_CMD_SEND_REL_ADDR, 
				       SD_rca_reg<<16);
    }
    else{
	status = SD_clk_restricted_cmd(SD_CMD_SEND_REL_ADDR, 0);
    }
	
    if (status == 1) {
	/* send CMD9 to get Card Specific Data (CSD) */
	status = SD_send_cmd(SD_CMD_SEND_CSD, SD_rca_reg<<16, 1);
	if (status == 1) {
	    SD_update_card_info();

	    /* send card to tranfer state */
	    SD_send_cmd(SD_CMD_SELECT_CARD, SD_rca_reg<<16, 1);    
	    if (SD_card_info.type > SD_MMC) {
		/* send ACMD51 to get SD configuration register */
		SD_scr_reg_ptr->sd_bus_widths = 0x1; /* default 1bit */
		SD_send_acmd(SD_ACMD_SEND_SCR, 0, 1);
	
		/* set to 4bit data bus if possible */
		SD_set_bus_width(2);

		/* send ACMD13 to get SD Status register */
		SD_send_acmd(SD_ACMD_SD_STATUS, 0, 1);
	    }
	    /* we have valid SD/MMC card */
	    status = 5;
	} else {
	    status = -2; /* failed to get CSD */
	}   
    } else {
	SD_card_info.type = SD_UNKNOWN;
	status = 0;
    }    

    SD_enable_io(0);
    
    return (status);
}


/* 
  Function: SD-memory/MMC card reset.

  input:

  output:		      

  side-effects:
*/
void SD_reset(void)
{
    unsigned sclk_high, sclk_low;

    SD_GET_SCLK_VAL(sclk_high, sclk_low);

    SD_send_cmd(SD_CMD_GO_IDLE_STATE, 0, 1);

    SD_xmit_info.data_width = 0; /* initially only D0 used */
    SD_card_info.type = SD_UNKNOWN;
    sd_is_mmc = 0;
    SD_card_info.inserted = 0;
    SD_card_info.capacity = 0; /* used to check if CSD received */
    SD_xmit_info.com_state = SD_IDLE;
#if SD_CHECK_RECV_CRC
    SD_xmit_info.crc7_err_cnt = 0;
    SD_xmit_info.crc16_err_cnt = 0;
#endif

    SD_acmdq.cmd = SD_CMD_EMPTY;
    SET_SD_CMD; /* initially high */
}


/* 
  Function:  Set data bus width, 4bit or 1bit.

  input: 
	0 - 1bit data bus (narrow bus)
	2 - 4bit data bus (wide bus)

  output:		      
	1:	success
otherwise:	failed
*/
int SD_set_bus_width(int width)
{
    uint status = 0;
    
    dawei(("SD_set_bus_width( %d )\n", width));
    if ((SD_scr_reg_ptr->sd_bus_widths & 0x4)) {
	/* 4bit supported by card */
	if ((width>>1) != SD_xmit_info.data_width) {
	    status = SD_send_acmd(SD_ACMD_SET_BUS_WIDTH, width, 1);
	    if (status==1) SD_xmit_info.data_width = (width>>1);
	}
    }

    return (status);
}

/* 
  Function: Read single block from SD. The max block size is card
	    specific, in the range of 512 to 2048 bytes. The minimum
	    block size is 1 byte if card support "partial block read".
	    SD memory card always support PBR.
	    (NOTE: currently our code is hardwired to 512B block)

  input:
	addr: location of SD data (lba).
	blk_sz: block size to read. (2^val bytes)
	data_ptr: SD data destination.
	immed: 1 - complete data read in function.
	       0 - initiate data read..let SD_service() finish
	           in background.
  output:		      
	-4:	unsupported block size.
	-3:	timed out (reached retry limit)
	-2:	communication busy
	-1:	invalid or unsupported command or no card.
	 0:	read initiated.."passed" to SD_service(). 
     	 1:	successful

  side-effects:
*/
int SD_read_blk(int addr, int blk_sz, uint *data_ptr, int immed)
{
    int status;


    if (blk_sz != SD_xmit_info.cur_blk_size) {
	/* check if card allows block size */
	if ((blk_sz == SD_csd_reg_ptr->rd_blk_len) ||
	    (SD_csd_reg_ptr->rd_blk_len_partial && 
	     blk_sz < SD_csd_reg_ptr->rd_blk_len)) {
	    SD_send_cmd(SD_CMD_SET_BLOCKLEN, (1<<blk_sz), immed);
	} else {
	    return (-4); /* invalid block size */
	}
    }
    SD_xmit_info.cur_blk_size = blk_sz;
    SD_xmit_info.rd_dest_ptr = data_ptr;
    
    status=SD_send_cmd(SD_CMD_READ_SINGLE_BLOCK, addr, immed);

    return (status);
}

static int SD_write_blk(int addr,int blk_sz,int nblk,int*data_ptr, int immed)
{
    int status = 1;
    int erase_blk_en, sec_size, wr_bl_len, wr_blk_len_partial;

    if (blk_sz != SD_xmit_info.cur_blk_size) {
	/* check if card allows block size */
	if ((blk_sz == SD_csd_reg_ptr->wr_blk_len) ||
	    (SD_csd_reg_ptr->wr_blk_partial && 
	     blk_sz < SD_csd_reg_ptr->wr_blk_len)) {
	    status = SD_send_cmd(SD_CMD_SET_BLOCKLEN, (1<<blk_sz), immed);
	} else {
	    return (-4); /* invalid block size */
	}
    }
    if(status != 1){
	JPRINTF(("SD Set Block_len error. status %d\n", status));
	return -1;
    }
    SD_xmit_info.cur_blk_size = blk_sz;
    SD_xmit_info.wr_src_ptr = data_ptr;
    SD_xmit_info.data_len = nblk*(1<<blk_sz);
    if(nblk>1)
	status=SD_send_cmd(SD_CMD_WRITE_MULTI_BLOCK, addr, immed);
    else
	status=SD_send_cmd(SD_CMD_WRITE_BLOCK, addr, immed);
    if(status != 1){
	JPRINTF(("SD Set Write Cmd error.\n"));
	return -1;
    }
    else if(SD_xmit_info.result != 0){
	JPRINTF(("SD Writing   error.\n"));
	return -1;
    }
    return 0;
}
/* 
  Function: Read multiple blocks from SD. The max block size is card
	    specific, in the range of 512 to 2048 bytes. 
	    (NOTE: currently our code is hardwired to 512B block)

  input:
	addr: location of SD data (lba).
	nblk: number of blocks to read. 
	data_ptr: SD data destination.
	immed: 1 - complete data read in function.
	       0 - initiate data read..let SD_service() finish
	           in background.
  output:		      
	-3:	timed out (reached retry limit)
	-2:	communication busy
	-1:	invalid or unsupported command or no card.
	 0:	read initiated.."passed" to SD_service(). 
     	 1:	successful

  side-effects:
*/
int SD_read_nblk(int addr, int nblk, uint *data_ptr, int immed)
{
    int status, limit;

    /* make sure block size is 512B..FAT hardwired */
    if (SD_xmit_info.cur_blk_size != 9) {
	SD_send_cmd(SD_CMD_SET_BLOCKLEN, 512, immed);
    }
    SD_xmit_info.cur_blk_size = 9; /* 512..(2^9) */
    SD_xmit_info.rd_dest_ptr = data_ptr;

    limit = nblk*512;

#if 0
    status = SD_send_cmd(MMC_CMD_READ_UNTIL_STOP, addr, 0);
#endif
    status = SD_send_cmd(SD_CMD_READ_MULTI_BLOCK, addr, 0);
    SD_xmit_info.data_len = nblk*512;
    SD_xmit_info.data_cnt = 0;
    /* NOTE: for "non-immediate" case, make sure similar process
     * below is present in background task to complete the read.
     */
    if ((status >= 0) && immed) {
	PRINTF(("com_state %d\n",SD_xmit_info.com_state));
	while (SD_xmit_info.com_state) {
	    SD_service();
	    if (SD_xmit_info.data_cnt >= limit
		&& !sd_is_mmc) break;
	}	
	status = SD_send_cmd(SD_CMD_STOP_TRANSMIT, 0, immed);
	PRINTF(("xmit bytes %d, required bytes %d, status\n", 
		 SD_xmit_info.data_cnt, SD_xmit_info.data_len, status));
    }else{
	JPRINTF(("SD_read_nblk... error \n"));
	
    }

    return (status);
}

/* 
  Function: used in SD_service() for post-processing of commands...
	    1) command retry for errors (up to SD_MAX_RETRIES).
	    2) send app-command if CMD55 was previously sent.
	    3) send pending command in queue if any.

  input: no arguments..but app-commands and pending commands are
	 stored in "SD_acmdq" structure for processing.
  
  output:

  side-effects:
*/
int SD_get_next_cmd(void)
{
    int send=0;

    
    if (SD_xmit_info.response_expected &&
	!SD_xmit_info.response_recv) {
	if (SD_xmit_info.retry_cnt < SD_MAX_RETRIES) {
	    /* failed/aborted commands..retry */
	    SD_xmit_info.wait_nclk = SD_NCR_MAX;
	    send = 1;	    
	} else {
	    /* reach retry limit */
	    SD_xmit_info.retry_cnt = 0xff; 
	}
    } else {	
	/* command specific post-processing */
	switch (SD_xmit_info.cmd) {
	case SD_CMD_APP_CMD:
	    /* send app-command */
	    SD_set_cmd(SD_acmdq.cmd, SD_acmdq.arg);
	    SD_acmdq.cmd = SD_CMD_EMPTY; /* clear cmd-Q */
	    send = 1;
	    break;
	    
	default:
	    if (SD_acmdq.cmd != SD_CMD_EMPTY) {
		/* cmd pending */
		send = SD_set_cmd(SD_acmdq.cmd, SD_acmdq.arg);
		SD_acmdq.cmd = SD_CMD_EMPTY; /* clear cmd-Q */
	    }
	    break;
	}
    }
    
    return (send);
}


/* 
  Function: send command to SD card.  

  input:
	command: command index (0-63).
	arg:	command argument.
	immed:	1-complete command immediately 
		0-initiate command..let SD_service() finish

  output:		      
	-3:	timed out (reached retry limit)
	-2:	communication busy
	-1:	invalid or unsupported command or no card.
	 0:	pending..command "passed" to SD_service(). 
     	 1:	successful
*/
int SD_send_cmd(int command, uint arg, int immed)
{
    int status=0;


    if (!SD_card_info.inserted || command > 63) 
	return (-1); /* sanity check */    
    
    /* send command w/ CRC7*/
    if ( (SD_xmit_info.com_state == SD_IDLE) || 
	 (command == SD_CMD_STOP_TRANSMIT) ) {

	if (!SD_set_cmd(command, arg)) return (-1);

	SD_xmit_info.com_state = HOST2SD_START;
	
	if (immed) {
	    while (SD_xmit_info.com_state) SD_service();

	    status = (SD_xmit_info.retry_cnt == 0xff) ? -3 : 1;
	}
    } else {
	/* put in cmd-Q..if not app-command */
	if (!(command & ACMD_MARKER) && 
	    (command != SD_CMD_APP_CMD)) {
	    SD_acmdq.cmd = command;
	    SD_acmdq.arg = arg;
	} else {
	    status = -2; /* Bus is busy..lost app-command */
	}
    }

    return (status);
}


/* 
  Function: send application specific command to SD card.
	    App-commands needs to send pre-command(0x55).

  input:
	command: app-command index.
	arg:	app-command argument.
	immed:	1-complete command immediately 
		0-initiate command..let SD_service() finish

  output:		      
	-2:	communication busy
	-1:	invalid command.
	 0:	pending..command "passed" to SD_service(). 
     	 1:	successful
*/
int SD_send_acmd(int acmd, uint arg, int immed)
{
    int status;
    
    /* set app-command */
    SD_acmdq.cmd = acmd;
    SD_acmdq.arg = arg;
    status = SD_send_cmd(SD_CMD_APP_CMD, SD_rca_reg<<16, immed);
    
    return (status);
}

/* 
  Function: Initializes xmit data structure for new command. 
	    Checks card(CSD reg) for command class support.

  input:
	command: command index.
	arg:	command argument.

  output:		      
	 0:	command not supported by card.
     	 1:	successful
*/
static int SD_set_cmd(int command, uint arg) 
{
    uint is_acmd, cmd, tmp;
    uchar *sd_resp_ptr;
    

    cmd = command & 0x3f;
    is_acmd = command & ACMD_MARKER;

    if (SD_card_info.capacity) {
	/* card has been initialized..check class support */
	tmp = (is_acmd) ? SD_CL8 : SD_cmd2class[cmd]; /* class */
	if (!(SD_csd_reg_ptr->ccc & (1<<tmp))) {
	    return(0); /* card does not support command class */
	}
    }
    sd_resp_ptr = (is_acmd) ? SD_acmd2resp : SD_cmd2resp;


    SD_xmit_info.cmd = command;

⌨️ 快捷键说明

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