SD nand 与 SD卡的SPI模式驱动
文章目录
1. 概述
首先简单介绍下SD卡和SD nand:
-
SD卡,也称之为内存卡,在早些年间的手机上出现过,主要用来存储数据;

-
SD nand,贴片式SD卡,使用起来和SD卡一致,不同的是采用,通常采用LGA-8封装,尺寸为8mm x 6mm x 0.75mm,重点是采用贴片封装,可以直接贴在板卡上,直接解决了SD卡固定问题,再也不用为SD卡的接触稳定性操心!

SD nand 与 SD卡除了封装上的区别,使用起来基本没什么不一样,因此下文中不再做区分,统一以SD nand作为描述。
SD nand 和 SD 卡、SPI Nor flash、 nand flash、eeprom一样,都是嵌入式系统中常见的用来存储数据所使用的存储芯片,这几种存储芯片主要的区别在于存储数据容量不一样、操作的大小不一样,价格不一样,因此在实际产品设计中,往往需要根据自身产品的需求来选择对应的存储芯片。
SD nand存储空间大小在上述存储系列芯片中属于偏大的,其存储空间小到 1Gb(256MB) 起步,大到可以到32G,最小读写单元通常是 512 Byte,与SD卡一样,均支持SD接口模式以及SPI接口模式(后文会详细描述其区别)。
关于采用SPI接口模式完成于SD nand和SD卡的通讯,网上也有相关资料,但描述均不是很清楚或完整,因此特整理此博客,以作记录及分享。
本博文以 CS 创世 CSNPGCR01-AOW 这颗IC为例,着重描述如何通过SPI接口完成SD nand(SD卡)的读写驱动。
2. SPI接口模式与SD接口模式区别
2.1 接口模式区别
SD nand同时支持SPI接口和SD接口,接下来主要从以下几个维度分析二者的区别:
- 硬件资源角度:
- SD接口需要控制器具有SDIO外设硬件支持
- SPI接口如果控制器具有SPI硬件外设那就最好了,没有也可以使用软件模式SPI
- 传输效率:
- SD接口支持四线同时传输
- SPI只有MOSI一根总线
- 且接口速度上SD接口速度通常要大于SPI接口,因此SD效率远高于SPI接口
- 控制难度:
- SPI协议比较简单,也是嵌入式开发中最常使用的协议之一,只有MISO和MOSI两根数据总线,因此控制难度简单;
- SD协议相对SPI要复杂,且需要控制的引脚多,内部还存在状态机,相比SPI较为复杂
综上分析,SD接口效率更高,但是需要芯片有对应外设支持,而SPI接口虽然效率比不上SD接口,但是控制起来简单,且对芯片外设硬件依赖不高,对于低端的控制器,亦可使用软件模式SPI来驱动SD nand。
2.2 硬件引脚
SD nand以及SD 卡在SPI接口以及SD接口模式下,硬件引脚如下图所示:
-
SD nand SPI接口及SD接口模式IO定义

-
SD卡 SPI接口及SD接口模式IO定义

2.3 注意事项
此外对于使用SPI接口需要注意的是,SPI接口只是定义了物理传输层,并没有定义完整的数据传输协议,因此上层软件还是需要遵循SD接口协议!
3. SD接口协议
在2.3中我们重点强调了,SPI接口只是定义了物理层,也即硬件链路层,关于协议层并没有定义,写一次依旧遵循SD接口协议,因此我们需要首先了解下SD总线协议的内容。
SD 总线协议由SD卡协议定义,是一个通用的标准协议。首先说明的是,SD总线协议不仅仅只适用于SD卡,还支持IO卡,MMC卡等等,而且对这些不同类型的设备均能做出区分的!有点像USB一样牛逼!

我们首先来了解下SD总线协议中的命令及响应。
3.1 命令
命令由主机发出,分为广播命令和寻址命令
-
广播命令是针对与SD主机连接的所有设备发出的
-
寻址命令是指定某个地址的设备进行命令传输
3.1.1 命令格式
命令由48bit位(6字节)组成,格式如下:

- 起始位:1bit 固定为0
- 传输位:1bit 主要用于区分传输方向,1代表主机发送给从机的命令,0代表从机响应的主机命令
- 命令号:6bit 命令号索引,总共能表示2^6=64个命令
- 命令参数:32bit 命令所包含的参数信息
- CRC7:7bit CRC校验位,用于保证数据传输的正确性,生成器多项式为:
G(x) = x^7 + x^3 + 1
3.1.2 命令类型
命令主要有4种类型:
- bc:无响应广播命令
- bcr:有响应广播命令
- ac:寻址命令,发送到选定卡,DAT线没有数据传输
- adtc:寻址数据传输命令,发送到选定的卡,且DAT线有数据传输
在SD总线协议中,经常见到的CMDx,代表的就是命令号,后面的x代表命令索引,在3.1.1中命令格式组成中描述了命令号总共占6bit,所以CMDx的范围是CMD0 - CMD63,CMD后面的数字代表的就是命令号command index的值。
对于SD这么复杂的协议,64种命令类型通常还不能涵盖所有类型的数据,因此SD协会在制定此协议的时候将命令继续细化,分了两种类型的命令:CMD和ACMD,CMD代表常规命令,ACMD代表特定应用的命令,ACMD通常为制造商特定使用的。
那么SD协议又是如何区分CMD和ACMD命令的呢?
在发送ACMD命令之前必须发送特定的CMD命令(APP_CMD)表明接下来的一帧命令是ACMD命令,在SD协议种规定此特定命令名称叫APP_CMD,也就是CMD55。
需要注意的是,CMD命令类型这么多,但实际上并没有都使用,针对SD nand(SD卡)的命令也就那么几条(注意SD模式命令的响应和SPI模式命令的响应有些许不同,SD模式请自行查阅手册)





上图中,命令序号对应3.1.1节命令格式中的命令号 command index,参数对应3.1.1节命令格式中的命令参数argument。
3.2 响应
针对需要响应的命令(bcr),SD nand(SD卡)在接收到命令之后会做出响应,根据命令的不同,响应的类型也不相同,其中命令中已规定哪个命令需要响应,并且返回什么类型的响应。
响应总共分为7中类型,分别是R1~R7,需要注意的是,SD nand(SD卡)没有R4、R5类型的响应。
响应的数据长度也并非完全一样,响应根据内容长度分为短响应和长响应,短响应长度为48bit(6Byte),长响应长度为136bit(17Byte),其中只有R2属于长响应,其他均属于短响应。
3.2.1 响应格式





其中重点讲下R1响应,在上图中我们可以看到R1返回的内容为卡的状态,关于卡状态的描述如下,每个bit均代表着对应的含义,如下图中所示:
4. SD nand(SD卡)结构描述

上图是SD nand的内部结构,与SD卡完全类似,主要有五个部分组成,这里就不细述了,不然此篇文章会过于臃长,关于这块大家可以上网查找,需要重点注意的是内部有7个寄存器,主要用来对卡片进行配置和读取卡片有关的信息,描述如下,其中SD接口有些命令就指定了读取哪个寄存器的内容!
5. SD nand SPI通讯
主要参考资料:官方文档《Part_1_Pjysical_Layer_Specification_Ver2.0.0pdf》
建议大家有时间的话也可以读一读,还是有收获的,如果没时间的话也可以先参考本博文
5.1 SD nand SPI 通讯概述
SD nand SPI通讯接口完成驱动主要可以分为三大部分:
- 上电初始化以及模式切换
- SD nand(SD卡)识别
- 数据传输两大步
在以上三大部分中,每个部分均有命令传输,从3.1.1中我们可以知道发送给SD nand的命令为48bit,也就是8字节,那么SPI模式下与SD nand通讯,发送命令其实就是采用SPI总线往SD nand传输8个字节的数据,大家把握这这个思路去理解下文的通讯过程也就简单多了。
需要注意的是:
- SD nand或SD卡上电默认均为SD模式,需要对齐完成初始化以及模式切换后才能切换到SPI模式。
- SD 模式,所有命令默认开启CRC校验,因此没有切换到SPI模式之前,所有命令都必须携带正确的CRC校验值
- 进入SPI模式后,默认关闭CRC校验,此时CRC校验字段默认填充1即可,当然也可以通过命令配置打开SPI模式的CRC校验
5.2 SPI 时序
在开始进行通讯读写前,我们先来看下SPI时序,使用SPI完成于SD nand(SD卡)的通讯与我们平常使用SPI与其他设备通讯会有一点点小小的区别,主要在于往SD nand写了数据之后,回复不是马上的,以及在必要的数据之间需要增加间隔,我们挑几个重点看下,在实际开发中有需要注意的在后文对应处有描述,不用过于担心。
- 主机发送命令给卡,卡响应,注意图中的NCR,NCR最小不是0,因此主机发送了命令之后,SD nand不是马上就响应的

- 卡连续响应两个指令之间需要有间隔,如图中的NRC

5.3 上电初始化及模式切换
5.3.1 初始化及模式切换流程说明
- 首先配置控制器SPI外设
- SD nand(SD卡)电源应该在250ms内到大VCC,这是硬件电路要求
- 同时保持CS引脚为高电平状态,CLK时钟引脚至少发送74个时钟给SD nand已启动SD nand
- 之后SD nand进入空闲状态,发送CMD0命令至SD卡切换进入SPI模式
- 注意务必保证CMD0是第一包命令
- SD卡选择了对应的模式之后不可切换,如果需要重新切换,需要重新上电

5.3.2 代码实现
- SPI外设配置代码如下:
#ifndef __BSP_SPI_H__
#define __BSP_SPI_H__
#include "stm32f10x.h"
#define PIN_HIGH 1
#define PIN_LOW 0
int sd_spi_config(void);
void set_sd_spi_cs_pin(uint8_t state);
#endif /* __BSP_SPI_H__ */
#include "./spi/bsp_spi.h"
/**
* @brief spi gpio configuration
*
* @note CLK:PA5 MISO:PA6 MOSI:PA7 CS:PA8
*
*/
static void _spi_gpio_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure = {
0};
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/* Configure SD_SPI pins: SCK */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure SD_SPI pins: MOSI */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure SD_SPI pins: MISO */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/*!< Configure SD_SPI_CS_PIN pin: SD Card CS pin */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
/**
* @brief configer spi1 peripher.
*
* @note Data rising edge acquisition.
*/
static void _spi_config(void)
{
SPI_InitTypeDef SPI_InitStructure = {
0};
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
/*!< SD_SPI Config */
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 0;
SPI_Init(SPI1, &SPI_InitStructure);
SPI_Cmd(SPI1, ENABLE);
}
int sd_spi_config(void)
{
_spi_gpio_init();
_spi_config();
return 0;
}
void set_sd_spi_cs_pin(

本文详细介绍了如何通过SPI接口驱动SDnand(SD卡),包括SPI与SD接口的区别、初始化流程、模式切换、数据传输等步骤,并提供了相应的代码示例。内容涵盖了SDnand的结构、SD接口协议、SPI时序以及识别和数据读写过程,旨在帮助读者理解并实现SDnand的SPI模式通讯。
最低0.47元/天 解锁文章
1007

被折叠的 条评论
为什么被折叠?



