项目中处于成本考虑,要把Nor Flash换成低成本的Nand Flash。
这里总结下芯片应用。
总体概述:
1)W25N01(NandFlash)和W25Q(Nor Flash)的操作大不一样。
NandFlash擦除以块(128KB)为单位,读写以页(2KB)为单位,适合存储大量数据,且明确会产生坏块,需要进行坏块管理。 -- 而Nor Flash擦除单元大小最小为4KB,读写最小单位可以是1字节,更方便处理数据。
2)W25N01有内部2KB缓冲区机制,数据要先写缓冲区,再从缓冲区导入物理地址;读取与之相反。
3)基本指令的实现,都一个鸟样。按照指令表的内容和时序,收发数据即可。
目录
1. 芯片特性
2. 针脚定义
3. 芯片架构
4. 芯片寄存器
5. 芯片指令表
5.1 读取ID
5.2 读写寄存器
5.3 复位&写使能&写失能
5.4 页读取
5.5 页写入
5.6 块擦除
6. 芯片时间参数
1. 芯片特性
见下图,这里简单说下主要特性:
1)W25N01,为1Gbit大小,即128M字节
2)104MHz的标准时钟速度
3)50MB/S的传输速率
4)擦除的最小单位是块,128KB大小
5)读写的最小单位是页,2KB大小。即1G Bit分为 1024个块,每个块64页。
2. 针脚定义
1)注意标准SPI和Quad SPI
我们把标准的SPI接口,CS/CLK/MOSI/MISO 称为2线式接口(即数据线只有MOSI和MISO),此外还有Quad SPI接口,它将WP和HOLD复用为数据传输线,称为4线式接口(数据收发从1bit变成2bit)
3. 芯片架构
这是第一个必须要理解的图,很重要,不要跳过请先看懂它。
简述下图(框图):
1)Data Buffer,是芯片内部的缓冲区,总共2112字节(分为2048字节 + 64字节)。
a)其中64字节,是备用区域,一是用于标记坏块,二是用于保存ECC码(纠错码)
b)2048字节的数据缓冲区。
在读取时,要先从物理地址读到缓冲区,然后再读取缓冲区。
在写入时,要先将数据写入缓冲区,再将缓冲区数据写入物理地址。
c)Column Address CA[11:0],即缓冲区的地址。在读写缓冲区的参数 CA 即表示该值。
2)页地址
Page Address (PA) [15:0],即页面地址,其高10bit表示块号索引(10bit的最大值为1023),低6bit表示页索引(6bit的最大值为63)。
标黄的两个参数很重要,后面的寄存器表都会用到这两个参数。
4. 芯片寄存器
寄存器如下3张图,
1)SR1为保护寄存器,地址为0xAx(0xA0),,,一般写0x00关闭保护即可
如果需要保护特定块,需要按照章节 7.4 W25N01GV Status Register Memory Protection 配置保护寄存器。
2)SR2为配置寄存器,地址为0xBx(0xB0),,,一般写0x18即可,即默认使能ECC校验和BUF=1模式
3)SR3为状态寄存器,只读的
a)其中BUSY位用于判断写、擦除等指令是否结束
b)FAIL位用于判断写失败和擦除失败
c)ECC用于判断读取数据是否正确
5. 芯片指令表
这是第二个必须要理解的图,很重要,不要跳过请先看懂它。
下面简述下指令表该怎么看:
1)第1列为命令类型
2)第2列OpCode表示操作码,是发送的第一个字节数据(CMD)
3)后序列Byte2/3/4……,表示后续的发送字节
4)实现单个命令功能时,只需要按照该指令表发送字节数据。。
上层的读写功能需要多个命令组合实现……
下面再简述下关键指令:
5.1 读取ID
就以这个命令简述下,每个命令的时序该怎样看:
1)DI一行表示要发送的数据,DO一行表示要接收的数据。
2)只要数据是按照时序图发的就没问题。
3)每一个指令的开始,都要以CS拉低开始,最后1字节发送结束之后马上拉高CS。
对于这个 Read JEDEC ID 命令,可知:
先发送0x9F,再发送Dummy(空字节、数据任意),然后再发送3个字节任意字节数据,对端依次响应3个字节数据。
对于W25N01,回复固定,依次是0xEF,0xAA,0x21。
5.2 读写寄存器
读寄存器:发送0x0F或0x05,再发送寄存器地址,然后读取1字节数据 - 即为寄存器值
写寄存器:发送0x1F或0x01,再发送寄存器地址,然后发送1字节数据 - 即为寄存器设定值
5.3 复位&写使能&写失能
CS拉低,发1字节,CS再拉高,结束。
复位是0xFF,控制芯片复位。
写使能0x06,在写缓冲区、块擦除之前,必须要先写使能。使能之后状态寄存器会置位bit1。
写失能0x04,恢复写保护。
5.4 页读取
基本操作概述:
1)先发送0x13指令,将指定物理地址的数据读到内部缓冲区;
先发送0x13,再发送0x00,发送页地址PA的高8位,最后发送页地址PA的低8位。
发完结束,等待完成即可。
2)再发送0x03指令,将缓冲区的数据读到用户的Buff中;
先发送0x03,发送列地址CA的高8位,然后发送列地址CA的低8位,最后发送0x00。
发完结束,等待完成即可。
3)读取完毕之后,检查状态寄存器的ECC校验位,判断是否读取正确。
下面是我的可用代码:
uint8_t W25N01_PageRead(uint16_t blocks, uint16_t pages, uint8_t *Buff)
{
uint16_t PA = (blocks << 6) + (pages & 0x3F);
SPI_FLASH_CS_LOW();
SpiReadWriteByte(0x13);
SpiReadWriteByte(0x00);
SpiReadWriteByte((uint8_t)(PA>>8));
SpiReadWriteByte((uint8_t)(PA&0xFF));
SPI_FLASH_CS_HIGH();
HAL_Delay(1);
SPI_FLASH_CS_LOW();
SpiReadWriteByte(0x03);
SpiReadWriteByte(0x00);
SpiReadWriteByte(0x00);
SpiReadWriteByte(0x00);
SpiFlashReceive(Buff, 2048);
SPI_FLASH_CS_HIGH();
if( (W25N01_ReadReg(FLASH_STATUS_REG3_ADDR) & 0x30) >= 0x20)
return W25N01XX_FAIL;
return W25N01XX_OK;
}
5.5 页写入
1)Buff写缓冲区
必须先发送0x06写使能命令
再发送0x02命令,发送2个 0x00,然后传输2048字节数据
2)缓冲区写物理地址
先发送0x10,发送0x00,
然后发送页地址PA的高8位,最后发送页地址PA的低8位,结束,
等待传输完成
下面是我的可用代码:
uint8_t W25N01_PageWrite(uint16_t blocks, uint16_t pages, uint8_t *Buff)
{
uint16_t PA = (blocks << 6) + (pages & 0x3F);
W25N01_WriteEnable();
HAL_Delay(1);
SPI_FLASH_CS_LOW();
SpiReadWriteByte(0x02);
SpiReadWriteByte(0x00);
SpiReadWriteByte(0x00);
SpiFlashTrans(Buff, 2048);
SPI_FLASH_CS_HIGH();
HAL_Delay(1);
SPI_FLASH_CS_LOW();
SpiReadWriteByte(0x10);
SpiReadWriteByte(0x00);
SpiReadWriteByte((uint8_t)(PA>>8));
SpiReadWriteByte((uint8_t)(PA&0xFF));
SPI_FLASH_CS_HIGH();
W25N01_WaitBusy();
if( (W25N01_ReadReg(FLASH_STATUS_REG3_ADDR) & FLASH_SR_WRITE_FAIL)
== FLASH_SR_WRITE_FAIL)
return W25N01XX_FAIL;
return W25N01XX_OK;
}
5.6 块擦除
必须先发送0x06写使能命令
然后发送0xD8,发送0x00,然后发送页地址PA的高8位,最后发送页地址PA的低8位,结束,
等待擦除完成
uint8_t W25N01_BlockErase(uint16_t blocks, uint16_t pages)
{
uint16_t PA = (blocks << 6) + (pages & 0x3F);
W25N01_WriteEnable();
HAL_Delay(1);
SPI_FLASH_CS_LOW();
SpiReadWriteByte(0xD8);
SpiReadWriteByte(0x00);
SpiReadWriteByte((uint8_t)(PA>>8));
SpiReadWriteByte((uint8_t)(PA&0xFF));
SPI_FLASH_CS_HIGH();
W25N01_WaitBusy();
if( (W25N01_ReadReg(FLASH_STATUS_REG3_ADDR) & FLASH_SR_ERASE_FAIL)
== FLASH_SR_ERASE_FAIL)
return W25N01XX_FAIL;
return W25N01XX_OK;
}
6. 芯片时间参数
其中,
tRD表示读操作的时间,最大60us,最快7us
tPP表示写操作的时间,最大700us
tBE表示擦除操作的时间,最大10ms