SD卡 SPI模式操作(1)初始化SD卡

原文(本人转载):帆登小站-SD卡 SPI模式操作(1)初始化SD卡
作者是初学者,水平有限,本文仅作为个人学习笔记使用,不能保证内容的正确性。部分资料来源于网络,参考了SD卡协议2.0手册等资料,如果有歧义,可以与作者联系。

目录

SD卡 SPI模式操作(1)初始化SD卡
SD卡 SPI模式操作(2)读操作
SD卡 SPI模式操作(3)写操作

省流直接看图,文章下面有比较详细的初始化流程

Pasted image 20230128214632.png

常见问题

1、 为什么发送初始化命令之后,SD卡一直返回0xFF?

作者亲自遇到过这个问题,我的工具是某宝上十几块钱的逻辑分析仪,芯片是CH32V203C8T6,开发板长这样子的
Pasted image 20230203214636.png

首先检查线路的连接,MCU的MISO连接SD卡的DO,MOSI连接SD卡的DI,如果MCU有多个SPI外设,一定要看清楚SD卡连接的是哪个SPI。
最有效的方法,就是用逻辑分析仪连接到SD卡所连接的线路上,看有没有信号输出。
确定线路连接正常之后,再检查上电需要的时钟信号是否正确,必须在100k~400kHz的频率之间,如果你的MCU主频设置过高,如144MHz,就算SPI用256级的分频,依然是非常大的。144MHz分频256次:
M C U 主频 S P I 分频数 = 144 M H z 256 = 562.5 K b i t / s \frac{MCU主频}{SPI分频数}=\frac{144MHz}{256}=562.5Kbit/s SPI分频数MCU主频=256144MHz=562.5Kbit/s
所以在合适的主频下,选择合适的SPI分频数。初始化完成之后,再调高SPI的主频,用于数据通信。
最后一个办法,可以检查初始化步骤是否在上电时操作。
有些开发板上的SD卡槽的电源,是直接连接开发板电源,所以要求SD卡初始化的操作必须在开发板刚上电时完成。但是调试时,一般只会让MCU复位而不会让开发板断电,从而SD卡无法进入初始化模式。
在这种情况下,我建议每次下载完程序之后,让开发板重新上电,或者先购买一个SD卡模块,让GPIO控制SD卡的上电,直到写完初始化部分的功能,代码能正常初始化SD卡之后,再换回开发板的卡槽。

2、关于TF卡

有些TF卡不支持SPI模式操作,这个需要注意,可以多准备几张卡。目前我的8G金士顿TF卡,这个没问题,但是我的32G闪迪没法进入SPI模式。

3、 MCU应该在什么时候发送命令?

SD卡的DO线,空闲的情况下应该是高电平,当SD卡忙的时候,DO线会被SD卡拉低,所以应该在DO线为高电平的时候,发送命令。

简介

SPI模式是MCU在没有SDIO的情况下控制MMC和SD卡的备用操作模式。比起SDIO模式,SPI模式的传输协议稍微简单一些,代价是传输速度也会变慢。

引脚说明

Pasted image 20230118202918.png
Pasted image 20230118202939.png
(图片来源于网络)

引脚设置

在SPI模式下使用SD卡,按照SD卡的要求正确接线之后,需要将MCU的引脚进行如下设置:

SD引脚MCU引脚MCU引脚模式
CSNSS复用推挽输出
SCLKSCK复用推挽输出
DIMOSI复用推挽输出
DOMISO浮空输入
VDD(任意引脚)复用推挽输出
VSSGND

其中,SD卡的VDD可以使用一个引脚去控制SD卡的电源,从而使用MCU控制SD卡上电。
注意,有些SD卡的DO引脚需要一个上拉电阻,否则会在初始化的过程中失败。

SPI模式设置

SD卡使用的是SPI模式0(CPHA=0,CPOL=0)和SPI模式3(CPHA=1,CPOL=1),一般情况下选择SPI模式3。命令发送模式为高位优先(MSB-first)。

报文格式

从主机到卡的命令帧的长度是下图所示的固定长度的报文。
命令报文 1.png
在SPI通信模式下,数据通信由主机控制,形式为:主机拉低NSS信号,发送命令令牌,SD卡发送响应令牌,如果需要返回数据,那么数据将跟在响应令牌后面。
发送完命令之后,应该继续发送0xFF,并且检查是否收到可用的应答。如果在设定时间内没有收到回应,那么视作超时处理。在收到应答之前,应该将NSS保持低电平。

命令令牌格式

SPI模式的命令令牌固定为6个字节,命令的传输从最高位开始。

位号4746[45:40][39:8][7:1]0
位宽1163271
“0”“1”xxx“1”
描述开始位数据传输位命令号(CMDx)参数CRC校验结束位

其中,在SPI模式下,CRC仅在初始化卡时有效,如CMD0、CMD8等。不使用CRC时,可将CRC所有位置1。
当命令为CMD0时,低8位应该为0x95,
当命令为CMD8时,低8位应该为0x87。

命令令牌描述

命令令牌分为CMD和ACMD,ACMD是应用程序命令,在发送ACMD之前,应该先发送CMD55(APP_CMD)。填充位和保留位均为"0"。

命令号参数响应名称描述
CMD0[31:0]:填充位R1GO_IDLE_STATE将卡复位到IDLE状态
CMD8[31:12]:保留位,[11:8]:支持的电压(VHS),[7:0]:需要回显的参数(echo-back)R7SEND_IF_COND发送包含主机电源电压信息,询问被访问的卡是否能在供电电压范围内工作
CMD12[31:0]:填充位R1bSTOP_TRANSMISSION强制停止当前SD卡的数据传输,用于多块数据操作,结束传输
CMD16[31:0]:块长度R1SET_BLOCKLEN设置SD卡的块大小(字节),后续所有块操作命令(读和写)都是以此设置的大小为准,对于高容量卡,块大小固定为512字节
CMD17[31:0]:数据地址,单位:字节(SDSC),单位:512字节(SDHC)R1READ_SINGLE_BLOCK读取一个块的数据,参数为块的首地址。块的长度由CMD16设置,对于高容量卡,块大小固定为512字节
CMD18[31:0]:数据地址,单位:字节(SDSC),单位:512字节(SDHC)R1READ_MULTIPLE_BLOCK连续读取多块数据,直到主机发送CMD12命令,参数为块的首地址。块的长度由CMD16设置,对于高容量卡,块大小固定为512字节
CMD24[31:0]:数据地址,单位:字节(SDSC),单位:512字节(SDHC)R1WRITE_BLOCK写入一个块的数据,参数为块的首地址。块的长度由CMD16设置,对于高容量卡,块大小固定为512字节
CMD25[31:0]:数据地址,单位:字节(SDSC),单位:512字节(SDHC)R1WRITE_MULTIPLE_BLOCK连续写入多块数据,直到主机发送CMD12命令,参数为块的首地址。块的长度由CMD16设置,对于高容量卡,块大小固定为512字节
CMD55[31:0]:填充位R1APP_CMD通知SD卡,接下来发送的命令是特定于应用程序的命令,而不是标准命令
CMD58[31:0]:填充位R3READ_OCR读取OCR寄存器
ACMD23[31:23]:保留位,[22:0]:数据块数R1SET_WR_BLK_ERASE_COUNT需要预擦除的数据块个数,以提升SD卡写入的性能
ACMD41[31]:保留位,[30]:HCS, [29:0]:保留位R1SD_SEND_OP_COND发送主机容量支持信息,并将卡初始化,HCS一般置“1”

响应令牌格式

有几种类型的响应令牌,所有数据都是先传输高位。所有令牌的高8位都是R1令牌。

R1令牌

除SEND_STATUS命令外,SD卡在每次收到命令后都会发送此响应令牌。长度为1字节,MSB始终设置为"0"。[0:6]是错误指示,"1"为发生错误。

Pasted image 20230128211046.png

位号描述
0处于空闲状态:SD卡处于空闲状态,且正在运行初始化程序
1擦除重置:在执行擦除前,一个擦除指令序列被清除,因为收到了一个超出擦除序列的指令。
2非法指令
3CRC错误:上一条命令的CRC检查失败
4擦除序列错误:在擦除指令序列中发现错误
5地址错误:命令中使用了与块长度不匹配的未对齐地址。
6参数错误:命令的参数(例如地址、块长度)超出了此卡的允许范围。
7固定为0

R1b令牌

该响应令牌与R1格式相同,但可选地添加了忙信号。忙信号令牌可以是任意数量的字节。零值表示卡正忙。非零值表示卡已准备好下一个命令。

R2令牌

通常情况下只会用到R2令牌的最低位,也就是卡被写保护。该令牌是CMD13(SEND_STATUS)的响应令牌。高8位为R1令牌。
Pasted image 20230128212104.png

R3令牌

该令牌是CMD58(READ_OCR)的响应令牌,共5个字节,用于获取OCR寄存器的数据。高8位为R1令牌,低4字节为OCR寄存器的数据。
Pasted image 20230128212417.png

R7令牌

该令牌是CMD8(SEND_IF_COND)的响应令牌,共5字节,主要用于获取SD卡工作电压信息,高8位为R1令牌。
Pasted image 20230128213548.png

位号描述
[0:7]发送CMD8时会发送一个1字节的参数echo-back,这里将返回这个参数,一般用于检查通讯是否正常。一般在CMD8使用10101010b作为参数
[8:11]SD卡能接受的电压值(见电压值表,通常为0001b)
[12:27]保留位,固定为“00000h”
[28:31]命令号,固定为“001000b”

电压值如下:

描述
0000b未定义
0001b2.7-3.6V
0010b保留为更加低的电压值
0100b保留
1000b保留

初始化SD卡

由于SD卡进入SPI模式后,只能通过断电退出,为了方便调试,建议使用GPIO控制SD卡的上电。
Pasted image 20230128214632.png

上电复位

Pasted image 20230129042952.png

SD卡上电之后,需要往sclk线发送至少74个时钟信号,注意频率在100k~400kHz之间,建议直接使用低速SPI发送10个0xFF,在此过程中,即使是为了进入SPI模式,CS线也需要保持高电平。
当SD卡上电完毕(可以延迟1ms)之后,需要发送CMD0进行复位操作。为了使SD卡进入SPI模式,需要将CS线拉低,然后发送CMD0,注意CMD0的格式,命令长度固定为6个字节。
对于CMD0命令,应该发送0x40、0x00、0x00、0x00、0x00、0x95,发送完毕之后还需要发送若干个0xFF等待SD卡响应。
当SD卡响应时,应该返回一个R1令牌,且内容为0x01。
接收完毕之后,应该拉高CS,然后再发送一个0xFF。
Pasted image 20230129042629.png

如果在此期间,SD卡一直没有返回R1令牌,MISO一直为0xFF,那么有以下几个点需要检查:
1、 检查当前复位操作是否为上电操作,该操作应该是SD卡刚上电时的操作。如果当前是个debug程序,应该将SD卡的VDD引脚接到MCU,由MCU控制SD卡的上电。
2、 检查SD卡的连接是否正确,MOSI和MISO是不是接反了?正确的接法是MOSI接DI,MISO接DO。
3、 检查上电时,SCLK的时钟是否发送正确,必须大于74个时钟,而且频率必须在100k~400kHz之间。

检查卡版本是否为Ver 1.X

通过发送一个CMD8命令,如果SD卡响应该命令无效,说明该卡的版本为Ver1.X。如果有响应,说明卡版本为Ver2.X或者更高的版本。
CMD8的参数一般为0x000001AA,SD卡收到响应之后,应该首先检查高8位,也就是R1令牌部分。
当R1的第二位,也就是 R1 & 0x0004为真时,该命令无效,说明卡版本为Ver1.X。
当CMD8有效时,应该抛弃剩余的4字节数据。

检查支持电压范围(可选)

主要通过CMD58命令获取OCR寄存器的信息,以获得SD卡的支持电压范围。

开始初始化SD卡

通过发送ACMD41命令去初始化SD卡。注意,在发送ACMD41之前,应该先发送CMD55命令,而且CMD55命令会响应一个R1令牌,此处的R1令牌可以直接抛弃。

对于Ver1.X版本的卡,ACMD41的参数应该为0x00000000;
对于Ver2.X以及更高版本的卡,ACMD41的参数一般使用0x40000000。

这时需要不断发送0xFF同时检查接收R1令牌(其实这里的等待接收步骤和CMD0一样),直到R1为0,表示SD卡初始化成功。这里的循环建议添加超时计数。

获取卡的容量状态

通过CMD58命令获取OCR寄存器的信息,其中CCS位位于OCR寄存器的第30位。
1为高容量卡(SDHC)
0为标准容量卡(SDSC)

设置块大小

SD卡的所有读写操作,都是以块为单位去读写,因此需要预先设置一个块的大小。
通过CMD16命令设置SD卡的块大小(字节),后续所有块操作命令(读和写)都是以此设置的大小为准,对于高容量卡,块大小固定为512字节。
对于低容量的卡,为了统一,一般建议将块大小设置为512字节。

结尾

SD卡初始化完成之后,可以将SPI总线切换成高速总线,将在下一章继续介绍SD卡的读操作。

参考文章

  • 9
    点赞
  • 65
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值