之前一直在做SD卡,一开始是基于8366的,但后面为了给同学方便,直接做成XS的了。现在可以进行SD卡的读写,TXT的创建与BMP的创建。

下面是SD卡的驱动程序(基于XS128)。

#include "SD_Card.h"

#define  SD_CS    PTM_PTM3

//PLL初始化
void PLL_Init(void) //PLLCLK=2*OSCCLK*(SYNR+1)/(REFDV+1)
{                   //PLLCLK=2*16M*(2+1)/(0+1)= 96M
   SYNR  = 0xC2;        //总线频率为PLL频率的一半48M
   REFDV = 0xC0;
   ECLKCTL &= ~0x80;
   while(!(CRGFLG&0x08)); //自循环语句,等待时钟频率稳定后允许锁相环时钟作为系统时钟
   CLKSEL=0x80;           //选择锁相环频率为系统时钟频率
}

//SPI初始化
void SPI_Init(void)
{
   MODRR   = 0x00; 
   MODRR_MODRR4=1;  //使用PM 口
   DDRM   |= 0x38;  //可知SCK0=1,MOSI=1,SS0=1 本步可以忽略,这样做复位可以抗干扰下,并且直接让
                    //片选无效
   SPI0CR1 = 0x5e;  //CPOL=1,时钟选择低有效,spsck空闲时为高电平
                    //CPHA=1 会在发送 8 位数据开始 sck就发生一次跳变
   SPI0CR2 = 0x10;  //modfen=1 .和上面 ssoe=1  确定 spi在 master 模式下 ss 位从机选择输出。并允许 modf标志设置
   SPI0BR  = 0x17;  //波特率设置波特率= BR=busclk/((SPPR + 1)· 2^(SPR + 1))=48M / (1+1)*2^(7+1) = 93KHz 
}

//设置 spi 高速
void SPI_High(void)
{
   SPI0BR = 0x01; //BR=busclk/((SPPR + 1)· 2^(SPR + 1))=48M / 4= 12m
}

//用SPI写1byte
void SPI_Write(unsigned char date)
{  
    while (!SPI0SR_SPTEF);      //等待发送器空
    (void)SPI0SR; 
    SPI0DRL = date;
    while (!SPI0SR_SPIF);       //等待发送完成
    (void)SPI0DRL;   
}

//用SPI读1byte
unsigned char SPI_Read(void) 
{  
    while (!SPI0SR_SPTEF);     //等待发送器空
    (void)SPI0SR;
    SPI0DRL = 0xff;  
    while (!SPI0SR_SPIF);      //等待发送完成
    (void)SPI0DRL;
    return SPI0DRL;   
}

//SPI写命令
uchar SD_Send_Cmd(uchar cmd,ulong arg,uchar crc,uchar Res)
{
    volatile unsigned char r1;
    unsigned char Retry = 200;

unsigned char addr_1;
    unsigned char addr_2;
    unsigned char addr_3;
    unsigned char addr_4;
       
    arg <<= 9;   //arg = arg * 512;
   
    addr_1 = arg & 0xff;
    addr_2 = (arg >> 8 ) & 0xff;
    addr_3 = (arg >> 16) & 0xff;
    addr_4 = (arg >> 24) & 0xff;
   
     SD_CS=1;
     SPI_Write(0xff); //提高兼容性,如果没有这里,有些SD卡可能不支持  
     SD_CS=0;
   
     //SPI_Write(0xff);

//发送
    SPI_Write(cmd | 0x40);                         //分别写入命令
    SPI_Write(addr_4);
    SPI_Write(addr_3);
    SPI_Write(addr_2);
    SPI_Write(addr_1);
    SPI_Write(crc);

//等待响应,或超时退出
   do
   {
     r1 = SPI_Read();
     Retry--;
     if(r1 == Res) break;
   }
    while(Retry>0);

//在总线上额外增加个时钟,让SD卡完成剩下的工作
    SPI_Write(0xFF);

//返回状态值
    if(Retry>0)  return 0;        //成功返回0
    else         return 1;        //失败返回1
}

void SDCard_Init(void)
{
    unsigned char Success_Flag = 0;
    unsigned int  Count = 0;        //最高要大于600,所以选择16位
    unsigned char r1 = 0xFF;

SPI_Init(); 
  
   SD_CS = 1;                      //CS抬高,补74以上时钟
   for(Count=0;Count<10;Count++) SPI_Write(0xFF);
   SD_CS = 0;                      //CS拉低,补16以上时钟
   for(Count=0;Count<4;Count++)  SPI_Write(0xFF);
  
   //-----------------------复位SD卡,并选择为SPI模式----------------------------- 
   do
    {
       SD_CS = 0;         //SD卡片选拉低   ,使能
       for(Count=0;Count<4;Count++)  SPI_Write(0xFF); //补时钟(大于16个时钟)
       r1 = SD_Send_Cmd(SD_CMD0,0x00000000,0x95,SD_IDLE);
       Count++;
    }
    while((r1 != 0x00) && Count < 20);
    SD_CS = 1;         //SD卡禁能
    (void)SPI_Read();  // Dummy SPI cycle   //相当于补8个时钟
   
    //--------------------------激活SD卡------------------------------------------
    //备注:此种激活使用APP类命令,首先发送CMD55然后发送ACMD41
    if(Count < 20)
    {
     SD_CS = 0;          //SD卡使能
     do
     {
      r1 = SD_Send_Cmd(SD_CMD55,0x00000000,0x95,SD_IDLE);   //写CMD55
      r1 = SD_Send_Cmd(SD_CMD41,0x00000000,0x95,SD_OK  );   //写ACMD41
      Count++;
     }
     while((r1 != 0x00) && Count <300); 
     SD_CS = 1;         //SD卡禁能   
     (void)SPI_Read();  // Dummy SPI cycle
    }
   
}

//-----------------------设置读块写块长度-----------------------------
unsigned char Set_BL(void)
{
    unsigned int Count = 0;   //计数
    unsigned int r1    = 0;   //响应
    SD_CS = 0;          //SD卡使能
   do  
   {
    r1 = SD_Send_Cmd(SD_CMD16,0x00000200,0xFF,SD_OK);   //写CMD16,设置块长度为512
    Count ++;
   }
    while((r1 != 0x00) && Count <100);
    SD_CS = 1;          //SD卡使能  
    (void)SPI_Read();  // Dummy SPI cycle
    if(Count <  100)  return 0;    //成功返回0
    if(Count >= 100)  return 1;    //成功返回1
}

//求2的N次方
unsigned long Match_2N(unsigned int number)
{
   unsigned int count  = 0;
   unsigned int answer = 1;
  for(count = 0;count < number;count++)
  {
    answer *= 2;
  }
   return answer;
}

//----------------------读CSD寄存器-----------------------
unsigned char SD_Read_CSD(void)
{
    unsigned int   count = 0;
    unsigned char  r1 = 0;
    volatile unsigned int   buffer[16] = {0};
    volatile unsigned long C_SIZE = 0;    //设备大小
    volatile unsigned long MULT   = 0;    //乘数
    volatile unsigned long BL_LEN = 0;    //块长度
    volatile float         SD_SIZE= 0;    //经过计算后的SD卡大小
       
    SD_CS = 0;         //SD卡使能
   do
   {
      r1 = SD_Send_Cmd(SD_CMD9,0x00000000,0xFF,SD_OK); //发送"CMD9"指令读取寄存器CSD,不需要CRC验证(CRC位置为0xFF)
       count++;
   }
    while((r1 != 0x00) && count <200);
   
    if(count>=200)
    {
       SD_CS = 1;           //SD卡禁能   
      (void)SPI_Read();    // Dummy SPI cycle 
      return 1;            //失败    
    }
   
    while((SPI_Read() != 0xFE));        //等待数据起始位
   
    for(count = 0;count <16; count++)
    {
      buffer[count] = SPI_Read();
    }
                       
    SD_CS = 0;            //SD卡禁能
    (void)SPI_Read();  // Dummy SPI cycle
    
    //-------------------------计算尺寸,块数量-------------------//
  
    C_SIZE = (((buffer[6] & 0x03) << 10) + (buffer[7]<<2) + (buffer[8]>>6));
    MULT   = Match_2N(((buffer[9]&0x03)<<1) + (buffer[10]>>7)+2); 
    BL_LEN = Match_2N((buffer[5] & 0x0f));
   
    SD_SIZE  = (float)(((C_SIZE+1)*(BL_LEN)*(MULT))/1048576);

return 0;
}

//-------------------------读块函数----------------------------------
unsigned char SD_Read_BL(unsigned long Addr,unsigned char *buffer)
{
 unsigned int r1 = 0;
 unsigned int count = 0;
 
 SD_CS = 0;         //SD卡使能
 do
 {
     r1 = SD_Send_Cmd(SD_CMD17,Addr,0xFF,SD_OK); //发送"CMD17"指令按地址读块
     count++;
 }
  while((r1 != 0x00) && count <100);
   
  if(count>=100)
  {
     SD_CS = 1;         //SD卡禁能   
     (void)SPI_Read();  // Dummy SPI cycle
     return 1;            //失败    
  }
   
  while((SPI_Read() != 0xFE));        //等待数据起始位
   
  for(count = 0;count <512; count++)
  {
     *buffer++ = SPI_Read();
  }
 
  (void)SPI_Read();  // 读取两个校验码,然后扔掉
  (void)SPI_Read();   
 
  SD_CS = 1;             //SD卡禁能
 
  SPI_Write(0xFF);
   
  return 0;
}

//-------------------------写块函数----------------------------------
unsigned char SD_Write_BL(unsigned long Addr,unsigned char *buffer)
{
   unsigned int r1 = 0;
   unsigned int count = 0;
   unsigned char temp;
   unsigned char i = 0;
 
   SD_CS = 0;                    //SD卡使能
   do
   {
     r1 = SD_Send_Cmd(SD_CMD24,Addr,0xFF,SD_OK); //发送"CMD24"指令按地址写块
   }
    while((r1 != 0x00) && count <100);
   
    if(count>=100)
    {
      SD_CS = 1;           //SD卡禁能   
     //(void)SPI_Read();  // Dummy SPI cycle
     return 1;            //失败    
    }   
   
    for(i=0;i<100;i++) //这里要插入若干时钟信号
    {
        SPI_Write(0xFF);
    }

SPI_Write(0xFE);        //写入数据起始位
   
    for(count = 0;count <512; count++)
    {
        SPI_Write(*buffer++);        //写入数据起始位
    }
   
    SPI_Write(0xFF);
    SPI_Write(0xFF);     //两个字节的CRC校验码,不用关心
   
    temp = SPI_Read();        //读返回值
   
    if((temp&0x1F)!=0x05) 
    {
        SD_CS = 1;           //SD卡禁能   
       return 1;            //失败  
    }
 
    while(SPI_Read()!=0xff);//等到SD卡不忙(数据被接受以后,SD卡要将这些数据写入到自身的FLASH中,需要一个时间)
                         //忙时,读回来的值为0x00,不忙时,为0xff
   
    SD_CS = 1;             //SD卡禁能
 
    SPI_Write(0xFF);         //按照时序,补8个时钟
   
    return 0;
}

有些地方有些改动。

改动1.写命令时候,地址自动乘了512(右移9位),为了方便读块与写块。读写某个块时候,只要输入块就可以,不用折算为地址。

改动2.写命令之前,将时钟拉高,补了8个时钟,再将其拉低,为了提高兼容性。(此处来源于振南老师的源代码,实际效果未知,我手上的卡基本都兼容。)

改动3.读块时候,把512字节数据读出后多读了两次,为了读出CRC校验码,之后补了8个时钟。

改动4.写块时候,写完512字节数据后,多写了两个0xFF作为校验码,之后增加了等待0x05响应(数据成功接受),之后拉高CS端口补了8个时钟。

按照这个,可以完成SD卡的读写。如果要加入读写TXT与BMP,就要加入FAT32文件层的相关东西了。TXT不需要文件头,只需要在FAT表中标明数据启始与结束。BMP文件则需要特定的文件头,那么通过单片机写入文件头与数据,PC端口才能打开。如果想通过嵌入式设备需要读出BMP文件的数据,则要去掉文件头。

其实8366用来驱动SD卡,程序都差不多,只是寄存器不同而已。之前8366的程序我已经贴出来了,但是以上要注意的地方再改动一下就可以了。完整的程序我还没有,以后做的话,在贴出来分享吧。

SD卡驱动(基于XS128)相关推荐

  1. sd 卡驱动--基于高通平台

    点击打开链接 内容来自以下博客: http://blog.csdn.net/qianjin0703/article/details/5918041 Linux设备驱动子系统第二弹 - SD卡 (有介绍 ...

  2. CE下基于Zylonite硬件平台的SD卡驱动开发

    摘要:本文结合实际项目(一款以WINCE为操作系统内核的GSM/PHS双模智能手机)对嵌入式系统Windows CE5.0的底层驱动(SD卡)的架构进行了分析和研究,以MARVELL公司提供的基于IN ...

  3. 卡函数or1200基于simple-spi的SD卡驱动

    每日一贴,天今的内容关键字为卡函数 这篇blog来说说基于simple-spi这个ipcore编写spi模式的SD Card裸机的驱动程序,植移依附分不清什么SD卡啊,micro SD啊,miniSD ...

  4. Exynos4412 移植针对Samsung的Linux-6.1(二)SD卡驱动——解决无法挂载SD卡的根文件系统

    系列文章目录 Exynos4412 移植针对Samsung的Linux-6.1(一)下载.配置.编译Linux-6.1 Exynos4412 移植针对Samsung的Linux-6.1(二)SD卡驱动 ...

  5. sd 卡驱动在2.6内核的编写.sd/mmc/sdio kernel,sd/mmc/sdio 内核

    [转帖请注明出处:blog.csdn.net/lanmanck] sd卡驱动主要参照已有的文件即可,2410,9260都挺好.其实写驱动主要是搞清楚工作流程即可.我这里写一些心得与大家分享下,基于2. ...

  6. rt-thread SDIO驱动框架分析(SD卡驱动\SD Nand驱动)

    rt-thread SDIO驱动框架分析之SD卡驱动 文章目录 rt-thread SDIO驱动框架分析之SD卡驱动 1. 前言 2. SDIO通用驱动框架介绍 3. 文件架构分析 4. SDIO设备 ...

  7. SD卡驱动分析(二)

    三.下面分析一下高通的android2.3的代码中SD卡驱动的流程. 在kernel中,SD卡是作为平台设备加入到内核中去的,在/kernel/arch/arm/mach-msm/devices-ms ...

  8. SD卡驱动分析(一)

    Android下的SD卡驱动与标准LINUX下的SD卡驱动好像没有太大的区别,这里就以高通的ANDROID 2.3以代表,来简要分析一下LINUX下SD卡驱动的写法.由于小弟的技术有限,分析的有错的地 ...

  9. Linux SD卡驱动开发(五) —— SD 卡驱动分析Core补充篇

    Core层中有两个重要函数 mmc_alloc_host 用于构造host,前面已经学习过,这里不再阐述:另一个就是 mmc_add_host,用于注册host 前面探测函数s3cmci_probe, ...

  10. 嵌入式linux sd卡读写,嵌入式Linux之我行——S3C2440上MMC/SD卡驱动实例开发讲解(二)...

    嵌入式Linux之我行,主要讲述和总结了本人在学习嵌入式linux中的每个步骤.一为总结经验,二希望能给想入门嵌入式Linux的朋友提供方便.如有错误之处,谢请指正. 一.开发环境 主  机:VMWa ...

最新文章

  1. R语言ggplot2可视化:使用gganimate包和gapminder包为生成的动画文件gif设置尺寸、分辨率
  2. H3C——BGP联盟配置
  3. 【Android 逆向】IDA 工具使用 ( 交叉引用数量设置 | 调试设置 )
  4. ccf-csp #201912-2 回收站选址
  5. C#几个经常犯错误汇总
  6. python办公自动化博客_自动化办公 Python 操控 Word
  7. MySQL 按指定字段自定义列表排序
  8. Arm Linux交叉编译和连接过程分析(2)
  9. java 刷新jtextarea_Java JTextArea不能实时刷新的问题
  10. java controller json_springMVC的controller层接收前端json数据
  11. oracle 10g的闪回删除与回收站
  12. 虚拟机+centOS挂载ISO步骤
  13. 一文弄懂特征缩放(归一化/正则化)
  14. MSDN 访谈录(MSDN Show)C#编程
  15. SHA256 算法 加密文件、防文件篡改、文件校验
  16. Python处理excel表格中的数据
  17. adobe ae cs6中文版汉化(11.02)win版汉化安装教程
  18. 详解网站建设方案流程
  19. 2个步骤,让人才成为组织进化的发动机
  20. 宇枫资本投资理财的几大定律

热门文章

  1. 信号与系统->系统的时域分析
  2. Oracle生成日历表
  3. 浅谈那些年,我的鬼迷心窍(来自一个可爱女孩的心声)!
  4. jmp指令和call指令
  5. 微信公众号接入图灵机器人
  6. 荧光猝灭剂BHQ-1 acid/NHS/azide/amine/BHQ染料染料
  7. 【一篇无聊的影评】吐槽《从你的全世界路过》
  8. 如果应下载文件,请添加 MIME 映射
  9. 借助近距离通信,实现手机作为游戏控制器掌控大屏游戏
  10. 恩智浦 飞思卡尔Freescale Kinetis KEA128学习笔记3--GPIO模块(二)