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. Skia 编译及踩坑实践

    本文要点 •了解并入门 Skia.OpenGL 和 Vulkan •了解 Skia 在后端渲染上的坑点 前言 Skia 是什么 Skia 是一个开源 2D 图形库,提供可跨各种硬件和软件平台工作的通用 ...

  2. click与addEventListener和removeEventListener事件与移除正确的移除事件详解

    1. onclick事件 es5 普通事件就是直接触发事件,相同的事件会被覆盖掉.代码如下: let demoDiv=document.querySelector(".demo") ...

  3. 【JS 逆向百例】Ether Rock 空投接口 AES256 加密分析

    关注微信公众号:K哥爬虫,持续分享爬虫进阶.JS/安卓逆向等技术干货! 声明 本文章中所有内容仅供学习交流,抓包内容.敏感网址.数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后 ...

  4. vue基础系列文章12---创建脚手架

    一.交互式命令行创建 1.运行 vue create myvue 选择默认创建模式,会在指定的文件夹下创建文件 2.进入到myvue文件夹,运行:npm  run serve 3.访问本地的地址就可以 ...

  5. AppCan 打包无限次下载解决方案

    1.下载AppCan 官网上打包好的文件apk文件 2.将apk文件放在指定的服务器文件内,谇文件发布到IIS,一般都会用已发布发的网站上面随便一个目录就可以了. 3.MIME类型中填写apk的MIM ...

  6. 阿里天池实验室简明教程以及Docker安装使用[一]

    1.天池notebook简介和使用 天池实验室是基于PAI DSW探索版开发的,PAI DSW (Data Science Workshop)是为算法开发者量身打造的云天池实验室是基于PAI DSW探 ...

  7. Centos7 本地与网络Yum源配置

    虽然Yum工具,只需要你的主机连接互联网,就可以直接使用,但是有些时候我们需要自定义Yum源实现加速,下面我们将配置一个本地Yum源,来使用光盘中的软件,其他网络配置操作步骤相同,只是会在baseur ...

  8. 协程(Python)

    一.gevent #__author__:Kelvin #date:2020/5/13 13:34 from gevent import monkey monkey.patch_all() impor ...

  9. PHP 编程技巧与优化

    PHP 编程技巧与优化 1. 尽量采用大量的PHP内置函数. 2. 使用echo代替print,并且使用echo的多重参数(译注:指用逗号而不是句点)代替字符串连接 3. 用单引号代替双引号来包含字符 ...

  10. 19.2 显式加载/隐式加载--《Windows核心编程》

    部分笔记来自于:https://blog.csdn.net/blade1080/article/details/81364161 注:关于DLL存放位置,一般是放到可执行文件的目录下. 下面时加载程序 ...