SD卡相关CMD命令
1 public static byte CMD0 = 0;//卡复位 2 public static byte CMD1 = 1; 3 public static byte CMD9 = 9;//命令9 ,读CSD数据 4 public static byte CMD10 = 10;//命令10,读CID数据 5 public static byte CMD12 = 12;//命令12,停止数据传输 6 public static byte CMD16 = 16;//命令16,设置SectorSize 应返回0x00 7 public static byte CMD17 = 17;//命令17,读sector 8 public static byte CMD18 = 18;//命令18,读Multi sector 9 public static byte ACMD23 = 23;//命令23,设置多sector写入前预先擦除N个block 10 public static byte CMD24 = 24;//命令24,写sector 11 public static byte CMD25 = 25;//命令25,写Multi sector 12 public static byte ACMD41 = 41;//命令41,应返回0x00 13 public static byte CMD55 = 55;//命令55,应返回0x01 14 public static byte CMD58 = 58;//命令58,读OCR信息 15 public static byte CMD59 = 59;//命令59,使能/禁止CRC,应返回0x00 16 17 public static byte SD_Type = 0; 18 public static byte SD_TYPE_MMC = 0; 19 public static byte SD_TYPE_V1 = 1; 20 public static byte SD_TYPE_V2 = 2; 21 public static byte SD_TYPE_V2HC = 4; 22 //SD传输数据结束后是否释放总线宏定义 23 public static byte NO_RELEASE = 0; 24 public static byte RELEASE = 1; 25 //SD卡回应标记字 26 public static byte MSD_RESPONSE_NO_ERROR = 0x00; 27 public static byte MSD_IN_IDLE_STATE = 0x01; 28 public static byte MSD_ERASE_RESET = 0x02; 29 public static byte MSD_ILLEGAL_COMMAND = 0x04; 30 public static byte MSD_COM_CRC_ERROR = 0x08; 31 public static byte MSD_ERASE_SEQUENCE_ERROR = 0x10; 32 public static byte MSD_ADDRESS_ERROR = 0x20; 33 public static byte MSD_PARAMETER_ERROR = 0x40; 34 public static byte MSD_RESPONSE_FAILURE = 0xFF; 35 //数据写入回应字意义 36 public static byte MSD_DATA_OK = 0x05; 37 public static byte MSD_DATA_CRC_ERROR = 0x0B; 38 public static byte MSD_DATA_WRITE_ERROR = 0x0D; 39 public static byte MSD_DATA_OTHER_ERROR = 0xFF;
//把SD卡设置到挂起模式
//返回值:0,成功设置
// 1,设置失败
1 public static bool SD_Idle_Sta() 2 { 3 byte r1 = 0x0; 4 for (int i = 0; i < 0xf00; i++) ;//纯延时,等待SD卡上电完成 5 6 CH341DLL.CH341SetStream(mIndex, m_iChipSelect); 7 byte[] byInit = new byte[10]; 8 pub_Func.memset(byInit, 0xFF, 10); 9 CH341DLL.CH341StreamSPI4(mIndex, m_iChipSelect, 10, byInit); 10 11 for (int i = 0; i < 10; i++) //等待响应,或超时退出 12 { 13 r1 = SD_SendCommand(CMD0, 0, 0x95); 14 if (r1 == 0x01) 15 break; 16 } 17 if (r1 == 0x01) 18 return false; 19 else 20 return true; 21 }
/// <summary>
/// 向SD卡发送一个命令(结束是不失能片选,还有后续数据传来)
/// </summary>
/// <param name="cmd">命令</param>
/// <param name="arg">命令参数</param>
/// <param name="crc">crc校验值</param>
/// <returns></returns>
1 public static byte SD_SendCommand(byte cmd,int arg ,byte crc) 2 { 3 byte r1 = 0xFF; 4 CH341DLL.CH341SetStream(mIndex, m_iChipSelect & 0x00); 5 byte[] byInit = new byte[3]; 6 pub_Func.memset(byInit, 0xFF, 3); 7 CH341DLL.CH341StreamSPI4(mIndex, m_iChipSelect, 3, byInit); //高速写命令延时 8 CH341DLL.CH341SetStream(mIndex, m_iChipSelect & 0x80); //片选端置低,选中SD卡 9 10 byte[] data = new byte[6]; 11 data[0] = (byte)((int)cmd | 0x40); //分别写入命令 12 data[1] = (byte)(arg >> 24); 13 data[2] = (byte)(arg >> 16); 14 data[3] = (byte)(arg >> 8); 15 data[4] = (byte)(arg); 16 data[5] = crc; 17 CH341DLL.CH341StreamSPI4(mIndex, m_iChipSelect, 6, data); 18 19 byte[] byteint = new byte[1]; 20 byteint[0] = 0xFF; 21 for(int i=0;i<200;i++) //等待响应,或超时退出 22 { 23 CH341DLL.CH341StreamSPI4(mIndex, m_iChipSelect, 1, byteint); 24 if ((r1=byteint[0]) != 0xFF) 25 { 26 r1 = byteint[0]; 27 break; 28 } 29 30 } 31 32 CH341DLL.CH341SetStream(mIndex, m_iChipSelect & 0x00); //关闭片选 33 34 byte[] byInit2 = new byte[1]; 35 pub_Func.memset(byInit2, 0xFF, 1); 36 CH341DLL.CH341StreamSPI4(mIndex, m_iChipSelect, 1, byInit2); //在总线上额外增加8个时钟,让SD卡完成剩下的工作 37 38 return r1; 39 }
SD卡初始化
1 public static bool SD_Init() 2 { 3 int retry; 4 byte r1 = 0xFF; 5 if (SD_Idle_Sta()) 6 { 7 spiSD.pCurrentWin.showLog.AppendText("初始化失败!\n"); 8 return false; 9 } 10 //-----------------SD卡复位到idle结束----------------- 11 CH341DLL.CH341SetStream(mIndex, m_iChipSelect & 0x80); 12 r1 = SD_SendCommand(8, 0x1aa, 0x87); //获取卡片的SD版本信息 13 if (r1 == 0x05) 14 { 15 //设置卡类型为SDV1.0,如果后面检测到为MMC卡,再修改为MMC 16 SD_Type = SD_TYPE_V1; 17 //如果是V1.0卡,CMD8指令后没有后续数据 18 //片选置高,结束本次命令 19 CH341DLL.CH341SetStream(mIndex, m_iChipSelect & 0x00); 20 byte[] byInit = new byte[1]; 21 pub_Func.memset(byInit, 0xFF, 1); 22 CH341DLL.CH341StreamSPI4(mIndex, m_iChipSelect, 1, byInit); //在总线上额外增加8个时钟,让SD卡完成剩下的工作 23 //-----------------SD卡、MMC卡初始化开始----------------- 24 //发卡初始化指令CMD55+ACMD41 25 // 如果有应答,说明是SD卡,且初始化完成 26 // 没有回应,说明是MMC卡,额外进行相应初始化 27 retry = 0; 28 do 29 { 30 //先发CMD55,应返回0x01;否则出错 31 r1 = SD_SendCommand(CMD55, 0, 0); 32 if (r1 == 0XFF) 33 { 34 spiSD.pCurrentWin.showLog.AppendText("初始化失败!\n"); 35 return false;//只要不是0xff,就接着发送 36 } 37 //得到正确响应后,发ACMD41,应得到返回值0x00,否则重试200次 38 r1 = SD_SendCommand(ACMD41, 0, 0); 39 retry++; 40 } while ((r1 != 0x00) && (retry < 400)); 41 // 判断是超时还是得到正确回应 42 // 若有回应:是SD卡;没有回应:是MMC卡 43 //----------MMC卡额外初始化操作开始------------ 44 if (retry == 400) 45 { 46 retry = 0; 47 //发送MMC卡初始化命令(没有测试) 48 do 49 { 50 r1 = SD_SendCommand(1, 0, 0); 51 retry++; 52 } while ((r1 != 0x00) && (retry < 400)); 53 if (retry == 400) 54 { 55 spiSD.pCurrentWin.showLog.AppendText("初始化失败!\n"); 56 return false; //MMC卡初始化超时 57 } 58 //写入卡类型 59 SD_Type = SD_TYPE_MMC; 60 } 61 //----------MMC卡额外初始化操作结束------------ 62 63 64 //禁止CRC校验 65 r1 = SD_SendCommand(CMD59, 0, 0x95); 66 if (r1 != 0x00) 67 { 68 spiSD.pCurrentWin.showLog.AppendText("初始化失败!\n"); 69 return false; //命令错误,返回r1 70 } 71 //设置Sector Size 72 r1 = SD_SendCommand(CMD16, 512, 0x95); 73 if (r1 != 0x00) 74 { 75 spiSD.pCurrentWin.showLog.AppendText("初始化失败!\n"); 76 return false;//命令错误,返回r1 77 } 78 //-----------------SD卡、MMC卡初始化结束----------------- 79 } 80 else if (r1 == 0x01) 81 { 82 byte[] buff = new byte[4]; 83 byte[] byInit = new byte[1]; 84 pub_Func.memset(buff, 0xFF, 4); 85 pub_Func.memset(byInit, 0xFF, 1); 86 // V2.0的卡,CMD8命令后会传回4字节的数据,要跳过再结束本命令 87 CH341DLL.CH341StreamSPI4(mIndex, m_iChipSelect, 4, buff); 88 CH341DLL.CH341SetStream(mIndex, m_iChipSelect & 0x00); 89 CH341DLL.CH341StreamSPI4(mIndex, m_iChipSelect, 1, byInit); //在总线上额外增加8个时钟,让SD卡完成剩下的工作 90 //V2.0的卡,CMD8命令后会传回4字节的数据,要跳过再结束本命令 91 //判断该卡是否支持2.7V-3.6V的电压范围 92 //if(buff[2]==0x01 && buff[3]==0xAA) //不判断,让其支持的卡更多 93 { 94 retry = 0; 95 //发卡初始化指令CMD55+ACMD41 96 do 97 { 98 r1 = SD_SendCommand(CMD55, 0, 0); 99 if (r1 != 0x01) 100 { 101 spiSD.pCurrentWin.showLog.AppendText("初始化失败!\n"); 102 return false; 103 } 104 r1 = SD_SendCommand(ACMD41, 0x40000000, 0); 105 if (retry > 200) 106 { 107 spiSD.pCurrentWin.showLog.AppendText("初始化失败!\n"); 108 return false; //超时则返回r1状态 109 } 110 } while (r1 != 0); 111 //初始化指令发送完成,接下来获取OCR信息 112 //-----------鉴别SD2.0卡版本开始----------- 113 r1 = SD_SendCommand(CMD58, 0, 0); 114 if (r1 != 0x00) 115 { 116 CH341DLL.CH341SetStream(mIndex, m_iChipSelect & 0x00);//释放SD片选信号 117 return false; //如果命令没有返回正确应答,直接退出,返回应答 118 }//读OCR指令发出后,紧接着是4字节的OCR信息 119 CH341DLL.CH341StreamSPI4(mIndex, m_iChipSelect, 4, buff); 120 //OCR接收完成,片选置高 121 CH341DLL.CH341SetStream(mIndex, m_iChipSelect & 0x00); 122 CH341DLL.CH341StreamSPI4(mIndex, m_iChipSelect, 1, byInit); 123 //检查接收到的OCR中的bit30位(CCS),确定其为SD2.0还是SDHC 124 //如果CCS=1:SDHC CCS=0:SD2.0 125 if ((buff[0] & 0x40) == 0x40) 126 { 127 SD_Type = SD_TYPE_V2HC; //检查CCS 128 spiSD.pCurrentWin.showLog.AppendText("初始化完成!\n"); 129 spiSD.pCurrentWin.showLog.AppendText("SD卡类型:V2HC\n"); 130 131 } 132 else 133 { 134 SD_Type = SD_TYPE_V2; 135 spiSD.pCurrentWin.showLog.AppendText("初始化完成!\n"); 136 spiSD.pCurrentWin.showLog.AppendText("SD卡类型:V2\n"); 137 } 138 //-----------鉴别SD2.0卡版本结束----------- 139 } 140 } 141 142 return true; 143 }
向SD卡读取数据
1 public static bool ReadData(int addr ,ref byte[] data)//读取1个扇区数据 2 { 3 byte r1; 4 //int buff = count * 512; 5 data = new byte[512]; 6 //byte[] byInit = new byte[1]; 7 //pub_Func.memset(byInit, 0xFF, 1); 8 if (SD_Type != SD_TYPE_V2HC) 9 { 10 addr <<= 9;//如果不是SDHC卡 11 } 12 r1 = SD_SendCommand(CMD17, addr, 0);//发送读扇区命令 13 if (r1==0x01) return false; //应答不正确,直接返回 14 CH341DLL.CH341SetStream(mIndex, m_iChipSelect & 0x80); 15 if (SD_GetResponse(0xFE)== MSD_RESPONSE_FAILURE)//等待SD卡发回数据起始令牌0xFE 16 { 17 CH341DLL.CH341SetStream(mIndex, m_iChipSelect & 0x00); //关闭SD卡 18 return false;//读取失败 19 } 20 pub_Func.memset(data, 0xFF, 512); 21 CH341DLL.CH341StreamSPI4(mIndex, m_iChipSelect, 512, data); 22 byte[] byInit = new byte[2]; 23 pub_Func.memset(byInit, 0xFF, 2); 24 CH341DLL.CH341StreamSPI4(mIndex, m_iChipSelect, 2, byInit);//发送伪CRC码 25 CH341DLL.CH341SetStream(mIndex, m_iChipSelect & 0x00);//关闭SD卡 26 return true; 27 } 28 29 public static bool ReadDatanum(int addr, ref byte[] data,int counts) //读取多个扇区数据 30 { 31 int buff = 512 * counts; 32 data = new byte[buff]; 33 for(int i=0;i<counts;i++) 34 { 35 byte[] da1 = new byte[512]; 36 if (!ReadData(addr, ref da1)) 37 return false; 38 pub_Func.memcpy(data, i * 512, da1, 0, 512); 39 addr++; 40 41 } 42 return true; 43 }
向SD卡写入数据
1 public static bool SD_WriteMultiBlock( ref int sector,byte[] data,int count) 2 { 3 byte r1; 4 int sectornum = count / 512; 5 if ((count % 512) != 0) 6 sectornum++; 7 //byte[] da = new byte[512]; 8 if (SD_Type != SD_TYPE_V2HC) 9 sector = sector << 9;//如果不是SDHC,给定的是sector地址,将其转换成byte地址 10 if (SD_Type != SD_TYPE_MMC) 11 r1 = SD_SendCommand(ACMD23, count, 0x00);//如果目标卡不是MMC卡,启用ACMD23指令使能预擦除 12 r1 = SD_SendCommand(CMD25, sector, 0x00);//发多块写入指令 13 if (r1 != 0x00) return false; //应答不正确,直接返回 14 CH341DLL.CH341SetStream(mIndex, m_iChipSelect & 0x80);//开始准备数据传输 15 byte[] byInit = new byte[3]; 16 pub_Func.memset(byInit, 0xFF, 3); 17 CH341DLL.CH341StreamSPI4(mIndex, m_iChipSelect, 3, byInit);//先放3个空数据,等待SD卡准备好 18 //--------下面是N个sector写入的循环部分 19 for(int i=0;i< sectornum;i++) 20 { 21 byInit = new byte[1]; 22 pub_Func.memset(byInit, 0xFC, 1); 23 CH341DLL.CH341StreamSPI4(mIndex, m_iChipSelect, 1, byInit);//放起始令牌0xFC 表明是多块写入 24 byte[] tda = new byte[512]; 25 for (int j = 0; j < 512; j++) 26 { 27 if ((j + i * 512) < count) 28 { 29 tda[j] = data[j + i * 512]; 30 } 31 else 32 { 33 tda[j] = 0xFF; 34 } 35 } 36 CH341DLL.CH341StreamSPI4(mIndex, m_iChipSelect, 512, tda); 37 byInit = new byte[2]; 38 pub_Func.memset(byInit, 0xFF, 2);//发2个Byte的dummy CRC,第3个byte等待SD卡应答 39 CH341DLL.CH341StreamSPI4(mIndex, m_iChipSelect, 2, byInit); 40 /* 41 r1 = byInit[2]; 42 if ((r1 & 0x1F) != 0x05) 43 { 44 CH341DLL.CH341SetStream(mIndex, m_iChipSelect & 0x00); //如果应答为报错,则带错误代码直接退出 45 return false; 46 } 47 */ 48 //等待SD卡写入完成 49 CH341DLL.CH341SetDelaymS(mIndex, 2); 50 if (!SD_WaitDataReady()) 51 { 52 CH341DLL.CH341SetStream(mIndex, m_iChipSelect & 0x00); //等待SD卡写入完成超时,直接退出报错 53 return false; 54 } 55 56 } 57 //发结束传输令牌0xFD 58 byInit = new byte[1]; 59 pub_Func.memset(byInit, 0xFD, 1); 60 CH341DLL.CH341StreamSPI4(mIndex, m_iChipSelect, 1, byInit); 61 /* 62 r1 = byInit[0]; 63 if (r1 == 0x00) 64 { 65 return false; 66 } 67 if (SD_WaitDataReady()) //等待准备好 68 { 69 CH341DLL.CH341SetStream(mIndex, m_iChipSelect & 0x00); 70 return false; 71 } 72 */ 73 //写入完成,片选置1 74 CH341DLL.CH341SetStream(mIndex, m_iChipSelect & 0x00); 75 byInit = new byte[1]; 76 pub_Func.memset(byInit, 0xFF, 1); 77 CH341DLL.CH341StreamSPI4(mIndex, m_iChipSelect, 1, byInit); 78 79 sector += sectornum; 80 81 return true; 82 83 }
//等待SD卡写入完成
1 public static bool SD_WaitDataReady() 2 { 3 byte r1 = MSD_DATA_OTHER_ERROR; 4 int retry = 0; 5 //CH341DLL.CH341SetStream(mIndex, m_iChipSelect & 0x80); 6 do 7 { 8 byte[] byInit = new byte[1]; 9 pub_Func.memset(byInit, 0xFF, 1); 10 CH341DLL.CH341StreamSPI4(mIndex, m_iChipSelect, 1, byInit); 11 r1 = (byte)(byInit[0] & 0X1F);//读到回应 12 if (retry == 200) return false; 13 retry++; 14 switch (r1) 15 { 16 case 0x05://数据接收正确了 17 r1 = MSD_DATA_OK; 18 break; 19 case 0x0B: //CRC校验错误 20 return false; 21 case 0x0D://数据写入错误 22 return false; 23 default://未知错误 24 r1 = MSD_DATA_OTHER_ERROR; 25 break; 26 } 27 } while (r1 == MSD_DATA_OTHER_ERROR); //数据错误时一直等待 28 29 retry = 0; 30 for(int i=0;i<200;i++) 31 { 32 byte[] byInit = new byte[1]; 33 pub_Func.memset(byInit, 0xFF, 1); 34 CH341DLL.CH341StreamSPI4(mIndex, m_iChipSelect, 1, byInit); 35 if (byInit[0] != 0)//读到数据为0,则数据还未写完成 36 break; 37 if (i == 199) 38 return false; 39 } 40 return true;//成功了 41 }
GetResponse
1 public static byte SD_GetResponse(byte Response) 2 { 3 int Count = 0xFFF; 4 byte[] byInit = new byte[1]; 5 pub_Func.memset(byInit, 0xFF, 1); 6 CH341DLL.CH341StreamSPI4(mIndex, m_iChipSelect, 1, byInit); 7 while ((byInit[0] != Response) && (Count!=0)) 8 { 9 CH341DLL.CH341StreamSPI4(mIndex, m_iChipSelect, 1, byInit); 10 Count--;//等待得到准确的回应 11 } 12 if (Count == 0) return MSD_RESPONSE_FAILURE;//得到回应失败 13 else return MSD_RESPONSE_NO_ERROR;//正确回应 14 }