STM32 NOR FLASH(SPI FLASH)驱动移植(1)

一)NOR Flash 简介
1)Flash 简介
Flash 是常的用于存储数据的半导体器件,它具有容量大、可重复擦写、按“扇区/块”
擦除、掉电后数据可继续保存的特性。常见的Flash主要有NOR Flash和Nand Flash两种类型,它们的特性如下表 所示。NOR (或非门)和 NAND (与非门)是两种数字门电路,可以简单地认为 Flash 内部存储单元使用哪种门作存储单元就是哪类型的 Flash。U 盘,SSD,eMMC 等为 NAND 型,而 NOR Flash 则根据设计需要灵活应用于各类 PCB 上,如 BIOS,手机等。NOR Flash 和 NAND Flash 特性对比:

1,NOR 与 NAND 在数据写入前都需要有擦除操作,但实际上 NOR Flash 的一个 bit 可以从 1变成 0,而要从 0 变 1 就要擦除后再写入(NOR门特性:当所有输入都为 0 时,输出才为 1;只要有一个输入为 1,输出就是 0),
NAND Flash 这两种情况都需要擦除。擦除操作的最小单位为“扇区/块”,这意味着有时候即使只写一字节的数据,则这个“扇区/块”上之前的数据都可能会被擦除。NOR 的地址线和数据线分开,它可以按“字节”读写数据,符合 CPU 的指令译码执行要求,所以假如 NOR 上存储了代码指令,CPU 给 NOR 一个地址,NOR 就能向 CPU 返回一个数据让CPU执行,中间不需要额外的处理操作,这体现于表中的支持XIP特性(eXecute In Place)。因此可以用 NOR Flash 直接作为嵌入式 MCU 的程序存储空间
2,NAND 的数据和地址线共用,只能按“块”来读写数据,假如 NAND 上存储了代码指令,CPU 给 NAND 地址后,它无法直接返回该地址的数据,所以不符合指令译码要求。若代码存储在 NAND 上,可以把它先加载到 RAM 存储器上,再由 CPU 执行。所以在功能上可以认为 NOR 是一种断电后数据不丢失的 RAM,但它的擦除单位与 RAM 有区别,且读写速度比 RAM 要慢得多。
3,Flash 也有对应的缺点,我们在使用过程中需要尽量去规避这些问题:一是 Flash 的使用寿命,另一个是可能的位反转。使用寿命体现在:读写上是 FLASH 的擦除次数都是有限的(NOR Flash 普遍是 10 万次左右),当它的使用接近寿命的时候,可能会出现写操作失败。由于 NAND 通常是整块擦写,块内有一位失效整个块就会失效,这被称为坏块。使用 NAND Flash 最好通过算法扫描介质找出坏块并标记为不可用,因为坏块上的数据是不准确的。位反转是数据位写入时为 1,但经过一定时间的环境变化后可能实际变为 0 的情况,反之亦然。位反转的原因很多,可能是器件特性也可能与环境、干扰有关,由于位反转的的问题可能存在,所以 FLASH 存储器需要“探测/错误更正(EDC/ECC)”算法来确保数据的正确性。
4,FLASH 芯片有很多种芯片型号, norflash.h 头文件中有定义芯片 ID 的宏定义,对应的就是不同型号的 NOR FLASH 芯片,比如有:W25Q128、W25Q256、BY25Q128、NM25Q128,它们是来自不同的厂商的同种规格的 NOR FLASH 芯片,内存空间都是 128M 字,即 16M 字节。它们的很多参数、操作都是一样的,下面我们以 W25Q256 为例,认识一下具体的 NOR Flash 的特性。
W25Q256 是一款大容量 SPI FLASH 产品,其容量为 16M。它将 16M 字节的容量分为 256个块(Block),每个块大小为 64K 字节,每个块又分为 16 个扇区(Sector),每一个扇区 16 页,每页 256 个字节,即每个扇区 4K 个字节。W25Q256 的最小擦除单位为一个扇区,也就是每次必须擦除 4K个字节。这样我们需要给 W25Q256开辟一个至少 4K的缓存区,这样对 SRAM要求比较高,要求芯片必须有 4K 以上 SRAM 才能很好的操作。W25Q256 的擦写周期多达 10W 次,具有 20 年的数据保存期限,支持电压为 2.7~3.6V,NM25Q128 支持标准的 SPI,还支持双输出/四输出的 SPI,最大 SPI 时钟可以到 104Mhz(双输出时相当于 208Mhz,四输出时相当于 416M)。


芯片引脚连接如下:
CS 即片选信号输入,低电平有效;
DO 是 MISO 引脚,在 CLK 管脚的下降沿输出数据;
WP 是写保护管脚,高电平可读可写,低电平仅仅可读;
DI 是 MOSI 引脚,主机发送的数据、地址和命令从 DI 引脚输入到芯片内部,在 CLK 管脚的上升沿捕获数据;
CLK 是串行时钟引脚,为输入输出提供时钟脉冲;
HOLD 是保持管脚,低电平有效。
STM32F429 通过 SPI 总线连接到 W25Q256 对应的引脚即可启动数据传输。
二)NOR FLASH 工作时序
1)W25Q256读操作时序:

从上图可知读数据指令是 03H,可以读出一个字节或者多个字节。发起读操作时,先把CS 片选管脚拉低,然后通过 MOSI 引脚把 03H 发送芯片,之后再发送要读取的 24 位地址,这些数据在 CLK上升沿时采样。芯片接收完 24位地址之后,就会把相对应地址的数据在 CLK引脚下降沿从 MISO 引脚发送出去。从图中可以看出只要 CLK 一直在工作,那么通过一条读指令就可以把整个芯片存储区的数据读出来。当主机把 CS 引脚拉高,数据传输停止。
2)W25Q256写时序(页写,每一个扇区 16 页,每页 256 个字节,即每个扇区 4K 个字节)

在发送页写指令之前,需要先发送“写使能”指令。然后主机拉低 CS 引脚,然后通过
MOSI 引脚把 02H 发送到芯片,接着发送 24 位地址,最后你就可以发送你需要写的字节数据到芯片。完成数据写入之后,需要拉高 CS 引脚,停止数据传输。
3)W25Q256扇区擦除时序

扇区擦除指的是将一个扇区擦除,通过前面的介绍也知道,W25Q256 的扇区大小是 4K 字节。擦除扇区后,扇区的位全置 1,即扇区字节为 FFh。同样的,在执行扇区擦除之前,需要先执行写使能指令。这里需要注意的是当前 SPI 总线的状态,假如总线状态是 BUSY,那么这个扇区擦除是无效的,所以在拉低 CS 引脚准备发送数据前,需要先要确定 SPI 总线的状态,这就需要执行读状态寄存器指令,读取状态寄存器的 BUSY 位,需要等待 BUSY 位为 0,才可以执行擦除工作。
接着按时序图分析,主机先拉低CS引脚,然后通过MOSI引脚发送指令代码20h到芯片,然后接着把 24 位扇区地址发送到芯片,然后需要拉高 CS 引脚,通过读取寄存器状态等待扇区擦除操作完成。
此外还有对整个芯片进行擦除的操作,时序比扇区擦除更加简单,不用发送 24bit 地址,只需要发送指令代码 C7h 到芯片即可实现芯片的擦除。
在 W25Q256手册中还有许多种方式的读/写/擦除操作,可以参考 W25Q256 手册。
三) 硬件知识
目前我就接触到了华邦的flash芯片,包括:W25Q80、W25Q16、W25Q32、W25Q64、W25Q128、W25Q256、W25Q512等.
1) W25QXX系列FLASH的块儿、扇区、页、字节之间的关系:
1块儿 = 16扇区
1块儿 = 16 * 16 * 256字节(Byte)= 65536Byte = 64KB(65536Byte/1024=64KB)
1扇区 = 16页
1扇区 = 16 * 256(Byte)= 4096Byte = 4KB
1页 = 256字节
2) W25QXX系列FLASH芯片不同型号的相同点:
1、1块=16扇区;1扇区=16页;1页=256字节;
2、 FLASH芯片只能按扇区、块为单位擦除,或者是全片擦除。写可以1~256字节写,一次最多写256字节 。
3) W25QXX系列FLASH芯片不同型号的不同点:
1、W25Q16有32块、W25Q32有64块、W25Q64有128块、W25Q128有256块、W25Q256有512块、W25Q512有1024块;
2、W25Q16、W25Q32、W25Q64、W25Q128的内存地址为3字节(3×8=24bit);但是W25Q256和W25Q512的内存空间地址为4字节(4×8=32bit);需要注意:因为这个内存空间地址字节数不同,我们在写W25Q256和W25Q512的驱动时,前面的几种型号芯片程序就无法和这两个芯片的驱动直接兼容,需要修改指令后跟的地址(由原来的三字节改为四字节)才行。
4) W25QXX系列FLASH芯片的容量:
不同型号的块数量、内存容量、内存空间地址
W25Q80有16个块儿,共1665536 = 1048576 Byte;1048576/1024/1024 = 1MB,寻址空间:0x000000~0x0FFFFF;
W25Q16有32个块儿,共32
65536 = 2097152 Byte;2097152/1024/1024 = 2MB,寻址空间:0x000000~0x1FFFFF;
W25Q32有64个块儿,共6465536 = 4194304 Byte;4194304/1024/1024 = 4MB,寻址空间:0x000000~0x3FFFFF;
W25Q64有128个块儿,共128
65536 = 8388608 Byte;8388608/1024/1024 = 8MB,寻址空间:0x000000~0x7FFFFF;
W25Q128有256块儿,共25665536 = 16777216 Byte;1677216/1024/1024 = 16MB,寻址空间:0x000000~0xFFFFFF;
W25Q256有512块儿,共512
65536 = 33554432 Byte;33554432/1024/1024 = 32MB,寻址空间:0x00000000~0x01FFFFFF;
W25Q512有1024块儿,共1024*65536 = 67108864 Byte;67108864/1024/1024 = 64MB,寻址空间:0x00000000~0x03FFFFFF;
5) W25QXX系列FLASH芯片不同型号的ID:
W25Q80的芯片ID为:0XEF13
W25Q16 的芯片ID为:0XEF14
W25Q32 的芯片ID为:0XEF15
W25Q64 的芯片ID为:0XEF16
W25Q128的芯片ID为:0XEF17
W25Q256的芯片ID为:0XEF18
W25Q512的芯片ID为:0XEF19

四)程序设计
1)norflash 驱动代码(norflash.c 和 norflash.h)
首先是 norflash.h 头文件,我们做了一个 FLASH 芯片列表(宏定义),这些宏定义是一些支持的 FLASH 芯片的 ID。接下来是 FLASH 芯片指令表的宏定义,这个请参考 FLASH 芯片手册比对得到,这里就不将代码列出来了。下面介绍norflash.c文件几个重要的函数,首先是NOR FLASH初始化函数,其定义如下:

/**
* @brief 初始化 SPI NOR FLASH
* @param 无
* @retval 无
*/
void norflash_init(void)
{
 uint8_t temp;
 NORFLASH_CS_GPIO_CLK_ENABLE(); /* NORFLASH CS 脚 时钟使能 */
 GPIO_InitTypeDef gpio_init_struct;
 gpio_init_struct.Pin = NORFLASH_CS_GPIO_PIN;
 gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;
 gpio_init_struct.Pull = GPIO_PULLUP;
 gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(NORFLASH_CS_GPIO_PORT, &gpio_init_struct);
/* CS 引脚模式设置(复用输出) */
 NORFLASH_CS(1); /* 取消片选 */
 spi5_init(); /* 初始化 SPI5 */
 spi5_set_speed(SPI_BAUDRATEPRESCALER_2);/* SPI5 切换到高速状态 45Mhz */
 g_norflash_type = norflash_read_id(); /* 读取 FLASH ID. */
	if (g_norflash_type == W25Q256 || g_norflash_type == BY25Q256) 
	 {/* SPI FLASH 为 25Q256, 必须使能 4 字节地址模式 */
	 	temp = norflash_read_sr(3); /* 读取状态寄存器 3,判断地址模式 */
		 if ((temp & 0X01) == 0) //如果不是 4 字节地址模式,则进入 4 字节地址模式 
		 {
			 norflash_write_enable(); /* 写使能 */
			 temp |= 1 << 1; /* ADP=1, 上电 4 位地址模式 */
			 norflash_write_sr(3, temp); /* 写 SR3 */
			 
			 NORFLASH_CS(0);
			 spi5_read_write_byte(FLASH_Enable4ByteAddr); //使能 4 字节地址指令 
			 NORFLASH_CS(1);
		 }
	 }
}

在初始化函数中,将 SPI 通信协议用到的 CS 引脚配置好,同时根据 FLASH 的通信要求,
通过调用 spi5_set_speed 函数把 SPI5 切换到高速状态。然后尝试读取 flash 的 ID,由于 25Q256
的容量比较大,通信的时候需要 4 个字节,为了函数的兼容性,我们这里做了判断处理。当然,
我们使用的 25Q256 是 3 字节地址模式的。如果能读到 ID 则说明我们的 SPI 时序能正常操作
Flash,便可以通过 SPI 接口读写 NOR FLASH 的数据了。

作者:黑果果的思考

物联沃分享整理
物联沃-IOTWORD物联网 » STM32 NOR FLASH(SPI FLASH)驱动移植(1)

发表回复