SD Card 驱动流程分析
来源:互联网 发布:北京淘宝寒假培训班 编辑:程序博客网 时间:2024/05/17 08:24
首先来看一下SD card的一个硬件应用电路,如下图所示:
SD卡有两种工作模式,一个是spi接口模式,一个是SD模式,后者传输速率快些,这里讨论SD模式;SD总线包含4个数据总线(SDIO0-SDIO3),1个命令线(SDCMD)和一个同步时钟SDCLK;图上第10脚是卡检测信号。这里需注意的是传输总线必须加上拉。数据总线不一定全部要用到,根据需求可以选择数据总线个数。
二、SD卡初始化过程
SD卡的初始化过程,简单一点说包括:1.主机reset所有挂在SD总线上的CARD. 2.确认卡的工作电压范围。3.获取卡的RCA(相对地址)。卡划分为十个工作状态,分别是如下所示:
初始化阶段需要涉及前面四个状态,即inactive state、idle 、ready、identification state。 初始化状态图如下:
SD卡是通过命令与host互动的,主机发命令,sd卡接收到命令后返回相应的响应。所有命令和响应的传输都是在命令线上进行的。刚上电时,host发送CMD0来reset所有的sd卡(不管当前处于什么状态),使之进入idle状态。
通过发送CMD8命令,告诉SD卡host提供的工作电压范围,若SD卡支持host提供的工作范围,将在命令线上返回该值,可以说明当前是ver2.0SD存储卡。若SD卡不支持host提供的工作电压范围,它将没有响应而继续处在idle state。如果该卡没有响应则是ver1.x。对于高容量SD存储卡CMD8命令是必须的。接下来需要发送ACMD41来决定是否拒绝或者说抛弃当前的SD卡(让它们进入inactive state),很明显那些与host设计工作电压范围不匹配的卡将会遭此待遇。另外ACMD41命令的参数里面还包含了HCS位,即host capicity support,置1表示host支持高容量sd卡。对于高容量SD存储卡,该位必须设为1,否则高容量卡响应中的busy 位不会置1,该busy位在OCR寄存器的第31位,是用来指示SD卡是否初始化完毕,即进入ready state(busy bit is set to 1)。对于标准SD容量卡,HCS位设为0。要使的sd卡初始化完成并进入ready状态,不仅HCS位要设置正确,host还必须重复发送ACMD41命令,直到busy 位置1。ACMD41的响应中除了busy位,还有一个CCS位(card capcity status),当CCS = 1时,表示当前sd卡是高容量sd卡,CCS=0表示当前sd卡是标准容量sd卡。
接着host发送cmd2来获取sd卡的一些出厂信息(CID),比如出厂序列号之类的,这些信息也是通过命令响应的方式传送给host,sd卡返回CID信息后就进入identification state。
发送cmd3使card传送rca给host,rca是用来给sd卡编址的,用于后面的数据传送。一旦获取了rca,sd卡就进入stand-by state。这个时候如果host想得到新的rca,再次发送cmd3即可。
具体的初始化和卡识别流程如下图:
初始化注意事项:1、在初始化动作之前,至少发送74个null clock ,否则可能会遇到初始化失败。
2、ACMD命令发送之前需要发送cmd55命令,告诉sd卡host接下来要发送ACMD类型的命令,A表示application,初始化的时候cmd55命令参数中的rca使用默认的值0x0000,初始化之后必须是相应rca。
3、整个初始化过程使用小于400KHZ时钟,因为有的卡在初始化和识别阶段对clock有限制,在数据传送之前把clock调整即可。
三、数据传送
从上图可以很清晰地看到它的一个流程,进入数据传送模式开始sd卡是处在Stand-by状态的,此时可以发送命令获取SD卡的一些信息,比如发送cmd9来计算sd卡的容量。要想进入transfer状态,我们必须通过CMD7先选中某一张卡,该命令的参数设为我们想要选中sd卡的RCA,即初始化阶段得到的RCA。在同一个时刻,只能有一张卡处在transfer状态,其他与cmd7命令携带参数(RCA)不匹配的卡会回到stand-by状态。所以说要选中某张卡,只要设置相应的RCA,而释放一张卡,我们就设置与之不匹配的RCA(一般设为默认的值0x0000)。选中卡之后就进入transfer state,这时我们可以发送acmd6设置数据传输的总线位宽,默认是1,注意此操作有两个前提,一是处在transfer state ,二是当前卡没有被lock。发送cmd17读单快数据,cmd18读多块数据,cmd24写单块,cmd25写多块,这些命令都带需要读取数据的首地址。在对多块进行读写的时,直到host发送cmd12才停止。
对block写数据操作完成后,sd卡会进入编程阶段,sd卡是提供缓冲区的,也就是说上一个block在编程时可以写下一个block数据。当缓冲区满了,并且这是卡还在programming,这时DAT0数据线会被拉低,告诉host此时忙碌。
四、程序
程序是在ZSP200内核的DSP芯片上实现的,16位数据总线,60MH的奔跑速度。下面是调试代码,还没来及优化,实现了block的读写,在板子上验证ok。
- <SPAN style="FONT-SIZE: 12px; FONT-FAMILY: Microsoft YaHei"></SPAN>
- <SPAN style="FONT-SIZE: 12px; FONT-FAMILY: Microsoft YaHei">void sd_mmc_setup()
- {
- uint16 reg16_val;
- uint32 reg32_val;
- U8 i;
- SysReadAMBAReg((uint32)SYS_PWRPEN_REG,reg32_val);
- reg32_val |= (1L<<2);
- SysWriteAMBAReg((uint32)SYS_PWRPEN_REG,reg32_val); //开启SD/MMC控制器
- sys_delay_ms(300L);
- mmc_write_reg(MMC_CAR_SEL, 0xdd); // enable module, enable mmcclk
- mmc_write_reg(MMC_CRC_CTL, 0xd0); // CRC circuit enable
- mmc_write_reg(MMC_CTL, 0x0b); // 1bit,low speed(256KHZ),1/4 divider,auto transfer, mmc mode.
- //mmc_write_reg(MMC_INT_MASK, 0x7f); // unmask all interrupt
- for (i = 0; i<10; i++) // at least 74 clock for setup
- {
- mmc_write_reg(MMC_IO,0x24); // only 8 null clock generation
- mmc_read_reg(MMC_INT_CLR,reg16_val);
- while(reg16_val != 0x01)
- {
- mmc_read_reg(MMC_INT_CLR,reg16_val);
- }
- mmc_write_reg(MMC_INT_CLR,reg16_val);
- }
- myptf("sd_mmc_setup finished!\r\n");
- return;
- }
- U8 sd_write_cmd(U8 *cmd, BOOL b_resp)
- {
- U8 i;
- uint16 reg16_val;
- uint32 addr = MMC_CMD_BUF4;
- for(i=0;i<5;i++)
- {
- mmc_write_reg(addr, cmd[i]);
- addr -= 2;
- }
- if(b_resp == FALSE)
- {
- mmc_write_reg(MMC_IO,0x04); //auto only command enable
- }
- else if ((cmd == cmd2) || (cmd == cmd9))
- {
- mmc_write_reg(MMC_IO,0x54); //auto command + response,enable get CID front command buffer[135:8]
- //mmc_write_reg(MMC_IO,0x0c); //auto only response enable
- }
- /*else if (cmd == cmd24)
- {
- mmc_write_reg(MMC_IO, 0x01); //write data, trig transfer
- }*/
- else
- {
- mmc_write_reg(MMC_IO,0x44); //auto command + response
- }
- /*wait and clear sdmmc CMD done interrupt*/
- mmc_read_reg(MMC_INT_CLR,reg16_val);
- while(!(reg16_val & (1<<0)))
- {
- mmc_read_reg(MMC_INT_CLR,reg16_val);
- if ((reg16_val & (1<<6)) != 0) //command or response timer out
- {
- mmc_write_reg(MMC_INT_CLR,0x40); //clear interrupt;
- myptf("Send Cmd%d Timerout!\r\n", cmd[0]-0x40);
- return 0;
- }
- }
- myptf("Interrupt Flag : %d\r\n", reg16_val);
- mmc_write_reg(MMC_INT_CLR,0x1); //clear CMD done interrupt;
- return 1;
- }
- SD_RESPONSE_INFO get_response_info(void) //Only for 48 bit response
- {
- SD_RESPONSE_INFO res;
- uint16 reg16_val;
- uint32 reg32_val,addr;
- U8 i;
- addr = MMC_CMD_BUF3;
- mmc_read_reg(MMC_CMD_BUF4, reg16_val);
- myptf("res.cmd_index =%d\r\n", reg16_val);
- res.cmd_index = reg16_val;
- for (i=0; i<4; i++)
- {
- reg32_val <<= 8;
- mmc_read_reg(addr, reg16_val);
- reg32_val |= reg16_val;
- addr -= 2;
- }
- res.card_status = reg32_val;
- myptf("res.card_status =%ld\r\n", reg32_val);
- mmc_read_reg(MMC_CRC_VAL, reg16_val);
- res.crc = reg16_val;
- return res;
- }
- BOOL sd_mmc_identify()
- {
- SD_RESPONSE_INFO resp;
- U16 reg16_val;
- U8 i;
- sd_write_cmd(cmd0,FALSE); //set the card into idle state
- sd_write_cmd(cmd8,TRUE); //verify the card operation condition;
- resp = get_response_info();
- CardType = 0; //ver2.0
- if ( (resp.cmd_index != 0x08)
- || (resp.card_status != 0x15a) )
- {
- myptf("Erro Response for cmd8\r\n");
- CardType = 1;
- }
- myptf("Ready to Tansmit ACMD!\r\n");
- do
- {
- CMD55:
- sd_write_cmd(cmd55, TRUE); //For Transmit ACMD;
- resp = get_response_info();
- if ((resp.card_status & (1L<<5)) != 0x20)
- {
- goto CMD55;
- }
- if(CardType == 0)
- sd_write_cmd(acmd41_1, TRUE);
- else
- sd_write_cmd(acmd41_0, TRUE);
- resp = get_response_info();
- if ( (resp.cmd_index != 0x3f)
- || ((resp.card_status & 0x00ffffff) != 0xff8000) )
- {
- myptf("Unusable Card!\r\n");
- //return FALSE;
- }
- }while( (resp.card_status & (1L<<31)) == 0 ); //card is busy Wait for power up!
- myptf("SD Card Power On!\r\n");
- if ( !(resp.card_status & (1L<<30)) )
- {
- myptf("This is Standard Capacity SD Memery Card!\r\n");
- }
- else
- {
- myptf("This is High Capacity SD Memery Card!\r\n");
- }
- CMD2:
- sd_write_cmd(cmd2,TRUE); //it makes card identification state
- mmc_read_reg(MMC_CMD_BUF15, reg16_val);
- if (reg16_val != 0x3f)
- {
- goto CMD2;
- }
- myptf("Read CID...\r\n");
- CMD3:
- sd_write_cmd(cmd3,TRUE); //get the card's RCA and change to standby state;
- resp = get_response_info();
- if (resp.cmd_index != 0x03)
- {
- //myptf("Erro Response for cmd3!\r\n");
- goto CMD3;
- }
- card_addr = (U16)((resp.card_status & 0xffff0000) >> 16);
- card_state = (U16)(resp.card_status & 0x0000ffff);
- myptf("current card addr is %ld\r\n",card_addr);
- myptf("current card state is %ld\r\n",card_state);
- return TRUE;
- }
- BOOL read_cards_capacity(U16 rca)
- {
- U16 reg16_val;
- U32 c_size;
- cmd9[1] = rca/256;
- cmd9[2] = rca%256;
- sd_write_cmd(cmd9, TRUE);
- mmc_read_reg(MMC_CMD_BUF15, reg16_val);
- if (reg16_val != 0x3f)
- {
- myptf("Read Capacity Failed!\r\n");
- return FALSE;
- }
- mmc_read_reg(MMC_CMD_BUF7, reg16_val); //read c_zize value
- c_size = reg16_val & 0x3f;
- c_size <<= 8;
- mmc_read_reg(MMC_CMD_BUF6, reg16_val);
- c_size |= reg16_val;
- c_size <<= 8;
- mmc_read_reg(MMC_CMD_BUF5, reg16_val);
- c_size |= reg16_val;
- card_capacity = ((c_size + 1) * 512) / 1024;
- return TRUE;
- }
- void card_select(U16 rca, BOOL sel) //change between standby and transfer state;
- {
- SD_RESPONSE_INFO resp;
- cmd7[1] = 0x00; //deselect card;
- cmd7[2] = 0x00;
- if (sel == TRUE) //Select card
- {
- cmd7[1] = rca/256;
- cmd7[2] = rca%256;
- }
- CMD7:
- if (!(sd_write_cmd(cmd7, TRUE)))
- {
- goto CMD7;
- }
- //get_response_info();
- }
- void set_bus_width(U8 wide) // width = 0:1bit; width = 2: 4bit ;
- {
- acmd6[4] = wide;
- cmd55[1] = card_addr/256;
- cmd55[2] = card_addr%256; //note: cmd55's argument include rca;
- SETBUS:
- sd_write_cmd(cmd55, TRUE); //For Transmit ACMD;
- //get_response_info();
- if (!(sd_write_cmd(acmd6, TRUE)))
- goto SETBUS;
- get_response_info();
- return;
- }
- void set_block_size()
- {
- sd_write_cmd(cmd16, TRUE); // set block length 512 bytes;
- get_response_info();
- }
- void read_block(U32 addr, U8 block_cnt)
- {
- U16 reg16_val;
- U32 reg32_val;
- U8 i,j;
- //SD_RESPONSE_INFO resp;
- //addr <<= 9; // addr*521
- mmc_write_reg(MMC_buf_ctl, 0x9000); //active fifo status,flush fifo,disable dma,read sd-card,wm-128
- if (block_cnt < 2) //read single block
- {
- cmd17[1] = (U8)(addr>>24);
- cmd17[2] = (U8)((addr>>16) & 0xff);
- cmd17[3] = (U8)((addr>>8) & 0xff);
- cmd17[4] = (U8)(addr & 0xff);
- CMD17:
- if(!(sd_write_cmd(cmd17, TRUE)))
- {
- goto CMD17;
- }
- get_response_info();
- mmc_write_reg(MMC_BYTE_CNTH, 0x02); //transfer 512 bytes
- mmc_write_reg(MMC_IO, 0x03); //read data, auto transfer
- }
- else //read multi blockss
- {
- cmd18[1] = (U8)(addr>>24);
- cmd18[2] = (U8)((addr>>16) & 0xff);
- cmd18[3] = (U8)((addr>>8) & 0xff);
- cmd18[4] = (U8)(addr & 0xff);
- CMD18:
- if (!(sd_write_cmd(cmd18, TRUE)))
- {
- goto CMD18;
- }
- //get_response_info();
- //sys_delay_ms(20L); //delay befor trig transfer orelse erro
- mmc_write_reg(MMC_BLOCK_CNT, block_cnt); // set read block number;
- //mmc_write_reg(MMC_IO, 0xc0);
- mmc_write_reg(MMC_IO_MBCTL, 0x53); // trig data transfer;
- }
- mmc_read_reg(MMC_buf_ctl, reg16_val);
- while( !( reg16_val & ( 1<<0 ) ) ) //wait for fifo full;
- {
- mmc_read_reg(MMC_buf_ctl, reg16_val);
- }
- //myptf("FIFO Full\r\n");
- for(j=0; j<128*block_cnt; j++)
- {
- /*mmc_read_reg(MMC_buf_ctl, reg16_val);
- while( ( reg16_val & ( 1<<1 ) ) == 0x02 ) // fifo empty?
- {
- mmc_read_reg(MMC_buf_ctl, reg16_val);
- myptf("fifo empty!\nPlease Wait...\r\n");
- }*/
- SysReadAMBAReg(MMC_DATA_BUF0, sd_rd_buf[j]);
- //for(i=0; i<50; i++); //delay for reading data else data erro appeared;
- }
- mmc_read_reg(MMC_INT_CLR,reg16_val); //wait for data transfer finished
- while( (reg16_val & (1<<1)) != 0x02 )
- {
- mmc_read_reg(MMC_INT_CLR,reg16_val);
- }
- myptf("Read Data Finished!\r\n");
- mmc_write_reg(MMC_INT_CLR,0x02); //clear interrupt;
- //mmc_read_reg(MMC_buf_ctl, reg16_val);
- //myptf("fifo full?:%d\r\n", (reg16_val&0x01));
- //myptf("fifo Empty?:%d\r\n", (reg16_val&0x02));
- if (block_cnt > 1)
- {
- while((reg16_val & (1<<4)) != 0x10)
- {
- mmc_read_reg(MMC_INT_CLR,reg16_val);
- }
- mmc_write_reg(MMC_INT_CLR,0x10); //clear interrupt flag;
- myptf("Read Muliti Block Finished!\r\n");
- CMD12:
- if (!(sd_write_cmd(cmd12, TRUE)))
- {
- goto CMD12;
- }
- }
- }
- void write_block(U32 addr, U8 block_cnt) //block_cnt <65536
- {
- U16 reg16_val;
- U8 i,j;
- //SD_RESPONSE_INFO resp;
- //addr <<= 9;
- if (block_cnt < 2) //write single block
- {
- cmd24[1] = (U8)(addr>>24);
- cmd24[2] = (U8)((addr>>16) & 0xff);
- cmd24[3] = (U8)((addr>>8) & 0xff);
- cmd24[4] = (U8)(addr & 0xff);
- CMD24:
- if(!(sd_write_cmd(cmd24, TRUE)))
- {
- goto CMD24;
- }
- //get_response_info();
- //sys_delay_ms(20L);
- mmc_write_reg(MMC_BYTE_CNTH, 0x02); //transfer 512 bytes
- mmc_write_reg(MMC_buf_ctl, 0x9800); //active fifo status,disable dma, write sd-card,
- mmc_write_reg(MMC_IO, 0x01); //write data, trig transfer
- }
- else //write multi block
- {
- cmd25[1] = (U8)(addr>>24);
- cmd25[2] = (U8)((addr>>16) & 0xff);
- cmd25[3] = (U8)((addr>>8) & 0xff);
- cmd25[4] = (U8)(addr & 0xff);
- cmd55[1] = card_addr / 256;
- cmd55[2] = card_addr % 256;
- acmd23[3] = block_cnt / 256;
- acmd23[4] = block_cnt % 256;
- ACMD23:
- sd_write_cmd(cmd55, TRUE);
- if(!(sd_write_cmd(acmd23, TRUE)))
- {
- goto ACMD23;
- }
- CMD25:
- if(!(sd_write_cmd(cmd25, TRUE)))
- {
- goto CMD25;
- }
- //get_response_info();
- //sys_delay_ms(20L);
- mmc_write_reg(MMC_BLOCK_CNT, block_cnt); // set write block number;
- mmc_write_reg(MMC_buf_ctl, 0x9800); //active fifo status,disable dma, write sd-card,
- mmc_write_reg(MMC_IO_MBCTL, 0x51); // trig data transfer;
- }
- mmc_read_reg(MMC_buf_ctl, reg16_val);
- while( !( reg16_val & ( 1<<1 ) ) ) //wait for fifo empty;
- {
- mmc_read_reg(MMC_buf_ctl, reg16_val);
- }
- //myptf("FIFO Empty\r\n");
- for(j=0; j<128*block_cnt; j++)
- {
- SysWriteAMBAReg(MMC_DATA_BUF0, sd_rd_buf[j]);
- //for(i=0; i<220; i++);
- /*mmc_read_reg(MMC_buf_ctl, reg16_val);
- while((reg16_val & 0x01) == 0x01) //fifo full?
- {
- myptf("fifo full!\nPlease Wait...\r\n");
- mmc_read_reg(MMC_buf_ctl, reg16_val);
- }*/
- }
- mmc_read_reg(MMC_INT_CLR,reg16_val); //wait for data transfer finished
- while((reg16_val & (1<<1)) != 0x02 )
- {
- mmc_read_reg(MMC_INT_CLR,reg16_val);
- }
- myptf("Interrupt Flag : %d\r\n", reg16_val);
- mmc_write_reg(MMC_INT_CLR,0x02); //clear data done interrupt;
- myptf("Write Data finished!\r\n");
- if ( block_cnt > 1 )
- {
- while((reg16_val & (1<<4)) != 0x10) //wait multi block done
- {
- mmc_read_reg(MMC_INT_CLR,reg16_val);
- }
- mmc_write_reg(MMC_INT_CLR,0x10); //clear multi block done interrupt;
- myptf("Write multi block finished!\r\n");
- CMD12_1:
- if (!(sd_write_cmd(cmd12, TRUE))) //End Data transfer;
- {
- goto CMD12_1;
- }
- get_response_info();
- }
- }
- void sd_mmc_initial()
- {
- sd_mmc_setup();
- if (sd_mmc_identify() == FALSE)
- {
- myptf("sd card initial failed!\r\n");
- }
- else
- {
- myptf("sd card initial succesful!\r\n");
- if ( read_cards_capacity(card_addr) == TRUE )
- {
- myptf("current card capacity is: %ldM\r\n", card_capacity);
- }
- card_select(card_addr, TRUE);
- set_bus_width(BUS_4_BIT); // set transfer data bus;
- set_block_size();
- mmc_write_reg(MMC_CTL,0xc3); // 4bit data,high speed(30M),1/2 divider,auto transfer, mmc mode.
- mmc_write_reg(MMC_IO_MBCTL, 0x50); // timer out scal
- }
- }
- </SPAN>
void sd_mmc_setup(){ uint16 reg16_val; uint32 reg32_val; U8 i; SysReadAMBAReg((uint32)SYS_PWRPEN_REG,reg32_val); reg32_val |= (1L<<2); SysWriteAMBAReg((uint32)SYS_PWRPEN_REG,reg32_val); //开启SD/MMC控制器 sys_delay_ms(300L); mmc_write_reg(MMC_CAR_SEL, 0xdd); // enable module, enable mmcclk mmc_write_reg(MMC_CRC_CTL, 0xd0); // CRC circuit enable mmc_write_reg(MMC_CTL, 0x0b); // 1bit,low speed(256KHZ),1/4 divider,auto transfer, mmc mode. //mmc_write_reg(MMC_INT_MASK, 0x7f); // unmask all interrupt for (i = 0; i<10; i++) // at least 74 clock for setup { mmc_write_reg(MMC_IO,0x24); // only 8 null clock generation mmc_read_reg(MMC_INT_CLR,reg16_val); while(reg16_val != 0x01) { mmc_read_reg(MMC_INT_CLR,reg16_val); } mmc_write_reg(MMC_INT_CLR,reg16_val); } myptf("sd_mmc_setup finished!\r\n"); return;}U8 sd_write_cmd(U8 *cmd, BOOL b_resp){ U8 i; uint16 reg16_val; uint32 addr = MMC_CMD_BUF4; for(i=0;i<5;i++) { mmc_write_reg(addr, cmd[i]); addr -= 2; } if(b_resp == FALSE) { mmc_write_reg(MMC_IO,0x04); //auto only command enable } else if ((cmd == cmd2) || (cmd == cmd9)) { mmc_write_reg(MMC_IO,0x54); //auto command + response,enable get CID front command buffer[135:8] //mmc_write_reg(MMC_IO,0x0c); //auto only response enable } /*else if (cmd == cmd24) { mmc_write_reg(MMC_IO, 0x01); //write data, trig transfer }*/ else { mmc_write_reg(MMC_IO,0x44); //auto command + response } /*wait and clear sdmmc CMD done interrupt*/ mmc_read_reg(MMC_INT_CLR,reg16_val); while(!(reg16_val & (1<<0))) { mmc_read_reg(MMC_INT_CLR,reg16_val); if ((reg16_val & (1<<6)) != 0) //command or response timer out { mmc_write_reg(MMC_INT_CLR,0x40); //clear interrupt; myptf("Send Cmd%d Timerout!\r\n", cmd[0]-0x40); return 0; } } myptf("Interrupt Flag : %d\r\n", reg16_val); mmc_write_reg(MMC_INT_CLR,0x1); //clear CMD done interrupt; return 1;}SD_RESPONSE_INFO get_response_info(void) //Only for 48 bit response{ SD_RESPONSE_INFO res; uint16 reg16_val; uint32 reg32_val,addr; U8 i; addr = MMC_CMD_BUF3; mmc_read_reg(MMC_CMD_BUF4, reg16_val); myptf("res.cmd_index =%d\r\n", reg16_val); res.cmd_index = reg16_val; for (i=0; i<4; i++) { reg32_val <<= 8; mmc_read_reg(addr, reg16_val); reg32_val |= reg16_val; addr -= 2; } res.card_status = reg32_val; myptf("res.card_status =%ld\r\n", reg32_val); mmc_read_reg(MMC_CRC_VAL, reg16_val); res.crc = reg16_val; return res;}BOOL sd_mmc_identify(){ SD_RESPONSE_INFO resp; U16 reg16_val; U8 i; sd_write_cmd(cmd0,FALSE); //set the card into idle state sd_write_cmd(cmd8,TRUE); //verify the card operation condition; resp = get_response_info(); CardType = 0; //ver2.0 if ( (resp.cmd_index != 0x08) || (resp.card_status != 0x15a) ) { myptf("Erro Response for cmd8\r\n"); CardType = 1; } myptf("Ready to Tansmit ACMD!\r\n"); do {CMD55: sd_write_cmd(cmd55, TRUE); //For Transmit ACMD; resp = get_response_info(); if ((resp.card_status & (1L<<5)) != 0x20) { goto CMD55; } if(CardType == 0) sd_write_cmd(acmd41_1, TRUE); else sd_write_cmd(acmd41_0, TRUE); resp = get_response_info(); if ( (resp.cmd_index != 0x3f) || ((resp.card_status & 0x00ffffff) != 0xff8000) ) { myptf("Unusable Card!\r\n"); //return FALSE; } }while( (resp.card_status & (1L<<31)) == 0 ); //card is busy Wait for power up! myptf("SD Card Power On!\r\n"); if ( !(resp.card_status & (1L<<30)) ) { myptf("This is Standard Capacity SD Memery Card!\r\n"); } else { myptf("This is High Capacity SD Memery Card!\r\n"); }CMD2: sd_write_cmd(cmd2,TRUE); //it makes card identification state mmc_read_reg(MMC_CMD_BUF15, reg16_val); if (reg16_val != 0x3f) { goto CMD2; } myptf("Read CID...\r\n");CMD3: sd_write_cmd(cmd3,TRUE); //get the card's RCA and change to standby state; resp = get_response_info(); if (resp.cmd_index != 0x03) { //myptf("Erro Response for cmd3!\r\n"); goto CMD3; } card_addr = (U16)((resp.card_status & 0xffff0000) >> 16); card_state = (U16)(resp.card_status & 0x0000ffff); myptf("current card addr is %ld\r\n",card_addr); myptf("current card state is %ld\r\n",card_state); return TRUE;}BOOL read_cards_capacity(U16 rca){ U16 reg16_val; U32 c_size; cmd9[1] = rca/256; cmd9[2] = rca%256; sd_write_cmd(cmd9, TRUE); mmc_read_reg(MMC_CMD_BUF15, reg16_val); if (reg16_val != 0x3f) { myptf("Read Capacity Failed!\r\n"); return FALSE; } mmc_read_reg(MMC_CMD_BUF7, reg16_val); //read c_zize value c_size = reg16_val & 0x3f; c_size <<= 8; mmc_read_reg(MMC_CMD_BUF6, reg16_val); c_size |= reg16_val; c_size <<= 8; mmc_read_reg(MMC_CMD_BUF5, reg16_val); c_size |= reg16_val; card_capacity = ((c_size + 1) * 512) / 1024; return TRUE; }void card_select(U16 rca, BOOL sel) //change between standby and transfer state;{ SD_RESPONSE_INFO resp; cmd7[1] = 0x00; //deselect card; cmd7[2] = 0x00; if (sel == TRUE) //Select card { cmd7[1] = rca/256; cmd7[2] = rca%256; }CMD7: if (!(sd_write_cmd(cmd7, TRUE))) { goto CMD7; } //get_response_info();}void set_bus_width(U8 wide) // width = 0:1bit; width = 2: 4bit ;{ acmd6[4] = wide; cmd55[1] = card_addr/256; cmd55[2] = card_addr%256; //note: cmd55's argument include rca;SETBUS: sd_write_cmd(cmd55, TRUE); //For Transmit ACMD; //get_response_info(); if (!(sd_write_cmd(acmd6, TRUE))) goto SETBUS; get_response_info(); return;}void set_block_size(){ sd_write_cmd(cmd16, TRUE); // set block length 512 bytes; get_response_info();}void read_block(U32 addr, U8 block_cnt){ U16 reg16_val; U32 reg32_val; U8 i,j; //SD_RESPONSE_INFO resp; //addr <<= 9; // addr*521 mmc_write_reg(MMC_buf_ctl, 0x9000); //active fifo status,flush fifo,disable dma,read sd-card,wm-128 if (block_cnt < 2) //read single block { cmd17[1] = (U8)(addr>>24); cmd17[2] = (U8)((addr>>16) & 0xff); cmd17[3] = (U8)((addr>>8) & 0xff); cmd17[4] = (U8)(addr & 0xff); CMD17: if(!(sd_write_cmd(cmd17, TRUE))) { goto CMD17; } get_response_info(); mmc_write_reg(MMC_BYTE_CNTH, 0x02); //transfer 512 bytes mmc_write_reg(MMC_IO, 0x03); //read data, auto transfer } else //read multi blockss { cmd18[1] = (U8)(addr>>24); cmd18[2] = (U8)((addr>>16) & 0xff); cmd18[3] = (U8)((addr>>8) & 0xff); cmd18[4] = (U8)(addr & 0xff);CMD18: if (!(sd_write_cmd(cmd18, TRUE))) { goto CMD18; } //get_response_info(); //sys_delay_ms(20L); //delay befor trig transfer orelse erro mmc_write_reg(MMC_BLOCK_CNT, block_cnt); // set read block number; //mmc_write_reg(MMC_IO, 0xc0); mmc_write_reg(MMC_IO_MBCTL, 0x53); // trig data transfer; } mmc_read_reg(MMC_buf_ctl, reg16_val); while( !( reg16_val & ( 1<<0 ) ) ) //wait for fifo full; { mmc_read_reg(MMC_buf_ctl, reg16_val); } //myptf("FIFO Full\r\n"); for(j=0; j<128*block_cnt; j++) { /*mmc_read_reg(MMC_buf_ctl, reg16_val); while( ( reg16_val & ( 1<<1 ) ) == 0x02 ) // fifo empty? { mmc_read_reg(MMC_buf_ctl, reg16_val); myptf("fifo empty!\nPlease Wait...\r\n"); }*/ SysReadAMBAReg(MMC_DATA_BUF0, sd_rd_buf[j]); //for(i=0; i<50; i++); //delay for reading data else data erro appeared; } mmc_read_reg(MMC_INT_CLR,reg16_val); //wait for data transfer finished while( (reg16_val & (1<<1)) != 0x02 ) { mmc_read_reg(MMC_INT_CLR,reg16_val); } myptf("Read Data Finished!\r\n"); mmc_write_reg(MMC_INT_CLR,0x02); //clear interrupt; //mmc_read_reg(MMC_buf_ctl, reg16_val); //myptf("fifo full?:%d\r\n", (reg16_val&0x01)); //myptf("fifo Empty?:%d\r\n", (reg16_val&0x02)); if (block_cnt > 1) { while((reg16_val & (1<<4)) != 0x10) { mmc_read_reg(MMC_INT_CLR,reg16_val); } mmc_write_reg(MMC_INT_CLR,0x10); //clear interrupt flag; myptf("Read Muliti Block Finished!\r\n");CMD12: if (!(sd_write_cmd(cmd12, TRUE))) { goto CMD12; } }}void write_block(U32 addr, U8 block_cnt) //block_cnt <65536{ U16 reg16_val; U8 i,j; //SD_RESPONSE_INFO resp; //addr <<= 9; if (block_cnt < 2) //write single block { cmd24[1] = (U8)(addr>>24); cmd24[2] = (U8)((addr>>16) & 0xff); cmd24[3] = (U8)((addr>>8) & 0xff); cmd24[4] = (U8)(addr & 0xff);CMD24: if(!(sd_write_cmd(cmd24, TRUE))) { goto CMD24; } //get_response_info(); //sys_delay_ms(20L); mmc_write_reg(MMC_BYTE_CNTH, 0x02); //transfer 512 bytes mmc_write_reg(MMC_buf_ctl, 0x9800); //active fifo status,disable dma, write sd-card, mmc_write_reg(MMC_IO, 0x01); //write data, trig transfer } else //write multi block { cmd25[1] = (U8)(addr>>24); cmd25[2] = (U8)((addr>>16) & 0xff); cmd25[3] = (U8)((addr>>8) & 0xff); cmd25[4] = (U8)(addr & 0xff); cmd55[1] = card_addr / 256; cmd55[2] = card_addr % 256; acmd23[3] = block_cnt / 256; acmd23[4] = block_cnt % 256;ACMD23: sd_write_cmd(cmd55, TRUE); if(!(sd_write_cmd(acmd23, TRUE))) { goto ACMD23; }CMD25: if(!(sd_write_cmd(cmd25, TRUE))) { goto CMD25; } //get_response_info(); //sys_delay_ms(20L); mmc_write_reg(MMC_BLOCK_CNT, block_cnt); // set write block number; mmc_write_reg(MMC_buf_ctl, 0x9800); //active fifo status,disable dma, write sd-card, mmc_write_reg(MMC_IO_MBCTL, 0x51); // trig data transfer; } mmc_read_reg(MMC_buf_ctl, reg16_val); while( !( reg16_val & ( 1<<1 ) ) ) //wait for fifo empty; { mmc_read_reg(MMC_buf_ctl, reg16_val); } //myptf("FIFO Empty\r\n"); for(j=0; j<128*block_cnt; j++) { SysWriteAMBAReg(MMC_DATA_BUF0, sd_rd_buf[j]); //for(i=0; i<220; i++); /*mmc_read_reg(MMC_buf_ctl, reg16_val); while((reg16_val & 0x01) == 0x01) //fifo full? { myptf("fifo full!\nPlease Wait...\r\n"); mmc_read_reg(MMC_buf_ctl, reg16_val); }*/ } mmc_read_reg(MMC_INT_CLR,reg16_val); //wait for data transfer finished while((reg16_val & (1<<1)) != 0x02 ) { mmc_read_reg(MMC_INT_CLR,reg16_val); } myptf("Interrupt Flag : %d\r\n", reg16_val); mmc_write_reg(MMC_INT_CLR,0x02); //clear data done interrupt; myptf("Write Data finished!\r\n"); if ( block_cnt > 1 ) { while((reg16_val & (1<<4)) != 0x10) //wait multi block done { mmc_read_reg(MMC_INT_CLR,reg16_val); } mmc_write_reg(MMC_INT_CLR,0x10); //clear multi block done interrupt; myptf("Write multi block finished!\r\n");CMD12_1: if (!(sd_write_cmd(cmd12, TRUE))) //End Data transfer; { goto CMD12_1; } get_response_info(); } }void sd_mmc_initial(){ sd_mmc_setup(); if (sd_mmc_identify() == FALSE) { myptf("sd card initial failed!\r\n"); } else { myptf("sd card initial succesful!\r\n"); if ( read_cards_capacity(card_addr) == TRUE ) { myptf("current card capacity is: %ldM\r\n", card_capacity); } card_select(card_addr, TRUE); set_bus_width(BUS_4_BIT); // set transfer data bus; set_block_size(); mmc_write_reg(MMC_CTL,0xc3); // 4bit data,high speed(30M),1/2 divider,auto transfer, mmc mode. mmc_write_reg(MMC_IO_MBCTL, 0x50); // timer out scal } }
/*测试代码*/
- U8 cmd0[5]={0x40,0x00,0x00,0x00,0x00};
- U8 cmd2[5]={0x42,0x00,0x00,0x00,0x00};
- U8 cmd3[5]={0x43,0x00,0x00,0x00,0x00};
- U8 cmd7[5]={0x47,0x00,0x00,0x00,0x00};
- U8 cmd8[5]={0x48,0x00,0x00,0x01,0x5a}; // 2.7-3.6V; use‘10101010b’for the‘check pattern’
- U8 cmd9[5]={0x49,0x00,0x00,0x00,0x00};
- U8 cmd12[5]={0x4c,0x00,0x00,0x00,0x00}; // stop transfer command;
- U8 cmd16[5]={0x50,0x00,0x00,0x02,0x00}; // set block length 512 bytes;
- U8 cmd17[5]={0x51,0x00,0x00,0x00,0x00}; // read single block;
- U8 cmd18[5]={0x52,0x00,0x00,0x00,0x00}; // read multi block;
- U8 cmd24[5]={0x58,0x00,0x00,0x00,0x00}; // write single block;
- U8 cmd25[5]={0x59,0x00,0x00,0x00,0x00}; // write single block;
- U8 cmd55[5]={0x77,0x00,0x00,0x00,0x00};
- U8 acmd6[5]={0x46,0x00,0x00,0x00,0x00}; // set transfer data bus
- U8 acmd23[5]={0x57,0x00,0xff,0x80,0x00};
- U8 acmd41_1[5]={0x69,0x40,0xff,0x80,0x00}; // HCS =1; voltage range 2.7-3.6V;
- U8 acmd41_0[5]={0x69,0x00,0xff,0x80,0x00}; // HCS =0; voltage range 2.7-3.6V;
- typedef struct
- {
- U8 cmd_index;
- uint32 card_status;
- U8 crc;
- }SD_RESPONSE_INFO;
- uint16 card_addr;
- uint16 card_state;
- U8 CardType;
- U32 card_capacity;
- U32 sd_rd_buf[1024]={0};
- U32 sd_write_buf[512]={0};
U8 cmd0[5]={0x40,0x00,0x00,0x00,0x00};U8 cmd2[5]={0x42,0x00,0x00,0x00,0x00};U8 cmd3[5]={0x43,0x00,0x00,0x00,0x00};U8 cmd7[5]={0x47,0x00,0x00,0x00,0x00};U8 cmd8[5]={0x48,0x00,0x00,0x01,0x5a}; // 2.7-3.6V; use‘10101010b’for the‘check pattern’U8 cmd9[5]={0x49,0x00,0x00,0x00,0x00};U8 cmd12[5]={0x4c,0x00,0x00,0x00,0x00}; // stop transfer command;U8 cmd16[5]={0x50,0x00,0x00,0x02,0x00}; // set block length 512 bytes;U8 cmd17[5]={0x51,0x00,0x00,0x00,0x00}; // read single block;U8 cmd18[5]={0x52,0x00,0x00,0x00,0x00}; // read multi block; U8 cmd24[5]={0x58,0x00,0x00,0x00,0x00}; // write single block;U8 cmd25[5]={0x59,0x00,0x00,0x00,0x00}; // write single block;U8 cmd55[5]={0x77,0x00,0x00,0x00,0x00};U8 acmd6[5]={0x46,0x00,0x00,0x00,0x00}; // set transfer data busU8 acmd23[5]={0x57,0x00,0xff,0x80,0x00};U8 acmd41_1[5]={0x69,0x40,0xff,0x80,0x00}; // HCS =1; voltage range 2.7-3.6V;U8 acmd41_0[5]={0x69,0x00,0xff,0x80,0x00}; // HCS =0; voltage range 2.7-3.6V; typedef struct{ U8 cmd_index; uint32 card_status; U8 crc;}SD_RESPONSE_INFO;uint16 card_addr;uint16 card_state;U8 CardType;U32 card_capacity;U32 sd_rd_buf[1024]={0};U32 sd_write_buf[512]={0};
- void main()
void main()
- {
{
- sd_mmc_initial();
- while(1)
- {
- sys_wdtrestart();
- read_block(153600, 8);
- //read_block(153601, 3); //31760
- //read_block(300, 3); //30760*512
- //read_block(30, 1); //30*512
- for(j=0; j<128; j++)
- {
- myptf("sd_rd_buf[%d] = %ld\r\n", j, sd_rd_buf[j]);
- }
- write_block(153605, 1);
- write_block(153606, 8);
- //write_block(153609, 3);
- //read_block(153604, 3);
- /*for(j=0; j<384; j++)
- {
- myptf("sd_rd_buf[%d] = %ld\r\n", j, sd_rd_buf[j]);
- }*/
- //while(1);
- }
sd_mmc_initial(); while(1) { sys_wdtrestart(); read_block(153600, 8); //read_block(153601, 3); //31760 //read_block(300, 3); //30760*512 //read_block(30, 1); //30*512 for(j=0; j<128; j++) { myptf("sd_rd_buf[%d] = %ld\r\n", j, sd_rd_buf[j]); } write_block(153605, 1); write_block(153606, 8); //write_block(153609, 3); //read_block(153604, 3); /*for(j=0; j<384; j++) { myptf("sd_rd_buf[%d] = %ld\r\n", j, sd_rd_buf[j]); }*/ //while(1); }
- }
}
就分析到这里,有分析不对的地方请博友们指正,愿意同大家交流。
http://blog.csdn.net/rxllh/article/details/8100698
- SD Card 驱动流程分析
- SD Card 驱动流程分析
- SD Card 驱动流程分析
- SD Card驱动分析(二)
- sd卡驱动分析之card
- sd card 识别流程
- [sd card] sd card初始化流程
- LINUX SD card driver分析
- wince Micro SD Card驱动 详解
- [sd card] sd card块设备(mmc_blk)读写流程学习笔记
- [sd card] mmc_blk层为sd card创建块设备流程
- [sd card] mmc硬件总线扫描流程(以sd card为例)
- sd card
- sd card
- WinCE SD驱动分析
- Linux SD驱动分析
- SD卡驱动分析
- SD卡驱动分析
- C#综合揭秘——细说多线程(下)
- 几种常用的压缩包
- java笔记day_2
- Oracle Agile PLM产品生命周期管理(0):PLM简介
- Android中onInterceptTouchEvent与onTouchEvent
- SD Card 驱动流程分析
- 搭建hadoop集群笔记
- java Logger 的使用(转藏)
- android触发说明
- 图的广度优先搜索 深度优先搜索 最短路径 拓扑排序(邻接链表表示)
- Android获取View坐标方法
- Unity3D后台数据库交互 php接口设计
- 怎样才能输出结果
- 省市级联下拉框使用感