一、前言
随着信息技术的飞速发展,存储技术成为了电子设备不可或缺的核心部分。尤其是在物联网、大数据、人工智能等领域蓬勃发展的今天,高性能、高可靠性的存储解决方案成为行业关注的焦点。
近年来,国内对集成电路,尤其是存储芯片的需求与日俱增,这不仅反映了国内科技产业的迅速成长,也彰显出市场对于存储技术多样化、个性化需求的增长趋势。面对这样的市场需求,了解各类存储产品的特性和应用场合显得尤为重要。本文下面对常见的存储产品进行分类介绍,并详细描述部分产品的特点,帮助大家更深入地理解这些存储技术的基本原理及其在实际应用中的表现,从而为选择最适合自己项目需求的存储解决方案提供参考依据。
二、存储产品分类
我们把存储产品大概可以分为E2PROM,NOR,NAND 3类,他们框架如下:
从技术角度分类可以按下面这么分:
- NOR Flash:主要用于存储代码或小容量的数据,因其可以随机访问(即无需先擦除即可写入),特别适合于频繁更新的小型程序或启动代码。
- NAND Flash:适用于大容量存储,如用户数据存储,由于成本效益高,广泛应用于固态硬盘(SSD)、存储卡等。
- eMMC (Embedded Multi-Media Card):是一种内嵌式的存储解决方案,常用于智能手机、平板电脑等移动设备中,它集成了控制器和NAND Flash,提供了更高的可靠性和性能。
- UFS (Universal Flash Storage):比eMMC更先进的存储标准,提供了更快的数据传输速度,同时支持全双工操作,可以在读取数据的同时写入数据。
- SD NAND:指以SD卡形式封装的NAND Flash存储器,通常用于消费电子产品中,如相机、移动设备等。
- Raw NAND:指的是未经封装的NAND Flash芯片,通常需要额外的错误校正码(ECC)和其他管理机制才能有效使用。
二、NOR Flash
NOR Flash(非易失性存储器)是一种半导体存储技术,以其在微控制器和嵌入式系统中的广泛应用而闻名。与NAND Flash相比,NOR Flash的特点在于它支持字节级的随机访问能力,这使得它非常适合用来存储代码或执行直接从内存中运行的操作系统和应用程序。
NOR Flash的主要优势之一是它的编程和擦除操作更为简单。与NAND Flash需要先进行整页擦除不同,NOR Flash可以直接对单个字节或字进行编程和擦除,这使得它在需要频繁更新代码或数据的应用中更为实用。此外,NOR Flash通常带有内置的地址线和数据线,这意味着它可以像SRAM(静态随机存取存储器)一样通过简单的三态门接口与微处理器相连,从而简化了硬件设计和系统集成。
另一个显著的优点是NOR Flash的可靠性。由于其架构设计,NOR Flash能够提供较长的寿命和更高的数据保持时间。这意味着即使是在恶劣的工作环境下,NOR Flash也能保证数据的完整性和一致性,这对于工业控制、汽车电子以及其他需要长期稳定工作的应用来说非常重要。
尽管NOR Flash在许多方面表现出色,但它也有自身的限制。相比于NAND Flash,NOR Flash的单位成本较高,而且容量也相对较小。这主要是由于其架构上的差异导致的。NOR Flash为了支持随机访问而牺牲了一定的存储密度,因此在需要大容量存储的应用场景中,NAND Flash往往更加合适。
NOR Flash在需要快速启动和即时响应的应用中,如移动设备的引导加载程序、小型操作系统以及嵌入式控制单元中的固件,NOR Flash提供了无可替代的价值。
三、SD NAND
SD NAND(Secure Digital NAND)作为一种结合了NAND Flash技术和SD卡物理形式的存储解决方案,在现代电子设备中发挥着重要作用。这种存储技术的主要优势在于它既保留了NAND Flash存储介质的高性价比和大容量特性,又具备了SD卡的便携性和易于插入的便利性。因此,SD NAND在多种应用场合中找到了它的定位。
SD NAND非常适合应用于便携式存储设备中。例如,在数码相机中,SD NAND作为存储介质,可以为用户提供大量的照片和视频存储空间。此外,在便携式媒体播放器中,SD NAND也因其小巧的外形和高容量而备受青睐。用户可以通过简单地插入或更换SD NAND卡来增加存储容量,而无需更改设备的硬件设计或内部结构。
在嵌入式系统中,SD NAND同样表现出色。对于那些需要高密度存储空间并且对成本敏感的应用场景,如工业控制系统、智能家居设备以及汽车娱乐系统等,SD NAND提供了一个经济高效的选择。其灵活的存储扩展能力使得设备制造商可以根据最终产品的不同需求来调整存储容量,从而优化成本结构。
移动设备也是SD NAND的重要应用领域之一。在智能手机和平板电脑中,用户可以通过插入SD NAND卡来扩展设备的存储空间,这对于那些经常拍摄大量照片或下载高清视频的用户来说尤其重要。SD NAND不仅为移动设备提供了额外的存储空间,而且由于其标准的SD卡接口,使得用户可以在不同品牌和型号的设备之间轻松地共享数据。
SD NAND的优势还体现在其标准化接口上。SD NAND遵循SD卡协会制定的标准规范,这意味着它可以在任何支持SD卡接口的设备中使用,无需额外的适配器或复杂的驱动程序支持。这一点极大地简化了设备的硬件设计,并减少了因兼容性问题带来的开发障碍。
SD NAND作为一种兼具成本效益和便携性的存储解决方案,在多种应用场景中展现出其独特的优势。无论是对于追求成本效益的设备制造商,还是希望获得更大存储容量的终端用户,SD NAND都提供了一个理想的选择。
这里推荐一款非常易用稳定的Flash产品:CS创世 SD NAND
这款CS创世 SD NAND
是不用写驱动程序自带坏块管理的NAND Flash(贴片式TF卡),尺寸小巧,简单易用,兼容性强,稳定可靠,固件可定制,LGA-8封装,标准SDIO接口,兼容SPI/SD接口,兼容各大MCU平台,可替代普通TF卡/SD卡,尺寸6x8mm毫米,内置SLC晶圆擦写寿命10万次,通过1万次随机掉电测试耐高低温,支持工业级温度-40°~+85°,机贴手贴都非常方便,速度级别Class10(读取速度23.5MB/S写入速度12.3MB/S)标准的SD 2.0协议使得用户可以直接移植标准驱动代码,省去了驱动代码编程环节。
支持TF卡启动的SOC都可以用SD NAND,提供STM32参考例程及原厂技术支持,主流容量:128MB/512MB/2GB/4GB/8GB,比TF卡稳定,比eMMC便宜,样品免费试用。
具体可以去官网看详细介绍:http://www.longsto.com/product/31.html
目前支持样品免费试用。
下面是芯片的实物图
这是官网申请的样品,焊接了转接板,可以直接插在SD卡卡槽上测试。 最终选型之后,设计PCB板时,设计接口,直接贴片上去使用,非常稳定,抖动也不会导致,外置卡TF卡这种容易松动的问题。
下面是CS创世 SD NAND 与STM32开发的板的接线实物图:
这里贴上CS创世 SD NAND
的驱动代码,SPI协议。
下面这份代码采用SPI模拟时序实现,不管你51、AVR、STM32,还是其他单片机,都可以直接移植使用。
/*
函数功能: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;
}
/*
函数功能:取消选择,释放SPI总线
*/
void SDCardCancelCS(void)
{
SDCARD_CS=1;
SDCardReadWriteOneByte(0xff);//提供额外的8个时钟
}
/*
函数 功 能:选择sd卡,并且等待卡准备OK
函数返回值:0,成功;1,失败;
*/
void SDCardSelectCS(void)
{
SDCARD_CS=0;
SDCardWaitBusy();//等待成功
}
/*
函数 功 能:等待卡准备好
函数返回值:0,准备好了;其他,错误代码
*/
void SDCardWaitBusy(void)
{
while(SDCardReadWriteOneByte(0XFF)!=0XFF){}
}
/*
函数功能:等待SD卡回应
函数参数:
Response:要得到的回应值
返 回 值:
0,成功得到了该回应值
其他,得到回应值失败
*/
u8 SDCardGetAck(u8 Response)
{
u16 Count=0xFFFF;//等待次数
while((SDCardReadWriteOneByte(0XFF)!=Response)&&Count)Count--;//等待得到准确的回应
if(Count==0)return SDCard_RESPONSE_FAILURE;//得到回应失败
else return SDCard_RESPONSE_NO_ERROR;//正确回应
}
/*
函数功能:从sd卡读取一个数据包的内容
函数参数:
buf:数据缓存区
len:要读取的数据长度.
返回值:
0,成功;其他,失败;
*/
u8 SDCardRecvData(u8*buf,u16 len)
{
if(SDCardGetAck(0xFE))return 1;//等待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;
SDCardWaitBusy(); //等待忙状态
SDCardReadWriteOneByte(cmd);
if(cmd!=0XFD)//不是结束指令
{
for(t=0;t<512;t++)SDCardReadWriteOneByte(buf[t]);//提高速度,减少函数传参时间
SDCardReadWriteOneByte(0xFF); //忽略crc
SDCardReadWriteOneByte(0xFF);
t=SDCardReadWriteOneByte(0xFF); //接收响应
if((t&0x1F)!=0x05)return 2; //响应错误
}
return 0;//写入成功
}
/*
函数功能:向SD卡发送一个命令
函数参数:
u8 cmd 命令
u32 arg 命令参数
u8 crc crc校验值
返回值:SD卡返回的响应
*/
u8 SendSDCardCmd(u8 cmd, u32 arg, u8 crc)
{
u8 r1;
SDCardCancelCS(); //取消上次片选
SDCardSelectCS(); //选中SD卡
//发送数据
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卡的CID信息,包括制造商信息
函数参数:u8 *cid_data(存放CID的内存,至少16Byte)
返 回 值:
0:成功,1:错误
*/
u8 GetSDCardCISDCardOutnfo(u8 *cid_data)
{
u8 r1;
//发SDCard_CMD10命令,读CID
r1=SendSDCardCmd(SDCard_CMD10,0,0x01);
if(r1==0x00)
{
r1=SDCardRecvData(cid_data,16);//接收16个字节的数据
}
SDCardCancelCS();//取消片选
if(r1)return 1;
else return 0;
}
/*
函数说明:
获取SD卡的CSD信息,包括容量和速度信息
函数参数:
u8 *cid_data(存放CID的内存,至少16Byte)
返 回 值:
0:成功,1:错误
*/
u8 GetSDCardCSSDCardOutnfo(u8 *csd_data)
{
u8 r1;
r1=SendSDCardCmd(SDCard_CMD9,0,0x01); //发SDCard_CMD9命令,读CSD
if(r1==0)
{
r1=SDCardRecvData(csd_data, 16);//接收16个字节的数据
}
SDCardCancelCS();//取消片选
if(r1)return 1;
else return 0;
}
/*
函数功能:获取SD卡的总扇区数(扇区数)
返 回 值:
0表示容量检测出错,其他值表示SD卡的容量(扇区数/512字节)
说 明:
每扇区的字节数必为512字节,如果不是512字节,则初始化不能通过.
*/
u32 GetSDCardSectorCount(void)
{
u8 csd[16];
u32 Capacity;
u16 csize;
if(GetSDCardCSSDCardOutnfo(csd)!=0) return 0; //取CSD信息,如果期间出错,返回0
if((csd[0]&0xC0)==0x40) //SDHC卡,按照下面方式计算
{
csize = csd[9] + ((u16)csd[8] << 8) + 1;
Capacity = (u32)csize << 10;//得到扇区数
}
return Capacity;
}
/*
函数功能: 初始化SD卡
返 回 值: 非0表示初始化失败!
*/
u8 SDCardDeviceInit(void)
{
u8 r1; // 存放SD卡的返回值
u8 buf[4];
u16 i;
SDCardSpiInit();//初始化底层IO口
for(i=0;i<10;i++)SDCardReadWriteOneByte(0xFF); //发送最少74个脉冲
do
{
r1=SendSDCardCmd(SDCard_CMD0,0,0x95);//进入IDLE状态 闲置
}while(r1!=0X01);
SD_Type=0; //默认无卡
if(r1==0X01)
{
if(SendSDCardCmd(SDCard_CMD8,0x1AA,0x87)==1) //SD V2.0
{
for(i=0;i<4;i++)buf[i]=SDCardReadWriteOneByte(0XFF);
if(buf[2]==0X01&&buf[3]==0XAA) //卡是否支持2.7~3.6V
{
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卡版本开始
{
for(i=0;i<4;i++)buf[i]=SDCardReadWriteOneByte(0XFF);//得到OCR值
if(buf[0]&0x40)SD_Type=SDCard_TYPE_V2HC; //检查CCS
else SD_Type=SDCard_TYPE_V2;
}
}
}
}
printf("SD_Type=0x%X\r\n",SD_Type);
SDCardCancelCS(); //取消片选
if(SD_Type)return 0; //初始化成功返回0
else if(r1)return r1; //返回值错误值
return 0xaa; //其他错误
}
/*
函数功能:读SD卡
函数参数:
buf:数据缓存区
sector:扇区
cnt:扇区数
返回值:
0,ok;其他,失败.
说 明:
SD卡一个扇区大小512字节
*/
u8 SDCardReadData(u8*buf,u32 sector,u32 cnt)
{
u8 r1;
if(SD_Type!=SDCard_TYPE_V2HC)sector<<=9;//转换为字节地址
if(cnt==1)
{
r1=SendSDCardCmd(SDCard_CMD17,sector,0X01);//读命令
if(r1==0) //指令发送成功
{
r1=SDCardRecvData(buf,512); //接收512个字节
}
}else
{
r1=SendSDCardCmd(SDCard_CMD18,sector,0X01);//连续读命令
do
{
r1=SDCardRecvData(buf,512);//接收512个字节
buf+=512;
}while(--cnt && r1==0);
SendSDCardCmd(SDCard_CMD12,0,0X01); //发送停止命令
}
SDCardCancelCS();//取消片选
return r1;//
}
/*
函数功能:向SD卡写数据
函数参数:
buf:数据缓存区
sector:起始扇区
cnt:扇区数
返回值:
0,ok;其他,失败.
说 明:
SD卡一个扇区大小512字节
*/
u8 SDCardWriteData(u8*buf,u32 sector,u32 cnt)
{
u8 r1;
if(SD_Type!=SDCard_TYPE_V2HC)sector *= 512;//转换为字节地址
if(cnt==1)
{
r1=SendSDCardCmd(SDCard_CMD24,sector,0X01);//读命令
if(r1==0)//指令发送成功
{
r1=SDCardSendData(buf,0xFE);//写512个字节
}
}
else
{
if(SD_Type!=SDCard_TYPE_MMC)
{
SendSDCardCmd(SDCard_CMD55,0,0X01);
SendSDCardCmd(SDCard_CMD23,cnt,0X01);//发送指令
}
r1=SendSDCardCmd(SDCard_CMD25,sector,0X01);//连续读命令
if(r1==0)
{
do
{
r1=SDCardSendData(buf,0xFC);//接收512个字节
buf+=512;
}while(--cnt && r1==0);
r1=SDCardSendData(0,0xFD);//接收512个字节
}
}
SDCardCancelCS();//取消片选
return r1;//
}
四、NAND Flash
NAND Flash 是一种非易失性存储技术,广泛应用于各种消费电子设备和计算机系统中。与NOR Flash不同,NAND Flash主要以其高密度和低成本而著称,这使得它非常适合用于大规模数据存储。NAND Flash在设计上侧重于提供高容量和高性价比的存储解决方案,因而被广泛用于固态硬盘(SSD)、存储卡、USB闪存驱动器以及各种便携式媒体播放器等设备中。 NAND Flash 算是目前最热门的存储芯片。在生活中经常使用的电子产品都会涉及到它。比如你买手机,肯定会考虑64GB,还是256GB?买笔记本是买256GB,还是512GB容量的硬盘呢?(目前电脑大部分采用了基于NAND Flash产品的固态硬盘)。
NAND Flash 的核心优势在于其能够以较低的成本提供较大的存储容量。这是因为NAND Flash采用了不同于NOR Flash的架构设计,使得每个存储单元可以更加密集地排列在一起。这种高密度的设计意味着,相同面积的硅片上可以容纳更多的存储单元,从而降低了每比特的成本。此外,NAND Flash的读写操作通常是以页为单位进行的,而不是以字节为单位,这也进一步提升了其效率和容量。
NAND Flash也有其自身的局限性。由于数据的读取和写入操作是以块为单位进行的,所以在进行写入操作之前,整个块必须先被擦除。这意味着,如果需要在一个已写入数据的块中修改某一部分数据,则整个块的数据必须先被复制到其他地方,然后擦除整个块,再重新写入新数据,这增加了复杂性和时间开销。不过,现代的NAND Flash控制器通常会采用各种算法来优化这个过程,以减少这种擦除-重写循环带来的负面影响。
NAND Flash 的耐用性也是一个值得关注的问题。每次擦除操作都会略微降低存储单元的可靠性,这被称为“磨损”。现代NAND Flash器件通常配备有磨损均衡技术,该技术可以在不同存储单元之间均匀分布擦写操作,从而延长整个设备的使用寿命。此外,错误校正编码(ECC)也被广泛应用于NAND Flash中,以检测和纠正数据读取过程中可能出现的位错误。
下面从几个方面做一个分类:
4.1 内部材质
NAND FLASH从材质上可以分为SLC/MLC/TLC/QLC,本质区别就是在最小的存储单元内能存放多少bit的信息。SLC(2bit)/MLC(4bit)/ TLC(8bit)/ QLC(16bit). 这样晶圆的存储密度会翻倍。这4种晶圆的特点如下:
可以看到从SLC 到QLC 擦写寿命越来越短,性能和品质越来越差。目前我们主流的消费类电子产品使用的大容量产品,基本都是TLC/QLC了。比如手机,笔记本里的固态硬盘。
4.2 生产工艺
目前主要有2D和3D。主流生产工艺已经升级到3D了。2D和3D区别可以看如下的示意图:
可以理解2D工艺就是老的砖瓦房,3D工艺就是摩天大楼。带来的最大好处就是存储密度N倍的增长。最近几年手机,笔记本的主流容量都在变大跟产业使用了3D工艺有直接关系。
4.3 使用特点/管理机制
NAND Flash产品本身存在一定的特性,要正常使用,必须配备对应的管理机制。主要有:
1,NAND Flash存在位翻转和位偏移。本来存储的是0101的数据,有一定概率会变成1010。这个时候就需要配备EDC/ECC机制;
2,NAND Flash出厂时会有坏块(不用惊讶,原厂出厂的时候都会标识出来,而且比例是很低),在使用当中也可能产生坏块。因此需要配备 动态和静态坏块管理机制;
3,NAND Flash有写入寿命的限制。每个块都有擦写寿命。因此需要配备 平均读写机制。让整体的块能够均衡的被使用到;
4,NAND Flash是先擦后写,集中擦写的强电流会对周边块有影响等。需要配备 垃圾回收,均衡电荷散射机制等。
CS创世 SD NAND把这些算法都集成到内部了。示意图如下
4.4 产品分类
简单的可以按照如下划分:
Raw NAND本质上是把NAND Flash晶圆的Pad点引出来,封装成TSOP48/BGA等颗粒。 由于里面不带控制器,针对NAND Flash的各种管理算法都需要在CPU端来做,一来会涉及到写驱动的问题;二来会增加CPU的负荷。
带控制器的产品,我们分为芯片类和模组类两种。由于产品的设计初衷不一样,导致两类产品的品质要求有很大区别。
在这里有一篇文章专门讲过这个:http://www.longsto.com/news/25.html
芯片类产品有SD NAND,eMMC, SPI NAND. 他们共同特点是内部都带了针对NAND Flash的管理机制。相对来说可以减轻CPU的负荷。但SPI NAND除外,它内部只带了部分管理算法,因此还是需要写驱动。 模组类产品主流的有TF/SD卡,SSD,U盘等。
这里我们把几个常用产品做一个简单的对比:
CS创世 SD NAND和几个产品的具体对比,也可以参考如下文章:
SD NAND VS TF卡: http://www.longsto.com/news/8.html
SD NAND VS Raw NAND: http://www.longsto.com/news/6.html
SD NAND VS eMMC: http://www.longsto.com/news/7.html
SD NAND VS SPI NAND: http://www.longsto.com/news/26.html