当前位置: 首页 > news >正文

W25Q64 驱动--基于SPI2接口

前言

(1)本系列是基于STM32的项目笔记,内容涵盖了STM32各种外设的使用,由浅入深。

(2)小编使用的单片机是STM32F105RCT6,项目笔记基于小编的实际项目,但是博客中的内容适用于各种单片机开发的同学学习和使用。

学习目标

本章有四个任务:

  1. 读取W25Q64,制造商ID 和特定芯片的ID,验证SPI驱动
  2. W25Q64的读操作
  3. W25Q64的写操作
  4. 25Q64验证测试,完成25q64的数据存储
  5. 提醒:基于SPI协议的25Q64读写操作,大家只要掌握把代码嫖过去,使用成功即可,至于SPI读取数据原理,大家只要了解时序图,知道是按时序图写程序就行。

任务一:读取SPI的ID,验证SPI通讯

获取芯片ID的操作时序图

获取芯片ID函数

//读取芯片ID W25X64的ID:0XEF16
unsigned short mt_flashReadID(void)
{unsigned short Temp = 0;	  hal_spi2CSDrive(0); 	//片选拉低		    hal_spi2ReadWriteByte(0x90);//发送读取ID命令	    hal_spi2ReadWriteByte(0x00); 	    hal_spi2ReadWriteByte(0x00); 	    hal_spi2ReadWriteByte(0x00); 	 			   Temp|=hal_spi2ReadWriteByte(0xFF)<<8;  //读取制造商ID,高八位Temp|=hal_spi2ReadWriteByte(0xFF);	 //读取设备ID,低八位hal_spi2CSDrive(1); 	//片选拉高		    return Temp;
}  

编写flash初始化代码,并调用读芯片ID函数。验证SPI通讯

void mt_flashInit(void)
{static unsigned short produid;hal_spi2Init(); produid = mt_flashReadID();}

mt_flash.h 头文件

#ifndef _MT_FLASH_H
#define _MT_FLASH_H#define FLASH_PAGE_SIZE       4096
//指令表
#define W25X_WriteEnable		  0x06 
#define W25X_ReadStatusReg	  0x05 
#define W25X_ReadData	          0x03 
#define W25X_PageProgram		  0x02 
#define W25X_SectorErase		   0x20 
#define W25X_ManufactDeviceID	   0x90 void mt_flashInit(void);#endif

修改main.c文件,并通过仿真读取芯片ID

#include "stm32f10x.h"
#include "hal_timer.h"
#include "hal_led.h"
#include "hal_gpio.h"
#include "mt_flash.h"int main(void)
{hal_LedInit();hal_GpioConfig_init();	hal_timerInit();mt_flashInit();while (1){	}
}
仿真结果图,可见芯片ID为EF16,说明SPI通讯接通

到此,验证SPI通讯成功。

任务二:25Q64读操作

读操作只有一个函数:

void mt_flashRead(unsigned char *pBuffer,unsigned int ReadAddr,unsigned int NumByteToRead);

25Q64读操作时序图

//pBuffer-读取数据存储地址,ReadAddr-Flash地址,NumByteToRead-读取字节数
void mt_flashRead(unsigned char *pBuffer,unsigned int ReadAddr,unsigned int NumByteToRead)   
{ unsigned char  *pBuff;unsigned short i,num;  unsigned int RdAddr;RdAddr = ReadAddr;num = NumByteToRead;pBuff = pBuffer;hal_spi2CSDrive(0);                            //使能器件   hal_spi2ReadWriteByte(0x03);         //发送读取命令   -
//      00 12 34 56Hhal_spi2ReadWriteByte((unsigned char )((RdAddr)>>16));  //发送24bit地址    hal_spi2ReadWriteByte((unsigned char )((RdAddr)>>8));   hal_spi2ReadWriteByte((unsigned char )RdAddr);   for(i=0;i<num;i++){ pBuff[i]=hal_spi2ReadWriteByte(0XFF);   //循环读数  }hal_spi2CSDrive(1);                             //取消片选     	      
}  

任务三:25Q64写操作

写操作有三种方式,即三个函数:页写、块写、任意写,在使用过程中根据需要选择调用即可。

1、25Q64数据的页写操作

页写操作代码

//SPI在一页(0~65535)内写入少于256个字节的数据
//在指定地址开始写入最大256字节的数据
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大256),该数不应该超过该页的剩余字节数!!!	 
void mt_flashWritePage(unsigned char * pBuffer,unsigned int WriteAddr,unsigned short NumByteToWrite)
{unsigned char  *pBuff;unsigned short i,num;  unsigned int wAddr;pBuff = pBuffer;wAddr = WriteAddr;num = NumByteToWrite;mt_flashWriteEnable();                  //SET WEL hal_spi2CSDrive(0);                              //使能器件   hal_spi2ReadWriteByte(W25X_PageProgram);      //发送写页命令   hal_spi2ReadWriteByte((unsigned char )((wAddr)>>16)); //发送24bit地址    hal_spi2ReadWriteByte((unsigned char )((wAddr)>>8));   hal_spi2ReadWriteByte((unsigned char )wAddr);   for(i=0;i<num;i++)hal_spi2ReadWriteByte(pBuff[i]);//循环写数  hal_spi2CSDrive(1);   mt_flashWaitBusy();   //等待写入结束
} 
//SPI_FLASH写使能	
//将WEL置位   
void mt_flashWriteEnable(void)   
{hal_spi2CSDrive(0);                            //使能器件   hal_spi2ReadWriteByte(W25X_WriteEnable);      //发送写使能  0x06hal_spi2CSDrive(1);                           //取消片选     	      
} //读取SPI_FLASH的状态寄存器
//BIT7  6   5   4   3   2   1    0
//SPR   RV  TB BP2 BP1 BP0 WEL   
//SPR:默认0,状态寄存器保护位,配合WP使用
//TB,BP2,BP1,BP0:FLASH区域写保护设置
//WEL:写使能锁定
//BUSY:忙标记位(1,忙;0,空闲)
//默认:0x00
unsigned char  mt_flashReadSR(void)   
{  unsigned char  byte=0;   hal_spi2CSDrive(0);                            //使能器件   hal_spi2ReadWriteByte(W25X_ReadStatusReg);    //发送读取状态寄存器命令    byte=hal_spi2ReadWriteByte(0Xff);             //读取一个字节  hal_spi2CSDrive(1);                             //取消片选     return byte;   
} 
//等待空闲
void mt_flashWaitBusy(void)   
{   while ((mt_flashReadSR()&0x01)==0x01);   // 等待BUSY位清空
}  

2、25Q64扇区写操作 4096

我们每个扇区有4K的存储空间,从上面可以看出,页操作只能写256个字节。 如何实现块写?

应用场景:

举例,如果起始地址:200(十进制)写长度为500个字节的数据

代码

//FLASH 块写操作
//必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
//具有自动换页功能 
//在指定地址开始写入指定长度的数据,但是要确保地址不越界!
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大65535)
//CHECK OK
void mt_flashWrite_Secor(unsigned char * pBuffer,unsigned int WriteAddr,unsigned short NumByteToWrite)   
{ 			 		 unsigned char  *pBuff;  数据地址指针unsigned short num;  unsigned int wAddr;  ///写的起始地址unsigned short pageremain;	pBuff = pBuffer;num = NumByteToWrite;wAddr = WriteAddr;pageremain=256-wAddr%256; //单页剩余的字节数		 	    if(num<=pageremain)pageremain=num;//不大于256个字节while(1){	   mt_flashWritePage(pBuff,wAddr,pageremain);if(num==pageremain)break;//写入结束了else //NumByteToWrite>pageremain{pBuff+=pageremain;wAddr+=pageremain;	//200  56   100num-=pageremain;			  //减去已经写入了的字节数if(num>256)pageremain=256; //一次可以写入256个字节else pageremain=num; 	  //不够256个字节了}		}	    
} 

3、25Q64任意写操作(常用)

应用场景

现在要对起始地址是 4000(十进制)写长度为6000个字节的数据。

函数功能说明

增加自动翻页写操作

//写SPI FLASH  
//在指定地址开始写入指定长度的数据
//该函数带擦除操作!
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大256)  
void mt_flashWrite(unsigned char * pBuffer,unsigned int WriteAddr,unsigned short NumByteToWrite)   { unsigned char  SPI_FLASH_BUF[4096];
//	   unsigned char testaa[200];unsigned char  *pBuff;unsigned int secpos;        ///需要写的起始的扇区unsigned short secoff;      ///写入到额起始扇区的 偏移地址unsigned short secremain;	 ///第一个写入扇区需要写入的数据的个数     unsigned short i,num;  unsigned int wAddr;pBuff = pBuffer;wAddr = WriteAddr;num = NumByteToWrite;  secpos=wAddr/4096;//扇区地址        secoff=wAddr%4096;//在扇区内的偏移secremain=4096-secoff;//扇区剩余空间大小   if(num<=secremain)  ///num  是需要写入数据的格式   如果需要写入的数据的个数小于本扇区剩余的个数secremain=num;//不大于4096个字节   在同一个区里面写while(1) {	mt_flashRead(SPI_FLASH_BUF,secpos*4096,4096);//读出整个扇区的内容mt_flashEraseSector(secpos);//擦除这个扇区for(i=0;i<secremain;i++)	   //复制{SPI_FLASH_BUF[i+secoff]=pBuff[i];}mt_flashWrite_Secor(SPI_FLASH_BUF,secpos*4096,4096);//写入整个扇区 写已经擦除了的,直接写入扇区剩余区间. 				 if(num==secremain)   ///需要写入的数据长度和 数据长度一致的话,break;//写入结束了else//写入未结束{secpos++;//扇区地址增1secoff=0;//偏移位置为0 	 pBuff+=secremain;  //指针偏移wAddr+=secremain;//写地址偏移	   num-=secremain;				//字节数递减if(num>4096)secremain=4096;	//下一个扇区还是写不完else secremain=num;			//下一个扇区可以写完了}	 }	 	 } //擦除一个扇区
//Dst_Addr:扇区地址 0~511 for w25x16
//擦除一个扇区的最少时间:45ms,最大300ms
void mt_flashEraseSector(unsigned int Dst_Addr)   
{   unsigned int DstAddr;DstAddr = Dst_Addr;DstAddr*=4096;mt_flashWriteEnable();                  //SET WEL 	 mt_flashWaitBusy();   hal_spi2CSDrive(0);                              //使能器件   hal_spi2ReadWriteByte(W25X_SectorErase);      //发送扇区擦除指令 hal_spi2ReadWriteByte((unsigned char )((DstAddr)>>16));  //发送24bit地址    hal_spi2ReadWriteByte((unsigned char )((DstAddr)>>8));   hal_spi2ReadWriteByte((unsigned char )DstAddr);  hal_spi2CSDrive(1);                             //取消片选     	      mt_flashWaitBusy();   				   //等待擦除完成
}

任务四:测试25Q64读取

目标

起始地址是:4000 ,写6000个数据,再读取6000;

测试函数

unsigned char falshtest[6000];
void mt_flash_test(void)
{unsigned int i;unsigned int falshdadrx;falshdadrx = 4000;for(i=0;i< 6000;i++){falshtest[i] = i;}		mt_flashWrite(&falshtest[0],falshdadrx,6000);for(i=0;i< 6000;i++){falshtest[i] = 0;}	mt_flashRead(&falshtest[0],falshdadrx,6000);
}

修改初始化程序:

unsigned char falshtest[6000];
void mt_flash_test(void)
{unsigned int i;unsigned int falshdadrx;falshdadrx = 4000;for(i=0;i< 6000;i++){falshtest[i] = i;}		mt_flashWrite(&falshtest[0],falshdadrx,6000);for(i=0;i< 6000;i++){falshtest[i] = 0;}	mt_flashRead(&falshtest[0],falshdadrx,6000);
}

测试验证

通过仿真的形式,验证Flash 25Q64的读写操作。

实现方法

先定义一个长度为6000的数组,对数组初始化;用任意写函数,将此数组里的内容写入指定地址,再对数组清零,最后读取指定地址中的内容,若此内容同之前初始化的数组中内容一致,则测试成功。

相关文章:

W25Q64 驱动--基于SPI2接口

前言 &#xff08;1&#xff09;本系列是基于STM32的项目笔记&#xff0c;内容涵盖了STM32各种外设的使用&#xff0c;由浅入深。 &#xff08;2&#xff09;小编使用的单片机是STM32F105RCT6&#xff0c;项目笔记基于小编的实际项目&#xff0c;但是博客中的内容适用于各种单片…...

禁用无线键盘指定按键

文章目录 前言主体 前言 睡一觉把键盘压坏了一个按键,一开机键盘就自动打出这个字母,我在想用其他按键平替这个字母即可,使用软件修改内部的映射,那么使用autoHotkey软件是十分容易做到的 主体 letter_replace.ahk 创建一个如此命名的文件,然后输入命令即可 a::b 代表平替 a…...

分数规划(二分)

链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 来源&#xff1a;牛客网 题目描述 小咪是一个土豪手办狂魔&#xff0c;这次他去了一家店&#xff0c;发现了好多好多&#xff08;n个&#xff09;手办&#xff0c;但他是一个很怪的人&#xff0c;每次只想买k个手办&a…...

Vue2向Vue3过度Vue3状态管理工具Pinia

目录 1. 什么是Pinia2. 手动添加Pinia到Vue项目3. Pinia基础使用4. getters实现5. action异步实现6. storeToRefs工具函数7. Pinia的调试8. Pinia持久化插件 1. 什么是Pinia Pinia 是 Vue 的专属的最新状态管理库 &#xff0c;是 Vuex 状态管理工具的替代品 2. 手动添加Pinia到…...

STM32--SPI通信与W25Q64(1)

文章目录 前言SPI通信硬件电路移位过程 SPI时序起始与终止条件交换一个字节 W25Q64硬件电路框图 FLASH操作注意事项软件SPI读写W25Q64 前言 USART串口链接入口 I2C通信链接入口 SPI通信 SPI&#xff08;Serial Peripheral Interface&#xff09;是一种高速的、全双工、同步的串…...

版本控制工具Git常见用法

Git 是一个非常强大和灵活的版本控制工具&#xff0c;提供了许多命令和功能来管理代码的版本、分支、合并等。以下是一些 Git 的详细用法&#xff1a; 配置相关命令&#xff1a; 设置用户名和邮箱&#xff1a; git config --global user.name "Your Name" git conf…...

Multisim软件安装包分享(附安装教程)

目录 一、软件简介 二、软件下载 一、软件简介 Multisim软件是一款电路仿真和设计软件&#xff0c;由美国国家仪器公司&#xff08;National Instruments&#xff09;开发。它提供了一个交互式的图形界面&#xff0c;使用户能够轻松地构建和仿真电路。以下是Multisim软件的详…...

【android12-linux-5.1】【ST芯片】HAL移植后开机卡死

按照ST的官方readme移植HAL后开机一直卡在android界面&#xff0c;看logcat提示写文件时errorcode&#xff1a;-13。查下资料大致明白13错误码是权限不足&#xff0c;浏览代码在写文件的接口加日志后&#xff0c;发现是需要写iio:device*/buffer/enable这类文件的时候报错的。千…...

线程池也就那么一回事嘛!

线程池详讲 一、线程池的概述二、线程池三、自定义线程池四、线程池工作流程图五、线程池应用场景 一、线程池的概述 线程池其实就是一种多线程处理形式&#xff0c;处理过程中可以将任务添加到队列中&#xff0c;然后在创建线程后自动启动这些任务。这里的线程就是我们前面学过…...

设计模式(11)观察者模式

一、概述&#xff1a; 1、定义&#xff1a;观察者模式定义了一种一对多的依赖关系&#xff0c;让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象&#xff0c;使它们能够自动更新自己。 2、结构图&#xff1a; public interface S…...

开源的安全性:挑战与机会

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…...

wireshark 流量抓包例题重现

[TOC](这里写目录标题 wireshark抓包方法wireshark组成 wireshark例题 wireshark抓包方法 wireshark组成 wireshark的抓包组成为&#xff1a;分组列表、分组详情以及分组字节流。 上面这一栏想要显示&#xff0c;使用&#xff1a;CtrlF 我们先看一下最上侧的搜索栏可以使用的…...

Smartbi电子表格软件版本更新,首次推出Excel轻应用和语音播放

Smartbi电子表格软件又又又更新啦&#xff01; 此次更新&#xff0c;首次推出了新特性——Excel轻应用和语音播报。另外&#xff0c;还对产品功能、Demo示例、配套文档进行了完善和迭代。 低代码开发Excel轻应用 可实现迅速发布web应用 业务用户的需求往往都处于“解决问题”…...

ElasticSearch简介、安装、使用

一、什么是ElasticSearch&#xff1f; Elasticsearch 是 Elastic Stack 核心的分布式搜索和分析引擎。 Logstash 和 Beats 有助于收集、聚合和丰富您的数据并将其存储在 Elasticsearch 中。 Kibana 使您能够以交互方式探索、可视化和分享对数据的见解&#xff0c;并管理和监…...

Navicat 连接 mysql 问题

需要将mysql配置文件设置为远程任意ip可登陆&#xff0c;注释掉一下两行配置 # bind-address>->--- 127.0.0.1 # mysqlx-bind-address>-- 127.0.0.1Cant connect to MySQL server on "192.168.137.139 (10013 "Unknown error") 检查Navicat是否联网H…...

Adobe Media Encoder软件安装包分享(附安装教程)

目录 一、软件简介 二、软件下载 一、软件简介 Adobe Media Encoder是一款由Adobe公司开发的视频和音频后期制作软件&#xff0c;它集成了多种编码格式和输出选项&#xff0c;可以帮助用户将视频和音频文件转换成适合各种用途的格式。该软件可以与Adobe Premiere Pro、After …...

[C#][原创]操作注册表一些注意点

C#注册表只需要引入 using Microsoft.Win32; C#注册表操作都是通过2个类Registry和RegistryKey进行所有操作。但是有些基本注意事项经常忘记&#xff0c;不常用就很容易忘记。 第一&#xff0c;打开注册表&#xff0c;第2个bool参数问题&#xff1a; RegistryKey key Regi…...

“华为杯”研究生数学建模竞赛2016年-【华为杯】C题:基于无线通信基站的室内三维定位问题

目录 摘 要: 一、问题的重述 1.1 问题背景 1.2 具体要求 1.3 数据分析...

双目视觉之-棋盘格标定板制作

棋盘格设计地址&#xff1a; https://markhedleyjones.com/projects/calibration-checkerboard-collection 包括A0&#xff0c;A1&#xff0c;A2&#xff0c;A3和A4多种规格的棋盘格标定板&#xff0c;支持自定义设置棋盘格grid宽度和高度。 基于Matlab的双目视觉标定流程和O…...

自然对数底e的一些事

自然对数底e的一些事 走的人多了就成了路 中国清代数学家李善兰&#xff08;1811—1882&#xff09; 凡此变数中函彼变数者&#xff0c;则此为彼之函数 自然对数底也是使用习惯 &#x1f349; 李善兰把function翻译为函数&#xff0c;函就是包含&#xff0c;含有变量&#xff…...

Ubuntu系统下交叉编译openssl

一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机&#xff1a;Ubuntu 20.04.6 LTSHost&#xff1a;ARM32位交叉编译器&#xff1a;arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

电脑插入多块移动硬盘后经常出现卡顿和蓝屏

当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时&#xff0c;可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案&#xff1a; 1. 检查电源供电问题 问题原因&#xff1a;多块移动硬盘同时运行可能导致USB接口供电不足&#x…...

macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用

文章目录 问题现象问题原因解决办法 问题现象 macOS启动台&#xff08;Launchpad&#xff09;多出来了&#xff1a;Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显&#xff0c;都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

让AI看见世界:MCP协议与服务器的工作原理

让AI看见世界&#xff1a;MCP协议与服务器的工作原理 MCP&#xff08;Model Context Protocol&#xff09;是一种创新的通信协议&#xff0c;旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天&#xff0c;MCP正成为连接AI与现实世界的重要桥梁。…...

Java 二维码

Java 二维码 **技术&#xff1a;**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...

MySQL 8.0 事务全面讲解

以下是一个结合两次回答的 MySQL 8.0 事务全面讲解&#xff0c;涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容&#xff0c;并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念&#xff08;ACID&#xff09; 事务是…...

[ACTF2020 新生赛]Include 1(php://filter伪协议)

题目 做法 启动靶机&#xff0c;点进去 点进去 查看URL&#xff0c;有 ?fileflag.php说明存在文件包含&#xff0c;原理是php://filter 协议 当它与包含函数结合时&#xff0c;php://filter流会被当作php文件执行。 用php://filter加编码&#xff0c;能让PHP把文件内容…...

tomcat指定使用的jdk版本

说明 有时候需要对tomcat配置指定的jdk版本号&#xff0c;此时&#xff0c;我们可以通过以下方式进行配置 设置方式 找到tomcat的bin目录中的setclasspath.bat。如果是linux系统则是setclasspath.sh set JAVA_HOMEC:\Program Files\Java\jdk8 set JRE_HOMEC:\Program Files…...

水泥厂自动化升级利器:Devicenet转Modbus rtu协议转换网关

在水泥厂的生产流程中&#xff0c;工业自动化网关起着至关重要的作用&#xff0c;尤其是JH-DVN-RTU疆鸿智能Devicenet转Modbus rtu协议转换网关&#xff0c;为水泥厂实现高效生产与精准控制提供了有力支持。 水泥厂设备众多&#xff0c;其中不少设备采用Devicenet协议。Devicen…...

图解JavaScript原型:原型链及其分析 | JavaScript图解

​​ 忽略该图的细节&#xff08;如内存地址值没有用二进制&#xff09; 以下是对该图进一步的理解和总结 1. JS 对象概念的辨析 对象是什么&#xff1a;保存在堆中一块区域&#xff0c;同时在栈中有一块区域保存其在堆中的地址&#xff08;也就是我们通常说的该变量指向谁&…...