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("初始化失败!
");
  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("初始化失败!
");
 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("初始化失败!
");
 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("初始化失败!
");
 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("初始化失败!
");
 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("初始化失败!
");
102                             return false;
103                         }
104                         r1 = SD_SendCommand(ACMD41, 0x40000000, 0);
105                         if (retry > 200)
106                         {
107                             spiSD.pCurrentWin.showLog.AppendText("初始化失败!
");
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("初始化完成!
");
129                         spiSD.pCurrentWin.showLog.AppendText("SD卡类型:V2HC
");
130 
131                     } 
132                     else
133                     {
134                         SD_Type = SD_TYPE_V2;
135                         spiSD.pCurrentWin.showLog.AppendText("初始化完成!
");
136                         spiSD.pCurrentWin.showLog.AppendText("SD卡类型:V2
");
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

原文地址:https://www.cnblogs.com/Alvis-Lv/p/10621245.html