Bootstrap

零基础STM32单片机编程入门(二十) 华邦W25Q32 SPI FLASH实战含源码

一.概要

FLASH是一种存储芯片,通过程序可以修改数据,即平时所说的“闪存”。
FLASH闪存是非易失存储器,可以对称为块的存储器单元块进行擦写和再编程。任何Flash器件的写入操作只能在空或已擦除的单元内进行,所以大多数情况下,在进行写入操作之前必须先执行擦除。
SPI Flash使用SPI接口进行数据传输,采用一种主从模式。主控制器通过发送命令和地址来访问SPI Flash,然后接收或写入数据。SPI Flash在接收到命令后,将相应的数据返回给主控制器。
SPI Flash的读取速度相对较慢,不支持直接执行代码。因此,它更适合用于存储配置数据、固件升级或数据存储等需要大容量存储但不需要频繁读取的应用。
本文对W25Q32 SPI FLASH的原理,指令,通讯时序等进行讲解,并通过STM32F103C8T6单片机对W25Q32 进行数据读写实验。

在这里插入图片描述

二.W25Q32 SPI FLASH主要参数

FLASH芯片型号:W25Q32JVSSIQ
制造商:Winbond
产品种类:SPI NOR FLASH
封装 :SOIC-8
系列:W25Q32JV
存储容量:32 Mbit
最大时钟频率:133 MHz
接口类型:SPI
数据总线宽度:8 bit
电源电压: 2.7~3.6 V
电源电流—最大值: 25 mA
最小工作温度: - 40°C~85°C

模块接口说明:
1.VCC 供电电源 3.3V
2.CS SPI通讯CS引脚
3.DO SPI通讯MISO引脚
4.GND 电源地
5.CLK SPI通讯CLK引脚
6.DI SPI通讯MOSI引脚

在这里插入图片描述

三.W25Q32 SPI FLASH芯片介绍

引脚定义
在这里插入图片描述

在这里插入图片描述

1.W25Q32 芯片内部框图

在这里插入图片描述

如上图所示:
W25Q32的存储单位
Page(页)
256字节,编程最小单位(向FLASH写入内容),一次最多编程256字节。
Sector(扇区)
擦除的最小单位,1个Sector一般包含16个Page,即4KB。
Block(块)
包含16个Sector,块擦除可以32KB(半块)、64KB(整块)两种擦除方式。

2.W25Q32 芯片指令表格

下图是指令表格,每个不同的指令所发的字节数量是不同的,第一个字节发送的都是命令号,比如擦除指令,擦除第0个Sector,SPI所发送的内容是0x20,0x00,0x00,0x00这四个字节。

在这里插入图片描述

3.W25Q32 芯片通讯时序

我们以读数据为例,解析下通讯时序,根据SPI通讯规则,CPOL为0,CPHA为0,MCU提供CLK,跟CS控制。
根据指令表格,读的命令4字节内容,是0x03+3字节地址,就能获取到对应地址的数据内容,数据内容是1字节。
在这里插入图片描述

在这里插入图片描述

四.W25Q32 SPI FLASH读写实验

硬件准备:

STLINK接STM32F103C8T6小系统板,STLINK接电脑USB口。

用6根杜邦线把模块与开发板相连
板子3.3----模块VCC
板子A4-----模块CS
板子A5-----模块CLK
板子A6-----模块DO
板子A7-----模块DI
板子G------模块GND

在这里插入图片描述

打开STM32CubeMX软件,新建工程
在这里插入图片描述
Part Number处输入STM32F103C8,再双击就创建新的工程
在这里插入图片描述
配置下载口引脚
在这里插入图片描述
配置外部晶振引脚
在这里插入图片描述
配置系统主频
在这里插入图片描述

SPI1引脚配置,以及PA4引脚普通GPIO配置
在这里插入图片描述

配置工程文件名,保存路径,KEIL5工程输出方式
在这里插入图片描述
生成工程
在这里插入图片描述
用Keil5打开工程
在这里插入图片描述

添加相关代码
在这里插入图片描述

主要代码

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
	 MX_GPIO_Init();
	 MX_SPI1_Init();
	  /* USER CODE BEGIN 2 */
	FlashJedecid = spi_flash_read_id();//读取Jedecid
	FlashDeviceid=SFLASH_ReadID();//读取Device ID
	Flash_ReadSomeBytes(ReadBuff,0,8);//从FLASH 0地址读取8字节内容放入ReadBuff数组
	Flash_WriteSR(0x42);//解除保护
	HAL_Delay(100);//等待100ms
	Flash_ReadSR();//读状态寄存器
	Flash_WriteSomeBytes(WriteBuff,0,8);//把WriteBuff数组中的内容写入FLASH 0地址
	HAL_Delay(100);//等待100ms
	Flash_ReadSomeBytes(ReadBuff,0,8);//从FLASH 0地址读取8字节内容放入ReadBuff数组
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */

  }
  /* USER CODE END 3 */
}
void Flash_ErasePage(uint32_t _ulPageAddr)
{
	_ulPageAddr *= 256;
	Flash_WriteEnable();
	Flash_WaitNobusy();
	FLASH_CS_0();
	spi_master_send_recv_byte(FLASH_ERASE_PAGE);//页擦除指令
	spi_master_send_recv_byte((uint8_t)(_ulPageAddr>>16));	//写入24位地址
	spi_master_send_recv_byte((uint8_t)(_ulPageAddr>>8));
	spi_master_send_recv_byte((uint8_t)(_ulPageAddr>>0));
	FLASH_CS_1();
	Flash_WaitNobusy();	//等待写入结束
}


void Flash_EraseSector(uint32_t _ulSectorAddr)
{
	uint8_t command = FLASH_ERASE_SECTOR;
	uint8_t temp_buff[3] = {0};
	
	temp_buff[0] = (uint8_t)(_ulSectorAddr >> 16);
	temp_buff[1] = (uint8_t)(_ulSectorAddr >> 8);
	temp_buff[2] = (uint8_t)(_ulSectorAddr >> 0);
	
	_ulSectorAddr *= 4096;	//1个扇区 4 KBytes
	Flash_WriteEnable();
	Flash_WaitNobusy();
	FLASH_CS_0();
	spi_master_send_recv_byte(command);
	spi_master_send_recv_byte(temp_buff[0]);
	spi_master_send_recv_byte(temp_buff[1]);
	spi_master_send_recv_byte(temp_buff[2]);
	FLASH_CS_1();
	Flash_WaitNobusy();	//等待写入结束
}


void Flash_EraseBlock(uint32_t _ulBlockAddr)
{
	uint8_t command = FLASH_ERASE_BLOCK;
	_ulBlockAddr *= 65536;	//块地址,一块64K
	
	Flash_WriteEnable();
	Flash_WaitNobusy();
	FLASH_CS_0();
	spi_master_send_recv_byte(command);
	spi_master_send_recv_byte(_ulBlockAddr>>16);
	spi_master_send_recv_byte(_ulBlockAddr>>8);
	spi_master_send_recv_byte(_ulBlockAddr>>0);
	FLASH_CS_1();
	Flash_WaitNobusy();	//等待写入结束
}


void Flash_EraseChip(void)
{
	uint8_t command = FLASH_ERASE_CHIP;
	Flash_WriteEnable();	//flash芯片写使能
	Flash_WaitNobusy();	//等待写操作完成
	FLASH_CS_0();
	spi_master_send_recv_byte(command);
	FLASH_CS_1();
	Flash_WaitNobusy();	//等待写入结束
}
void Flash_ReadSomeBytes(uint8_t *ucpBuffer, uint32_t _ulReadAddr, uint16_t _usNByte)
{
	uint8_t command = FLASH_READ_DATA;
	uint8_t temp_buff[3] = {0};

	temp_buff[0] = (uint8_t)(_ulReadAddr >> 16);
	temp_buff[1] = (uint8_t)(_ulReadAddr >> 8);
	temp_buff[2] = (uint8_t)(_ulReadAddr >> 0);
	FLASH_CS_0();
	spi_master_send_recv_byte(command);
	spi_master_send_recv_byte(temp_buff[0]);
	spi_master_send_recv_byte(temp_buff[1]);
	spi_master_send_recv_byte(temp_buff[2]);
	spi_master_recv_some_bytes(ucpBuffer, _usNByte);
	FLASH_CS_1();
}

五.CubeMX工程源代码下载

链接:https://pan.baidu.com/s/1UErozpM7nE7LMovXO3FILw
提取码:15di
如果链接失效,可以联系博主给最新链接
程序下载下来之后解压就行

六.小结

SPI Flash广泛应用于各种产品中,如智能手机、平板电脑、路由器、网络设备、工业控制系统、汽车电子、穿戴设备等。由于其灵活性和可靠性,SPI Flash成为许多嵌入式系统首选的存储解决方案之一。

;