STM32开发_利用SPI协议读写SD卡、介绍SD卡SPI时序

这篇具有很好参考价值的文章主要介绍了STM32开发_利用SPI协议读写SD卡、介绍SD卡SPI时序。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、​  SD卡引脚接口功能介绍

1.1 SD卡引脚

目录

一、​  SD卡引脚接口功能介绍

1.1 SD卡引脚接口图

1.2 SPI方式驱动SD卡介绍

1.3 开发板接口定义

二、MMC卡、SD卡介绍

2.1 SD卡和MMC两者间区别

2.2 SD卡版本说明

2.3 SD卡常用的指令表

三、向SD卡发送命令的步骤介绍(SendSDCardCmd)

3.1 取消选中SD卡(SDCardCancelCS)

3.2 选中SD卡(SDCardSelectCS)

3.3 向SD卡发送操作命令cmd

3.4 向SD卡发送命令参数

3.5 发送CRC校验

3.6 等待SD卡响应

四、SD卡的寄存器与操作命令介绍

4.1 SDCard_CMD0:卡复位命令

4.2 SDCard_CMD8:检测是否是2.0版本的SD卡

4.3 SDCard_CMD9: 获取SD卡的CSD信息

4.4 SDCard_CMD17: 设置单个读取的扇区

4.5 SDCard_CMD18: 设置读扇区(连续读扇区使用)

4.6 SDCard_CMD12: 停止数据传输

4.7 SDCard_CMD24: 设置写单个扇区

4.8 SDCard_CMD55

4.9 SDCard_CMD23: 多扇区写入前预先擦除块数量

4.10 SDCard_CMD25: 设置写多个扇区

4.11 SDCard_CMD41

4.12 SDCard_CMD58

五、SD卡SPI接口命令

5.1 SPI接口时序

5.2 SPI模式下: SD卡初始化步骤(SDCardDeviceInit)

5.3 SPI模式下: 向SD卡发送数据包步骤(SDCardSendData)

5.4 SPI模式下: 从SD卡读取数据包步骤(SDCardRecvData)

5.5 SPI模式下: 向SD卡指定扇区写数据(SDCardWriteData)

5.6 SPI模式下: 从SD卡读取指定扇区数据(SDCardReadData)

5.7 SPI模式下: 获取SD卡的总扇区数(GetSDCardSectorCount)

六、示例代码

6.1 sdcard.c文件

6.2 sdcard.h文件


接口图

stm32 sd卡dma读写时序,STM32单片机开发基础,stm32,单片机,嵌入式硬件

图1-1 SD卡引脚图

stm32 sd卡dma读写时序,STM32单片机开发基础,stm32,单片机,嵌入式硬件

图1-2 SD卡引脚说明

SD卡支持两种总线方式:SD方式与SPI方式。其中SD方式采用6线制,使用CLK、CMD、DAT0~DAT3进行数据通信。而SPI方式采用4线制,使用CS、CLK、DataIn、DataOut进行数据通信。

SD方式时的数据传输速度与SPI方式要快,采用单片机对SD卡进行读写时一般都采用SPI模式。采用不同的初始化方式可以使SD卡工作于SD方式或SPI方式。

1.2 SPI方式驱动SD卡介绍

SD卡的SPI通信接口使其可以通过SPI通道进行数据读写。

从应用的角度来看,采用SPI接口的好处在于,很多单片机内部自带SPI控制器,不光给开发上带来方便,同时也见降低了开发成本。然而,它也有不好的地方,如失去了SD卡的性能优势,要解决这一问题,就要用SD方式,因为它提供更大的总线数据带宽。SPI接口的选用是在上电初始时向其写入第一个命令时进行的。以下介绍SD卡的驱动方法,只实现简单的扇区读写。

1.3 开发板接口定义

根据当前所用开发板原理图为例,SD卡卡槽的接口与STM32 IO口对应如下:

PC11 片选 SDCardCS

PC12 时钟 SDCardSCLK

PD2 输出 SPI_MOSI--主机输出从机输入

PC8 输入 SPI_MISO--主机输入从机输出




SD卡与开发板的SPI方式接线关系如下:

DATA0---PC8-----OUT---MISO---主机输入从机输出

DATA1---PC9

DATA2---PC10

DATA3---PC11----CS

CLK-----PC12-------SCLK

CMD-----PD2------INPUT--MOSI--主机输出从机输入

二、MMC卡、SD卡介绍

2.1 SD卡和MMC两者间区别

SD卡和MMC(多媒体卡)似乎可以使用同一个插槽,两者间有什么区别呢?

不过,虽说外型几乎一致,但还是有点差异的。MMC比SD卡要薄一些。

stm32 sd卡dma读写时序,STM32单片机开发基础,stm32,单片机,嵌入式硬件

图2-1 MMC卡与SD卡

首先得从MMC卡的发展谈起。 MMC卡是由西门子设计,和SanDisk合作开发的小型存储卡标准。 在1997年,作为使用闪存的存储卡(I / O卡或ROM卡都可以)开始发售,日立和NEC,摩托罗拉,诺基亚等共同建立了MMCA(多媒体卡协会)。 并促进了标准​​化和市场推广。

SanDisk公司,也是在94年提出小型闪存卡(以下简称CF)的厂商,但是CF在用于紧凑型概念的产品时,采用了和广泛使用的PC卡的ATA兼容的接口。 这种设计消除了不需要的信号线,管脚数也由68针减少到50针,电气方面可以相互兼容,并且被设计为仅仅通过简单的适配器就可以安装在PC卡插槽中。 然而,CF虽然了PC卡容易替换的好处,但由于管脚的数量巨大,宽度达到43毫米,这样就不太能减下去。 这个在涉及到​​移动电话时,你将无法容纳CF。 因此,在新的设计中,硬件兼容性被舍弃,只致力于小型化的MMC。

CF卡和PC卡的接口,多个并行传输的地址信号和数据信号,各种控制线紧密被布置一起。规格上就是PC的扩展总线这样的接口,但在MMC中,据传输方式变更为串行传输,地址的指定和各种控制也用的是通过一个串行接口交换数据包的方式。 其结果是,主要的信号变成三个:数据,命令,时钟,接口可以降低到仅7针。 接口也从两排的针/socket这种面接触类型变换成小型的薄卡片。体积比的话,CF是PC卡(基于Ⅰ型)的三分之一,而MMC的话则是十四分之一,这么看来MMC已经变得非常紧凑。

以MMC为基础实现了安全(安全性)功能的是东芝,松下,SanDisk三家公司共同研发的SD卡。 该标准本身不是MMC卡的扩展,而是另一种标准,虽然该标准成立了另一个叫SDA(SD卡协会)组织,但它的一大特色是被设计成能够和MMC卡共享插槽 。SD卡的表面积和MMC卡是相同大小的,但是厚度比1.4毫米的MMC增大了0.7毫米,变成2.1毫米。 然而,SD卡的左右部分和MMC卡的厚度一样的,为1.4毫米,所以MMC卡可以直接插入SD卡插槽。(相反,SD卡不能插入MMC卡插槽) 接口的规格也是在MMC卡的管脚排列基础上添加的两条信号线到两侧,传输方法因为和MMC相兼容,也可以从SD卡host访问到MMC。 记录数据的逻辑规范,因为它们用的是相同的FAT文件系统,只要是它被用作简单的记录媒体那就是兼容的。

然而,实际上SD卡主机端的应用程序能否使用的MMC上的数据,因为是涉及到安全和文件格式的问题,所以是由应用程序决定。 特别是用到安全性的情况下,基本上没有兼容性。 SD卡的版权保护机制用到的松下和东芝倡导的是CPRM(内容保护可记录媒体)。 此外,作为MMC卡的安全版本,MMCA发布了安全MMC的版本,它是与MMC完全兼容的更高的标准,但是这里用到是的日立倡导的UDAC MB(Universal Distribution with Access Control-Media Base)的版权保护机制,所以与SD卡不兼容。 此外,现在还没有支持UDAC-MB和CPRM的商品。

此外,SD里添加的两条信号线都是用于数据的信号线。MMC中只有一个数据信号通道,但在SD中MMC中的7号管脚(数据信号)和一号管脚(在MMC中未使用),加上新加的8,9号管脚一共4个通道可以使用,这样就能达到更高的传输速度。 MMC的传输时钟最大是20MHz(时钟可变),所以传输速度最大为20Mbps(2.5MB/s)。 虽说这是和闪存读出速度相当的速度,做为存储卡的规格来说是够了,但是用到I/O卡的情况下,它可能是不够的。 而用到所有四个管脚的SD卡,目前可达到80Mbps(10MB / s)速度。

2.2 SD卡版本说明

SD卡版本:SD V1.X(即SD标准卡)最大容量2GB

SD V2.0 2.0版本的标准卡,最多2GB

SD V2.0HC 2.0高容量卡,最多32GB

说明: 本程序主要针对SD卡2.0 HC 2.0高容量卡协议进行说明。

SD卡默认操作的扇区大小是512字节。扇区大小,可以通过指令设置。就算不是512,也可以通过指令设置成512,因为这个值不太大,占用内存不太多,适合单片机使用。

2.3 SD卡常用的指令表

#define SDCard_CMD0 0 //卡复位

#define SDCard_CMD8 8 //命令8 ,SEND_IF_COND

#define SDCard_CMD9 9 //命令9 ,读CSD数据

#define SDCard_CMD12 12 //命令12,停止数据传输

#define SDCard_CMD13 16 //命令16,设置扇区大小 应返回0x00

#define SDCard_CMD17 17 //命令17,读扇区

#define SDCard_CMD18 18 //命令18,读多个扇区

#define SDCard_CMD23 23 //命令23,设置多扇区写入前预先擦除block

#define SDCard_CMD24 24 //命令24,写扇区

#define SDCard_CMD25 25 //命令25,写多个扇区

#define SDCard_CMD41 41 //命令41,应返回0x00

#define SDCard_CMD55 55 //命令55,应返回0x01

#define SDCard_CMD58 58 //命令58,读OCR信息

三、向SD卡发送命令的步骤介绍(SendSDCardCmd)

3.1 取消选中SD卡(SDCardCancelCS)

发送新的命令之前,需要取消之前的片选,额外发多 8个 CLK (发送0xFF无效数据),结束之前的操作。 (1). 取消片选 (2). 最多发送 8个 CLK

stm32 sd卡dma读写时序,STM32单片机开发基础,stm32,单片机,嵌入式硬件

图3-1 时序图

3.2 选中SD卡(SDCardSelectCS)

(1).选中片选 (2).等待SD卡忙状态

说明: 向SD卡发送0xFF,如果SD卡也返回0xFF就表示SD卡已经准备好,如果返回不是0xFF就表示SD卡还没有准备好,需要等待。

stm32 sd卡dma读写时序,STM32单片机开发基础,stm32,单片机,嵌入式硬件

图3-2 时序图

3.3 向SD卡发送操作命令cmd

将要发送的命令 |0x40 发给SD卡。 示例: cmd | 0x40

命令是8位数据。

stm32 sd卡dma读写时序,STM32单片机开发基础,stm32,单片机,嵌入式硬件

图3-3 时序图

3.4 向SD卡发送命令参数

命令参数是32位数据,SPI每次发送8位,需要发送4次,先发送最高8位,依次再发送低位。

stm32 sd卡dma读写时序,STM32单片机开发基础,stm32,单片机,嵌入式硬件

图3-4 时序图

3.5 发送CRC校验

CRC是8位数据。

注意: 如果发送的是CMD12命令(停止数据传输),在发送CRC校验之后,需要再发送一个0xFF数据。

stm32 sd卡dma读写时序,STM32单片机开发基础,stm32,单片机,嵌入式硬件

图3-5-1 时序图

stm32 sd卡dma读写时序,STM32单片机开发基础,stm32,单片机,嵌入式硬件

图3-5-2 时序图

3.6 等待SD卡响应

向SD卡发送0xFF数据,如果SD卡返回的数据最高位为0,就是表示SD卡响应完成,否则就继续发送0xFF,再判断,直到SD卡响应成功。

SD卡响应之后,完成一次命令发送,并将返回的数据当做返回值返回去。

推荐: 使用do{…}while()循环结构,更加方便判断。

stm32 sd卡dma读写时序,STM32单片机开发基础,stm32,单片机,嵌入式硬件

图3-6 时序图

四、SD卡的寄存器与操作命令介绍

4.1 SDCard_CMD0:卡复位命令

stm32 sd卡dma读写时序,STM32单片机开发基础,stm32,单片机,嵌入式硬件

图 4-1 时序图

4.2 SDCard_CMD8:检测是否是2.0版本的SD卡

发送只有V2.0版的SD卡才具有的命令CMD8,然后检测返回值: 返回值若是0x01,则表示此卡为V2.0卡,然后再发送循环命令CMD55+CMD41,直到返回0x00,确定SD2.0卡初始化成功;

然后再发送CMD58命令,接收返回的OCR寄存器的数据,其中第31位用于判断V2.0的卡是否为SDHC类型。 

若返回值不为0x01,则进一步判断是V1.0卡还是MMC卡:先发送循环命令CMD55+CMD41进行复位,如果复位不成功则考虑是MMC卡,如果复位成功,则为V1.0卡。在复位不成功的情况下,再使用CMD1进行复位,如果复位成功,则表明是MMC卡,如果复位不成功,则表示是无法识别的卡。

stm32 sd卡dma读写时序,STM32单片机开发基础,stm32,单片机,嵌入式硬件

图4-2-1 时序图

stm32 sd卡dma读写时序,STM32单片机开发基础,stm32,单片机,嵌入式硬件

图4-2-2 时序图

stm32 sd卡dma读写时序,STM32单片机开发基础,stm32,单片机,嵌入式硬件

图4-2-3 时序图

stm32 sd卡dma读写时序,STM32单片机开发基础,stm32,单片机,嵌入式硬件

图4-2-4 时序图

鉴别到v2.0版本之后,可以读取OCR 寄存器的值,继续判断是否是V2.0高速卡。

SD卡响应命令成功,可以继续接收4字节的OCR寄存器值;

OCR寄存器的第30位(CCS)指示了卡的类型是否为SDHC,此位为1则为SDHC,为0则为SDSC。

OCR 寄存器,储存了卡的 VDD 电压轮廓图。任何标准的 SD 卡主控制器可以使用 2V 至 3.6V 的工作电压来让 SD 卡能执行这个电压识别操作(CMD1)。而访问存储器的阵列操作无论如何都需要 2.7V 至 3.6V 的工作电压。OCR 寄存器显示了在访问卡的数据时所需要的电压范围。

OCR 寄存器的结构描述:

stm32 sd卡dma读写时序,STM32单片机开发基础,stm32,单片机,嵌入式硬件

图4-2-5 时序图

stm32 sd卡dma读写时序,STM32单片机开发基础,stm32,单片机,嵌入式硬件

图4-2-6 时序图

4.3 SDCard_CMD9: 获取SD卡的CSD信息

CSD包括容量和速度信息,存放CID的内存,至少16Byte

CMD9的命令:

stm32 sd卡dma读写时序,STM32单片机开发基础,stm32,单片机,嵌入式硬件

图4-3

4.4 SDCard_CMD17: 设置单个读取的扇区

stm32 sd卡dma读写时序,STM32单片机开发基础,stm32,单片机,嵌入式硬件

图4-4

4.5 SDCard_CMD18: 设置读扇区(连续读扇区使用)

stm32 sd卡dma读写时序,STM32单片机开发基础,stm32,单片机,嵌入式硬件

图4-5

4.6 SDCard_CMD12: 停止数据传输

stm32 sd卡dma读写时序,STM32单片机开发基础,stm32,单片机,嵌入式硬件

图4-6

4.7 SDCard_CMD24: 设置写单个扇区

stm32 sd卡dma读写时序,STM32单片机开发基础,stm32,单片机,嵌入式硬件

图4-7

4.8 SDCard_CMD55

stm32 sd卡dma读写时序,STM32单片机开发基础,stm32,单片机,嵌入式硬件

图4-8

4.9 SDCard_CMD23: 多扇区写入前预先擦除块数量

stm32 sd卡dma读写时序,STM32单片机开发基础,stm32,单片机,嵌入式硬件

图4-9

4.10 SDCard_CMD25: 设置写多个扇区

stm32 sd卡dma读写时序,STM32单片机开发基础,stm32,单片机,嵌入式硬件

图4-10

4.11 SDCard_CMD41

stm32 sd卡dma读写时序,STM32单片机开发基础,stm32,单片机,嵌入式硬件

图4-11

4.12 SDCard_CMD58

stm32 sd卡dma读写时序,STM32单片机开发基础,stm32,单片机,嵌入式硬件

图4-12

五、SD卡SPI接口命令

5.1 SPI接口时序

stm32 sd卡dma读写时序,STM32单片机开发基础,stm32,单片机,嵌入式硬件

图5-1 SPI时序图

stm32 sd卡dma读写时序,STM32单片机开发基础,stm32,单片机,嵌入式硬件

图5-2 SPI时序图

数据先发/先收高位

从图上得知(SD卡在SPI模式下): 下降沿写数据、时钟的上升沿读数据。

示例:

u8 SDCardReadWriteOneByte(u8 DataTx)
{		 
    u8 i;
    u8 data=0;
    for(i=0;i<8;i++)
    {
        SDCARD_SCK=0;
        if(DataTx&0x80)SDCARD_MOSI=1;
        else SDCARD_MOSI=0;
        SDCARD_SCK=1;
        DataTx<<=1;
        
        data<<=1;
        if(SDCARD_MISO)data|=0x01;
    }
    return data;
}

5.2 SPI模式下: SD卡初始化步骤(SDCardDeviceInit)

SD卡的初始化是非常重要的,只有进行了正确的初始化,才能进行后面的各项操作。在初始化过程中,SPI的时钟不能太快,否则会造初始化失败。在初始化成功后,应尽量提高SPI的速率。在刚开始要先发送至少74个时钟信号,这是必须的。如果接到复位命令(CMD0)时,CS信号有效(低电平),SPI模式启用。

详细步骤:

1. 初始化与 SD卡连接的硬件条件(MCU的 SPI配置,IO口配置等等)




2. 向总线最少发送74个脉冲,为了让SD卡正常启动 (唤醒SD卡)

(解释: 就是时钟线至少需要74个跳变,向MOSI发送0xFF数据即可,这是无效数据)




3. 复位卡(CMD0),进入 IDLE(闲置)状态。

说明: 最后的返回值等于0x01就表示复位成功。




4. 发送 CMD8,检查是否支持 2.0协议,因为这个命令是在2.0的协议里面才添加的

说明: 发送 CMD8命令之后,返回值等于0x01表示就是2.0版本的SD卡。




5. 如果是2.0版本的SD卡,就需要循环发送CMD55+ CMD41命令等待2.0卡初始化成功,如果CMD41命令的返回值等于0就表示卡复位成功。(先发CMD55,再发CMD41)




6. 2.0卡初始化成功后,再发送CMD58命令,继续判断是否是高速卡。

说明: CMD58命令返回值等于0,表示执行成功。然后就可以读取4字节的OCR 寄存器的值。OCR寄存器的第30位(CCS)指示了卡的类型是否为SDHC,此位为1则为SDHC,为0则为SDSC。

如果只是为了判断是否是高速卡,可以只读取1个字节数据即可,因为SD返回的数据先返回的是高位数据(24~31),后面的数据可以不读取。




7. 取消片选,结束初始化。

说明: 取消片选之后,需要再额外发送8个时钟信号,结束本次操作。

5.3 SPI模式下: 向SD卡发送数据包步骤(SDCardSendData)

每次发送数据包默认为512字节。

1. 等待SD卡忙状态

向SD卡发送一个0xFF数据,如果SD卡也原路返回0xFF就表示SD卡处于闲置状态。

2. 发送(开始传输)/(结束传输)的标志

写一个扇区的情况下发送0xFE开始传输数据。

写多个扇区的情况下发送0xFC开始传输数据。

写多个扇区的情况下,连续发送数据完成之后,发送0xFD结束数据发送。

3. 如果不是结束标志(0xFD),就是表示发送的是正常的数据包,就进行循环发送512字节的数据。

注意: 每次发送数据包的单位是按扇区为单位的,也就是512字节,一包数据长度固定为512字节。

4. 数据发送完之后,再接着发送0xFF忽略CRC校验(连续发送3个0xFF)。

stm32 sd卡dma读写时序,STM32单片机开发基础,stm32,单片机,嵌入式硬件

图5-3-1

5.4 SPI模式下: 从SD卡读取数据包步骤(SDCardRecvData)

1、等待SD卡发回数据起始令牌0xFE

向SD卡发送0xFF,如果SD卡返回0xFE就表示等待成功。

stm32 sd卡dma读写时序,STM32单片机开发基础,stm32,单片机,嵌入式硬件

图5-4-1

2、收到返回的数据起始令牌之后就可以连续读取数据了(接收的数量以传入的cnt为准),读完数据发送两个伪CRC

stm32 sd卡dma读写时序,STM32单片机开发基础,stm32,单片机,嵌入式硬件

图5-4-2

5.5 SPI模式下: 向SD卡指定扇区写数据(SDCardWriteData)

封装的函数原型: SDCardWriteData(u8*buf,u32 sector,u32 cnt)

写一个扇区步骤:

1、发送CMD24命令,设置要写的扇区。(写单个扇区使用CMD24命令)

2、接着向SD卡写数据包(参考5.3小节)。

stm32 sd卡dma读写时序,STM32单片机开发基础,stm32,单片机,嵌入式硬件

图5-5-1

写多个扇区的步骤:

1、发送CMD55命令(正常应返回0x01)

2、​ 发送CMD23命令(设置多扇区写入前预先擦除N个block)---写入的数量

3、​ 发送CMD25命令,设置写入的扇区位置。(设置写多个扇区)

4、 接着向SD卡写数据包(参考5.3小节)。

stm32 sd卡dma读写时序,STM32单片机开发基础,stm32,单片机,嵌入式硬件

图5-5-2

5、写结束指令0xFD,完成写入。

stm32 sd卡dma读写时序,STM32单片机开发基础,stm32,单片机,嵌入式硬件

图5-5-3

6、 取消片选

5.6 SPI模式下: 从SD卡读取指定扇区数据(SDCardReadData)

读取一个扇区的步骤:

1、​ 发送CM17命令,设置读取的扇区

2、 接着进行接收SD卡返回的数据包。(参考5.4小节)

每次固定接收512字节,以扇区为单位。

3、 取消片选,完成数据读取

说明: 取消片选之后,需要再额外发送8个时钟信号,结束本次操作。

读取多个扇区的步骤:

1、 发送CMD18命令,设置读取的扇区(连续读多个扇区使用)

2、​ 接着循环接收SD卡返回的数据包。(参考5.4小节)

每次固定接收512字节,以扇区为单位。

3、 发送CMD12指令,停止数据传输

4、 取消片选,完成数据读取

说明: 取消片选之后,需要再额外发送8个时钟信号,结束本次操作。

5.7 SPI模式下: 获取SD卡的总扇区数(GetSDCardSectorCount)

1、 发送CMD9命令,读取CSD信息

2、 连续接收16个字节数据包。(参考5.4小节)

3、 取消片选,完成读取

4、 判断是否是v2.0 SDHC高速卡。

使用读取的第一个字节数据csd[0]&0xC0判断是否等于0x40,如果等于0x40就是v2.0高速卡。

5、 如果是v2.0 SDHC高速卡就按照以下公式计算得到扇区数量文章来源地址https://www.toymoban.com/news/detail-567947.html

csize=csd[9]+(csd[8]<<8)+1;

Capacity=csize<<10;//得到总扇区数

六、示例代码

6.1 sdcard.c文件

#include "sdcard.h"			   

/*
函数功能:SD卡底层接口,通过SPI时序向SD卡读写一个字节
函数参数:data是要写入的数据
返 回 值:读到的数据
*/
u8 SDCardReadWriteOneByte(u8 DataTx)
{		 
    u8 i;
    u8 data=0;
    for(i=0;i<8;i++)
    {
        SDCARD_SCK=0;
        if(DataTx&0x80)SDCARD_MOSI=1;
        else SDCARD_MOSI=0;
        SDCARD_SCK=1;
        DataTx<<=1;
        
        data<<=1;
        if(SDCARD_MISO)data|=0x01;
    }
    return data;
}


//4种: 边沿两种、电平是两种
/*
函数功能:底层SD卡接口初始化

本程序SPI接口如下:
PC11  片选 SDCardCS
PC12  时钟 SDCardSCLK
PD2   输出 SPI_MOSI--主机输出从机输入
PC8   输入 SPI_MISO--主机输入从机输出
*/
void SDCardSpiInit(void)
{
  /*1. 开启时钟*/
 	RCC->APB2ENR|=1<<5;		    //使能PORTD时钟
	RCC->APB2ENR|=1<<4;		    //使能PORTC时钟
  
  /*2. 配置GPIO口模式*/
  GPIOC->CRH&=0xFFF00FF0;
  GPIOC->CRH|=0x00033008;
  
  GPIOD->CRL&=0xFFFFF0FF;
  GPIOD->CRL|=0x00000300;
  
  /*3. 上拉*/
  GPIOC->ODR|=1<<8;
  GPIOC->ODR|=1<<11;
  GPIOC->ODR|=1<<12;
  GPIOD->ODR|=1<<2;
}

/*
函数功能:从sd卡读取一个数据包的内容
函数参数:
				buf:数据缓存区
				len:要读取的数据长度.
返回值:
			0,成功;其他,失败;	
*/
u8 SDCardRecvData(u8*buf,u16 len)
{			  	  
		while(SDCardReadWriteOneByte(0xFF)!=0xFE){}//等待SD卡发回数据起始令牌0xFE 
    while(len--)//开始接收数据
    {
        *buf=SDCardReadWriteOneByte(0xFF);
        buf++;
    }
    //下面是2个伪CRC(dummy CRC)
    SDCardReadWriteOneByte(0xFF);
    SDCardReadWriteOneByte(0xFF);									  					    
    return 0;//读取成功
}


/*
函数功能:向sd卡写入一个数据包的内容 512字节
函数参数:
					buf 数据缓存区
					cmd 指令
返 回 值:0表示成功;其他值表示失败;
*/
u8 SDCardSendData(u8*buf,u8 cmd)
{	
	u16 t;		  	  
	while(SDCardReadWriteOneByte(0xFF)!=0xFF){}  //等待忙状态
	SDCardReadWriteOneByte(cmd);
	if(cmd!=0xFD)//不是结束指令
	{
		  for(t=0;t<512;t++)SDCardReadWriteOneByte(buf[t]);//提高速度,减少函数传参时间
	    SDCardReadWriteOneByte(0xFF); //忽略crc
	    SDCardReadWriteOneByte(0xFF);
		  SDCardReadWriteOneByte(0xFF); //接收响应								  					    
	}						 									  					    
  return 0;//写入成功
}


/*
函数功能:向SD卡发送一个命令
函数参数:
				u8 cmd   命令 
				u32 arg  命令参数
				u8 crc   crc校验值	
返回值:SD卡返回的响应
*/												  
u8 SendSDCardCmd(u8 cmd, u32 arg, u8 crc)
{
	u8 r1;	
	SDCARD_CS=1; //取消上次片选
 	SDCardReadWriteOneByte(0xff);//提供额外的8个时钟
	SDCARD_CS=0; //选中SD卡
	while(SDCardReadWriteOneByte(0xFF)!=0xFF){};//等待成功

	//发送数据
	SDCardReadWriteOneByte(cmd | 0x40);//分别写入命令
	SDCardReadWriteOneByte(arg >> 24);
	SDCardReadWriteOneByte(arg >> 16);
	SDCardReadWriteOneByte(arg >> 8);
	SDCardReadWriteOneByte(arg);	  
	SDCardReadWriteOneByte(crc); 
	
	if(cmd==SDCard_CMD12)SDCardReadWriteOneByte(0xff);//Skip a stuff byte when stop reading
	do
	{
		r1=SDCardReadWriteOneByte(0xFF);
	}while(r1&0x80);	  //等待响应,或超时退出
	return r1;
}


/*
函数功能:获取SD卡的总扇区数(扇区数)   
返 回 值:
				0表示容量检测出错,其他值表示SD卡的容量(扇区数/512字节)
说   明:
				每扇区的字节数必为512字节,如果不是512字节,则初始化不能通过.	
*/
u32 GetSDCardSectorCount(void)
{
    u8 csd[16];
    u32 Capacity=0;  
	  u16 csize;
		//获取SD卡的CSD信息,包括容量和速度信息,存放CID的内存,至少16Byte
		SendSDCardCmd(SDCard_CMD9,0,0x01);//发SDCard_CMD9命令,读CSD
	  SDCardRecvData(csd,16);//接收16个字节的数据 
		SDCARD_CS=1;//取消片选
		SDCardReadWriteOneByte(0xff);//提供额外的8个时钟
    if((csd[0]&0xC0)==0x40)  //SDHC卡,按照下面方式计算
    {	
			csize=csd[9]+(csd[8]<<8)+1;
			Capacity=csize<<10;//得到扇区数	 		   
    }
    return Capacity;
}


/*
函数功能: 初始化SD卡
返 回 值: 非0表示初始化失败!
*/
u8 SDCardDeviceInit(void)
{
  u8 r1=0;      // 存放SD卡的返回值
  u8 data;  
	u16 i;
	/*1. 初始化底层IO口*/
	SDCardSpiInit();
	
	/*2. 发送最少74个脉冲*/
 	for(i=0;i<10;i++)SDCardReadWriteOneByte(0xFF);
	
	/*3. 进入闲置状态*/
	do
	{
		r1=SendSDCardCmd(SDCard_CMD0,0,0x95);
	}while(r1!=0x01);
	
	/*4. 鉴别是否是2.0版本的SD卡*/
	if(SendSDCardCmd(SDCard_CMD8,0x1AA,0x87)==0x01)
	{
			do
			{
				SendSDCardCmd(SDCard_CMD55,0,0x01);	    //发送SDCard_CMD55
				r1=SendSDCardCmd(SDCard_CMD41,0x40000000,0x01);//发送SDCard_CMD41
			}while(r1);
			
			if(SendSDCardCmd(SDCard_CMD58,0,0x01)==0)//鉴别SD2.0卡版本开始
			{
				data=SDCardReadWriteOneByte(0xFF);//得到OCR值
				if(data&0x40)
				{
						r1=0; //高速卡
				}					
			}
	} 
	SDCARD_CS=1;//取消片选
 	SDCardReadWriteOneByte(0xff);//提供额外的8个时钟
	return r1;          //其他错误
}


/*
函数功能:读SD卡
函数参数:
				buf:数据缓存区
				sector:扇区
				cnt:扇区数
返回值:
				0,ok;其他,失败.
说  明:
				SD卡一个扇区大小512字节
*/
void SDCardReadData(u8*buf,u32 sector,u32 cnt)
{
	u32 i=0;
	if(cnt==1)
	{
		SendSDCardCmd(SDCard_CMD17,sector,0x01);//读扇区
		SDCardRecvData(buf,512);			//接收512个字节	   
	}
	else
	{
		SendSDCardCmd(SDCard_CMD18,sector,0x01);//连续读命令
		for(i=0;i<cnt;i++)
		{
			SDCardRecvData(buf,512);//接收512个字节	 
			buf+=512;  
		}
		SendSDCardCmd(SDCard_CMD12,0,0x01);	//停止数据传输
	}   
	SDCARD_CS=1;//取消片选
 	SDCardReadWriteOneByte(0xff);//提供额外的8个时钟();
}


/*
函数功能:向SD卡写数据
函数参数:
				buf:数据缓存区
				sector:起始扇区
				cnt:扇区数
说  明:
				SD卡一个扇区大小512字节
*/
void SDCardWriteData(u8*buf,u32 sector,u32 cnt)
{
	u32 i=0;
	if(cnt==1)
	{
		SendSDCardCmd(SDCard_CMD24,sector,0x01);//写单个扇区
		SDCardSendData(buf,0xFE);//写512个字节	   
	}
	else
	{
		SendSDCardCmd(SDCard_CMD55,0,0x01);	
		SendSDCardCmd(SDCard_CMD23,cnt,0x01);   //设置多扇区写入前预先擦除N个block
 		SendSDCardCmd(SDCard_CMD25,sector,0x01);//写多个扇区
		for(i=0;i<cnt;i++)
		{
			SDCardSendData(buf,0xFC);//写512个字节	 
			buf+=512;  
		}
		SDCardSendData(0,0xFD);//写结束指令
	}
	SDCARD_CS=1;
 	SDCardReadWriteOneByte(0xff);//提供额外的8个时钟

6.2 sdcard.h文件

#ifndef SD_H_
#define SD_H_	 
#include "stm32f10x.h"
#include "led.h"
#include "key.h"
#include "usart.h"

/*----------------------------------------------
本程序SPI接口如下:
PC11  片选 SDCardCS
PC12  时钟 SDCardSCLK
PD2   输出 SPI_MOSI--主机输出从机输入
PC8   输入 SPI_MISO--主机输入从机输出
------------------------------------------------*/
#define SDCARD_CS PCout(11)
#define SDCARD_SCK PCout(12)
#define SDCARD_MOSI PDout(2)
#define SDCARD_MISO PCin(8)

// SD卡指令表  	   
#define SDCard_CMD0    0       //卡复位
#define SDCard_CMD8    8       //命令8 ,SEND_IF_COND
#define SDCard_CMD9    9       //命令9 ,读CSD数据
#define SDCard_CMD12   12      //命令12,停止数据传输
//#define SDCard_CMD13   16      //命令16,设置扇区大小 应返回0x00
#define SDCard_CMD17   17      //命令17,读扇区
#define SDCard_CMD18   18      //命令18,读多个扇区
#define SDCard_CMD23   23      //命令23,设置多扇区写入前预先擦除N个block
#define SDCard_CMD24   24      //命令24,写扇区
#define SDCard_CMD25   25      //命令25,写多个扇区
#define SDCard_CMD41   41      //命令41,应返回0x00
#define SDCard_CMD55   55      //命令55,应返回0x01
#define SDCard_CMD58   58      //命令58,读OCR信息

//函数声明              
u8 SDCardReadWriteOneByte(u8 data);                 //底层接口,SPI读写字节函数
u8 SDCardDeviceInit(void);							            //初始化
void SDCardReadData(u8*buf,u32 sector,u32 cnt);		  //读块(扇区)
void SDCardWriteData(u8*buf,u32 sector,u32 cnt);		//写块(扇区)
u8 SDCardSendData(u8*buf,u8 cmd);  									//发送数据包
u8 SDCardRecvData(u8*buf,u16 len);									//接收数据包
u32 GetSDCardSectorCount(void);   					        //读扇区数
#endif

到了这里,关于STM32开发_利用SPI协议读写SD卡、介绍SD卡SPI时序的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM-32:SPI通信协议/W25Q64简介—软件SPI读写W25Q64

    SPI是串行外设接口(Serial Peripheral Interface)的缩写,是美国摩托罗拉公司(Motorola)最先推出的一种同步串行传输规范,也是一种单片机外设芯片串行扩展接口,是一种高速、全双工、同步通信总线,所以可以在同一时间发送和接收数据,SPI没有定义速度限制,通常能达到甚

    2024年02月16日
    浏览(43)
  • STM32F429 Discovery开发板应用:实现SPI-SD Card文件写入(搭载FatFS文件系统)

    MCU:STM32F429ZIT6 开发环境:STM32CubeMX+MDK5   外购了一个SPI接口的SD Card模块,想要实现SD卡存储数据的功能。 首先需要打开STM32CubeMX工具。输入开发板MCU对应型号,找到开发板对应封装的MCU型号,双击打开(图中第三)。   此时,双击完后会关闭此界面,然后打开一个新界面。

    2024年02月08日
    浏览(54)
  • stm32读写SD卡(SDIO模式)

    目录 一、SD卡简介 二、源码下载 三、移植条件 1、芯片参数 2、硬件连接 四、驱动代码 1、依赖宏如下 2、驱动代码实现 3、测试代码 4、运行截图 五、总结 SD卡有SDIO驱动模式和SPI驱动模式,本例中使用SDIO模式驱动SD卡。 https://download.csdn.net/download/qq_30095023/88702705 https://downl

    2024年01月24日
    浏览(46)
  • STM32CubeMX教程27 SDIO - 读写SD卡

    正点原子stm32f407探索者开发板V2.4 STM32CubeMX软件(Version 6.10.0) keil µVision5 IDE(MDK-Arm) ST-LINK/V2驱动 逻辑分析仪nanoDLA 野火DAP仿真器 XCOM V2.6串口助手 使用STM32CubeMX软件配置STM32F407开发板 SDIO读写4线SD卡,实现轮询方式读写SD卡、以中断方式读取SD卡和以DMA方式读取SD卡 安全数码

    2024年02月19日
    浏览(64)
  • STM32的HAL库SPI操作(master 模式)-根据时序图配置SPI

    SPI基本概念请自行百度,参考:百度百科SPI简介.我们讲重点和要注意的地方。 接线一一对应 也就是说主控的MISO,MOSI,SCLK,[CSn]分别和设备的MISO,MOSI,SCLK,[CSn]一一对应相连,不交叉,不交叉,不交叉…(重要的事情说三遍)。 这是无线模块CC2500的SPI接口时序,这里可以看到,从

    2024年02月06日
    浏览(39)
  • STM32采集问答式串口传感器数据写入SD卡(spi模式)

    STM32f103RCT6板子 问答式温湿度传感器(TTL信号) 外接SD卡模块(淘宝都差不多) 1. SD卡模块 ,采用SPI1接线 (CLK)SCK —PA5 (DATA0)MISO —PA6 (CMD)MOSI —PA7 (DATA3)CS —PA4 前面小括号里的是SDIO模式的接线,可以忽略。 2. 传感器模块 问答式TTL信号的传感器都可以, 连接到板子的串口2,

    2024年02月05日
    浏览(45)
  • STM32F407 SPI配置和时序图讲解(二)

    上节讲了SPI的基本配置,这节主要讲解 如何看时序图 ,SPI数据到底是如何传输的。 SPI初始化后,就可以开始向对象发送数据了,但是要发送数据给W25Q128模块,需要按照它的时序图来发送( 个人用的是W25Q128模块 ) W25Q128模块简介 W25Q128是一款常见的串行闪存存储器模块,属

    2024年02月06日
    浏览(35)
  • 【STM32篇】SPI时序驱动W25Q64(硬件SPI和模拟SPI)

            由于MCU的FLASH空间有限,在特殊使用场所中会存在FLASH存储不够使用的情况。例如上篇中驱动LCD屏,需要将一个中文字库保存到MCU的FLASH中是不太现实的(STM32F103ZET6内部FLASH大小512KB),为此可使用外部FLASH作为拓展。         W25Q64(64Mbit)是为系统提供一个最小的空

    2024年02月08日
    浏览(49)
  • STM32CubeMX系列09——SDIO(SD卡读写、SD卡移植FATFS文件系统)

    ==== 文章汇总(有代码汇总) ==== 准备看看这方面的知识,一时间还没不清有什么区别,先补补课,不需要的跳过。 参考文章(内容来源):http://www.360doc.com/content/21/1125/22/59057945_1005908465.shtml 主要写这两个:SD卡、TF卡 共同点:SD、TF、MMC都是在MMC基础上演化发展不同的规范,

    2024年02月09日
    浏览(46)
  • 【STM32】STM32学习笔记-硬件SPI读写W25Q64(40)

    在大容量产品和互联型产品上,SPI接口可以配置为支持SPI协议或者支持I2S音频协议。SPI接口默认工作在SPI方式,可以通过软件把功能从SPI模式切换到I2S模式。 在小容量和中容量产品上,不支持I2S音频协议。 串行外设接口(SPI)允许芯片与外部设备以半/全双工、同步、串行方式

    2024年02月19日
    浏览(68)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包