STM32 NOR FLASH(SPI FLASH)驱动移植(2)

2)FLASH 读取函数

/*
* @brief 读取 SPI FLASH 
* @note 在指定地址开始读取指定长度的数据
* @param pbuf : 数据存储区
* @param addr : 开始读取的地址(最大 32bit)
* @param datalen : 要读取的字节数(最大 65535)
* @retval 无
*/
void norflash_read(uint8_t *pbuf, uint32_t addr, uint16_t datalen)
{uint16_t i;NORFLASH_CS(0);spi5_read_write_byte(FLASH_ReadData); /* 发送读取命令 */norflash_send_address(addr); /* 发送地址 */for (i = 0; i < datalen; i++){pbuf[i] = spi5_read_write_byte(0XFF); /* 循环读取 */}NORFLASH_CS(1);
}

3)FLASH写函数

/**
* @brief 写 SPI FLASH
* @note 在指定地址开始写入指定长度的数据 , 该函数带擦除操作!
* SPI FLASH 一般是: 256 个字节为一个 Page, 4Kbytes 为
* 一个 Sector, 16 个扇区为 1 个 Block 擦除的最小单位为 Sector. 
* @param pbuf : 数据存储区
* @param addr : 开始写入的地址(最大 32bit)
* @param datalen : 要写入的字节数(最大 65535)
* @retval 无
*/
uint8_t g_norflash_buf[4096]; /* 扇区缓存 */
void norflash_write(uint8_t *pbuf, uint32_t addr, uint16_t datalen)
{uint32_t secpos;uint16_t secoff;uint16_t secremain;uint16_t i;uint8_t *norflash_buf;norflash_buf = g_norflash_buf;secpos = addr / 4096; /* 扇区地址 */secoff = addr % 4096; /* 在扇区内的偏移 */secremain = 4096 - secoff; /* 扇区剩余空间大小 *///printf("ad:%X,nb:%X\r\n", addr, datalen); /* 测试用 */if (datalen <= secremain){secremain = datalen; /* 不大于 4096 个字节 */}while (1){norflash_read(norflash_buf, secpos * 4096, 4096); //读出整个扇区的内容 for (i = 0; i < secremain; i++) /* 校验数据 */{if (norflash_buf[secoff + i] != 0XFF){break; /* 需要擦除, 直接退出 for 循环 */}}if (i < secremain) /* 需要擦除 */{norflash_erase_sector(secpos); /* 擦除这个扇区 */for (i = 0; i < secremain; i++) /* 复制 */{norflash_buf[i + secoff] = pbuf[i];}norflash_write_nocheck(norflash_buf, secpos * 4096, 4096);/* 写入整个扇区 */}else /* 写已经擦除了的,直接写入扇区剩余区间. */{norflash_write_nocheck(pbuf, addr, secremain); /* 直接写扇区 */}if (datalen == secremain){break; /* 写入结束了 */}else /* 写入未结束 */{secpos++; /* 扇区地址增 1 */secoff = 0; /* 偏移位置为 0 */pbuf += secremain; /* 指针偏移 */addr += secremain; /* 写地址偏移 */datalen -= secremain; /* 字节数递减 */if (datalen > 4096){secremain = 4096; /* 下一个扇区还是写不完 */}else{secremain = datalen;/* 下一个扇区可以写完了 */}}}
}

该函数可以在 NOR FLASH 的任意地址开始写入任意长度(必须不超过 NOR FLASH 的容量)的数据。我们这里简单介绍一下思路:先获得首地址(WriteAddr)所在的扇区,并计算在扇区内的偏移,然后判断要写入的数据长度是否超过本扇区所剩下的长度,如果不超过,再先看看是否要擦除,如果不要,则直接写入数据即可,如果要则读出整个扇区,在偏移处开始写入指定长度的数据,然后擦除这个扇区,再一次性写入。当所需要写入的数据长度超过一个扇区的长度的时候,我们先按照前面的步骤把扇区剩余部分写完,再在新扇区内执行同样的操作,如此循环,直到写入结束。这里我们还定义了一个 g_norflash_buf 的全局变量,用于擦除时缓存扇区内的数据。
3)简单介绍一下写函数的实质调用,它用到的是通过无检验写 SPI_FLASH 函数实现的,而最终是用到页写函数 norflash_write_page,在前面也对页写时序进行了分析,现在看一下代码:

/**
* @brief SPI 在一页(0~65535)内写入少于 256 个字节的数据
* * @note 在指定地址开始写入最大 256 字节的数据
* @param pbuf : 数据存储区
* @param addr : 开始写入的地址(最大 32bit)
* @param datalen : 要写入的字节数(最大 256),该数不应该超过该页的剩余字节数!!!
* @retval 无
*/
static void norflash_write_page(uint8_t *pbuf, uint32_t addr, uint16_t datalen)
{uint16_t i;norflash_write_enable(); /* 写使能 */NORFLASH_CS(0);spi5_read_write_byte(FLASH_PageProgram); /* 发送写页命令 */norflash_send_address(addr); /* 发送地址 */for (i = 0; i < datalen; i++){spi5_read_write_byte(pbuf[i]); /* 循环读取 */}NORFLASH_CS(1);norflash_wait_busy(); /* 等待写入结束 */
}

在页写功能的代码中,先发送写使能命令,才发送页写命令,然后发送写入的地址,再把写入的内容通过一个 for 循环写入,发送完后拉高片选 CS 引脚结束通信,等待 flash 内部写入结束。检测 flash 内部的状态可以通过查看 25Q256 状态寄存器 1 的位 0。我们也定义了一个函数 norflash_read_sr,去读取 25Q256 状态寄存器的值,这里就不列出来了,主要实现的方式也是老套路:根据传参判断需要获取的是哪个状态寄存器,然后拉低片选线,调用 spi5_read_write_byte函数发送该寄存器的命令,然后通过发送一字节空数据获取读取到的数据,最后拉高片选线,函数返回读取到的值。
在 norflash_write_page 函数的基础上,增加了 norflash_write_nocheck 函数进行封装解决写入字节可能大于该页剩下的字节数问题,方便解决写入错误问题,其代码如下:

/**
* @brief 无检验写 SPI FLASH
* @note 必须确保所写的地址范围内的数据全部为 0XFF,否则在非 0XFF 处
* 写入的数据将失败! 具有自动换页功能在指定地址开始 
* 写入指定长度的数据,但是要确保地址不越界!
*
* @param pbuf : 数据存储区
* @param addr : 开始写入的地址(最大 32bit)
* @param datalen : 要写入的字节数(最大 65535)
* @retval 无
*/
static void norflash_write_nocheck(uint8_t *pbuf, uint32_t addr,uint16_t datalen)
{uint16_t pageremain;pageremain = 256 - addr % 256; /* 单页剩余的字节数 */if (datalen <= pageremain) /* 不大于 256 个字节 */{pageremain = datalen;}while (1){/* 当写入字节比页内剩余地址还少的时候, 一次性写完* 当写入直接比页内剩余地址还多的时候, 先写完整个页内剩余地址, * 然后根据剩余长度进行不同处理 */norflash_write_page(pbuf, addr, pageremain);if (datalen == pageremain) /* 写入结束了 */{break;}else /* datalen > pageremain */{pbuf += pageremain; /* pbuf 指针地址偏移,前面已经写了 pageremain 字节 */addr += pageremain; /* 写地址偏移,前面已经写了 pageremain 字节 */datalen -= pageremain; /* 写入总长度减去已经写入了的字节数 */if (datalen > 256) /* 剩余数据还大于一页,可以一次写一页 */{pageremain = 256; /* 一次可以写入 256 个字节 */}else /* 剩余数据小于一页,可以一次写完 */{pageremain = datalen; /* 不够 256 个字节了 */}}}
}

上面函数的实现主要是逻辑处理,通过判断传参中的写入字节的长度与单页剩余的字节数,来决定是否是需要在新页写入剩下的字节。这里需要大家自行理解一下。通过调用该函数实现了 norflash_write 的功能。下面简单介绍一下擦除函数 norflash_erase_sector,前面工作时序中也有对此描述,现在就来看一下代码:

/**
* @brief 擦除一个扇区
* @note 注意,这里是扇区地址,不是字节地址!!
* 擦除一个扇区的最少时间:150ms
*
* @param saddr : 扇区地址 根据实际容量设置
* @retval 无
*/
void norflash_erase_sector(uint32_t saddr)
{saddr *= 4096;norflash_write_enable(); /* 写使能 */norflash_wait_busy(); /* 等待空闲 */NORFLASH_CS(0);spi5_read_write_byte(FLASH_SectorErase); /* 发送写页命令 */norflash_send_address(saddr); /* 发送地址 */NORFLASH_CS(1);norflash_wait_busy(); /* 等待扇区擦除完成 */
}

该代码也是老套路,通过发送擦除指令实现擦除功能,要注意的是使用扇区擦除指令前,
需要先发送写使能指令,拉低片选线,发送扇区擦除指令之后,发送擦除的扇区地址,实现擦
除,最后拉高片选线结束通信。在函数最后通过读取寄存器状态的函数,等待扇区擦除完成。

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

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

相关文章

自从学会Git,感觉打开了一扇新大门

“同事让我用 Git 提交代码&#xff0c;我居然直接把项目文件压缩发过去了……”相信很多初学者都经历过类似的窘境。而当你真正掌握 Git 时&#xff0c;才会发现它就像一本魔法书&#xff0c;轻松解决代码管理的种种难题。 为什么 Git 能成为程序员的标配工具&#xff1f;它究…

【重庆】《政务数字化应用费用测算规范》(T/CDCIDA 001—2023)-省市费用标准解读系列36

《政务数字化应用费用测算规范&#xff08;报批稿&#xff09;》于2023年11月18日实施&#xff0c;本文件按照GB/T 1.1-2020给出的规则起草&#xff0c;主要适用于重庆政务数字化应用项目的费用测算。我司基于专业第三方信息化项目造价机构角度&#xff0c;从标准创新点、定制软…

Python | 学习type()方法动态创建类

getattr方法的使用场景是在访问不存在的属性时&#xff0c;会触发该方法中的处理逻辑。尤其是在动态属性获取中结合 type()动态创建类有着良好的使用关系。 type()方法常用来判断属性的类别&#xff0c;而动态创建类不常使用&#xff0c;通过如下的几个实例来学习使用&#xff…

机器学习之逻辑回归算法、数据标准化处理及数据预测和数据的分类结果报告

逻辑回归算法、数据标准化处理及数据预测和数据的分类结果报告 目录 逻辑回归算法、数据标准化处理及数据预测和数据的分类结果报告1 逻辑回归算法1.1 概念理解1.2 算法导入1.3 算法优缺点 2 LogisticRegression理解2.1查看参数定义2.2 参数理解2.3 方法2.4基本格式 3 数据标准…

.NET在中国的就业前景:开源与跨平台带来的新机遇

随着技术的不断发展和市场需求的变化&#xff0c;.NET在中国的就业前景正变得愈加广阔。尤其是在开源和跨平台的推动下&#xff0c;越来越多的中国中小型企业选择了.NET技术作为其开发平台&#xff0c;进一步提升了.NET技术人才的市场需求。尽管在中国市场&#xff0c;.NET的市…

Linux(Ubuntu24.04)源码编译安装VTK7.1.1记录

VTK&#xff08;Visualization Toolkit&#xff09;是一个开源的3D可视化开发工具包&#xff0c;用于开发可视化和图形处理应用程序。VTK提供了一系列的算法和工具&#xff0c;用于创建、渲染和处理复杂的3D图形和数据。VTK由C编写&#xff0c;并提供了Python、Java和Tcl等语言…

Hadoop解决数据倾斜方法

数据倾斜是指在分布式数据处理过程中&#xff0c;数据在某些节点上的分布不均匀&#xff0c;导致这些节点的处理负载过重&#xff0c;而其他节点的资源闲置&#xff0c;从而影响整个系统的性能。在 Hadoop 中&#xff0c;以下是一些解决数据倾斜的方法&#xff1a; 1. 数据预处…

【人工智能】人工智能与大模型

人工智能与大模型的结合正在深刻改变多个行业和领域的格局。 1. 人工智能 (AI) 人工智能指的是使计算机或机器具备模拟人类智能的能力&#xff0c;包括学习、推理、问题解决、自然语言处理、视觉感知等。AI的发展可以分为几个阶段&#xff1a; 弱人工智能 (Narrow AI)&#…

安卓11 SysteUI添加按钮以及下拉状态栏的色温调节按钮

最近客户想要做一个台灯产品&#xff0c;需要实现 串口调节台灯功能 &#xff0c;其中包括 亮度调节 色温调节 开关 三个功能 话不多说&#xff0c;贴代码 diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml old mode 100644 new …

node.js下载、安装、设置国内镜像源(永久)(Windows11)

目录 node-v20.18.0-x64 工具下载安装设置国内镜像源&#xff08;永久&#xff09; node-v20.18.0-x64 工具 系统&#xff1a;Windows 11 下载 官网https://nodejs.org/zh-cn/download/package-manager 版本我是跟着老师选的node-v20.18.0-x64如图选择 Windows、x64、v2…

如何轻松安全地销售旧 Android 手机

众所周知&#xff0c;手机不断更新换代。当您想要的手机终于到货时&#xff0c;您可能迫不及待地将旧 Android 手机更新为最新手机。在此之前&#xff0c;你们中的一些人可能会考虑以最多的钱卖掉旧的Android手机。 但永远不要冲动地卖掉你的旧 Android 手机&#xff01;为了安…

欧科云链研究院:ChatGPT 眼中的 Web3

编辑&#xff5c;OKG Research 转眼间&#xff0c;2024年已经进入尾声&#xff0c;Web3 行业经历了热闹非凡的一年。今年注定也是属于AI的重要一年&#xff0c;OKG Research 决定拉上 ChatGPT 这位“最懂归纳的AI拍档”&#xff0c;尝试把一整年的研究内容浓缩成精华。我们一共…

【从零开始入门unity游戏开发之——unity篇04】unity6基础入门——场景窗口(Scene)和层级窗口(Hierarchy)介绍

文章目录 场景窗口&#xff08;Scene&#xff09;和层级窗口&#xff08;Hierarchy&#xff09;一、层级窗口&#xff08;Hierarchy&#xff09;1、添加新的对象&#xff08;物体&#xff09;2、Hierarchy层级窗口快捷键3、搜索 二、Scene场景窗口1、工具栏控制台2、操作物体位…

Jboss EnhancedQueueExecutor 使用案例及源码解读

使用案例 EnhancedQueueExecutor配置类 Configuration Slf4j public class EnhancedQueueExecutorConfig {Beanpublic EnhancedQueueExecutor enhancedQueueExecutor() {return createExecutor(5, 100,"enhancedQueueExecutor","任务处理失败 {}");}priv…

如何确保涡度通量观测数据的准确性?涡度通量光敏感性分析、温度敏感性分析、数据风浪区分析等

确保涡度通量观测数据的准确性&#xff0c;可以采取以下几个步骤&#xff1a; 1.数据预处理&#xff1a;在进行数据分析之前&#xff0c;需要对原始的高频涡度通量数据进行预处理&#xff0c;包括剔除异常值和进行数据缺失插补。异常值剔除可以通过设定合理的阈值来识别并剔除数…

docker镜像构建(基于ISO)

1. 前言 本文详细介绍如何基于kylin v10 ISO文件构建出docker image。系统环境如下&#xff1a; dockder: 20.10.7 linux os: kylinv 10 (GFB) linux kernel: 4.19.90-52.23.v2207.gfb01.ky10.aarch642. 构建yum离线源 2.1. 挂载ISO文件 mount Kylin-Server…

Mac中配置vscode(第一期:python开发)

1、终端中安装 xcode-select --install #mac的终端中安装该开发工具 xcode-select -p #显示当前 Xcode 命令行工具的安装路径注意&#xff1a;xcode-select --install是在 macOS 上安装命令行开发工具(Command Line Tools)的关键命令。安装的主要组件包括&#xff1a;C/C 编…

快速将索尼手机联系人导出为 HTML 文件

我想将 Sony Xperia 手机上的联系人导出到计算机上进行备份&#xff0c;并在需要时进行编辑。这可以做到吗&#xff1f;如何做到&#xff1f;作为助手我需要下载什么工具吗&#xff1f; 当您的 Android 手机上存储了如此多的重要联系人&#xff0c;而您又不想丢失它们时&#…

学习threejs,导入AWD格式的模型

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.AWDLoader AWD模型加…

【OAA 】面向对象分析:从概念到实践

&#x1f525;个人主页&#xff1a; 中草药 &#x1f525;专栏&#xff1a;【Java】登神长阶 史诗般的Java成神之路 我们都知道Java是一门面向对象的开发语言&#xff0c;在软件开发的广袤天地中&#xff0c;面向对象分析&#xff08;Object-Oriented Analysis&#xff0c;简称…