一、W25Q64简介

1.1 简介       

W25Q64(Nor flash)、   24位地址,64Mbit/8MByte、是一种低成本、小型化、使用简单的非易失性存储器,常用于数据存储、字库存储、固件程序存储等场景 
        时钟频率:最大80MHz(STM32F103系统时钟为72MHz)、160MHz(MOSI,MISO同时发送,同时接受)、320MHz(将引脚DO、DI、WP、HOLD同时接收或发送)

W25Q64封装
引脚描述

VCC:  2.7-3.6V
WP:    写保护,低电平有效,当为低电平时,不可写
HOLD:数据保持、低电平有效;如果在正常读写flash时,突然产生中断,想用SPI去操控其他器件,要是把CS置1,则flash时序就会终止;若将HOLD置0,则时序可以保持原有状态

1.2 框图-地址划分

24位地址,可寻址范围:0x000000-0xFFFFFF;由于W25Q64的容量为8MB,所以其地址范围为0x000000-0x7FFFFF

flash 框图
flash 空间划分

将8MB的空间划分为块(block),每一个块的容量为64KB,共划分128块
将每一个64KB块划分为扇区,一个块可划分为16个扇区,一共有2048个扇区
将每一4KB的扇区划分为页,一个扇区可划分16个页;也可以看作一个flash可划分为32768个页
一页是256字节 ,一块是256页

如果想要往第3个块第210页的第118个字节写入,物理地址是多少呢?
第三个块对应高八位字节:0x020000
第210个页对应中间八位(页地址锁存器):0x00D100
第118个字节对应第八位((字节地址锁存器):0x000075
所以物理地址为:0x02D175(24位地址)


例如写入地址为0x123456,对应的是多少呢
0x12->18,也就是块17(或第18个块)
0x34->52,也就是块17页51(或第52个页)
0x56->86,也就是块17页51的85字节(或第86个字节)

也就是说18*16+52-1=4659,对应4659页的85字节开始写入

当往flash中写入数据时,写入的数据先缓存到256字节页缓冲区,再从缓冲区转到flash里,这需要一定的时间,在这期间,芯片的flash的busy标志位将被置1;
注意:由于缓冲区只有256个字节,所以写入的一个时序连续写入的数据量不能超过256个字节

1.3 读写flash注意事项

写入时
<1>写入操作前必须进行写使能
<2>每个数据位只能由1改写为0,不能由0改写为1
      例如 原来数据为0x78(01111000),想要在本地址直接写入0x11(00010001),就会变为              00010000
<3>写入前必须想先要擦除,擦除后,所有数据位变为1(0xFF表示空白)
<5>擦除必须按最小单元进行(最小单元为扇区(4KB=4096字节))
       想要单独改写某一个字节,可以先将扇区的全部数据读出后,该写完读出来的数据后再          写入或者一个字节占一个扇区
<6>连续写入多字节时,最多写入一页的数据;超过尾页的数据会回到页尾覆盖数据(不能跨页)
<7>写入操作结束后,芯片进入忙状态,不响应新的读写操作(擦除时也会进入忙状态)(可读状态寄存器的busy位)

读取
<1>直接调用读取时序、无需使能、无需额外操作,没有页的限制读取操作结束后不会进入忙状态,但不能在忙状态时读取

 注意:当给定一个地址时,数据会按地址自增写入,且不可跨页写入,如果大于页的容量会从本页头开始覆盖;写使能只对之后跟随的一条指令有效

 二、软件模拟SPI读取flash

SPI是一种协议,软件可以进行模拟,如果板子上没有SPI端口或者SPI的端口被占用时,软件可以进行模拟,通过软件控制四个引脚的高低电平,从而达到硬件的效果,本节进行软件模拟SPI(模式0),与硬件不同的是,对于软件的四个引脚,输入引脚(CS,CLK,MOSI)配置为上拉或浮空输入,输出引脚(MISO)配置为推挽输出
对于SPI不了解的可以看一下https://mpbeta.csdn.net/mp_blog/creation/editor/148934665

引脚配置

/****************************
*@brief    SPI引脚初始化
*@param  void
*@return   void
*@note     PB13->CLK PB14->MISO->DOPB12->CS  PB15->MOSI->DI/
对于软件来说输出引脚配置为推挽输出
输入引脚配置为上拉输入或浮空输入
*@time  2025-6-27
******************************/
void Soft_SPI_Init(void)
{/*1.打开IO引脚时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);/*2.引脚模式配置*/GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP                   ;GPIO_InitStruct.GPIO_Pin=GPIO_Pin_13|GPIO_Pin_15|GPIO_Pin_12 ;//输出配置为推挽输出GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz                  ;GPIO_Init(GPIOB,&GPIO_InitStruct)                            ;GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU                      ;//输入配置为浮空输入GPIO_InitStruct.GPIO_Pin=GPIO_Pin_14                         ;GPIO_Init(GPIOB,&GPIO_InitStruct)                            ;/*3.CS片选默认高电平、CLK默认低电平*/SOFT_SPI_CS(1)                                               ;//宏定义SOFT_SPI_CLK(0)                                              ;//宏定义
}
SPI模式0 时序

对于模式0,时钟默认低电平且在时钟的第一个边沿进行采样 ,有时序图可知,MCU在时钟下降沿通过MOSI输出高位,在时钟上升沿时,采样 从机通过MOSI(对应主机MISO的)输出的电平,在写数据收发时序时只需要盯着主机,从机我们无法干涉

数据交换

/****************************
*@brief  交换数据
*@param     void
*@return    void
*@note     高位先发,SPI模式0
*@time  2025-6-27
******************************/
int8_t Soft_SPI_Dataswap(int8_t Send_Data)
{int8_t Receive_Data=0x00;for(int8_t i=0;i<8;i++){SOFT_SPI_MOSI(Send_Data>>(7-i)&0x01)  ;//高位数据通过MOSI送出SOFT_SPI_CLK(1)                       ;//时钟上升沿//if(Soft_SPI_MISO()==1){Receive_Data |=(0x80>>i);}Receive_Data|=SOFT_SPI_MISO()<<(7-i)  ;//主机从从机的MOSI口接收的高位数据SOFT_SPI_CLK(0)                       ;//时钟下降沿}return Receive_Data;
}

当时钟为低电平时,主机通过 SOFT_SPI_MOSI(Send_Data>>(7-i)&0x01)  将1位数据通过MOSI口送出;当时钟位上升沿时,主机进行采样,通过 Receive_Data|=SOFT_SPI_MISO()<<(7-i)  将从机的MOSI上的数据采入
注意:由于C语言时逐语句进行的,所以不可能发送的同时进行接收,可以利用RTOS或者FPGA

flash函数封装

/****************************
*@brief  读取ID
*@param  uint8_t *MID 厂商IDuint16_t *DID 设备ID
*@return void
*@note   void
*@time  2025-6-28
******************************/
void Soft_SPI_ReadID_W25Q64(uint8_t *MID,uint16_t *DID)
{SOFT_SPI_START;Soft_SPI_Dataswap(SOFT_SPI_R_ID)  ;*MID = Soft_SPI_Dataswap(0XFF)    ;*DID = Soft_SPI_Dataswap(0XFF)    ;*DID <<= 8;*DID |=  Soft_SPI_Dataswap(0XFF);SOFT_SPI_STOP;
}
/****************************
*@brief    写使能
*@param  void
*@return   void
*@note     void
*@time  2025-6-28
******************************/
void Soft_SPI_W_ENABLE_W25Q64(void)
{SOFT_SPI_START;Soft_SPI_Dataswap(SOFT_SPI_W_ENABLE)  ;//指令SOFT_SPI_STOP;
}	
/****************************
*@brief   等待寄存器忙状态
*@param    void
*@return   void
*@note    busy位维1,表示忙
*@time  2025-6-28
******************************/
void Soft_SPI_R_Status_W25Q64_busy(void)
{SOFT_SPI_START;Soft_SPI_Dataswap(SOFT_SPI_GetStatus);//读取指令while(Soft_SPI_Dataswap(0xFF)&0x01)  ;//busy=1时等待SOFT_SPI_STOP;
}	
/****************************
*@brief    页编程
*@param  uint8_t ArrayData[]数据uint32_t Address写入的数据地址uint16_t len     字节个数
*@return   void
*@note     void
*@time  2025-6-28
******************************/
void Soft_SPI_W_Data_W25Q64(uint8_t *ArrayData,uint32_t Address,uint16_t cnt)
{Soft_SPI_W_ENABLE_W25Q64();//写使能SOFT_SPI_START;Soft_SPI_Dataswap(SOFT_SPI_W_DATA);//写指令/*函数Soft_SPI_Dataswap()一次只能交换8位*/Soft_SPI_Dataswap(Address>>16);   //高地址,决定哪块Soft_SPI_Dataswap(Address>>8);    //中间地址,决定哪个扇区Soft_SPI_Dataswap(Address>>0);    //低地址,决定哪个页/*写数据*/for(uint16_t i=0;i<cnt;i++){Soft_SPI_Dataswap(ArrayData[i]);}SOFT_SPI_STOP;Soft_SPI_R_Status_W25Q64_busy();//busy等待
}
/****************************
*@brief   扇区擦除
*@param  uint32_t Address擦除地址
*@return   void
*@note     void
*@time  2025-6-28
******************************/
void Soft_SPI_Sector_Clean_W25Q64(uint32_t Address)
{Soft_SPI_W_ENABLE_W25Q64();//写使能SOFT_SPI_START;Soft_SPI_Dataswap(SOFT_SPI_SECTOR_CLEAN );//指令/*函数Soft_SPI_Dataswap()一次只能交换8位*/Soft_SPI_Dataswap(Address>>16);   //高地址,决定哪块Soft_SPI_Dataswap(Address>>8);    //中间地址,决定哪个扇区Soft_SPI_Dataswap(Address>>0);    //低地址,决定哪个页SOFT_SPI_STOP;Soft_SPI_R_Status_W25Q64_busy();//busy等待
}
/****************************
*@brief    读数据
*@param  uint8_t* ArrayData 输出数据uint32_t Address   读出的数据起始地址uint16_t len       字节个数
*@return   void
*@note     void
*@time  2025-6-28
******************************/
void Soft_SPI_R_Data_W25Q64(uint8_t *ArrayData,uint32_t Address,uint32_t cnt)
{SOFT_SPI_START;Soft_SPI_Dataswap(SOFT_SPI_R_DATA);//写指令/*函数Soft_SPI_Dataswap()一次只能交换8位*/Soft_SPI_Dataswap(Address>>16);   //高地址,决定哪块Soft_SPI_Dataswap(Address>>8);    //中间地址,决定哪个扇区Soft_SPI_Dataswap(Address>>0);    //低地址,决定哪个页/*读数据*/for(uint32_t i=0;i<cnt;i++){ArrayData[i]= Soft_SPI_Dataswap(0xFF);}SOFT_SPI_STOP;
}

上述代码对读取ID,写使能,读数据,写数据,擦除进行了封装,相同的流程是
①片选语句拉低(SOFT_SPI_START)
②flash操作指令(Soft_SPI_Dataswap(指令))
③读/写数据
④片选语句拉低(SOFT_SPI_STOP)
注意:
可以跨页读但不能跨页写;
写之前须写使能;
一次最多写入256字节数据;
再次写入相同地址需要先擦除,再写入;
擦除、写入操作(包括写入寄存器)会使busy置1,busy置1不再响应读,写,擦除操作(读不能使busy置1,但busy置1时不可读)

三、整个代码

运行代码:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/86822.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/86822.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/86822.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue3+element-plus 组件功能实现 上传功能

一、整体功能概述 这段代码实现了一个基于 Vue 3 和 Element Plus 组件库的文件导入及预览功能模块。主要包含了一个主导入对话框&#xff08;用于上传文件、展示文件相关信息、进行导入操作等&#xff09;以及一个用于预览文件内容的预览对话框。支持导入特定格式&#xff08;…

OpenCV中创建Mat对象

第1章 创建Mat对象 1.1. 创建空的 Mat 对象 cv::Mat mat; 1.2. 创建灰度图像 // 创建一个 3 行 4 列、8位无符号单通道矩阵&#xff08;相当于灰度图&#xff09; cv::Mat mat(3, 4, CV_8UC1); 1.3. 创建彩色图像 // 创建三通道矩阵&#xff08;相当于彩色图像&#xff0…

10、做中学 | 五年级下期 Golang循环控制

一、一个小需求 我想要打印10遍hello world,你想怎么编写呢&#xff1f; // 需求&#xff1a;打印10遍"hello world"fmt.Println("hello world")fmt.Println("hello world")fmt.Println("hello world")fmt.Println("hello world…

机器学习算法-K近邻算法-KNN

1. K近邻算法是什么&#xff1f; 定义&#xff1a; K近邻是一种基于实例的懒惰学习&#xff08;Lazy Learning&#xff09;算法&#xff0c;用于分类和回归任务。 核心思想&#xff1a;“物以类聚”——通过计算样本间的距离&#xff0c;找到目标点的最近K个邻居&#xff0c;…

基于vue框架的法律知识咨询普及系统gwuv7(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;用户,知识类型,律师,律师推荐,法律知识,新闻类型,法律新闻,咨询律师 开题报告内容 基于Vue框架的法律知识咨询普及系统开题报告 一、研究背景与意义 随着法治社会建设的深入推进&#xff0c;公众对法律知识的需求呈现爆发式增长。然而…

Netty 揭秘CompositeByteBuf:零拷贝优化核心技术

CompositeByteBuf 类 核心设计目标​​ ​​虚拟缓冲区​​&#xff1a;将多个 ByteBuf 合并为单一逻辑视图&#xff0c;减少数据复制。​​零拷贝优化​​&#xff1a;通过组合而非复制提升性能。​​引用计数管理​​&#xff1a;统一管理底层 ByteBuf 的生命周期。 核心成…

用css实现文字字体颜色渐变

用css实现文字字体颜色渐变 background-clip 是CSS3中新增的属性&#xff0c;可以用于指定背景图片或颜色的绘制范围。利用 background-clip 属性实现文字颜色从左到右、从绿到白的渐变效果&#xff1a; 代码如下&#xff1a; .gradient-color {background-image: linear-gr…

SpringBatch处理数据性能优化

SpringBatch的Step默认使用同步方式批量处理数据&#xff0c;也可以通过配置将读数改为同步&#xff0c;处理和写入改为异步方式。 1、同步处理Step SpringBatch的Step一般由ItemReader、ItemProcessor和ItemWriter组成&#xff0c;其中ItemProcessor是可选的。他的设计思路的…

【机器学习深度学习】前馈神经网络(单隐藏层)

目录 一、什么是前馈神经网络&#xff1f; 二、数学表达式是什么&#xff1f; 三、为什么需要“非线性函数”&#xff1f; 四、NumPy 实现前馈神经网络代码示例 五、 运行结果 六、代码解析 6.1 初始化部分 6.2 前向传播 6.3 计算损失&#xff08;Loss&#xff09; 6…

设计模式系列(08):创建型模式 - 原型模式

系列导读&#xff1a;完成创建型模式的学习&#xff0c;我们来看最后一个创建型模式——原型模式。它通过复制已有对象来创建新对象&#xff0c;是一种独特的创建方式。 解决什么问题&#xff1a;通过复制现有对象来创建新对象&#xff0c;而不是重新实例化。适用于对象创建成本…

区块链到底是什么?

区块链本质上是一种去中心化的分布式账本技术&#xff0c;具有以下核心特点&#xff1a; - 去中心化&#xff1a;没有中央管理机构&#xff0c;数据由网络中的多个节点共同维护&#xff0c;比如比特币网络中各个节点都保存着完整账本。 - 分布式存储&#xff1a;数据不是存在一…

系统架构设计师论文分享-论ATAM的使用

我的软考历程 摘要 2023年2月&#xff0c;我司通过了研发纱线MES系统的立项&#xff0c;该系统为国内纱线工厂提供SAAS服务&#xff0c;旨在提高纱线工厂的数字化和智能化水平。我在本项目中担任系统架构设计师&#xff0c;负责整个项目的架构设计工作。本文结合我在该项目中…

vue-28(服务器端渲染(SSR)简介及其优势)

服务器端渲染&#xff08;SSR&#xff09;简介及其优势 服务器端渲染&#xff08;SSR&#xff09;是现代网络应用的关键技术&#xff0c;特别是使用 Vue.js 等框架构建的应用。它通过在服务器上渲染初始应用状态来弥补传统单页应用&#xff08;SPA&#xff09;的局限性&#x…

工业电子 | 什么是SerDes,为何工业和汽车应用需要它?

重点内容速览&#xff1a; 1. 什么是SerDes&#xff1f; 2. ADI&#xff1a;私有协议的GMSL将向公有协议转变 3. TI&#xff1a;工业和汽车有两套SerDes解决方案 4. Microchip&#xff1a;推出通用协议SerDes芯片 5. 罗姆&#xff1a;主要针对汽车领域 6. 国产SerDes芯…

大事件项目记录4-用户接口开发-更新用户基本信息

4&#xff09;更新用户基本信息。 UserController.java&#xff1a; UserMapper.java&#xff1a; Update("update user set nickname #{nickname},email #{email},update_time #{updateTime} where id #{id}")void update(User user); UserServiceInterface…

Transformer结构--输入编码(BPE,PE)

在Transformer结构中&#xff0c;输入编码是模型处理文本数据的关键步骤&#xff0c;其中**BPE&#xff08;Byte Pair Encoding&#xff0c;字节对编码&#xff09;和PE&#xff08;Positional Encoding&#xff0c;位置编码&#xff09;**是两种重要的编码方式&#xff0c;它们…

Confluence-测试用例设计指导方法

测试经验知识库 典型的测试场景验证点各个项目有价值的经验和测试点 测试经验知识库 - 草稿测试用例执行量化指导建议 何时需要进行全量测试和如何定义和执行测试用例量的一些建议和标准 端对端&#xff08;E2E&#xff09;测试用例设计指导方案 在测试行业中&#xff0c;端到端…

浅析JVM

一、JVM运行流程 如图&#xff1a; JVM由四个部分构成&#xff1a; 1.类加载器 加载类文件到内存2.运行时数据区 写的程序需要加载到这里才能运行3.执行引擎 负责解释命令&#xff0c;提交操作系统执行4.本地接口 融合不同编程语言为java所用&#xff0c;如Java程序驱动打印…

多个 Job 并发运行时共享配置文件导致上下文污染,固化 Jenkins Job 上下文

基于 context.py 固化 Jenkins Job 上下文的完整方案&#xff0c;适用于你当前的工作流&#xff08;Python Jenkins Pipeline&#xff09;&#xff0c;解决&#xff1a; 多个 Job 并发运行时共享配置文件导致上下文污染&#xff1b;读取环境变量或 JSON 文件时被其他 Job 修改…

简木易支付系统 功能齐全,对接接口超多

简木易支付系统&#xff0c;作为一款引领行业潮流的卓越支付解决方案&#xff0c;依托先进的 PHP MySQL 技术架构精心打造。在开发过程中&#xff0c;它巧妙运用了功能强大的 ThinkPHP8 框架&#xff0c;完美融合前端主流技术 Vue、Element 以及 Layuiadmin&#xff0c;共同铸…