[10min速通]STM32CubemMX配置W25Q128

[10min速通]🦏STM32CubemMX配置W25Q128

文章目录

1、下载源码

下载github开源驱动代码。

GitHub - nimaltd/w25qxx: w25qxx SPI FLASH driver for stm32 HAL

此处声明此工程不是本人所作。

这个工程的作者在Readme中提供的视频教程配置非常详细了,会魔法的同学可以直接去看视频进行配置,不用看此文。
如果访问不了github,可以直接下载文末的资料,打包好了。

2、配置Cube

2.1 基础配置

内容包含,时钟树、串口、SW下载接口等基础配置。此处不再赘述。

2.2 SPI配置

SW25Q128支持三种SPI通信模式:标准SPI,Dual SPI,Quad SPI。速度依次增加,每种模式所用到的通信时序也不一样,目前使用的是标准SPI。

SPI工作模式选择模式0或者3。写入时钟最大133M,读取时钟最大50M,这里我们把时钟控制在50M以内。

下面是依据硬件电路配置接口。以下是我的接口:

特别注意的是CS引脚,因为配置SPI的时候,没有选择硬件NSS引荐,因此我们这里单独把PB14设置为CS引脚。

3、配置MDK

3.1 添加源文件

github上下载下来的文件如下:

w25qxx就是我们需要加入到MDK里的驱动文件。

我们把w25qxx.c加入到.../Core/Src文件夹下。把w25qxx.h和w25qxxConf.h加入到.../Core/Inc文件夹。

3.2 管理源文件

接下来把文件导入到工程中。

如果找不到.h文件,需要设置下面的文件类型为All file

最终的文件结构如下:

3.3 完成接口配置

作者已经将所有的顶层配置集中在了w25qxxConf.h中,我们只需要更改其中的接口就可以完成基础的配置。

下面用代码注释的方式,讲解下如何配置:

c 复制代码
#ifndef _W25QXXCONFIG_H
#define _W25QXXCONFIG_H

#define _W25QXX_SPI                   hspi1         //使用到的是spi几
#define _W25QXX_CS_GPIO               GPIOB         //CS引脚的端口
#define _W25QXX_CS_PIN                GPIO_PIN_14   //CS引脚的引脚号
#define _W25QXX_USE_FREERTOS          0             //是否使用到了FreeRTOS,0为不使用。如果用到了其他RTOS,需要改动他的源码
#define _W25QXX_DEBUG                 0             //是否开启DEBUG模式,开启的话,需要提前配置好printf函数,工程运行时,会打印出运行过程。

#endif

此处我们用到的是spi1,CS引脚是PB14,关闭了RTOS跟DEBUG调试功能。

4、接口介绍

作者写的代码并没有提供多少注释,不过变量的命名已经可以做到见名知意。我通读了W25Qxx.c后,给大家介绍下常用的几个函数功能。

4.1 初始化

c 复制代码
bool W25qxx_Init(void);
/*
函数功能:初始化芯片。成功就返回1,失败返回0。
*/

4.2 擦除

c 复制代码
void W25qxx_EraseChip(void);
void W25qxx_EraseSector(uint32_t SectorAddr);
void W25qxx_EraseBlock(uint32_t BlockAddr);

上面三种擦除分别是:芯片全部擦除,擦除值定扇区,擦除值定块。SectorAddr是指扇区的编号,BlockAddr是指块的编号,编号不是地址。不太明白这句话可以接着往下看。

W25Q128有256个块(block),每个块由16个扇区(Sector)构成。一个块有64KB存储空间,一个扇区有4KB。下图是W25Q64的示意图,W25Q128内部也是这样的,就是block多一点。

我们想擦除第3个块,只需要:

c 复制代码
W25qxx_EraseBlock(2);

如果我们想要擦除第2个块中的第3个扇区。只需要:

c 复制代码
W25qxx_EraseSector(15+3);

解释以下,15是因为第一个块中包含了0-15,总共16个扇区,编号16对应着第二个块中的第1个扇区,那么18就对应着第2个块中的第3个扇区。

4.3 写入

c 复制代码
void W25qxx_WritePage(uint8_t *pBuffer, uint32_t Page_Address, uint32_t OffsetInByte, uint32_t NumByteToWrite_up_to_PageSize);
void W25qxx_WriteSector(uint8_t *pBuffer, uint32_t Sector_Address, uint32_t OffsetInByte, uint32_t NumByteToWrite_up_to_SectorSize);
void W25qxx_WriteBlock(uint8_t *pBuffer, uint32_t Block_Address, uint32_t OffsetInByte, uint32_t NumByteToWrite_up_to_BlockSize);

下面以W25qxx_WriteSector 为例讲解。

参数 含义
pBuffer 待写入的数据组指针
Sector_Address 想要写入的扇区编号
OffsetInByte 写入地址的字节偏置
NumByteToWrite_up_to_SectorSize 想要写入的字节数

如果我想要写入第19个扇区的第二个字节位置,写入一个两字节的变量。那么代码是:

c 复制代码
uint8_t WriteBuff[]={0x11,0x22};
...
W25qxx_WriteSector(WriteBuff, 18, 1,2);

4.4 读取

c 复制代码
void W25qxx_ReadPage(uint8_t *pBuffer, uint32_t Page_Address, uint32_t OffsetInByte, uint32_t NumByteToRead_up_to_PageSize);
void W25qxx_ReadSector(uint8_t *pBuffer, uint32_t Sector_Address, uint32_t OffsetInByte, uint32_t NumByteToRead_up_to_SectorSize);
void W25qxx_ReadBlock(uint8_t *pBuffer, uint32_t Block_Address, uint32_t OffsetInByte, uint32_t NumByteToRead_up_to_BlockSize);

下面以W25qxx_ReadSector为例讲解。

参数 含义
pBuffer 待读取的数据组指针
Sector_Address 想要读取的扇区编号
OffsetInByte 读取地址的字节偏置
NumByteToWrite_up_to_SectorSize 想要读取的字节数

如果我想要写入第19个扇区的第二个字节位置,写入一个两字节的变量。那么代码是:

c 复制代码
uint8_t ReadBuff[2];
...
W25qxx_ReadSector(ReadBuff, 18, 1,2);

5、代码示例

首先要包含头文件

c 复制代码
#include "w25qxx.h"

再定义读写变量:

c 复制代码
uint8_t WriteBuff[] = {0x11, 0x22};
uint8_t ReadBuff[2];

最后编写服务代码

c 复制代码
W25qxx_Init();                           // 初始化Flash芯片
W25qxx_EraseChip();                      // 擦除整个芯片
W25qxx_WriteSector(WriteBuff, 18, 1, 2); // 写入两字节数据
W25qxx_ReadSector(ReadBuff, 18, 1, 2);   // 读取两字节数据
printf("read data is 0x%x, 0x%x\n", ReadBuff[0], ReadBuff[1]);

6、其他

6.1 芯片擦除

由于FLASH存储器的特性决定了它只能把原来为"1"的数据位改写成"0",而原来为"0"的数据位不能直接改写为"1"。 所以这里涉及到数据"擦除"的概念,在写入前,必须要对目标存储矩阵进行擦除操作,把矩阵中的数据位擦除为"1", 在数据写入的时候,如果要存储数据"1",那就不修改存储矩阵,在要存储数据"0"时,才更改该位。

作为测试,我们更改示例代码的内容,,读取一个擦除后,没有被编程的地址:

c 复制代码
W25qxx_Init();                           // 初始化Flash芯片
W25qxx_EraseChip();                      // 擦除整个芯片
W25qxx_WriteSector(WriteBuff, 18, 1, 2); // 写入两字节数据
W25qxx_ReadSector(ReadBuff, 18, 0, 2);   // 读取两字节数据
printf("read data is 0x%x, 0x%x\n", ReadBuff[0], ReadBuff[1]);

会发现,打印的结果是

c 复制代码
0xff, 0x11

0xff的出现正是擦除后,每一位都变成了1。

6.2 没有掉电功能

这个开源代码包含了常用的功能,但是没有power down等不常用的功能。

6.3 这个开源代码适用其他w25qxx型号

6.4 FatFs

用flash存储少量信息没有问题,如果存储大量信息,可以考虑上文件系统,可以关注我的文章。

配套例程和源码

配套资源,0积分下载

相关推荐
__基本操作__几秒前
历遍单片机下的IIC设备[ESP--0]
单片机·嵌入式硬件
zy张起灵6 小时前
48v72v-100v转12v 10A大功率转换电源方案CSM3100SK
经验分享·嵌入式硬件·硬件工程
PegasusYu9 小时前
STM32CUBEIDE FreeRTOS操作教程(九):eventgroup事件标志组
stm32·教程·rtos·stm32cubeide·free-rtos·eventgroup·时间标志组
lantiandianzi13 小时前
基于单片机的多功能跑步机控制系统
单片机·嵌入式硬件
文弱书生65613 小时前
输出比较简介
stm32
哔哥哔特商务网13 小时前
高集成的MCU方案已成电机应用趋势?
单片机·嵌入式硬件
跟着杰哥学嵌入式13 小时前
单片机进阶硬件部分_day2_项目实践
单片机·嵌入式硬件
电子科技圈14 小时前
IAR与鸿轩科技共同推进汽车未来
科技·嵌入式硬件·mcu·汽车
东芝、铠侠总代1361006839315 小时前
浅谈TLP184小型平面光耦
单片机·嵌入式硬件·物联网·平面
lantiandianzi15 小时前
基于单片机中医药柜管理系统的设计
单片机·嵌入式硬件