本文主要是介绍SD Card 驱动流程分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
一、硬件接口电路首先来看一下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 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};
- 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 驱动流程分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!