STM32标准库内部Flash读写
STM32标准库FLASH读写
1. STM32内部FLASH介绍
STM32系列一般集成有内部flash,这部分内存可以直接通过指针的形式进行读取。但是由于内部flash一般存储为重要数据或程序运行数据,在进行写入或擦除时需要使用库函数的解锁和上锁函数进行读写。在STM32中,内部flash大致可以分为下图的几部分:
图1.1.STM32内部flash示意图
1.1. 主存储器
这部分为正常存储区,负责存储片上程序,若片上存储区充足,则可将某些需要掉电保存的数据存储至空闲区段。
判断片上程序截止位置可以通过查看项目的map文件来查看,具体方法为
双击keil左侧的项目文件夹打开项目map文件:
图1.2.map文件寻找
在map文件中找到Memory Map of the image这个表:
图1.3.内存加载表
在这个表的最后一行找到这么一段:
图1.4.内存占用位置
其中的load base的值就是片上程序的截止位置,从这里到片上flash的寻址结束都是可以用作数据存储的空闲空间。
1.2. 系统存储区
这部分为固定数据,不可修改擦除。所存储数据为芯片厂家出厂时保存的数据,用于ISP烧录功能等,相当于linux系统中的MMU,进行内存寻址等功能。
1.2. 选项字节
该区域用于配置片上flash的读写保护、待机/停机复位、软件硬件看门狗等功能,可以通过修改FLASH的的选项控制寄存器修改。
2. FLASH存储常见问题
在常见的FLASH芯片以及芯片片上FLASH中通常会仅允许FLASH页擦除,word写入或halfword写入。
页,是FLASH芯片中存储数据的最小单位。在某些芯片的资料中,也可能扇区是最小单位,
扇区与页的大小要根据芯片厂家资料的具体划分来看。FLASH的擦除操作最小单位只能是页,而写入单位为word或halfword,读取方式为以指针形式读取。这就出现了第一个矛盾:擦除量远大于写入量,而且由于FLASH是分页存储,若每次写入都擦除的话会导致上次的写入丢失。因此我的建议是给页或程序需要保存的数据建立一个页缓冲区,每次写入前先将数据写入缓冲区,然后一次性将缓冲区内的数据写入FLASH。可以减少数据丢失的问题。
FLASH是分页存储的,这就引发了第二个矛盾,若有一个数据横跨两个页面怎么读取写入,FLASH官方禁止跨页读写,且数据严格要求对齐。即在32位计算机中,若最小写入单位为word,写入的地址就只能为4的倍数,若最小写入单位为halfword,写入的地址就只能为2的倍数。不符合倍数要求的数据无法进行正常写入
3. 具体函数编写思路
野火的代码洋洋洒洒一大篇,但是我感觉不适合初学者,所以我对其进行了简化。
首先需要进行头文件引入与预编译变量定义:
#include "stm32f10x_flash.h"
#include "math.h"
#define FLASH_PAGE_SIZE ((uint16_t)0x800)//2048
#define WRITER_START_ADDR ((uint32_t)0x08008000)
#define WRITER_END_ADDR ((uint32_t)0x0800c000)
其中FLASH_PAGE_SIZE为片上flash每一页的大小,我所使用的芯片为STM32F103VET6,属于大容量,每一页的大小为2048字节。这个变量在正常读写时不使用,但是大批量擦除内存时可以使用这个变量编写函数。
引用math.h是为了使用floor函数,用于向下取整。
3.1. 写入函数
void flash_write_word(uint32_t data,uint32_t addr)//data变量为32个二进制变量的数据,addr为地址偏移量,我认为在程序编写时对偏移量修改,好过记一大串的地址。
{
uint32_t addr_true = addr + WRITER_START_ADDR;//addr_true为起始地址+地址偏移量,为数据在flash的实际地址。
uint32_t erase_page = floorf((addr + WRITER_START_ADDR) / FLASH_PAGE_SIZE);//这里是为了得到要擦除的第几页,floorf函数用于向下取整。
FLASH_Unlock();//解锁flash。
FLASH_ErasePage(WRITER_START_ADDR+(erase_page*FLASH_PAGE_SIZE));//擦除实际地址所在页面的flash。
FLASH_ProgramWord(addr_true,data);//向实际地址写入数据,在实际应用中还会遇到halfword写入的情况,在这里不进行讨论。
FLASH_Lock();//锁定flash。
}
3.2. 读取函数
uint32_t flash_read_word(uint32_t addr)//addr为地址偏移量,返回的值为读取到的数据。
{
uint32_t addr_true = addr + WRITER_START_ADDR;//addr_true为起始地址+地址偏移量,为数据在flash的实际地址。
return (*(__IO uint32_t*)addr_true);//将addr_true变量指针化,得到flahs地址存储的数据。
}
(__IO uint32_t)addr_true 是C或C++代码中的一个类型转换和解引用操作。我们可以将其分解为几个部分来理解其含义:
__IO:这是一个宏定义,通常在嵌入式编程中使用,特别是在与硬件寄存器交互时。__IO通常表示“输入/输出”,意味着该变量或地址可以读写。在某些嵌入式系统中,为了优化性能,开发者可能会区分“只读”和“可读/写”的内存区域,并使用宏来标记它们。
uint32_t:这是一个无符号32位整数类型,定义在stdint.h或cstdint头文件中。它确保变量或指针指向的内存区域被解释为32位无符号整数。
(uint32_t)addr_true:这是一个类型转换(或称为类型转换)。它将addr_true(可能是一个void类型的指针或其他类型的指针)转换为指向uint32_t类型的指针。
:这是一个解引用操作。当应用于指针时,它会获取该指针指向的值。
因此,(__IO uint32_t*)addr_true 的整体意思是:首先,将addr_true转换为一个指向uint32_t类型的指针(并确保该内存区域是可读/写的),然后获取该指针指向的32位无符号整数值。
这种操作在嵌入式编程中非常常见,特别是当需要直接访问或修改硬件寄存器的值时。
STM32标准库内部Flash读写的更多相关文章
- STM32 对内部FLASH读写接口函数(转)
源:STM32 对内部FLASH读写接口函数 因为要用内部FLASH代替外部EEPROM,把参数放在STM32的0x08000000+320K处,其中20K是bootloader,300K是应用程序. ...
- 单片机stm32零基础入门之--初识STM32 标准库
CMSIS 标准及库层次关系 因为基于Cortex 系列芯片采用的内核都是相同的,区别主要为核外的片上外设的差异,这些差异却导致软件在同内核,不同外设的芯片上移植困难.为了解决不同的芯片厂商生产的Co ...
- STM32 标准库
CMSIS 标准及库层次关系 因为基于Cortex 系列芯片采用的内核都是相同的,区别主要为核外的片上外设的差异,这些差异却导致软件在同内核,不同外设的芯片上移植困难.为了解决不同的芯片厂商生产的Co ...
- STM32标准库GPIO操作
STM32标准库GPIO操作 STM32任何外围设备的使用都分为两部分:初始化和使用.体现在代码上就是:(1)有一个初始化函数(2)main函数中的使用 1.初始化GPIO 初始化GPIO函数代码: ...
- 初识STM32标准库
1.CMSIS 标准及库层次关系 CMSIS 标准中最主要的为 CMSIS 核心层,它包括了: STM32标准库可以从官网获得: 在使用库开发时,我们需要把 libraries 目录下的库函数文件添加 ...
- STM32 对内部FLASH读写接口函数
因为要用内部FLASH代替外部EEPROM,把参数放在STM32的0x08000000+320K处,其中20K是bootloader,300K是应用程序. 原理:先要把整页FLASH的内容搬到RAM中 ...
- STM32 标准库V3.5启动文件startup_stm32f10xxx.s分析
layout: post tags: [STM32] comments: true 文章目录 layout: post tags: [STM32] comments: true 前言 分析startu ...
- STM32 HAL库 UART 串口读写功能笔记
https://www.cnblogs.com/Mysterious/p/4804188.html STM32L0 HAL库 UART 串口读写功能 串口发送功能: uint8_t TxData[10 ...
- [nRF51822] 11、基础实验代码解析大全 · 实验16 - 内部FLASH读写
一.实验内容: 通过串口发送单个字符到NRF51822,NRF51822 接收到字符后将其写入到FLASH 的最后一页,之后将其读出并通过串口打印出数据. 二.nRF51822芯片内部flash知识 ...
- STM32 标准库3.5修改默认外部8M晶振为16M晶振
ST官方标准库V3.5默认的外部晶振频率为8M,实际使用中外部晶振需要修改为16M: 经过实验,修改有效,具体的patch如下: 修改 HSE_VALUE 值 diff --git "a/L ...
随机推荐
- 我在京东做研发 | 京东云算法科学家解析爆火的ChatGPT
令人惊艳的ChatGPT横空出世 背后有怎样的前沿技术支撑 走向大规模产品应用又有何局限 深耕对话式AI技术十余年 京东云算法科学家将带您一同走进技术世界 解析ChatGPT的技术亮点与局限 分享下一 ...
- [LeetCode刷题记录]39 组合总和
题目描述 给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合.candidates 中的数字可以无限制 ...
- x86 x64 arm64的区别
我们常说的高通 865,麒麟990 不是 CPU 是 SoC(System On Chip),SoC 除了 CPU 外,还有 GPU,还有可选的浮点数加速器,专用于深度模型的加速器,等等.除此以外,S ...
- vim 从嫌弃到依赖(14)——快速跳转
之前介绍过众多的motion,根据移动范围来排序的话有 l.e.w.j等等,但是面对那么长的代码文件,仅仅使用这几个简单的motion不知道要移动多少次才能找到我想要的代码,这个速度有时候还不如我用鼠 ...
- 解决idea登录github出现的invalid authentication data 404 not found以及登录 token 失效
0.错误提醒: Your token is invalid, please re-login github and get token again. 报错无效的用户名(invalid username ...
- 火山引擎ByteHouse:分析型数据库如何设计并发控制?
更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 分析型数据库设计并发控制的主要原因是为了确保数据的完整性和一致性,同时提高数据库的吞吐量和响应速度.并发控制可以防 ...
- Leetcode刷题第二天-贪心
655:非递减数列 链接:665. 非递减数列 - 力扣(LeetCode) 直接找最大最小值进行替换不行,[1,5,4,6,7,8,9]最大最小值所处位置可能是非递减数列 如果nums[i]> ...
- ch57x/ch58x开启仿真
本次使用的平台是MounRiver Studio,使用的是WCH的CH582m与WCH-LinkE 仿真之前确保LinkE处在Risc-V模式下 空闲时蓝灯常灭 Step1:首先通过ISP工具开启两 ...
- AES算法:数据传输的安全保障
在当今数字化时代,数据安全成为了一个非常重要的问题.随着互联网的普及和信息技术的发展,我们需要一种可靠的加密算法来保护我们的敏感数据.Advanced Encryption Standard(AES) ...
- 【进阶篇】Java 实际开发中积累的几个小技巧(一)
目录 前言 一.枚举类的注解 二.RESTful 接口 三.类属性转换 四.Stream 流 五.判空和断言 5.1判空部分 5.2断言部分 文章小结 前言 笔者目前从事一线 Java 开发今年是第 ...