OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 3070|回复: 2

F429+SPI方式读取SD卡+USB挂载读卡器失败,电脑没有反应

[复制链接]

2

主题

6

帖子

0

精华

新手入门

积分
18
金钱
18
注册时间
2019-7-4
在线时间
3 小时
发表于 2019-7-4 12:22:52 | 显示全部楼层 |阅读模式
1金钱
本帖最后由 ljyzzy 于 2019-7-4 12:38 编辑

我是从原子哥的历程修改过去的,因为原子哥的历程是spi方式读取flash和SDIO方式读取SD卡,然后挂载USB读卡器。而我们的SDIO口因为IO口被占用掉了,所以选择的是SPI方式读取SD卡,然后通过USB挂载读卡器。现在问题是 1:用USB+SPI读取板载flash,可以实现电脑读取flash,因此usb和spi应该都是没有问题。 2:用SPI读取SD卡,实现fatfs文件系统读写sd卡也是没有问题的,因此我们的spi读取SD卡部分也是没有问题的。


3:我在原子哥的《实验51 USB读卡器(Slave)实验》里面把usbd_storage_msd.c文件中关于SDIO读取SD的部分换成spi SD卡读取函数,然后把板载flash的那些全部注释掉,结果连接电脑上之后没有什么反应,也没有进入sd卡的读取部分,所以我想问除了usbd_storage_msd.c之外,是不是还有哪里需要修改的,有没有什么我没注意到的部分。
请大家指点,感激不尽!!!
稍后上程序。
#include "usbd_msc_mem.h"
#include "usb_conf.h"
//#include "w25qxx.h"                         
#include "sdio_sdcard.h"         
//////////////////////////////////////////////////////////////////////////////////         
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK STM32F407开发板
//USB读卡器  驱动代码          
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//创建日期:2014/7/21
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2009-2019
//All rights reserved                                                                          
//*******************************************************************************
//修改信息
//无
//////////////////////////////////////////////////////////////////////////////////           

//最大支持的设备数,2个
#define STORAGE_LUN_NBR         2

////////////////////////////自己定义的一个标记USB状态的寄存器///////////////////
//bit0:表示电脑正在向SD卡写入数据
//bit1:表示电脑正从SD卡读出数据
//bit2:SD卡写数据错误标志位
//bit3:SD卡读数据错误标志位
//bit4:1,表示电脑有轮询操作(表明连接还保持着)
vu8 USB_STATUS_REG=0;
////////////////////////////////////////////////////////////////////////////////


//USB Mass storage 标准查询数据(每个lun占36字节)
const int8_t  STORAGE_Inquirydata[] = {

        /* LUN 0 */
        0x00,               
        0x80,               
        0x02,               
        0x02,
        (USBD_STD_INQUIRY_LENGTH - 4),
        0x00,
        0x00,       
        0x00,
    /* Vendor Identification */
    'A', 'L', 'I', 'E', 'N', 'T', 'E', 'K', ' ',//9字节
    /* Product Identification */
    'S', 'P', 'I', ' ', 'F', 'l', 'a', 's', 'h',//15字节
    ' ','D', 'i', 's', 'k', ' ',
    /* Product Revision Level */       
    '1', '.', '0', ' ',                                                        //4字节               
       
        /* LUN 1 */
        0x00,
        0x80,               
        0x02,               
        0x02,
        (USBD_STD_INQUIRY_LENGTH - 4),
        0x00,
        0x00,       
        0x00,
        /* Vendor Identification */
        'A', 'L', 'I', 'E', 'N', 'T', 'E', 'K',' ',        //9字节
        /* Product Identification */                               
        'S', 'D', ' ', 'F', 'l', 'a', 's', 'h', ' ',//15字节
        'D', 'i', 's', 'k', ' ', ' ',  
    /* Product Revision Level */
        '1', '.', '0' ,' ',                              //4字节
};
int8_t STORAGE_Init (uint8_t lun);
int8_t STORAGE_GetCapacity (uint8_t lun,uint32_t *block_num,uint32_t *block_size);
int8_t  STORAGE_IsReady (uint8_t lun);
int8_t  STORAGE_IsWriteProtected (uint8_t lun);
int8_t STORAGE_Read (uint8_t lun,uint8_t *buf,uint32_t blk_addr,uint16_t blk_len);
int8_t STORAGE_Write (uint8_t lun,uint8_t *buf,uint32_t blk_addr,uint16_t blk_len);
int8_t STORAGE_GetMaxLun (void);

//USB Device 用户回调函数接口
USBD_STORAGE_cb_TypeDef USBD_MICRO_SDIO_fops =
{
        STORAGE_Init,
        STORAGE_GetCapacity,
        STORAGE_IsReady,
        STORAGE_IsWriteProtected,
        STORAGE_Read,
        STORAGE_Write,
        STORAGE_GetMaxLun,
        (int8_t *)STORAGE_Inquirydata,
};
USBD_STORAGE_cb_TypeDef  *USBD_STORAGE_fops=&USBD_MICRO_SDIO_fops;//指向USBD_MICRO_SDIO_fops结构体.

//初始化存储设备
//lun:逻辑单元编号,0,SD卡;1,SPI FLASH
//返回值:0,成功;
//    其他,错误代码
int8_t STORAGE_Init (uint8_t lun)
{
        SD_Init();
        ;//W25QXX_Init();
        return 0;
}

//获取存储设备的容量和块大小
//lun:逻辑单元编号,0,SD卡;1,SPI FLASH
//block_num:块数量(扇区数)
//block_size:块大小(扇区大小)
//返回值:0,成功;
//    其他,错误代码
int8_t STORAGE_GetCapacity (uint8_t lun, uint32_t *block_num, uint32_t *block_size)
{     
        if(lun==1)
        {
                *block_size=512;  
                //*block_num=SDCardInfo.CardCapacity/512;
                *block_num=30405*1024/512;
        }else
        {
                *block_size=512;  
                *block_num=1024*1024*12/512;        //SPI FLASH的前面12M字节,文件系统用
        }       
        return 0;
}

//查看存储设备是否就绪
//lun:逻辑单元编号,0,SD卡;1,SPI FLASH
//返回值:0,就绪;
//    其他,未就绪
int8_t  STORAGE_IsReady (uint8_t lun)
{
        USB_STATUS_REG|=0X10;//标记轮询
        return 0;
}

//查看存储设备是否写保护
//lun:逻辑单元编号,0,SD卡;1,SPI FLASH
//返回值:0,没有写保护;
//    其他,写保护(只读)
int8_t  STORAGE_IsWriteProtected (uint8_t lun)
{
        return  0;
}

//从存储设备读取数据
//lun:逻辑单元编号,0,SD卡;1,SPI FLASH
//buf:数据存储区首地址指针
//blk_addr:要读取的地址(扇区地址)
//blk_len:要读取的块数(扇区数)
//返回值:0,成功;
//    其他,错误代码
int8_t STORAGE_Read (uint8_t lun,uint8_t *buf,uint32_t blk_addr,uint16_t blk_len)
{
        int8_t res=0;
        USB_STATUS_REG|=0X02;//标记正在读数据
        if(lun==1)
        {
                res=SD_ReadDisk(buf,blk_addr,blk_len);
                if(res)USB_STATUS_REG|=0X08;//SD卡读错误!
        }else
        {
                ;//W25QXX_Read(buf,blk_addr*512,blk_len*512);
        }
        return res;
}
//向存储设备写数据
//lun:逻辑单元编号,0,SD卡;1,SPI FLASH
//buf:数据存储区首地址指针
//blk_addr:要写入的地址(扇区地址)
//blk_len:要写入的块数(扇区数)
//返回值:0,成功;
//    其他,错误代码
int8_t STORAGE_Write (uint8_t lun,uint8_t *buf,uint32_t blk_addr,uint16_t blk_len)
{
        int8_t res=0;
        USB_STATUS_REG|=0X01;//标记正在写数据
        if(lun==1)
        {
                res=SD_WriteDisk (buf,blk_addr,blk_len);
                if(res)USB_STATUS_REG|=0X04;//SD卡写错误!         
        }else
        {
                ;//W25QXX_Write(buf,blk_addr*512,blk_len*512);
        }
        return res;
}
//获取支持的最大逻辑单元个数
//返回值:支持的逻辑单元个数-1
int8_t STORAGE_GetMaxLun (void)
{
        return (STORAGE_LUN_NBR - 1);
}

以下spi_sdcard.c

//#include "delay.h"
#include "stm32f4xx.h"
#include <stdio.h>

#include "usart.h"
#include "spi2.h"
#include "spi_sdcard.h"
#include "string.h"
#include "delay.h"

u8 SD_Type;
__align(4) u8 SPISD_DATA_BUFFER[512];

void testxx(void)
{
;}

//@brief: SD卡初始化
//@param :
//@retval: 1:错误 r1:命令响应
u8 SD_Init(void)
{
        u16 i;
        u8 r1;
        u16 retry;
        u8 buff[6];

        SPI2_Init();                                      //初始化SPI2

        SPI2_SetSpeed(SPI_BaudRatePrescaler_256);         //SD卡初始化时钟不能超过400KHz

        SPI_SD_CS_HIGH();                                      //打开SD卡片选引脚

        delay_ms(5);                                      //等待SD卡上电稳定,完成初始化

        for(i=0;i<10;i++)
        {
                SPI2_ReadWriteByte(0xff);                       //产生80个时钟脉冲
        }

//将SD卡复位至idle状态
       
        SPI_SD_CS_LOW();

        retry = 0;
        do
        {
                r1 = SD_SendCommand(CMD0,0,0X95);               //发送CMD0
                SPI2_ReadWriteByte(0xff);
                retry++;
        }while((r1!=0x01)&&(retry<200));                  //收到正确响应或超时后退出

        if(retry==200)                                    //如果退出原因为超时
        {
                printf("chaoshi!");
                return 1;
        }

        r1= SD_SendCommand(CMD8,0x01aa,0x87);                 //如果退出原因为SD卡复位至idle并收到正确响应,继续发送CMD8获取SD卡版本信息
//如果是v2.0版本的SD卡
        if(r1==0x01)                                      //接收到CMD8的正确响应接收CMD8响应后续传送的4字节数据
        {
                printf("59!");
                buff[0] = SPI2_ReadWriteByte(0xff);             //接收CMD8响应后续传送的4字节数据
                buff[1] = SPI2_ReadWriteByte(0xff);
                buff[2] = SPI2_ReadWriteByte(0xff);
                buff[3] = SPI2_ReadWriteByte(0xff);

//                SD_CS = 1;

//                SPI2_ReadWriteByte(0xff);                       //多发送8个时钟信号

//开始初始化SD卡
               
                SPI_SD_CS_LOW();//SD_CS = 0;

                retry = 0;

                do
                {
                        r1 = SD_SendCommand(CMD55,0,0xff);               //发送CMD55,通知SD卡下一条命令为应用相关命令而非通用命令
                        SPI2_ReadWriteByte(0xff);
                        if(r1!=0x01)                                  //如果主机未接收到CMD55的正确响应
                        {
                        //printf("81!");
                        return r1;
                                }
                        r1 = SD_SendCommand(ACMD41,0x40000000,1);      //否则继续发送ACMD41
                        SPI2_ReadWriteByte(0xff);
                        retry++;
                        if(retry>200)
                                {
                                //printf("89!r=%d!",r1);
                                //return r1;                                  //超时退出
                                }
                }while(r1!=0);                                  //接收到ACMD41的正确响应退出
               
                SPI_SD_CS_HIGH();
                SPI2_ReadWriteByte(0xff);
               
                SPI_SD_CS_LOW();

//初始化指令发送完成,继续获取OCR信息
//识别SD2.00版本的SD卡类型

                r1 = SD_SendCommand_NoDeassert(CMD58,0,0);      //发送CMD58

                if(r1!=0x00)
                        {
                        printf("101!");
                        return r1;                                    //未接收到CMD58的正确响应退出
                       
                        }
                buff[0] = SPI2_ReadWriteByte(0xff);             //否则接收CMD58响应后续传回的4字节COR信息
                buff[1] = SPI2_ReadWriteByte(0xff);
                buff[2] = SPI2_ReadWriteByte(0xff);
                buff[3] = SPI2_ReadWriteByte(0xff);

                SPI_SD_CS_HIGH();//SD_CS =1;

                SPI2_ReadWriteByte(0xff);

//分析OCR信息中的bit30(CCS)判断卡的类型
//CCS=1,SDHC;CCS=0;SD2.0;
               
        printf("here!");

        if(buff[0]&0x40)
        {
        printf("SDHC!");
                SD_Type = SD_TYPE_V2HC;                         //类型为SDHC
        }
        else
        {
        printf("SD2.0!");
                SD_Type = SD_TYPE_V2;                           //类型为SD2.0
        }
        SPI2_SetSpeed(SPI_BaudRatePrescaler_2 );          //SPI4时钟频率配置为45MHz

        }
        return 0;
       
}

//@brief:向SD卡发送命令(发送结束后关闭片选信号)
//@param:cmd start bit+transmission bit+command index
//@param:arg
//@param :crc CRC7+end bit
//@retval: r1:命令响应
u8 SD_SendCommand(u8 cmd,u32 arg,u8 crc)
{
        unsigned char r1;
        unsigned int Retry = 0;

        SPI_SD_CS_HIGH();//SD_CS = 1;

        SPI2_ReadWriteByte(0xff);

        SPI_SD_CS_LOW();//SD_CS = 0;

        SPI2_ReadWriteByte(cmd|0x40);                                //将CMD命令中的传输位设置为1
        SPI2_ReadWriteByte((u8)(arg>>24));                           //写入CMD命令的32位参数
        SPI2_ReadWriteByte((u8)(arg>>16));
        SPI2_ReadWriteByte((u8)(arg>>8));
        SPI2_ReadWriteByte((u8)(arg));
        SPI2_ReadWriteByte(crc);                                     //写入CRC校验和

        while((r1 = SPI2_ReadWriteByte(0xff))==0xff)                 //接收到相关命令的正确响应后退出
        {
                Retry++;
                if(Retry>800)
                        {
                        printf("time!!");
                        break;                                       //超时退出
                        }
        }

        SPI_SD_CS_HIGH();//SD_CS = 1;

        SPI2_ReadWriteByte(0xff);                                    //额外发送8个时钟信号,使SD卡完成剩余工作

        return r1;
}

//@brief:向SD卡发送命令(发送结束后持续打开片选信号)
//@param:cmd start bit+transmission bit+command index
//@param:arg
//@param :crc CRC7+end bit
//@retval:r1:命令响应
u8 SD_SendCommand_NoDeassert(u8 cmd,u32 arg,u8 crc)
{
        unsigned char r1;
        unsigned int Retry = 0;

        SPI_SD_CS_HIGH();//SD_CS = 1;

        SPI2_ReadWriteByte(0xff);

        SPI_SD_CS_LOW();//SD_CS = 0;

        SPI2_ReadWriteByte(cmd|0x40);
        SPI2_ReadWriteByte((u8)(arg>>24));
        SPI2_ReadWriteByte((u8)(arg>>16));
        SPI2_ReadWriteByte((u8)(arg>>8));
        SPI2_ReadWriteByte((u8)(arg));
        SPI2_ReadWriteByte(crc);

        while((r1 = SPI2_ReadWriteByte(0xff))==0xff)
        {
                Retry++;
                if(Retry >800) break;
        }
        return r1;
}

//@brief:从SD卡中读取指定长度的数据
//@param:*data 指向存储读回数据的缓冲区的指针
//@param:len 数据长度
//@param:release 读取结束后是否释放总线
//@retval:1:错误 0:正确
u8 SD_ReceiveData(u8 *data,u16 len,u8 release)
{
        u16 retry;
        u8 r1;
       

        SPI_SD_CS_LOW();//SD_CS = 0;

        retry = 0;
        do
        {
                r1 = SPI2_ReadWriteByte(0xff);
                retry++;
                if(retry>4000)
                {
                        SPI_SD_CS_HIGH();//SD_CS  = 1;
                        return 1;                                      //超时退出
                }
        }while(r1!=0xfe);                                  //主机收到SD卡传回的正确数据读取响应退出

//接收到正确响应后,开始接收数据
        while(len--)
        {
                *data = SPI2_ReadWriteByte(0xff);
                //printf("0x%02x ", *data);
                data++;
               
        }

        SPI2_ReadWriteByte(0xff);                          //发送2个无效CRC
        SPI2_ReadWriteByte(0xff);

        if(release == RELEASE)                             //是否需要释放总线
        {
                SPI_SD_CS_HIGH();//SD_CS = 1;
                SPI2_ReadWriteByte(0xff);
        }

        return 0;
}

//@brief:获取CID寄存器数据
//@param:*cid_data 指向存储CID寄存器数据的缓冲区的指针
//@retval:0:正确 r1:命令响应
u8 SD_GetCID(u8 *cid_data)
{
        u8 r1;
       

        r1 = SD_SendCommand(CMD10,0,0xff);                    //发送CMD10命令以获取CID寄存器数据
        if(r1!=0x00)
                return r1;                                      //主机未接收到正确响应退出

                SD_ReceiveData(cid_data,16,RELEASE);            //接收CID寄存器数据并释放总线
                return 0;
}

//@brief:获取CSD寄存器数据
//@param:*csd_data 指向存储CSD寄存器数据的缓冲区的指针
//@retval:0:正确 r1:命令响应
u8 SD_GetCSD(u8 *csd_data)
{
        u8 r1;
       

        r1 = SD_SendCommand(CMD9,0,0xff);                     //发送CMD9命令以获取CSD寄存器数据
        if(r1!=0x00)
                return r1;                                      //主机未接收到正确响应退出

                SD_ReceiveData(csd_data,16,RELEASE);            //接收CSD寄存器数据并释放总线
                return 0;
}
/*检查sd卡是否正常*/
u8 SD_is_Ready(void)
{
        u8 cid[36];
        return SD_GetCSD( cid );
}
//@brief:获取SD卡容量信息
//@param:
//@retval:Capacity:SD卡容量
u32 SD_GetCapacity(void)
{
    u8 csd[16];
    u32 Capacity;
    u8 r1;
    u16 i;
    u16 temp;

    if(SD_GetCSD(csd)!=0)
    return 0;                                      //未成功获取CSD寄存器数据退出

    if((csd[0]&0xC0)==0x40)                        //如果CSD寄存器版本为v2.0
    {
                        Capacity=((u32)csd[8])<<8;
      Capacity+=(u32)csd[9]+1;
                        Capacity = ((u32)Capacity)/2;
       //Capacity = (Capacity)*1024;                      //得到扇区数
       //Capacity*=512;                                    //得到字节数
                       
    }
    else                                                      //如果CSD寄存器版本是v1.0
    {
       i = csd[6]&0x03;
       i<<=8;
       i += csd[7];
       i<<=2;
       i += ((csd[8]&0xc0)>>6);
       r1 = csd[9]&0x03;
       r1<<=1;
       r1 += ((csd[10]&0x80)>>7);
       r1+=2;
       temp = 1;
       while(r1)
       {
        temp*=2;
         r1--;
       }
       Capacity = ((u32)(i+1))*((u32)temp);
       i = csd[5]&0x0f;
       temp = 1;
   while(i)
   {
      temp*=2;
      i--;
   }

   Capacity *= (u32)temp;                          //得到字节数
   }
   return (u32)Capacity;                           //返回SD卡容量(字节)
}

//@brief:singleblock读取
//@param:sector 数据地址(扇区地址)
//@param:*buffer 指向存储读回数据的缓冲的指针
//@retval:0:正确 r1:命令响应
u8 SD_ReadSingleBlock(u32 sector, u8 *buffer)
{
  u8 r1;       

  SPI2_SetSpeed(SPI_BaudRatePrescaler_256 );          //SPI4时钟频率配置为45MHz

  if(SD_Type!=SD_TYPE_V2HC)                                //如果不是SDHC卡
  {
    sector = sector<<9;                                    //512*sector即物理扇区的边界对齐地址
  }
   r1 = SD_SendCommand(CMD17,sector, 1);                  //发送CMD17 读单块命令
   if(r1 != 0x00)        return r1;                        //未接收到CMD17的正确响应退出
   r1 = SD_ReceiveData(buffer, 512, RELEASE);              //一个扇区为512字节 读取数据并释放总线
   if(r1 != 0)
     return r1;                                     //读取数据失败退出
   else
     return 0;                                                   //读取数据成功
}

//@brief:multiblock读取
//@param:sector 数据地址(扇区地址)
//@param:*buff 指向存储读回数据的缓冲的指针
//@param:count 要读取的扇区数量
//@retval:0:正确 count:未处理完扇区数 r1:命令响应
u8 SD_ReadMultiBlock(u8 *buffer, u32 sector, u32 count)
{
  u8 r1;        //u8 buffer;
       
  SPI2_SetSpeed(SPI_BaudRatePrescaler_2);                       //SPI4时钟频率配置为45MHz

  if(SD_Type != SD_TYPE_V2HC)
  {
            sector = sector<<9;
  }
  sector = sector;
  r1 = SD_SendCommand(CMD18, sector, 1);                        //发送CMD18 读多块命令
  if(r1 != 0x00)        return r1;
  do                                                                  //开始接收数据
  {
            if(SD_ReceiveData((u8 *)buffer, 512, NO_RELEASE) != 0x00)       //读取数据完成后不释放总线
            {
                       break;                                                //读取数据失败退出
            }
            buffer += 512;
  }while(--count);                                              //数据接收全部完成

  SD_SendCommand(CMD12, 0, 1);                                        //全部传输完成,发送停止命令
  SPI_SD_CS_HIGH();//SD_CS=1;                                                          //释放总线
  SPI2_ReadWriteByte(0xFF);
  if(count != 0)
    return count;                                               //如果数据传输中途因错误退出,返回剩余扇区个数
  else
    return 0;
}

//@brief:SD卡繁忙检测
//@param:
//@retval:0:空闲 1:繁忙
u8 SD_WaitReady(void)
{
  u8 r1;
  u16 retry=0;
  do
  {
    r1 = SPI2_ReadWriteByte(0xFF);              //当SD卡繁忙,数据线会被拉低;当SD卡结束繁忙后,数据线会被拉高
    retry++;
    if(retry==0xfffe)
            return 1;
  }while(r1!=0xFF);
   return 0;
}

//@brief:singleblock写入
//@param:sector 数据地址(扇区地址)
//@param:*data 指向存储要写入SD卡的数据的缓冲区的指针
//@retval:0:正确 1:超时 r1:命令响应
u8 SD_WriteSingleBlock(u32 sector, const u8 *data)
{
          u8 r1;
          u16 i;
          u16 retry;

          SPI2_SetSpeed(SPI_BaudRatePrescaler_2);                       //SPI4时钟频率配置为45MHz

    if(SD_Type!=SD_TYPE_V2HC)                                            //如果不是SDHC卡,将sector地址转为byte地址
          {
                     sector = sector<<9;
          }

        r1 = SD_SendCommand(CMD24, sector, 0x00);                        //发送CMD24 写扇区命令
          if(r1 != 0x00)
          {
                    return r1;
          }

        SPI_SD_CS_LOW();//SD_CS = 0;                                           //开始准备写入数据

          SPI2_ReadWriteByte(0xff);                                      //先发3个空数据,等待SD卡准备好
          SPI2_ReadWriteByte(0xff);
          SPI2_ReadWriteByte(0xff);

    SPI2_ReadWriteByte(0xFE);                                      //发送数据发送起始符号

          for(i=0;i<512;i++)                                            //发送一个sector的数据
          {
                     SPI2_ReadWriteByte(*data++);
          }

          SPI2_ReadWriteByte(0xff);                                      //发送2个无效CRC校验
          SPI2_ReadWriteByte(0xff);

          r1 = SPI2_ReadWriteByte(0xff);                                 //等待SD卡的数据响应符号

          if((r1&0x1F)!=0x05)                                           //如果为r1=0x05则数据写入成功
          {
                     SPI_SD_CS_HIGH();//SD_CS = 1;
                     return r1;                                                //否则释放总线并退出
          }

          retry = 0;                                                          //等待操作完成

          while(!SPI2_ReadWriteByte(0xff))                               //SD卡自编程时,数据线被拉低
          {
                     retry++;
                     if(retry>65534)                                           //如果超时写入未完成,退出报错
                     {
                        SPI_SD_CS_HIGH();//SD_CS = 1;
                        return 1;                                             //写入超时,返回1
                     }
          }

          SPI_SD_CS_HIGH();//SD_CS = 1;                                               //写入完成,片选置1
          SPI2_ReadWriteByte(0xff);
        return 0;
}

//@brief:multiblock写入
//@param:sector 数据地址(扇区地址)
//@param:*data 指向存储要写入SD卡的数据的缓冲区的指针
//@param:count 要写入的扇区数量
//@retval:0:正确 1:超时 count:未处理完扇区数 r1:命令响应
u8 SD_WriteMultiBlock(const u8 *data, u32 sector, u8 count)
{
          u8 r1;
          u16 i;

          SPI2_SetSpeed(SPI_BaudRatePrescaler_2);                       //SPI4时钟频率配置为45MHz

          if(SD_Type != SD_TYPE_V2HC)
        {
                sector = sector<<9;
        }
          /*if(SD_Type != SD_TYPE_MMC)
        {
                 r1 = SD_SendCommand(ACMD23, count, 0x01);               //启用ACMD23指令使能预擦除
        }*/

        r1 = SD_SendCommand(CMD25, sector, 0x01);                  //发送CMD25 写多块命令

          if(r1 != 0x00)        return r1;

          SPI_SD_CS_LOW();//SD_CS = 0;                                                  //开始准备数据传输

          SPI2_ReadWriteByte(0xff);                                       //发送3个空数据让SD卡准备好
          SPI2_ReadWriteByte(0xff);
    SPI2_ReadWriteByte(0xff);

          do                                                            //下面是N个sector循环写入的部分
          {

                 SPI2_ReadWriteByte(0xFC);                                //发送数据传输起始符号0xFC,表明是多块写入

                 for(i=0;i<512;i++)                                      //发1个sector的数据
                 {
                SPI2_ReadWriteByte(*data++);
                 }

           SPI2_ReadWriteByte(0xff);                                     //发2个伪CRC
     SPI2_ReadWriteByte(0xff);

                 r1 = SPI2_ReadWriteByte(0xff);                           //等待SD卡回应

                 if((r1&0x1F)!=0x05)                                     //如果r1=0x05则表示数据写入成功
                 {
                SPI_SD_CS_HIGH();//SD_CS = 1;                                         //写入失败则释放总线退出
                return r1;
                 }

                 if(SD_WaitReady()==1)                                   //检测SD卡忙信号
                {
                SPI_SD_CS_HIGH();//SD_CS = 1;                                           //如果长时间写入未完成,释放总线并退出
                return 1;
                }
   }while(--count);

       SPI2_ReadWriteByte(0xFD);                                   //发送数据传输结束符号0xFD

       if(SD_WaitReady())                                         //等待准备好
       {
           SPI_SD_CS_HIGH();//SD_CS = 1;                                            //超时未退出繁忙则释放总线并退出
           return 1;
        }

       SPI_SD_CS_HIGH();//SD_CS = 1;                                           //写入完成,片选置1
       SPI2_ReadWriteByte(0xff);

       return count;                                              //返回count值,如果写完,则count=0,否则count=未写完的sector数
}


//读SD卡
//buf:读数据缓存区
//sector:扇区地址
//cnt:扇区个数       
//返回值:错误状态;0,正常;其他,错误代码;                                                                   
u8 SD_ReadDisk(u8*buf,u32 sector,u8 cnt)
{
        u8 sta=0;
        long long lsector=sector;
        u8 n;
        lsector<<=9;
        if((u32)buf%4!=0)
        {
                 for(n=0;n<cnt;n++)
                {
                         sta=SD_ReadSingleBlock(lsector+512*n, SPISD_DATA_BUFFER);//单个sector的读操作
                        memcpy(buf,SPISD_DATA_BUFFER,512);
                        buf+=512;
                }
        }else
        {
                if(cnt==1)sta=SD_ReadSingleBlock(lsector, buf);            //单个sector的读操作
                else sta=SD_ReadMultiBlock(buf,lsector,cnt);//多个sector  
        }
        return sta;
}
//写SD卡
//buf:写数据缓存区
//sector:扇区地址
//cnt:扇区个数       
//返回值:错误状态;0,正常;其他,错误代码;       
u8 SD_WriteDisk(u8*buf,u32 sector,u8 cnt)
{
        u8 sta=0;
        u8 n;
        long long lsector=sector;
        lsector<<=9;
        if((u32)buf%4!=0)
        {
                 for(n=0;n<cnt;n++)
                {
                        memcpy(SPISD_DATA_BUFFER,buf,512);
                         sta=SD_WriteSingleBlock(lsector+512*n, SPISD_DATA_BUFFER);//单个sector的写操作
                        buf+=512;
                }
        }else
        {
                if(cnt==1)sta=SD_WriteSingleBlock(lsector, buf);            //单个sector的写操作
                else sta=SD_WriteMultiBlock(buf,lsector,cnt);        //多个sector  
        }
        return sta;
}



最佳答案

查看完整内容[请看2#楼]

额,把系统时钟初始化的部分改了终于好了。。。要不是我从其他地方找了个程序可以用,一点点对比发现时钟不一样。。。靠我自己一点点找死也找不出来这个原因。。。 还是不明白单独的用着是好的,合并为啥就坏了。。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

2

主题

6

帖子

0

精华

新手入门

积分
18
金钱
18
注册时间
2019-7-4
在线时间
3 小时
 楼主| 发表于 2019-7-4 12:22:53 | 显示全部楼层
额,把系统时钟初始化的部分改了终于好了。。。要不是我从其他地方找了个程序可以用,一点点对比发现时钟不一样。。。靠我自己一点点找死也找不出来这个原因。。。
还是不明白单独的用着是好的,合并为啥就坏了。。
回复

使用道具 举报

2

主题

6

帖子

0

精华

新手入门

积分
18
金钱
18
注册时间
2019-7-4
在线时间
3 小时
 楼主| 发表于 2019-7-4 19:42:51 | 显示全部楼层
自顶。求帮助啊。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-11 07:17

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表