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 }
源碼地址:https://download.csdn.net/download/mm3515/11072088