CMD0 SD卡上电后使用CMD0进入SPI模式,CMD0的返回值是1字节的R1,R1应该为空闲0x01
CMD0 sd_cs(0); sd_command(cmd, cc); res=sd_response(); sd_cs(1);
while ((rtn!=0x01)
CMD8 版本2.0以上的SD卡支持CMD8命令,包括大部分SDHC的卡和所有SDXC卡,早期的SDHC卡有可能仍属于V1.0卡 命令返回值R7,第一字节为R1,Ver1.0的卡对R1的“非法命令”位2置位,Ver2.0以上卡应返回0x01 CMD8rtn = sd_cmd8_version_check(&sdif); if ((rtn&0x04)==0x04) {
rtn=sd_v1_process(&sdif); } else { rtn=sd_v2_process(&sdif); } ACMD41和CMD1 ACMD41是为卡供电命令,供电前卡的状态为空闲(idle),R1的返回值为0x01,供电后为动作状态(ready) 一些早期的卡认为ACMD41是非法命令,只能用MMC的CMD1命令供电 ACMD41 Ready if (rtn == 0x01) { while (rtn==0x01) { rtn = sd_send_cond_acmd41_v1(); } }
if ((rtn&0x04)==0x04) { // invalid command rtn = 0x01; while (rtn==0x01) { rtn = sd_cmd1_mmc_ready(); } } CMD58 CMD58读取卡的状态,一个重要的标志位CCS,会影响到读写操作中地址数据的设定 CCS为1时为高版本卡,数据地址为页单位,512字节为一页 CCS为0时,地址为以字节为单位实际地址 CCS置位与否也取决于ACMD41中对HCS:30bit的置位请求 CMD58 CCSrtn = sd_read_ocr_cmd58(sd_inf->rx.r3); sd_inf->ccs = (sd_inf->rx.r3[0]>>6)&0x01;
CMD9 取得卡容量等信息,CSO寄存器,CSO是16个字节的结构体,加上2字节的CRC,应读取18字节的内容 Read CSO sd_cs(0); sd_command(cmd, cc); rtn = sd_response(); if (rtn == 0x00) { if(sd_data_token()==0xFE) { sd_data(cso, 20); } else { rtn = 0xFF; } } sd_cs(1); 卡的信息也有版本区别,需要分别处理 CSO Version sd_inf->csd_version = (cso[0]>>6)&0x3; if (sd_inf->csd_version==0x0) { sd_inf->block = cso[5]&0xF; sd_inf->unit = cso[6]&0x3; sd_inf->unit <<= 8; sd_inf->unit |= cso[7]; sd_inf->unit <<= 2; sd_inf->unit |= (cso[8]&0xC0)>>6; sd_inf->multi = (cso[9]&0x3); sd_inf->multi <<= 1; sd_inf->multi |= (cso[10]&0x80)>>7; sd_inf->page = sd_inf->unit + 1; sd_inf->page <<= (sd_inf->multi + 2); sd_inf->size = sd_inf->page << sd_inf->block; } else { sd_inf->block = cso[5]&0xF; sd_inf->unit = cso[7]&0x3F; sd_inf->unit <<= 8; sd_inf->unit |= cso[8]; sd_inf->unit <<= 8; sd_inf->unit |= cso[9]; sd_inf->page = sd_inf->unit * 1024; sd_inf->size = sd_inf->page << sd_inf->block; } CMD24 CMD17 CMD24写数据 CMD17读数据 SD的读写都要以页单位进行,无论是否是新版本。 老版本的地址设定也要从页的起始处,一般为512的倍数 数据块紧接在命令块的后面。 数据块长度515个字节,起始标志字节为0xFE,实际数据512字节,2字节CRC CRC使用CRC-16算法,不计算时可以设置为0xFF 写操作之后要等待非忙信号,忙信号使MISO为低电位,接收数据一直为0 |