[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以内。

Untitled

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

Untitled

Untitled

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

3、配置MDK

3.1 添加源文件

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

Untitled

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

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

3.2 管理源文件

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

6Q31MO(4%`KLZK0.png

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

Untitled

最终的文件结构如下:

Untitled

3.3 完成接口配置

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

Untitled

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

#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 初始化

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

4.2 擦除

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多一点。

image-20230817171513323

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

W25qxx_EraseBlock(2);

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

W25qxx_EraseSector(15+3);

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

4.3 写入

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个扇区的第二个字节位置,写入一个两字节的变量。那么代码是:

uint8_t WriteBuff[]={0x11,0x22};
...
W25qxx_WriteSector(WriteBuff, 18, 1,2);

4.4 读取

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个扇区的第二个字节位置,写入一个两字节的变量。那么代码是:

uint8_t ReadBuff[2];
...
W25qxx_ReadSector(ReadBuff, 18, 1,2);

5、代码示例

首先要包含头文件

#include "w25qxx.h"

再定义读写变量:

uint8_t WriteBuff[] = {0x11, 0x22};
uint8_t ReadBuff[2];

最后编写服务代码

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”时,才更改该位。

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

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]);

会发现,打印的结果是

0xff, 0x11

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

6.2 没有掉电功能

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

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

6.4 FatFs

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

配套例程和源码

配套资源,0积分下载

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值