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读写的更多相关文章

  1. STM32 对内部FLASH读写接口函数(转)

    源:STM32 对内部FLASH读写接口函数 因为要用内部FLASH代替外部EEPROM,把参数放在STM32的0x08000000+320K处,其中20K是bootloader,300K是应用程序. ...

  2. 单片机stm32零基础入门之--初识STM32 标准库

    CMSIS 标准及库层次关系 因为基于Cortex 系列芯片采用的内核都是相同的,区别主要为核外的片上外设的差异,这些差异却导致软件在同内核,不同外设的芯片上移植困难.为了解决不同的芯片厂商生产的Co ...

  3. STM32 标准库

    CMSIS 标准及库层次关系 因为基于Cortex 系列芯片采用的内核都是相同的,区别主要为核外的片上外设的差异,这些差异却导致软件在同内核,不同外设的芯片上移植困难.为了解决不同的芯片厂商生产的Co ...

  4. STM32标准库GPIO操作

    STM32标准库GPIO操作 STM32任何外围设备的使用都分为两部分:初始化和使用.体现在代码上就是:(1)有一个初始化函数(2)main函数中的使用 1.初始化GPIO 初始化GPIO函数代码: ...

  5. 初识STM32标准库

    1.CMSIS 标准及库层次关系 CMSIS 标准中最主要的为 CMSIS 核心层,它包括了: STM32标准库可以从官网获得: 在使用库开发时,我们需要把 libraries 目录下的库函数文件添加 ...

  6. STM32 对内部FLASH读写接口函数

    因为要用内部FLASH代替外部EEPROM,把参数放在STM32的0x08000000+320K处,其中20K是bootloader,300K是应用程序. 原理:先要把整页FLASH的内容搬到RAM中 ...

  7. STM32 标准库V3.5启动文件startup_stm32f10xxx.s分析

    layout: post tags: [STM32] comments: true 文章目录 layout: post tags: [STM32] comments: true 前言 分析startu ...

  8. STM32 HAL库 UART 串口读写功能笔记

    https://www.cnblogs.com/Mysterious/p/4804188.html STM32L0 HAL库 UART 串口读写功能 串口发送功能: uint8_t TxData[10 ...

  9. [nRF51822] 11、基础实验代码解析大全 · 实验16 - 内部FLASH读写

     一.实验内容: 通过串口发送单个字符到NRF51822,NRF51822 接收到字符后将其写入到FLASH 的最后一页,之后将其读出并通过串口打印出数据. 二.nRF51822芯片内部flash知识 ...

  10. STM32 标准库3.5修改默认外部8M晶振为16M晶振

    ST官方标准库V3.5默认的外部晶振频率为8M,实际使用中外部晶振需要修改为16M: 经过实验,修改有效,具体的patch如下: 修改 HSE_VALUE 值 diff --git "a/L ...

随机推荐

  1. 如何优雅的写 css 代码

    CSS(全称 Cascading Style Sheets,层叠样式表)为开发人员提供声明式的样式语言,是前端必备的技能之一,基于互联网上全面的资料和简单易懂的语法,CSS 非常易于学习,但其知识点广 ...

  2. 【VictoriaMetrics】一个小优化:循环改查表,性能提升56.48 倍

    作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 做了一个 vm-storage 数据文件 merge 的工 ...

  3. windows10卸载小娜

    适用于2004版本往后的 win+x如图 输入如下代码 Get-AppxPackage-allusersMicrosoft.549981C3F5F10|Remove-AppxPackage 运行结束后 ...

  4. 为游戏接入ios sdk的oc学习笔记

    开发手机游戏,需要接入ios的sdk,截止2021年7月23日虽然swift已经推出一些年头,但对于大部分的渠道sdk,还是oc的代码. oc不仅仅用来开发ios,还是mac上的app开发语言 从新手 ...

  5. PaddleHub--{超参优化AutoDL Finetuner}【二】

     相关文章: 基础知识介绍: [一]ERNIE:飞桨开源开发套件,入门学习,看看行业顶尖持续学习语义理解框架,如何取得世界多个实战的SOTA效果?_汀.的博客-CSDN博客_ernie模型 百度飞桨: ...

  6. 快递单信息抽取【二】基于ERNIE1.0至ErnieGram + CRF预训练模型

    相关文章: 1.快递单中抽取关键信息[一]----基于BiGRU+CR+预训练的词向量优化 2.快递单信息抽取[二]基于ERNIE1.0至ErnieGram + CRF预训练模型 3.快递单信息抽取[ ...

  7. 2.5 CE修改器:寻找数值指针

    上一步阐述了如何使用代码替换功能对付变化位置的数据地址,但这种方法往往不能达到预期的效果,所以我们需要学习如何利用指针,在本关的Tutorial.exe窗口下面有两个按钮,一个会改变数值,另一个不但能 ...

  8. LyScriptTools 反汇编类API接口手册

    LyScriptTools模块实在LyScript模块反汇编基础上封装而成,其提供了更多的反汇编方法,可以更好的控制x64dbg完成自动化反汇编任务,API参考手册如下. 插件地址:https://g ...

  9. 一篇学会软硬链接|快捷方式|操作系统|centos7

    前言 那么这里博主先安利一些干货满满的专栏了! 首先是博主的高质量博客的汇总,这个专栏里面的博客,都是博主最最用心写的一部分,干货满满,希望对大家有帮助. 高质量博客汇总https://blog.cs ...

  10. Oracle 数据库版本路线图

    经常会有客户困惑某个Oracle版本的支持周期,且希望得到确切的官方说明,其实这可以从MOS文档: Release Schedule of Current Database Releases (Doc ...