📄 sdd_mem.c
字号:
SD_xmit_info.arg = arg;
SD_xmit_info.response_expected = (sd_resp_ptr[cmd] & 0xf);
SD_xmit_info.response_recv = 0;
SD_xmit_info.use_data = (sd_resp_ptr[cmd]>>4);
SD_xmit_info.wait_nclk = SD_NCR_MAX;
SD_xmit_info.cmd_sent = 0;
SD_xmit_info.retry_cnt = 0;
if (SD_xmit_info.use_data == 2) { /* data read */
/* data destination */
if (SD_xmit_info.cmd == SD_ACMD_SD_STATUS) {
SD_xmit_info.cur_blk_size = 6; /* 64Bytes */
SD_xmit_info.rd_dest_ptr = (uint *)SD_status_ptr;
} else if (SD_xmit_info.cmd == SD_ACMD_SEND_SCR) {
SD_xmit_info.cur_blk_size = 3; /* 8Bytes */
SD_xmit_info.rd_dest_ptr = (uint *)SD_scr_reg_ptr;
}
} else if (!SD_xmit_info.use_data
|| SD_xmit_info.response_expected) {
/* response data destination */
if (SD_xmit_info.response_expected == SD_R2) {
SD_xmit_info.rd_dest_ptr =
(SD_xmit_info.cmd == SD_CMD_SEND_CSD) ?
(uint *)SD_csd_reg_ptr : (uint *)SD_cid_reg_ptr;
} else {
if (SD_xmit_info.response_expected == SD_R3){
SD_xmit_info.rd_dest_ptr = (uint *)SD_ocr_reg_ptr;
} else if (SD_xmit_info.response_expected == SD_R6){
/* R6 is special..*/
SD_xmit_info.rd_dest_ptr = &SD_rdata32;
} else { /* R1 or R1b */
SD_xmit_info.rd_dest_ptr = (uint *)SD_card_status_ptr;
}
}
}
return(1);
}
static int SD_slow_clk_data_out(uchar out_data)
{
int i;
unsigned sclk_high, sclk_low;
SD_GET_SCLK_VAL(sclk_high, sclk_low);
for(i=0; i<8; i++){
if (out_data & 0x80) {
SET_SD_CMD;
} else {
CLEAR_SD_CMD;
}
out_data <<= 1;
CLEAR_SD_CLK;
risc_sleep_a_bit(USEC(2));
SET_SD_CLK;
risc_sleep_a_bit(USEC(2));
}
}
/***********************************************
up to 1 DWORD
************************************************/
static int SD_slow_clk_data_in(int bit_cnt)
{
int data_in = 0, i;
unsigned sclk_high, sclk_low;
SD_GET_SCLK_VAL(sclk_high, sclk_low);
for (i=0; i<bit_cnt; i++) {
CLEAR_SD_CLK;
risc_sleep_a_bit(USEC(2));
SET_SD_CLK;
risc_sleep_a_bit(USEC(1));
data_in <<= 1;
data_in |= (SD_CMD_HIGH != 0);
risc_sleep_a_bit(USEC(1));
}
return data_in;
}
static void SD_slow_clk_pulse_l2h(void)
{
unsigned sclk_high, sclk_low;
SD_GET_SCLK_VAL(sclk_high, sclk_low);
CLEAR_SD_CLK;
risc_sleep_a_bit(USEC(2));
SET_SD_CLK;
risc_sleep_a_bit(USEC(2));
}
/*
Function: For init commands during SD card initialization,
under clock restriction (100KHz < clk < 400KHz).
(Also for MMC's CMD1)
input:
command: command index (CMD1,CMD2,CMD3,CMD55,ACMD41).
arg: command argument.
output:
-1: timed out (reached retry limit).
0: crc error.
1: successful
side-effects:
updates SD_card_status for CMD55 if success.
updates SD_ocr_reg for ACMD41/CMD1 if success.
updates SD_cid_reg for CMD2 if success.
updates SD_rca_reg for CMD3 if success.
*/
int SD_clk_restricted_cmd(int command, uint arg)
{
int i, j,cnt, sd_timeout, rcv_cnt, crc_check;
ushort sd_crc;
uint sd_mask, tmp, data_in, *sd_rdata_ptr;
char cmd_buf[8], rcv_buf[8], *pChar, *rdata_pchar;
unsigned sclk_high, sclk_low;
PRINTF(("SD_clk_restricted_cmd ...command %x, arg %x\n", command, arg));
SD_GET_SCLK_VAL(sclk_high, sclk_low);
pChar = cmd_buf;
data_in = 0x40|(command & 0x3f);
*pChar++ = data_in;
*pChar++ = (arg>>24) & 0xff;
*pChar++ = (arg>>16)& 0xff;
*pChar++ = (arg>>8) &0xff;
*pChar++ = arg & 0xff;
sd_crc = SD_calc_crc7(cmd_buf, 5);
for (i=0; i<5; i++)
SD_slow_clk_data_out(cmd_buf[i]);
tmp = (sd_crc<<1) | 1;
/* crc7 + end bit */
SD_slow_clk_data_out(tmp);
SD_CMD_INPUT; /* get ready for response */
if(SD_card_info.type == SD_MMC
&& command == SD_CMD_SEND_REL_ADDR)
sd_timeout = SD_NCR_MAX;
else
sd_timeout = SD_NID_MAX;
for (i = 0; (i < sd_timeout); i++) {
SD_slow_clk_pulse_l2h();
if (SD_CMD_LOW) { /* response start bit */
/* xmit bit */
SD_slow_clk_pulse_l2h();
/* get SD response */
sd_crc = 0;
break;
}
}
if (i >= sd_timeout){
/* timed out..*/
JPRINTF(("clk_res: timed out\n"));
return (-1);
} else {
cnt = 0;
crc_check = 0;
if (command == SD_CMD_ALL_SEND_CID
||command == SD_CMD_SEND_CID ) {
cnt = 3; /* extra data for R2 response */
sd_rdata_ptr = (uint *)SD_cid_reg_ptr;
} else if ((command == SD_ACMD_SD_SEND_OP_COND) ||
(command == SD_CMD_MMC_SEND_OP_COND)) {
sd_rdata_ptr = (uint *)SD_ocr_reg_ptr;
/* R3 */
} else if (command == SD_CMD_SEND_REL_ADDR
&& SD_card_info.type == SD_MEM) {
sd_rdata_ptr = &SD_rdata32;
/* R6 */
crc_check = 1;
} else { /* R1 (SD_CMD_APP_CMD)*/
sd_rdata_ptr = (uint *)SD_card_status_ptr;
crc_check = 1;
}
}
/* clock in cmd and arg (38bits)..save only arg (last 32bits) */
pChar = rcv_buf;
data_in = SD_slow_clk_data_in(6);
*pChar++ = data_in;
rcv_cnt = 1;
rdata_pchar = (char*)sd_rdata_ptr;
for(j=0; j<4; j++){
data_in = SD_slow_clk_data_in(8);
*pChar++ = data_in;
rcv_cnt++;
*rdata_pchar++ = data_in;
}
cnt <<= 2;
while (cnt){
*rdata_pchar++ = SD_slow_clk_data_in(8) ;
cnt--;
if (!cnt) goto sd_exit;
}
/* crc7 + end bit */
data_in = SD_slow_clk_data_in(8) ;
#if CHECK_RECV_CRC
if (!crc_check) {
sd_crc = 0x7f; /* no CRC for R3 response */
}else
sd_crc = SD_calc_crc7(rcv_buf, rcv_cnt);
data_in >>= 1; /* remove end bit */
PRINTF(("Received crc: %x, Computed crc: %x\n", data_in, sd_crc));
if (data_in != sd_crc) {
/* crc error */
CPRINTF(("CRC error in SD_clk_restricted_cmd()\n"));
CPRINTF(("cmd: %d, arg: %\n", command, arg));
CPRINTF(("xmit crc: 0x%x, gen crc: 0x%x\n", data_in, sd_crc));
BREAKPOINT(0);
return (0);
}
#endif
if (command == SD_CMD_SEND_REL_ADDR
&& SD_card_info.type == SD_MEM) {
sd_rdata_ptr = (uint *)SD_card_status_ptr;
*sd_rdata_ptr &= (~0x1fff); /* bit 0-12 */
*sd_rdata_ptr |= (SD_rdata32 & 0x1fff);
SD_card_status_ptr->error =
(SD_rdata32>>13) & 1;
SD_card_status_ptr->illegal_cmd =
(SD_rdata32>>14) & 1;
SD_card_status_ptr->com_crc_error =
(SD_rdata32>>15) & 1;
SD_rca_reg = SD_rdata32>>16; /* new RCA */
}
sd_exit:
/* extra 8 Clocks for SD card post-processing */
for (i = 0; i < 8; i++) {
SD_slow_clk_pulse_l2h();
}
return (1);
}
static void SD_cmd_output(uchar out_cmd)
{
int i;
unsigned sclk_high, sclk_low;
SD_GET_SCLK_VAL(sclk_high, sclk_low);
for (i=0; i<8; i++) {
if (out_cmd &0x80) {
SET_SD_CMD;
} else {
CLEAR_SD_CMD;
}
PULSE_SD_CLK_HL;
out_cmd <<= 1;
}
}
static void SD_1_bit_data_out(uchar out_data)
{
int i;
unsigned sclk_high, sclk_low;
SD_GET_SCLK_VAL(sclk_high, sclk_low);
for (i=0; i<8; i++) {
CLEAR_SD_CLK;
if (out_data & 0x80) {
SET_SD_DAT0;
} else {
CLEAR_SD_DAT0;
}
SET_SD_CLK;
out_data <<= 1;
}
}
static void SD_4_bit_data_out(char *pOutData, int cnt)
{
int i;
char out_data;
unsigned sclk_high, sclk_low;
SD_GET_SCLK_VAL(sclk_high, sclk_low);
for(i= 0; i<cnt; i++){
out_data = *pOutData++;
CLEAR_SD_CLK;
SET_SD_DAT3_0( ((out_data>>4) & 0xf));
SET_SD_CLK;
CLEAR_SD_CLK;
SET_SD_DAT3_0( (out_data&0xf));
SET_SD_CLK;
}
}
/*****************************************************************
up to 1 DWORD
******************************************************************/
static int SD_1_bit_data_in(int bit_cnt)
{
int i, data_in;
unsigned sclk_high, sclk_low;
SD_GET_SCLK_VAL(sclk_high, sclk_low);
data_in = 0;
for (i=0; i<bit_cnt; i++){
data_in <<= 1;
CLEAR_SD_CLK;
if(sd_is_mmc){
asm("nop"); asm("nop");asm("nop");
data_in |= SD_DAT0;
SET_SD_CLK;
}else{
SET_SD_CLK;
data_in |= SD_DAT0;
}
}
return data_in;
}
/*
Function: The main SD transmission state machine..processes
all SD/MMC related commands.
(ref. SD bus protocol, pp.10-83,
SD-mem Physical layer specifications)
input: no arguments, but relies on "SD_xmit_info" structure for
state transitions and transmission info.
output:
side-effects:
"SD_xmit_info" members are updated according to
transmission progress.
*/
void SD_service(void)
{
static uint sd_mask, sd_cmd_info, *sd_rdata_ptr, sd_cnt;
static ushort sd_crc[4];
int i,j, sd_cmd_high, sd_dat0_high, arg;
uint tmp, data_in;
int wr_feedback_crc;
char cmd_buf[8], *pChar;
unsigned sclk_high, sclk_low;
SD_GET_SCLK_VAL(sclk_high, sclk_low);
switch (SD_xmit_info.com_state) {
case HOST2SD_START:
SET_SD_CMD;
CLEAR_SD_CLK; /* prepare */
sd_cmd_info = (SD_xmit_info.cmd&0x3f)|0x40;
sd_cnt = 0;
pChar = cmd_buf;
*pChar++ = sd_cmd_info;
arg = SD_xmit_info.arg;
*pChar++ =(arg>>24)&0xff;
*pChar++ =(arg>>16)&0xff;
*pChar++ =(arg>>8)&0xff;
*pChar = arg & 0xff;
sd_crc[0] = SD_calc_crc7(cmd_buf, 5);
SD_xmit_info.com_state = HOST2SD_CMD;
SD_xmit_info.result = -1; /* need to set to be 0 when succeed,
currently only used in case of Erase */
/*break; save time..let it drop*/
case HOST2SD_CMD:
sd_cnt++; /* for timeout/mode check */
/* command index/argument..8bits at a time */
for(i=0; i<5; i++)
SD_cmd_output(cmd_buf[i]);
SD_xmit_info.com_state = HOST2SD_CRC7;
break;
case HOST2SD_CRC7:
/* send crc7 */
tmp = (sd_crc[0]<<1) | 1; /* crc7 + end bit */
SD_cmd_output(tmp);
CLEAR_SD_CLK;
if (SD_xmit_info.response_expected) {
SD_CMD_INPUT; /* tristate cmd */
if (SD_xmit_info.use_data == 2) {
/* data read */
if (SD_xmit_info.data_width) {
/* all four data lines used */
SD_DAT3_0_INPUT;
} else {
SD_DAT0_INPUT;
}
sd_cmd_info = 0; /* bytes received */
SD_xmit_info.wait_nclk = SD_card_info.n_ac_max;
}
else if(SD_xmit_info.response_expected == SD_R1b){
SD_DAT0_INPUT; /* busy check */
}
sd_rdata_ptr = SD_xmit_info.rd_dest_ptr;
SD_xmit_info.com_state = HOST2SD_WAIT;
} else {
SD_xmit_info.com_state = HOST2SD_8CYCLES;
}
break;
case HOST2SD_WAIT:
/* check 8 cycles at a time */
for (i = 0; SD_xmit_info.wait_nclk; i++) {
SD_LOCK15;
SET_SD_CLK;
if(sd_is_mmc){
CLEAR_SD_CLK;
sd_cmd_high = SD_CMD_HIGH? 1:0;
sd_dat0_high = SD_DAT0_HIGH? 1:0;
}else{
sd_cmd_high = SD_CMD_HIGH? 1:0;
sd_dat0_high = SD_DAT0_HIGH? 1:0;
CLEAR_SD_CLK;
}
if (SD_xmit_info.use_data != 2
&& !SD_xmit_info.response_recv
&& !sd_cmd_high){ /* response start bit */
SD_LOCK15;
SET_SD_CLK;
if(sd_is_mmc){
CLEAR_SD_CLK;
sd_cmd_high = SD_CMD_HIGH? 1:0;
}else{
sd_cmd_high = SD_CMD_HIGH? 1:0;
CLEAR_SD_CLK;
}
/* get SD response */
sd_crc[0] = 0;
sd_mask = 6; /* bit count */
sd_cmd_info = 0; /* clear received bits */
sd_cnt = 0; /* for timeout/mode check */
SD_xmit_info.com_state = SD2HOST_NODATA;
break;
} else if ((SD_xmit_info.use_data==2)
&& !sd_dat0_high) { /* data start bit? */
sd_crc[0] = 0; /* clear crc */
/* current block size (bytes) */
if(SD_xmit_info.cmd == MMC_CMD_READ_UNTIL_STOP)
sd_mask = SD_xmit_info.data_len;
else
sd_mask = 1 << (SD_xmit_info.cur_blk_size);
if(SD_xmit_info.data_width){
SD_xmit_info.com_state = SD2HOST_DATA4;
}
else{
SD_xmit_info.com_state = SD2HOST_DATA1;
}
break;
}
/* btan: After received response, we actually don't need wait n_wr_max clk. *
* 4 clk is ok for my SD. I did not test other SD. If you meet problem in *
* SD writing function, please increase it or let me know. */
else if (SD_xmit_info.use_data != 2 && SD_xmit_info.response_recv
&& sd_cmd_high && SD_xmit_info.wait_nclk > 4) {
SD_xmit_info.wait_nclk = 4;
}
SD_xmit_info.wait_nclk--;
}
if (!SD_xmit_info.wait_nclk) {
#ifdef SD_ENABLE_WRITE
if (SD_xmit_info.use_data == 1
&& SD_xmit_info.response_recv) {
/* prepare to write.. */
/* current block size (bytes) */
sd_cmd_info = 1 << (SD_xmit_info.cur_blk_size);
if (SD_xmit_info.data_width) {
/* write wide bus */
CLEAR_SD_DAT3_0;
SD_xmit_info.com_state = HOST2SD_DATA4;
} else {
CLEAR_SD_DAT0;
SD_xmit_info.com_state = HOST2SD_DATA1;
}
break;
} else
#endif /* SD_ENABLE_WRITE */
{
/* timed out..send again?? */
JPRINTF(("SD res:time out. xmit_len %d, xmit_cnt %d cmd %d\n",
SD_xmit_info.data_len, SD_xmit_info.data_cnt,
SD_xmit_info.cmd));
SD_xmit_info.retry_cnt++;
SD_xmit_info.com_state = HOST2SD_8CYCLES;
}
}
break;
#ifdef SD_ENABLE_WRITE
case HOST2SD_DATA1:
/* write data, one byte at a time */
sd_cmd_info = 1 << (SD_xmit_info.cur_blk_size);
pChar = (char*)SD_xmit_info.wr_src_ptr + SD_xmit_info.data_cnt;
/* crc16 calculation for narrow bus */
sd_crc[0] = SD_calc_crc16((uchar *)pChar,sd_cmd_info);
JPRINTF(("Xmit src %x, len %d\n", pChar, sd_cmd_info));
/* send start bit */
CLEAR_SD_DAT0;
CLEAR_SD_CLK;
SET_SD_CLK;
for(i=0; i<sd_cmd_info; i++)
SD_1_bit_data_out(*pChar++);
SD_xmit_info.data_cnt += sd_cmd_info; /* monitor total bytes */
/* set wait timeout cycles..in case multi-block */
SD_xmit_info.wait_nclk = SD_card_info.n_wr_max;
/* finished data..send CRC */
SD_xmit_info.com_state = HOST2SD_CRC16_DATA;
break;
case HOST2SD_DATA4:
/* wide bus write, 32bits at a time */
sd_cmd_info = 1 << (SD_xmit_info.cur_blk_size);
pChar = (char*)SD_xmit_info.wr_src_ptr + SD_xmit_info.data_cnt;
PRINTF(("wr_src_ptr %x, data_cnt %x pChar %x\n",
SD_xmit_info.wr_src_ptr, SD_xmit_info.data_cnt, pChar));
/* crc16 calculation for 4-bit bus */
SD_calc_crc16_4_bit((int*)pChar, sd_cmd_info>>2, sd_crc);
/* send start bit */
CLEAR_SD_DAT3_0;
CLEAR_SD_CLK;
SET_SD_CLK;
SD_4_bit_data_out(pChar, sd_cmd_info);
SD_xmit_info.data_cnt += sd_cmd_info; /* monitor total bytes */
/* set wait timeout cycles..in case multi-block */
SD_xmit_info.wait_nclk = SD_card_info.n_wr_max;
/* finished data "block"..get CRC */
SD_xmit_info.com_state = HOST2SD_CRC16_DATA;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -