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

SPI协议——对外部SPI Flash操作

目录

1. W25Q32JVSSIQ背景知识

1.1 64个可擦除块

1.2 1024个扇区(每个块有16个扇区)

1.3 页


1. W25Q32JVSSIQ背景知识

        

W25Q32JV阵列被组织成16,384个可编程页,每页有256字节。一次最多可以编程256个字节。页面可分为16组(4KB扇区清除)、128组(32KB块删除)、256组(64KB块删除)或整个芯片(芯片清除)。W25Q32JV分别有1,024个可擦除扇区和64个可擦除块。小型的4KB扇区允许在需要数据和参数存储的应用程序中具有更大的灵活性。

1.1 64个可擦除块

8M的空间被切割成128块,每块64kb

  

1.2 1024个扇区(每个块有16个扇区)

每块64kb又每切割成16个扇区,每扇区4kb(16*4=64kb)

1.3 页

一扇区是4KB,划分成16份每份256字节这就是页,而且擦除数据也只能按照扇区或者块来擦除,下图的00FF00H-00FFFFH刚好256字节,000000h-0000ff之间也是256字节

2. Flash操作注意事项

2.1 写入操作

1. 写入操作之前必须先进行写使能;

2. 每个数据只能由1改写为0,不能由0改写为1是因为FLASH芯片自身的限制决定,它没有完全任意修改的能力,所以芯片内部无数据的时候默认为0XFF,表示为空。;

3. 写入数据之前必须先进行擦除,擦除后所有的数据位为1;

4. 进行擦除时必须按照最小擦除单元进行擦除(最小擦除单位为扇区);

5.连续写入多字节数据时,最多写入一页的数据,如果超过一页则会覆盖前面写的内容;

6. 写入操作结束后, 芯片进入忙状态(寄存器中有一个busy位),不影响新的读写操作;

2.2 读操作

进行读操作时,直接调用读取操作时序,无需使能,但是别忘了拉低电平,没有页的限制,读取之后也不会进入到忙状态,但是不能在忙状态时读取数据;

3.代码编写

此次对SPI Flash进行读写操作还是采用SPI1,具体的配置请见上篇文章,在这里不做详细概述。

3.1 spi_flash.c添加代码

/* Flash 写使能 */
static void SPI1_FLASH_WriteEnable(void)
{cs_low();SPI_FLASH_SendByte( 0x06 ); //需要查芯片的datasheet来看具体的cs_high();
}/* Flash 等待写结束 */
static void SPI1_FLASH_WaitEnd(void)
{uint8_t	state = 0;cs_low();SPI_FLASH_SendByte(0x05); //需要查芯片的datasheet来看具体的do{state = SPI1_FLASH_ReadByte();}while( (state & 0x01) == SET );cs_high();
}// 扇区擦除验证函数
int SPI_FLASH_VerifyErase(uint32_t addr, uint32_t length)
{uint8_t buffer[16];uint32_t bytesRead;for (bytesRead = 0; bytesRead < length; bytesRead += sizeof(buffer)){uint32_t toRead = sizeof(buffer);if (bytesRead + toRead > length) {toRead = length - bytesRead;}// 读取地址开始的若干字节数据SPI_FLASH_BufferRead(addr + bytesRead, buffer, toRead);// 检查读取的数据是否为0xFFfor (uint32_t i = 0; i < toRead; i++){if (buffer[i] != 0xFF){return -1; // 如果不是0xFF,返回false,表示擦除失败}}}return 0; // 如果所有数据都是0xFF,返回true,表示擦除成功
}/*清空扇区*/
int SPI_FLASH_SectorErase(uint32_t addr)
{cs_low();/* 开始的时候要先发送写使能信号 */SPI1_FLASH_WriteEnable();/* 发送扇区擦除命令 */SPI_FLASH_SendByte(0x20);/* 发送扇区地址,高位先行 */SPI_FLASH_SendByte( (addr & 0xff0000) >> 16 );SPI_FLASH_SendByte( (addr & 0xff00) >> 8 );SPI_FLASH_SendByte( addr & 0xff );cs_high();/* 最后等待Flash 处理完这次信号之后退出 */SPI1_FLASH_WaitEnd();if (!SPI_FLASH_VerifyErase(addr, 4096)) // 通常扇区大小为4KB{printf("Sector erase failed at address 0x%06X\n", addr);}else{printf("Sector erase successful at address 0x%06X\n", addr);}return 0;}/* 按页写数据,在写数据之前要先擦除 */void SPI_FLASH_PageWrite(uint32_t addr, uint8_t *pBuffer, uint8_t size)
{/* 发送使能信号 */SPI1_FLASH_WriteEnable();cs_low();/* 发送页写入命令 */SPI_FLASH_SendByte(0x02);/* 发送要写入的地址,高位先行 */SPI_FLASH_SendByte( (addr & 0xff0000) >> 16 );SPI_FLASH_SendByte( ( addr & 0xff00) >> 8 );SPI_FLASH_SendByte(addr & 0xff );printf("Writing to address 0x%06X: ", addr);for (uint8_t i = 0; i < size; i++){SPI_FLASH_SendByte(pBuffer[i]); // 发送数据printf("%02X ", pBuffer[i]);}printf("\n");cs_high();SPI1_FLASH_WaitEnd();
}/* 读取数据,读取指定地址制定长度的数据 */
void SPI_FLASH_BufferRead(uint32_t addr, uint8_t *pBuffer, uint16_t size)
{cs_low();/* 发送读取命令 */SPI_FLASH_SendByte(0x03);/* 发送要读取的地址,高位先行*/SPI_FLASH_SendByte( (addr & 0xff0000) >> 16 );SPI_FLASH_SendByte( (addr & 0xff00 ) >> 8 );SPI_FLASH_SendByte(addr & 0xff );printf("Reading to address 0x%06X: ", addr);/* 逐位读取数据到指针上 */for (uint8_t i = 0; i < size; i++){pBuffer[i] = SPI_FLASH_SendByte(Dummy_Byte); // 发送数据}cs_high();}

3.2 详细分析

1. 地址分解

假设 addr 是一个24位的地址(0xFFFFFF范围内)。发送前需要将addr分解成三个8位字节,因为SPI通常以字节为单位发送数据。

SPI_SendData((addr & 0xff0000) >> 16);
  • addr & 0xff0000:使用位与操作(&)保留 addr 的高8位,其余位清零。
  • >> 16:将结果右移16位,使得高8位移到最低8位的位置。
  • SPI_SendData():将移位后的结果发送出去,这发送的是 addr 的高8位。
  • 例如:如果 addr = 0x123456,那么 (addr & 0xff0000) = 0x120000,右移16位得到 0x12,即发送的第一个字节是 0x12。

 其他同理

2. SPI1_FLASH_WaitEnd(void)函数

读取寄存器最低位BUSY的状态,如果为1表示忙,0表示空闲;

3.3 main.c函数

uint8_t Rx[100];
uint8_t Tx[] = "Hello!", n;
SPI_FLASH_SectorErase(0x00000);
n=sizeof(Tx) -1 ;
SPI_FLASH_PageWrite(0x00000 ,Tx ,n);
SPI_FLASH_BufferRead(0x00000 ,Rx ,n);
printf("the data is %s\n", Rx);

3.4 运行结果

 

相关文章:

SPI协议——对外部SPI Flash操作

目录 1. W25Q32JVSSIQ背景知识 1.1 64个可擦除块 1.2 1024个扇区&#xff08;每个块有16个扇区&#xff09; 1.3 页 1. W25Q32JVSSIQ背景知识 W25Q32JV阵列被组织成16,384个可编程页&#xff0c;每页有256字节。一次最多可以编程256个字节。页面可分为16组(4KB扇区清除&…...

kotlin类型检测与类型转换

一、is与!is操作符 1、使用 is 操作符或其否定形式 !is 在运行时检测对象是否符合给定类型。 fun main() {var a "1"if(a is String) {println("a是字符串类型:${a.length}")}// 或val b a is Stringprintln(b) } 二、"不安全的"转换操作符…...

【JDBC】Oracle数据库连接问题记录

Failed to load driver class oracle.jdbc.driver.OracleDriver in either of HikariConfig class oracle驱动包未正确加载&#xff0c;可以先尝试使用下面方式加载检查类是否存在&#xff0c;如果不存在需要手动下载odbc包 try {Class.forName("oracle.jdbc.driver.Ora…...

leetcode45 跳跃游戏II

题目 给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说&#xff0c;如果你在 nums[i] 处&#xff0c;你可以跳转到任意 nums[i j] 处: 0 < j < nums[i] i j < n 返回到达 nums[n - 1]…...

【数学】什么是方法矩估计?和最大似然估计是什么关系?

背景 方法矩估计&#xff08;Method of Moments Estimation&#xff09;和最大似然估计&#xff08;Maximum Likelihood Estimation, MLE&#xff09;是两种常用的参数估计方法。方法矩估计基于样本矩与总体矩的关系&#xff0c;通过样本数据计算样本矩来估计总体参数。最大似…...

C++初学者指南第一步---10.内存(基础)

C初学者指南第一步—10.内存&#xff08;基础&#xff09; 文章目录 C初学者指南第一步---10.内存&#xff08;基础&#xff09;1.内存模型1.1 纸上谈兵&#xff1a;C的抽象内存模型1.2 实践&#xff1a;内存的实际处理 2. 自动存储3.动态存储&#xff1a;std::vector3.1 动态内…...

扩散模型详细推导过程——编码与解码

符号表 符号含义 x ( i ) z 0 ( i ) \boldsymbol{x}^{(i)}\boldsymbol{z}_0^{(i)} x(i)z0(i)​第 i i i个训练数据&#xff0c;其为长度为 d d d的向量 z t ( i ) \boldsymbol{z}_t^{(i)} zt(i)​第 i i i个训练数据在第 t t t时刻的加噪版本 ϵ t ( i ) \boldsymbol{\epsilo…...

js如何实现开屏弹窗

开屏弹窗是什么&#xff0c;其实就是第一次登录后进入页面给你的一种公告提示&#xff0c;此后再回到当前这个页面时弹窗是不会再出现的。也就是说这个弹窗只会出现一次。 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>…...

C#——文件读取Directory类详情

文件读取Directory类 Durectory提供了目录以及子目录进行创建移动和列举操作方法 Directory和Directorylnfo类(主要操作文件目录属性列如文件是否隐藏的 或者只读等这些属性) Directory对目录进行复制、移动、重命名、创建和删除等操作DirectoryInfo用于对目录属性执行操作 …...

Ruby on Rails Post项目设置网站初始界面

在构建了Ruby的Web服务器后&#xff0c;第三步就可以去掉框架的官方页面&#xff0c;设置自己的网页初始页了。 Linux系统安装Ruby语言-CSDN博客 、在Ubuntu中创建Ruby on Rails项目并搭建数据库-CSDN博客、 Ruby语言建立Web服务器-CSDN博客 了解Ruby onRails项目中的主要文件…...

03-QTWebEngine中使用qtvirtualkeyboard

qt提供了 virtualKeyboard 虚拟键盘模块&#xff0c;只需要在在main函数中最开始加入这样一句就可以了 qputenv("QT_IM_MODULE", QByteArray("qtvirtualkeyboard")); 但是在使用的时候遇到了一些问题&#xff1a; 1、中文输入的时候没有输入提示 Qvirt…...

leetcode3无重复字符的最长字串(重点讲滑动窗口)

本文主要讲解无重复字符的最长字串的要点与细节&#xff0c;根据步骤一步步走更方便理解 c与java代码如下&#xff0c;末尾 具体要点&#xff1a; 1. 区分一下子串和子序列 子串&#xff1a;要求元素在母串中是连续地出现 子序列&#xff1a;不要求连续 2. 题目中有两个核心…...

Gobject tutorial 八

The GObject base class Object memory management Gobject的内存管理相关的API很复杂&#xff0c;但其目标是提供一个基于引用计数的灵活的内存管理模式。 下面我们来介绍一下&#xff0c;与管理引用计数相关的函数。 Reference Count 函数g_object_ref和g_object_unref的…...

DDMA信号处理以及数据处理的流程---cfar检测

Hello,大家好,我是Xiaojie,好久不见,欢迎大家能够和Xiaojie一起学习毫米波雷达知识,Xiaojie准备连载一个系列的文章—DDMA信号处理以及数据处理的流程,本系列文章将从目标生成、信号仿真、测距、测速、cfar检测、测角、目标聚类、目标跟踪这几个模块逐步介绍,这个系列的…...

【机器学习】从理论到实践:决策树算法在机器学习中的应用与实现

&#x1f4dd;个人主页&#xff1a;哈__ 期待您的关注 目录 &#x1f4d5;引言 ⛓决策树的基本原理 1. 决策树的结构 2. 信息增益 熵的计算公式 信息增益的计算公式 3. 基尼指数 4. 决策树的构建 &#x1f916;决策树的代码实现 1. 数据准备 2. 决策树模型训练 3.…...

Zookeeper 集群节点故障剔除、切换、恢复原理

Zookeeper 集群节点故障剔除、切换、恢复原理 zookeeper 集群节点故障时,如何剔除节点,如果为领导节点如何处理,如何进行故障恢 复的,实现原理? 在 Zookeeper 集群中,当节点故障时,集群需要自动剔除故障节点并进行故障恢复,确保集群的高 可用性和一致性。具体来说,…...

解决帝国cms栏目管理拼音乱码的问题

帝国CMS7.5版本utf-8版网站后台增加栏目生成乱码的问题怎么解决 1、需要改一个函数&#xff0c;并且增加一个处理文件&#xff0c;方法如下&#xff1a; 修改e/class/connect.php文件&#xff0c;找到ReturnPinyinFun函数&#xff0c;如未修改文件在4533-4547行&#xff0c;将…...

Git快速入门

一 快速使用 1.1 初始化 什么是版本库呢&#xff1f;版本库又名仓库&#xff0c;可以简单理解成一个目录&#xff0c;这个目录里面的所有文件都可以被Git管理起来&#xff0c;每个文件的修改、删除&#xff0c;Git都能跟踪&#xff0c;以便任何时刻都可以追踪历史&#xff0…...

【18.0】JavaScript---事件案例

【18.0】JavaScript—事件案例 【一】开关灯事件 【介绍】设置一个按钮&#xff0c;按下按钮触发事件&#xff0c;来回切换圆形图片的颜色 【分析】 图片设置&#xff1a;设置成圆形的图片背景颜色&#xff1a;设置红绿两个颜色&#xff0c;来回切换按钮设置&#xff1a;点击…...

推荐系统三十六式学习笔记:原理篇.矩阵分解12|如果关注排序效果,那么这个模型可以帮到你

目录 矩阵分解的不足贝叶斯个性化排序AUC构造样本目标函数训练方法 总结 矩阵分解在推荐系统中的地位非常崇高。它既有协同过滤的血统&#xff0c;又有机器学习的基因&#xff0c;可以说是非常优秀了&#xff1b;但即便如此&#xff0c;传统的矩阵分解无论是在处理显式反馈&…...

深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录

ASP.NET Core 是一个跨平台的开源框架&#xff0c;用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录&#xff0c;以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...

零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?

一、核心优势&#xff1a;专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发&#xff0c;是一款收费低廉但功能全面的Windows NAS工具&#xff0c;主打“无学习成本部署” 。与其他NAS软件相比&#xff0c;其优势在于&#xff1a; 无需硬件改造&#xff1a;将任意W…...

通过Wrangler CLI在worker中创建数据库和表

官方使用文档&#xff1a;Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后&#xff0c;会在本地和远程创建数据库&#xff1a; npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库&#xff1a; 现在&#xff0c;您的Cloudfla…...

C# 类和继承(抽象类)

抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

JDK 17 新特性

#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持&#xff0c;不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的&#xff…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

用docker来安装部署freeswitch记录

今天刚才测试一个callcenter的项目&#xff0c;所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...

Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信

文章目录 Linux C语言网络编程详细入门教程&#xff1a;如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket&#xff08;服务端和客户端都要&#xff09;2. 绑定本地地址和端口&#x…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)

漏洞概览 漏洞名称&#xff1a;Apache Flink REST API 任意文件读取漏洞CVE编号&#xff1a;CVE-2020-17519CVSS评分&#xff1a;7.5影响版本&#xff1a;Apache Flink 1.11.0、1.11.1、1.11.2修复版本&#xff1a;≥ 1.11.3 或 ≥ 1.12.0漏洞类型&#xff1a;路径遍历&#x…...

Mysql8 忘记密码重置,以及问题解决

1.使用免密登录 找到配置MySQL文件&#xff0c;我的文件路径是/etc/mysql/my.cnf&#xff0c;有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...