C#使用CH341 SPI模塊讀寫SD卡


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         }
View Code

向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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM