Nand Flash 笔记(五) W25N01G手册解读

Nand Flash 笔记

第一章 Nand概述
第二章 硬件接口规范
第三章 软件功能规范
第四章 接口规范
第五章 W25N01G手册解读
第六章 HC32F460_QSPI驱动
第七章 FatFs移植
第八章 lvgl文件系统移植
第九章 lvgl之tiny ttf engine



一、概述

1.1 产品简介

W25Nxx是中国台湾Winbond(华邦)公司推出的一系列Nand Flash产品,包括从512Mb-4Gb各容量的芯片。下图是从手册中摘出的命名规范:
命名规范
该芯片具有以下特性:

  • 兼容标准SPI 串行flash命令
  • 代码影射,XIP功能
  • 常规的缓冲读取模式(BUF=1)及特有的连续读模式(BUF=0)
  • 用户可配置的内置硬件ECC功能,采用海明码,支持1位纠错及2位检错能力
  • 支持部分编程,NoP=4(可1/4页写入)
  • 内置坏块管理功能
  • 支持JEDEC标准的厂商及设备ID,附加 UniqueID页,参数页及10个2K大小的OTP页

1.2 引脚

该芯片工作电压为2.7~3.6V,支持Standart/Dual/Quad Spi读写接口,常见多为WSON-8封装,引脚图如下
引脚图

\模式
\
引脚\
标准SPIDual SPIQual SPI备注
/CS片选片选片选低电平有效,上下电时必须跟随电源(可以加上拉电阻)
CLK时钟时钟时钟最大104MHz,SPI MODE 0 空闲时低电平,SPI MODE 3 空闲时高电平
DIMOSIIO0IO0-
DOMISOIO1IO1-
/WP写保护写保护IO2低电平有效,由SR-1寄存器的WP-E位控制,WP-E=0时,硬件写保护仅可作用于SR-1,由SRP[1:0]和BP[3:0]控制软件写保护的范围。WP-E=1时,四线SPI读操作不可用,硬件写保护作用于整个芯片
/HOLD状态保持状态保持IO3低电平有效,四线模式时不可用,CLK下降沿/HOLD 引脚电平变化 共同满足之后保持功能打开/关闭

ps: 数据输入输出口均为时钟上升沿写入,下降沿读取。

1.3 空间

W25N01G 共1024个块,每块64页,每页2048Byte数据空间,即:

1Gbit = 128MByte = (1024 Block per Chip) × (64 page per Block) × ( 2048 Byte per page)

为了满足ECC校验及坏块管理的功能,每页还有额外64Byte的Spare Area(空闲空间),空闲空间还提供了2+4字节的用户数据区用来存放自定义数据,有些文件系统(如jffs2)就用到了自定义数据来存放文件系统信息。
W25N01G支持部分编程,最小的编程单位是sector(扇区),每页分为4个512字节的扇区,空闲空间也对应分为16字节×4,部分编程时,每扇区的数据和它对应的空闲空间数据要一并写入。一个page的内部划分如下图所示
页内部空间
寻址采用 页地址(PA) + 列地址(CA) 方式:页地址长16位,由10bit块地址 + 6bit页地址 组成;列地址12位,寻址空间为0-4095,但只有前(2048 + 64)字节空间可以读写。32位地址的位域定义如下图
地址定义
主存储空间外,W25N01G还具有单独的1个UniqueID页,1个参数页及10个OTP页,地址如下:
附加页描述


二、寄存器

2.1 SR-1(写保护寄存器)

SR-1定义

  • WP-E = 0,SRP1 = 1: /WP引脚无写保护功能
    • SRP0 = 0:上下电时SRP0、SRP1复位为0
    • SRP0 = 1:寄存器SR-1上下电不丢失
  • WP-E = 0,SRP1 = 0:
    • SRP0 = 0:/WP引脚无写保护功能
    • SRP0 = 1:/WP引脚保护SR-1寄存器
  • WP-E = 1,SRP1 = 0:SR-1 不保护
  • WP-E = 1,SRP1 = 1,SRP0 = 0:SR-1上下电复位
  • WP-E = 1,SRP1 = 1,SRP0 = 1:寄存器上下电不丢失
  • WP-E = 1,/WP有效:全局写保护。

块保护寄存器的对应的保护范围表如下图
TB & BP

2.2 SR-2(配置寄存器)

SR-2定义
OTP-L:设为1将OTP锁定避免再次修改。
OTP-E:设为1后才可以访问OTP页,上电复位值为0
SR1-L:仅SRP1、SRP0均为1且OTP-E使能方可设为1,锁定SR-1寄存器
ECC-E:使能内置ECC校验,复位值为1
BUF:默认值见命名规则定义,BUF = 1使能缓冲读取,否则连续读取。

2.3 SR-3(状态寄存器)

SR-3定义
LUT-F:LUT-F默认值为0,当坏块管理表全部用完时,LUT-F置1
ECC-1,ECC-0:ECC使能时,读取数据之后应当查询这两位以确保数据完整性,上电、重置或完成一次页读取后均自动复位

P-FAIL:编程操作超时或试图写入被保护空间时此位置1,设备重置或执行编程操作时此位自动清零

E-FAIL:擦除超时或试图擦除被保护空间时置1,设备重置或执行编程操作时此位自动清零

WEL:写使能,复位值为0,输入写使能命令后置1,写禁止/编程/擦除/读取/OTP编程/坏块管理命令后自动清零

BUSY:上电未完成或执行页读取/编程/擦除、坏块管理、OTP操作命令时置1,BUSY时除了读取状态寄存器和读取JEDEC ID的指令均会被忽略,编程/擦除或写入状态寄存器操作完成后自动清零。


三、命令

指令集共27条基础指令,由 操作码(OpCode)+地址(Addr)+数据(Data) 组成。所有数据的传输都是高位优先(MSB first)。
有些情况下还包含虚拟字节(DummyByte),其作用是保证在该处输出8-bit的时钟,所以它的值不重要,可以是任意值。
/CS拉低之后第一个字节为指令。读指令可以在任一bit的时钟结束之后完成,而写/编程/擦除指令必须到完整的8-bit输入完成,/CS拉高后才认为完成,否则会被忽略掉,这一特性预防了对Nand的意外更改操作。

连续读取模式下,/CS拉高终止读取,缓冲内数据丢失,经过一段时间(tRD3)后设备busy状态解除,重新读取必须再次发送读指令。
缓冲读取模式下,/CS拉高终止读取,缓冲内数据不变,设备busy状态立刻解除。

W25N01GVxxxG默认为连续读模式
W25N01GVxxxT默认为缓冲读模式,他们除了读命令结构不同之外,共用其他命令。无论是否使能ECC,连续读取模式下,只读取2048字节的主空间数据;而缓冲读模式下,还要再读取64字节的空闲空间内容。
W25N01GVxxxR固定为缓冲读模式,该系列不支持5条4-Byte寻址读命令及2条坏块管理命令和获取ECC出错地址命令。

命令列表

  • 设备管理
指令FFh9FhA1hA5hA9h
描述重置JEDEC ID坏块管理读取坏块映射表查询ECC出错位置
  • 寄存器操作
指令0F/05h1F/01h06h04h
描述读状态寄存器写状态寄存器写使能写禁止
  • 擦写操作
指令描述指令描述
D8h块擦除10h编程执行
02h编程数据加载(buffer重置)32h四线编程数据加载(buffer重置)
84h随机编程数据加载34h四线随机编程数据加载
  • 读操作
指令03h13h
描述读取页读取
输入输出Output(00h)I/O(80h)读(00h)
\SPI
\
寻址\
二线(30h)四线(60h)二线(30h)四线(60h)标准(00h)
普通寻址(0Bh)3Bh6BhBBhEBh0Bh
四字节寻址(0Ch)3Ch6ChBChECh0Ch

需要注意的是,操作码只能在DI引脚上传输,而地址、数据可以采用标准/双线/四线方式传输。
标准SPI模式下,输入都在DI引脚,输出都在DO引脚。

多线输入输出指令的Output模式和I/O模式的区别在于是否采用多线方式进行输入
例如,在3Bh命令(2线Output读模式)下,地址和虚拟字节采用DI引脚传输,而读到的数据通过IO0,IO1引脚进行双线传输;
而在BBh命令(2线I/O读模式)下,地址和虚拟字节也采用IO0,IO1引脚进行双线传输。


命令解析

3.1 单字节命令

包括0xFF(设备重置),0x04(写禁止),0x06(写使能),时序图如下

单字节命令

3.2 读取JEDEC ID

此ID是指JEDEC标准规定的厂商和产品型号的标志码,对W25N01G来说,厂商ID是0xEF,设备ID是0xAA21。命令时序如下
JEDEC ID

3.3 读状态寄存器

写入指令和地址后状态寄存器的值会连续上传知道/CS拉高指令结束,由此可以实现一次指令实现多次读取状态寄存器,命令时序如下
读SR

状态寄存器地址如下

寄存器SR-1SR-2SR-3
地址AxhBxhCxh

3.4 写状态寄存器

写SR

3.5 坏块管理

普遍标准规定,Nand设备出厂时允许存在2%数量以内的坏块,对W25N01G来说,也就是1024 × 2% = 20个以下的坏块是允许的。为了保证Nand作为启动设备时可以正常工作,所以厂商保证了出厂时前8个block不是坏块,即最前面1M大小的空间不是坏块。
为了更加便捷的实现坏块管理功能,芯片内置了一张最大支持20条记录的坏块管理查询表(Bad Block Manage Look-Up Table),以 LBA(逻辑地址,坏块)---->PBA(物理地址,正常块) 的方式记录坏块。LBA的最高两位表明该条记录状态,如下,00表示未使用,10表示坏块记录有效,11表示记录废弃,01状态不允许存在。
LBA 标志位
芯片中的每个块之间都是隔离的,坏块的存在不会影响其他块的性能。出厂坏块通过每个块的page0的第一个字节写入非FF值标出,同时page0的空闲空间的前两字节也写入非FF值。注意,坏块信息一旦被擦除就无法恢复。因此,在使用之前,应当扫描所有块并建立坏块表。一个基本的坏块表初始化流程如图
坏块表初始化
除了出厂时可能存在的坏块,随着芯片使用也可能产生坏块,为此,在使用过程中请遵循如下规则:

  • 每528Byte至少有1位ECC校验以保证纠错能力
  • 读取操作必须校验ECC
  • 在每次擦除/编程之后,读取状态寄存器P-FAIL和E-FAIL位来确认操作是否成功,若失败,执行块替代操作:
    1. 检测到某页发生错误;
    2. 将该页所在块中前面的页全部复制到另一有效块
    3. 重新将该页写入新块
    4. 更新坏块管理表

命令0xA5可以逐个读取LUT表,/CS拉高控制命令结束,可以在任何一位后结束而无需等待全部的坏块管理表读完。
通常情况下,如果读到某条记录未使用(LBA高8位位0x00),那它后面的记录应当都没有使用,可以之间拉高/CS结束读取。
命令时序如下
读坏块管理表
坏块管理命令0xA1可以将坏块的LBA、PBA写入坏块管理表,该命令执行前必须执行写使能命令以允许坏块管理操作执行。更进一步的,我们需要首先读取坏块管理i表或读取状态寄存器3的LUT-F位来确认LUT是否有空间执行新的写入。命令时序如下
坏块管理命令

3.6 ECC校验

状态寄存器SR-2的ECC-E位置1使能内置ECC校验功能。
在编程过程中,ECC模块会自动计算Buffer中数据的ECC值并将之写入附加空间。
读取过程中,ECC信息用来检验读出的数据并进行有限位的纠错。寄存器SR-3的ECC-0,ECC-1位表示校验结果。

ECC-0ECC-1描述
00无错
01整个输出进行了1位纠错
10单个页面检测到2位错误,连续读取模式下还可使用A9h命令读取出错的页地址
11整个输出在多个页面检测到2位错误,连续读取模式下,A9h只能读到最后一个出错页的地址

连续模式下,读却结束后ECC-0,ECC-1表示整个传输过程中ECC校验的结果,若出错,使用0xA9命令可以读取出错页地址,命令时序如下
ECC出错地址读取

3.7 块擦除

W25N01G的擦除以Block为单位,擦除命令为0xD8,执行擦除命令之前必须执行写使能命令。命令时序如下
块擦除

3.8 编程

块内的页面必须从块内的LSB(最低有效位)页面到MSB(最高有效位)按顺序编程。LSB被定义为编程的起始页,不需要是块中的第0页。禁止随机页面编程。
编程操作分两个步骤:

  1. 加载待编程数据到缓冲区。
  2. 执行编程。
加载编程数据

加载数据只能采用标准SPI或者四线SPI,加载数据之前要先执行写使能命令。
缓冲区大小为2112字节,数据最少1字节,最多2112字节,超出忽略。
对于ECC使能状态来说,最大只能传输2048字节,

随机加载和普通加载的区别在于前者不会重置缓冲区,例如加载N个Byte,剩余(2112-N)个字节保持之前的值不变,而普通加载则会将剩余空间重置为0xFF。

0x02/0x84标准SPI加载数据命令时序如下
标准SPI加载数据

0x32/0x34四线SPI加载数据命令时序如下
四线SPI加载数据

执行编程

执行编程
块内的页需要从低地址到高地址顺序编程,不允许乱序编程。

3.9 读取

读取指令较复杂,主要由于有连续读和缓冲读两种模式,传输又分标准、二线、四线读几种,二线、四线传输又有双向和单向区别,而指令也分为3字节寻址(普通寻址)和4字节寻址两种,各种组合下来就有多种命令,但无论读取模式怎样,读取的基本流程和指令结构是共通的。
根据W25N01G手册来看,除了0x03普通读取命令之外,其他都是FastRead快速读取模式,后者支持更高的时钟频率,但由于引脚接收命令及内部传输延迟,当频率提高时就需要在命令后添加几个虚拟周期来让Flash作出反应。
和编程一样,读取也需要先将数据加载到缓冲区中,再执行读取指令将数据取出。

0x13页加载命令

时序如下
页数据加载

缓冲读取模式

缓冲模式下,读取指令后跟随2字节列地址,随后输出若干DummyByte,随即可以在DO引脚或IO引脚上读到数据。缓冲区数据传输完毕后数据引脚切到高阻态。
缓冲读取

连续读取模式

连续模式下,无需输入列地址,列地址对应的命令字节使用DummyByte代替。输出数据从缓冲区第一个字节开始,缓冲区传输完成后自动传输下一页。命令时序如下:
连续读取

3.10 OTP & UniqueID & Parameter

SR-2的OTP-E置位后,所有的读写操作指向附加页。OTP模式下只有缓冲读取模式可用。

OTP锁定后,OTP页无法更改,也无法解锁。锁定流程需要:1.OTP-L置位;2.执行编程命令(0x10),地址无作用。

UID页、参数页及地址如1.3节所述。

4. 综合

新手调试NandFlash,一个Flash编程器是相当有用的。推荐下图这款ch341A编程器,淘宝上很多,十几块钱一套
在这里插入图片描述

配套软件NeoProgrammer,这是基于开源软件AsProgrammer改进的一个版本,支持多种芯片,支持自定义脚本,后者的原作者我没能找到,只在git上找到了库UsbAsp-flashasprogrammer-dregmod,至于前者,我猜应该是某位毛子程序员发布的,证据是软件里面的文档居然是俄文+英文版的……在52pojie论坛上有更多详尽的资料和讨论,这里贴一个传送门

NeoProgrammer恰巧支持W25N01G这款芯片,但软件自带界面只支持简单的全片擦除和读写,要实现对某页的读写就需要用到自定义脚本功能了。我们以读取芯片的JEDEC ID和Unique ID为例。

脚本支持的命令如下
CMD_1

CMD_2

十六进制数用$xx来标识,如$BF表示0xBF。

这是读取JEDEC ID(通常编程器也是通过这个ID来识别芯片型号的,W25N01G是0xEFAA21)

{$ READ_JEDEC_ID}
begin
  ID:= CreateByteArray(3);
  if not SPIEnterProgMode(_SPI_SPEED_MAX) then LogPrint('Error setting SPI speed');
  LogPrint ('Read JEDEC ID');
  
  // read ID to test installation 
  SPIWrite (0, 2, $9F, $00);
  SPIRead(1, 3, ID);
  
  logprint('CHIP ID: ' + inttohex((GetArrayItem(ID, 0)),2)+ inttohex((GetArrayItem(ID, 1)),2) + inttohex((GetArrayItem(ID, 2)),2));
  LogPrint ('End read JEDEC ID');
  SPIExitProgMode ();
end

这是读取Unique ID,需要注意我们需要先写SR-2寄存器的OTP-E位,读完之后再把该位清零。
如1.3节所示,Unique ID是 32Byte × 16,也就是512个字节,我们接着看


{$ READ_UNIQUE_ID}
begin
  if not SPIEnterProgMode(_SPI_SPEED_MAX) then LogPrint('Error setting SPI speed');
  LogPrint ('Read Unique ID');
  sreg :=$FF;
  buff:= CreateByteArray(4);
  bufflen:= 512;
  
  //Read SR-2
  SPIWrite(0, 2, $0F, $B0);
  SPIRead(1, 1, sreg);

  //Set bit OTP-E
  SPIWrite(1, 3, $1F, $B0, (sreg or $40));
  
// load page 0 into buffer
  Page:= 0;
  SetArrayItem(buff, 0, $13);
  SetArrayItem(buff, 1, 0); // dummy
  SetArrayItem(buff, 2, (page shr 8)); // High 8-bit
  SetArrayItem(buff, 3, (page)); // Low 8-bit
  SPIWrite (1, 4, buff);

  // wait if busy
    repeat
      SPIWrite(0, 2, $0F, $C0);
      SPIRead(1, 1, sreg);
    until((sreg and 1) <> 1);
    
  //common read
  SetArrayItem(buff, 0, $03);
  SetArrayItem(buff, 1, 0); // CA15-8
  SetArrayItem(buff, 2, 0); // CA7-0
  SetArrayItem(buff, 3, 0); // dummy
  SPIWrite (0, 4, buff);

  SPIReadToEditor (1, bufflen);

  // exit otp
  SPIWrite(0, 2, $0F, $B0);
  SPIRead(1, 1, sreg);
  SPIWrite(1, 3, $1F, $B0, (sreg xor $40));

  LogPrint ('End read page');
  SPIExitProgMode ();
end

我们看读取到的是什么样子的:
UID
可以看到,每32个字节重复一次,手册中的 32Byte × 16 就解释通了,也就是说真正的Unique ID只有32字节,但是,真的是32字节吗?我们仔细看,可以看到,后16个字节是前16个字节的反码,而第8-15位是有规律交替的FF 00,所以,真正含有信息的只有前8字节!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值