zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    解决mysql因为服务名无效启动不了
    新手上路遇到的Whitelabel Error Page解决方案
    解决报错java.lang.UnsatisfiedLinkError: F:J2EEapache-tomcat-8.5.46in cnative-1.dll:Can't load AMD 64
    安装sqlserver导致80端口被占用解决方法
    【计算机网络】-传输层-Internet传输协议-UDP
    【计算机网络】-传输层-Internet传输协议-TCP
    【计算机网络】-传输层-拥塞控制
    文件系统-文件的物理结构与存储设备
    vant封装城市/联系人等选择器
    I5TING_TOC转成的HTML,怎样高亮代码
  • 原文地址:https://www.cnblogs.com/Alvis-Lv/p/10621245.html
Copyright © 2011-2022 走看看