stm32Flash操作

//G0B0 flash大小 0x08000000-0x0807FFFF 512K(0400 1K)//2k 1页
//初始化标记数据地址 放最前面 脱机烧写器可擦除掉
#define     CONST_INITMARKDATA_ADDRESS      (0x0807D000UL) //2k 1页
//射频数据地址
#define     CONST_FREQDATA_ADDRESS          (0x0807F000UL)  //2k 1页
//本振数据地址
#define     CONST_BWLODATA_ADDRESS          (0x0807F800UL)//用户数据标记
#define     CONST_USERDATA_ACTIVECOOKIE     (0xFEDCCDEF) 

========================================================================
__align(8) static uint8_t flashWriteBuf[2048];

  1. __align(8): 用于指定存储在内存中的变量的对齐方式为 8 字节。对齐的目的是为了优化内存访问,确保变量在内存中的地址是某个值的倍数(这里是 8 字节)。这通常对于某些硬件和特定的数据结构是必要的。
  2. static: 用于指示该变量的存储持续时间为整个程序的执行期间。在这里,flashWriteBuf 是一个静态变量,它在程序的整个执行期间都存在,并且其生命周期延伸到整个程序的运行时间。

这行代码定义了一个静态的、对齐为 8 字节的、包含 2048 个无符号8位整数的数组 flashWriteBuf

=========================================================================

为什么要使用 __align(8),以及对齐方式在内存中的表现是什么样的?

在C语言中,对齐方式是指变量在内存中的存储起始位置相对于地址的偏移量。
对齐的主要目的是优化内存访问速度,特别是对于一些体系结构或硬件,它们可能要求某些数据类型的变量从特定地址开始。

  1. 访问速度: 在某些架构中,对齐的数据访问速度更快。例如,某些处理器可能要求访问 4 字节整数从4字节对齐的地址开始,否则可能会引发性能损失或错误。

  2. 缓存行: 许多处理器以缓存行为单位加载数据到缓存中。如果变量的首地址是缓存行对齐的,那么对该变量的访问可能会更加高效。

  3. 硬件限制: 某些硬件要求特定数据类型从特定对齐方式的地址开始。如果不满足这些要求,可能会导致硬件异常或性能下降。

在具体的应用场景中,选择对齐方式通常是为了优化性能或者满足硬件的要求。然而,过度的对齐可能会导致内存空间的浪费。在实际开发中,对齐的选择需要根据具体的硬件和性能需求进行权衡。

=========================================================================
1. 实现逻辑:

uint8_t* coreFlashAcquireWriteBuffer(void)
{return flashWriteBuf;
}

该函数返回一个 uint8_t 类型的指针。函数体内只有一条语句,即返回名为 flashWriteBuf 的静态数组的首地址。

主要目的是获取可用于写入的缓冲区。由于返回的是指向 uint8_t 的指针,可以将这个指针用于写入字节数据。

2. 主要目的和适用场景:
这段代码的主要目的是提供一个接口,允许外部模块或函数获取一个可用于写入的缓冲区。

这种模式常见于需要进行数据写入或者数据缓冲的情境,例如将数据写入到 Flash 存储器中。

适用场景可能包括需要向 Flash 存储器写入数据的任务。通过调用 coreFlashAcquireWriteBuffer 函数,程序可以获取一个缓冲区,然后将待写入的数据写入该缓冲区。
这种设计允许程序灵活地控制数据的写入,同时提供了一种有效的机制来管理数据的写入操作。

====================================================================
1. 实现逻辑:

static uint32_t getPage(uint32_t addr)
{uint32_t page = 0;/* Bank 1 */page = (addr - FLASH_BASE) / FLASH_PAGE_SIZE;return page;
}

​ 这段代码定义了一个静态函数 getPage,接受一个 uint32_t 类型的地址参数,计算并返回与该地址相关的页面号(page number)。在这个实现中,页面号被计算为地址相对于基地址 FLASH_BASE 的偏移量除以页面大小 FLASH_PAGE_SIZE

2. 主要目的和适用场景:

​ 主要目的是根据给定的地址计算出相应的页面号。

​ 在嵌入式系统中,Flash存储器通常分为多个页面,每个页面存储一定量的数据。

​ 获取地址对应的页面号可以用于确定数据在Flash中的位置。

​ 适用场景可能包括在程序中管理Flash存储器的情况,比如需要存储和检索数据到Flash中的特定页面。通过调用 getPage 函数,程序可以获得给定地址所在的页面号,然后使用这个页面号进行相应的操作,例如擦除或写入数据。

总体而言,这个函数是一个用于获取地址对应页面号的工具函数,可以用于在嵌入式系统中管理Flash存储器中的数据。

========================================================================
1. 实现逻辑:

int32_t coreFlashWrite(void* dstAddr, const void* srcAddr, const uint32_t size)
{//...(变量定义和初始化)//初始化FLASH_EraseInitTypeDefFLASH_EraseInitTypeDef eraseInitStruct = {0x00};int32_t ret = ERR_FLASHOP_OK;  // 返回值//判断入参正确if (!srcAddr || !dstAddr || 0 == size){return ERR_FLASHOP_PARAM_INVAL;}if (0 != ((uint32_t)srcAddr & 0x00000007)){return ERR_FLASHOP_SRCADDR_UNALIGN;}if (0 != ((uint32_t)dstAddr & 0x00000007)){return ERR_FLASHOP_DSTADDR_UNALIGN;}//获取要擦除的第一页firstPage = getPage((uint32_t)dstAddr);//获取要从第一页擦除的页数nbOfPages = size / FLASH_PAGE_SIZE + (size % FLASH_PAGE_SIZE ? 1 : 0);eraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;eraseInitStruct.Page        = firstPage;  // 擦除起始页eraseInitStruct.NbPages     = nbOfPages;  // 擦除页数HAL_FLASH_Unlock();  // Flash解锁__disable_irq();  // 擦除前需要关闭中断if (HAL_FLASHEx_Erase(&eraseInitStruct, &pageError) != HAL_OK){__enable_irq();ret = -ERR_FLASHOP_FAIL_ERASE;goto exit;}__enable_irq();//开始写入FlashflashAddress = (uint32_t)dstAddr;nWriteAll = size;while (nHasWrite < nWriteAll){// 以64位为单位写入数据srcDW = *(uint64_t*)((uint32_t)srcAddr + nHasWrite);if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, flashAddress, srcDW) == HAL_OK){flashAddress += 8;nHasWrite += 8;}else{ret = ERR_FLASHOP_FAIL_PROG;goto exit;}}exit:HAL_FLASH_Lock();  // Flash加锁return ret;
}

2. 主要目的和适用场景:

​ 这段代码的主要目的是实现Flash存储器的写入操作。该函数接受目标地址 dstAddr、源地址 srcAddr 和写入大小 size 作为参数,首先擦除目标地址所在的Flash页面,然后将数据从源地址写入到目标地址。

​ 适用场景可能涉及到需要在嵌入式系统中进行Flash存储器的写入操作,例如在固件更新或配置保存等场景。

3. 使用的关键字和修饰符:

  • static: 该函数没有使用 static 关键字,因此在其他文件中可以访问。
  • uint32_t, void, const: 这些是数据类型,用于声明参数和变量的类型。
  • FLASH_EraseInitTypeDef: 这是一个结构体类型,用于配置Flash擦除的初始化参数。
  • HAL_FLASH_Unlock(), HAL_FLASH_Lock(): 这些是由HAL(Hardware Abstraction Layer)提供的函数,用于解锁和锁定Flash。

总体而言,这是一个用于在嵌入式系统中进行Flash存储器写入的函数,包括擦除和写入两个步骤。============================================================================
1. 实现逻辑:

bool initMarkDataIsActive(void)
{const volatile initMarkDataFlash_t* rawPtr = (const volatile initMarkDataFlash_t*)CONST_INITMARKDATA_ADDRESS;return (rawPtr->active == CONST_USERDATA_ACTIVECOOKIE);
}

这段代码定义了一个函数 initMarkDataIsActive,该函数返回一个布尔值。函数内部首先声明了一个指向 initMarkDataFlash_t 结构体类型的 volatile 常量指针 rawPtr,然后将其初始化为指向一个特定地址 CONST_INITMARKDATA_ADDRESS

函数最后通过比较 rawPtr->activeCONST_USERDATA_ACTIVECOOKIE 的值来确定初始化标记数据是否处于激活状态。

2. 主要目的和适用场景:

​ 主要目的是检查初始化标记数据是否处于激活状态。在嵌入式系统中,可能会有一些标记数据用于指示系统的初始化状态,这个函数就是用于检查这些标记数据是否处于激活状态。

​ 适用场景可能包括在系统启动时检查某些初始化数据,以确保系统处于已初始化的状态。

3. 使用的关键字和修饰符:

  • const, volatile: 这些关键字用于修饰指针 rawPtr,指明该指针指向的数据是常量且易变的,这通常用于防止编译器进行一些优化,确保每次访问都会从内存中读取最新的值。

总体而言,这个函数用于检查初始化标记数据是否处于激活状态,返回一个布尔值表示检查结果。

=========================================================================
1. 实现逻辑:

void initMarkDataReadFlash(void)
{const volatile initMarkDataFlash_t *rawPtr = (const volatile initMarkDataFlash_t*)CONST_INITMARKDATA_ADDRESS;if (initMarkDataIsActive()){memcpy(&initMarkDataFlash, (void*)rawPtr, sizeof(initMarkDataFlash_t));}
}

函数内部首先声明了一个指向 initMarkDataFlash_t 结构体类型的 volatile 常量指针 rawPtr,然后将其初始化为指向一个特定地址 CONST_INITMARKDATA_ADDRESS

接着,通过调用 initMarkDataIsActive 函数检查初始化标记数据是否处于激活状态。如果激活,那么通过 memcpy 函数将 Flash 中的数据复制到一个全局变量 initMarkDataFlash 中。

2. 主要目的和适用场景:

​ 主要目的是在系统启动时从 Flash 中读取初始化标记数据。在嵌入式系统中,初始化标记数据可能包含一些配置信息或者系统状态,该函数的目的是将这些数据读取到内存中,以便系统可以使用这些数据进行初始化。

​ 适用场景可能包括在系统启动时加载先前保存的配置或状态信息,以确保系统处于正确的状态。

总体而言,这个函数用于从 Flash 中读取初始化标记数据,如果数据处于激活状态,则将其复制到全局变量中。

=======================================================================
1. 实现逻辑:

int32_t initMarkDataSyncFlash(void)
{int32_t ret = 0;//用户数据写入ret = coreFlashWrite((void*)CONST_INITMARKDATA_ADDRESS, (void*)&initMarkDataFlash, sizeof(initMarkDataFlash_t));return ret;
}

函数内部首先声明了一个整数变量 ret,用于存储函数执行的结果。

接着,通过调用 coreFlashWrite 函数将全局变量 initMarkDataFlash 中的数据写入到 Flash 中的指定地址 CONST_INITMARKDATA_ADDRESS

最后,函数返回执行的结果。

2. 主要目的和适用场景:

​ 主要目的是将全局变量 initMarkDataFlash 中的数据同步到 Flash 中的指定地址。在嵌入式系统中,这可能用于将配置或状态信息保存到 Flash 中,以便在系统重新启动时恢复状态。

​ 适用场景可能包括在系统运行时修改了一些配置或状态信息,希望将这些更改保存到持久性存储中。

总体而言,这个函数用于将全局变量中的数据写入到 Flash 中的指定地址,返回一个表示执行结果的整数值。

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

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

相关文章

大数据技术4:Lambda和Kappa架构区别

前言&#xff1a;在大数据处理领域&#xff0c;两种突出的数据架构已成为处理大量数据的流行选择&#xff1a;Lambda 架构和 Kappa 架构。这些架构为实时处理和批处理提供了强大的技术解决方案&#xff0c;使组织能够从其数据中获得有价值的见解。随着互联网时代来临&#xff0…

Python VSCode 配置固定的脚本入口

Python VSCode 配置固定的脚本入口 打开或者新建一个启动配置 选择 .vscode目录下 launch.json文件 将 “program”: “${file}” 替换成 “program”: “mian.py”, //完成你自己的入口.py文件名即可 json启动配置文件 {// Use IntelliSense to learn about possible attrib…

4-redis高级-redis持久化(RDB 持久化方案、AOF持久化、RDB和AOF混合持久化)、redis主从复制

1 redis持久化 1.1 RDB 持久化方案 1.2 AOF持久化 1.3 混合持久化 2 redis主从复制 1 redis持久化 # 把redis数据从内存保存到硬盘上的过程称之为持久化# 所有的数据库&#xff0c;持久化方案快照&#xff1a;某时某刻数据的一个完成备份-mysql的Dump&#xff1a; mysqldump …

【ELK03】ES 索引的Mapping映射详解、数据类型和settings属性设置

一、ES 索引的映射和设置 1.MAPPING 映射(MAPPING)就是es中一个决定了文档如何存储,如何生成索引,字段各种类型定义的过程.类似于我们在关系型数据库中创建一个表格数据之前先定义表格有哪些字段,每个字段是什么类型,然后数据会按照这个配置写入表格,ES中同样是这个过程,它由…

数据结构:顺序表——相关习题2

【2018统考】给定一个含n个整数的数组&#xff0c;设计一个时间上尽可能高效的算法&#xff0c;找到数组中未出现的最小正整数。 void find_min_intnum(int A[],int n){int B[5*n]{0};int i;for (i 0; i < n; i){if(A[i]>0){B[A[i]];}}for(i1;i<5*n;i){if(B[i]0){pr…

面向对象中的单例模式

1、什么是设计模式 设计模式就是前人根据实际的问题提出的问题解决方案&#xff0c;我们把这种就称之为设计模式。 2、单例模式 单例模式是一种常见的设计模式&#xff01; 所谓的设计模式&#xff0c;不是一种新的语法&#xff0c;而是人们在实际的应用中&#xff0c;面对…

【银行测试】金融项目+测试方法范围分析,功能/接口/性能/安全...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、金融行业软件特…

3GPP标准查看、下载和几个UE相关系列标准

由于一直做终端侧协议。最近以UE为核心重新下载了一系列文档。 总结并举例一下分类标准。 如何查看3GPP标准列表 实际上在3GPP网站如下链接&#xff1a;Specifications by Series&#xff0c;每个系列以及分类都说的很清楚。 几个系列分类举例 和终端协议层工作比较关系密切…

如何使用Java Websocket实现实时数据监控功能?

随着互联网应用的不断发展&#xff0c;实时数据监控功能成为了许多应用的必备功能之一。本文将介绍如何使用Java WebSocket实现实时数据监控功能&#xff0c;并提供具体的代码示例。 关键词&#xff1a;Java WebSocket、实时数据监控、代码示例 一、什么是WebSocket&#xff…

ModuleNotFoundError: No module named ‘dlib‘

解决&#xff1a;ModuleNotFoundError: No module named ‘dlib’ 文章目录 解决&#xff1a;ModuleNotFoundError: No module named dlib背景报错问题报错翻译报错位置代码报错原因解决方法方法一&#xff0c;直接安装方法二&#xff0c;手动下载安装方法三&#xff0c;编译安…

setuid 的风险及开发过程中的避免方式

使用setuid&#xff08;Set User ID&#xff09;功能将执行程序的有效用户 ID 设置为文件所有者的用户 ID。这意味着执行程序将以文件所有者的特权运行&#xff0c;而不是以执行者自己的特权运行。 尽管setuid是一个有用的功能&#xff0c;但它也会带来一些安全风险。下面是几…

Linux C语言 37- 进程间通信IPC

Linux C语言 37-进程间通信IPC 本节关键字&#xff1a;C语言 进程间通信 信号 管道 消息队列 共享内存 网络通信&#xff08;套接字&#xff09; 相关库函数&#xff1a; 提示&#xff1a;先做内容框架梳理&#xff0c;后期进行完善补充&#xff01; 什么是进程间通信&#…

blender 数字键盘上的快捷键

数字0可以切换到相机视角&#xff0c;即从相机的位置和角度查看场景。数字1、3、7分别可以切换到正交的前视图、右视图和顶视图&#xff0c;即沿着X、Y、Z轴的垂直投影。数字5可以切换正交视图和透视视图&#xff0c;即是否考虑远近的视觉差异。数字2、4、6、8分别可以顺时针或…

SD之lora训练

目录 为什么要训练自己的模型 SD模型微调方法 准备素材 1 确定要训练的LoRA类型 2 图片收集 3 图片预处理 4 图片标注 安装Koyha_ss 训练lora 1.准备参数和环境 2.启动训练 使用模型 1 拷贝训练过的lora模型 2 启动SD WebUI进行图像生成 为什么要训练自己的模型 …

webpack该如何打包

1.我们先创建一个空的大文件夹 2.打开该文件夹的终端 输入npm init -y 2.1.打开该文件夹的终端 2.2在该终端运行 npm init -y 3.安装webpack 3.1打开webpack网址 点击“中文文档” 3.2点击“指南”在点击“起步” 3.3复制基本安装图片画线的代码 4.在一开始的文件夹下在创建一…

【Android】使用Netty库来实现Socket接收

在Android中使用Netty来实现Socket接收是可行的。Netty是一个高性能的网络通信框架&#xff0c;支持多种协议&#xff0c;包括原生的Socket通信。 以下是一个简单的示例代码&#xff0c;演示如何使用Netty在Android中实现Socket接收&#xff1a; 首先&#xff0c;在你的Andro…

案例061:基于微信小程序的互助学习系统

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;SSM JDK版本&#xff1a;JDK1.8 数据库&#xff1a;mysql 5.7 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.5.4 小程序框架&#xff1a;uniapp 小程序开发软件&#xff1a;HBuilder X 小程序…

Flask template中使用iframe

Flaks template中使用iframe嵌套新的网页&#xff08;new_page.html&#xff09;的网页到历史网页&#xff08;old_page.html&#xff09;中&#xff08;减少新网页的入口&#xff09; 1,增加iframe tag 在old_page.html中适当位置增加iframe入口标签&#xff1a; <ifram…

django与数据库交互关于当前时间的坑

背景 在线上服务中使用时间进行数据库操作时发现异常&#xff0c;而在本地环境无法成功复现此问题&#xff0c;导致难以进行故障排查。 核心问题 view.py class XxxViewSet(viewsets.ModelViewSet):queryset Xxx.objects.with_status().order_by("status", &quo…

【数据结构】插入排序,希尔排序,选择排序,堆排序,冒泡排序

1.插入排序 思路&#xff1a;插入排序将一个数插入一个有序的数组里面&#xff0c;将这个数和数组元素挨着比较&#xff0c;直到他插入到合适的位置。 动画演示&#xff1a; 步骤&#xff1a;1.定义一个变量tmp保存要插入的数据 2.在循环中用tmp和有序数组中的元素比较&#…