[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积分下载

相关推荐
szxinmai主板定制专家21 小时前
基于 ZYNQ ARM+FPGA+AI YOLOV4 的电网悬垂绝缘子缺陷检测系统的研究
arm开发·人工智能·嵌入式硬件·yolo·fpga开发
光子物联单片机21 小时前
STM32G474单片机开发入门(八)内部FLASH详解及读写实战
stm32·单片机·嵌入式硬件·mcu
BreezeJuvenile21 小时前
通用定时器_输入捕获介绍及案例实操
stm32·单片机·嵌入式硬件·输入捕获·通用定时器
时空自由民.1 天前
无人机系统耗电,低功耗管理问题解决方法(chatgpt)
单片机·嵌入式硬件·无人机
时空自由民.1 天前
无人机系统耗电,低功耗管理问题解决方法(腾讯元宝)
单片机·嵌入式硬件·无人机
牛马大师兄1 天前
STM32独立看门狗IWDG与窗口看门狗WWDG知识梳理笔记
笔记·stm32·单片机·嵌入式硬件·嵌入式·看门狗
夜月yeyue1 天前
STM32 Flash 访问加速器详解(ART Accelerator)
linux·单片机·嵌入式硬件·uboot·bootloard
A9better1 天前
嵌入式开发学习日志37——stm32之USART
stm32·嵌入式硬件·学习
国科安芯1 天前
ASP4644芯片低功耗设计思路解析
网络·单片机·嵌入式硬件·安全
广药门徒1 天前
Linux驱动开发与BuildRoot是什么关系与其的应用场景
linux·运维·驱动开发