使用__attribute__((at(addr))) 固定变量到指定 Flash 地址

文章目录

  • 一、代码示例:将变量固定到 Flash 0x08001000
  • 二、__attribute__((at(addr))) 的作用
  • 三、__attribute__((at(addr))) 可能导致的问题
  • 四、运行时修改 Flash 存储的变量
  • 五、在 GCC(STM32CubeIDE)中实现同样功能


在嵌入式开发中,有时我们需要在 Flash 指定地址存储特定的标志位或常量数据,例如 Bootloader 标志、固件版本信息、校验码等。这时,可以使用 __attribute__((at(addr))) 关键字,将变量固定存放在指定的 Flash 地址。

一、代码示例:将变量固定到 Flash 0x08001000

以下代码用于将 custom_data 变量固定到 Flash 地址 0x08001000,并赋值 0x12345678:

#define CUSTOM_FLAG_ADDR 0x08001000
#define SET_COMPILE_ADDR(addr) __attribute__((at(addr)))SET_COMPILE_ADDR(CUSTOM_FLAG_ADDR) const uint32_t custom_data = 0x12345678;

代码解析:
#define CUSTOM_FLAG_ADDR 0x08001000 :定义 Flash 目标存储地址 0x08001000,该地址必须是空闲的,否则可能会覆盖已有的代码或数据。

#define SET_COMPILE_ADDR(addr) __attribute__((at(addr))) :使用 attribute((at(addr))) 指定变量存放的物理地址(仅适用于 ARM Compiler 5)。

SET_COMPILE_ADDR(CUSTOM_FLAG_ADDR) const uint32_t custom_data = 0x12345678 :让 custom_data 变量存放在 0x08001000,并初始化值为 0x12345678。

在这里插入图片描述

二、attribute((at(addr))) 的作用

__attribute__((at(addr))) 是 Keil ARM Compiler 5(ARMCC5) 提供的编译器特性,允许开发者在编译时强制将变量存放到指定的 Flash 或 RAM 地址。例如:

  • 用于 Bootloader 和应用程序通信

  • 存储设备唯一 ID、固件版本等不可变数据

  • 存储升级标志位

Tips:

  • Keil ARM Compiler 6(ARMCC6)和 GCC(STM32CubeIDE)不支持 attribute((at(addr)))

    1. ARMCC6 和 GCC 需要使用链接脚本(scatter 文件或 .ld 文件)指定存储区域,不能直接使用 attribute((at(addr)))。
  • 变量存放地址必须是 Flash 空闲区

    1. 如果 0x08001000 处已有数据或程序代码,custom_data 可能会破坏已有内容,导致程序崩溃。

    2. 需要先查看 Keil 生成的 .map 文件,确保 0x08001000 是可用的。

  • Flash 不能直接修改

    1. custom_data 存在于 Flash,而 Flash 不能像 RAM 一样直接赋值修改。

    2. 如果要修改该变量的值,必须使用 Flash 擦除 + 重新写入 操作(见后文)。

三、attribute((at(addr))) 可能导致的问题

直接使用 attribute((at(addr))) 可能遇到的问题:

  • 问题 1:Flash 代码段冲突

    如果 0x08001000 处有代码或数据,custom_data 可能会覆盖已有内容,导致程序崩溃。

    ✅解决方案:

    1. 查看 .map 文件 确保 0x08001000 是空闲的。

    2. 修改 scatter 文件 或 STM32CubeIDE 的 .ld 文件,手动指定存储区域。

  • 问题 2:Flash 不能直接写入

    由于 Flash 只能在擦除后写入,custom_data 变量的值 0x12345678 无法在运行时修改。

    ✅解决方案:

    1. 使用 Flash 读写 API 修改该地址的数据,而不是使用 attribute((at(addr)))。

四、运行时修改 Flash 存储的变量

如果 custom_data 需要在程序运行过程中修改,就不能直接用 attribute((at(addr))),而是应该使用 Flash 读写 API,如下所示:

#include "stm32f4xx_hal.h"#define CUSTOM_FLAG_ADDR 0x08001000  // Flash 目标地址void Write_CustomData(uint32_t new_value) {HAL_FLASH_Unlock(); // 解锁 Flash 写权限// 擦除 Flash 扇区(0x08001000 可能属于 SECTOR_1,需确认)FLASH_EraseInitTypeDef EraseInitStruct;uint32_t SectorError;EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;EraseInitStruct.Sector = FLASH_SECTOR_1;  // 需要根据具体 MCU 修改EraseInitStruct.NbSectors = 1;HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError);// 写入新值HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, CUSTOM_FLAG_ADDR, new_value);HAL_FLASH_Lock(); // 锁定 Flash
}

🔹 该函数的作用:

  • 先解锁 Flash

  • 擦除 Flash 对应扇区

  • 重新写入新的值

  • 锁定 Flash,防止误操作

📌 优点

  • 可以在运行时修改 custom_data,不会破坏代码。

  • 适用于需要存储状态标志、参数配置的场景。

五、在 GCC(STM32CubeIDE)中实现同样功能

由于 __attribute__((at(addr))) 不支持 GCC,我们可以在 STM32CubeIDE 或 ARM Compiler 6 中使用链接脚本(.ld 文件) 实现相同效果。

1. 修改 STM32F4xx.ld
在 MEMORY 段中添加:

FLASH_CUSTOM (rx) : ORIGIN = 0x08001000, LENGTH = 4

然后,在 SECTIONS 段中添加:

.custom_data_section :
{*(.custom_data_section)
} > FLASH_CUSTOM

2. 在代码中存放变量

const uint32_t custom_data __attribute__((section(".custom_data_section"))) = 0x12345678;

📌 综上结论

  • 如果数据不需要修改,可以用 attribute((at(addr)))(仅限 ARMCC5)。

  • 如果数据需要修改,建议使用 Flash 读写 API。

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

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

相关文章

vmware虚拟机快照、克隆、迁移区别说明

一、快照 1.1 快照概念 记录了虚拟机在某个特定时间点的状态(软件部署、网络配置、照片备份、游戏存档等) 1.2快照用途 可以在需要时轻松地恢复虚拟机到快照创建时的状态。 备份和恢复:快速备份虚拟机状态的方法可以在数据丢失或损坏时快速恢复虚拟机到先前的状态。测试和…

面试常问系列(一)-神经网络参数初始化

一、背景 说到参数初始化,先提一下大家常见的两个概念梯度消失和梯度爆炸。 (一)、梯度消失:深层网络的“静默杀手” 定义: 在反向传播过程中,梯度值随着网络层数增加呈指数级衰减,最终趋近…

使用CSS3实现炫酷的3D翻转卡片效果

使用CSS3实现炫酷的3D翻转卡片效果 这里写目录标题 使用CSS3实现炫酷的3D翻转卡片效果项目介绍技术要点分析1. 3D空间设置2. 核心CSS属性3. 布局和定位 实现难点和解决方案1. 3D效果的流畅性2. 卡片内容布局3. 响应式设计 性能优化建议浏览器兼容性总结 项目介绍 在这个项目中…

AI Agent开发大全第七课-个人如何申请到靠谱的AI

前言 前面几个课程我们做了一些AI基础知识的铺垫,不要小看基础知识,这些基础知识往往是一些正在从事AI开发的工作者们都没有深入去了解的。 其实这就好比简历上写熟练使用mySql,而实际mySql里那些精妙的参数和设置以及一些底层真的都知道吗? 所以我特别强调基础得打造,…

什么是网络准入?十种常见的网络准入解决方案分享!

在数字化转型的浪潮中,企业网络的边界日益模糊,数据安全与访问控制成为了企业IT管理的核心挑战之一。OneNAC网络准入系统,作为新一代网络安全解决方案的佼佼者,凭借其强大的功能特性和灵活性,在众多网络准入控制&#…

Jetpack Compose 选项卡控件实现

这里写目录标题 介绍主体解释 介绍 实现选项卡控件 主体 import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.…

Java 大视界 -- Java 大数据在智慧文旅旅游目的地营销与品牌传播中的应用(150)

💖亲爱的朋友们,热烈欢迎来到 青云交的博客!能与诸位在此相逢,我倍感荣幸。在这飞速更迭的时代,我们都渴望一方心灵净土,而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识,也…

使用密码连接Redis服务的两种方式

说明:本文介绍连接需要密码的Redis服务的两种方式 方式一 连接时,携带密码,如下: redis-cli -a [密码]如下: 有两个问题: 密码直接放在命令里,可通过 history 找到,不安全&#x…

搭建React简单项目

一、项目构建 目录结构: 安装脚手架 npm install -g create-react-app // or yarn add -g create-react-app 一、项目版本 1、react:"^18.3.1"; 2、react-router-dom:"^6.23.1"; 3、项目创…

知识库已上线

目录 知识库上线了加入知识库注册账号切换租户加入租户找到知识库点击申请等待管理员审核通过后,点击去后台可以开始创作了创建我们的第一个知识库点击详情进入创作页面,创建我们的第一篇知识 发布知识将我们的知识库变更为公开状态发布知识等待管理员审…

对象克隆以及BigInteger()方法,与BigDecima()方法的学习

BigInteger()方法: ①获取一个随机的大整数: public class Test3 {public static void main(String[] args) {Random rnew Random();BigInteger bigIntegernew BigInteger(4,r);System.out.println(bigInteger);} } ②&#xf…

学习记录-vue2,3-vue实现tab栏

目录 vue实现tab栏功能描述实现效果vue实现tab栏实现步骤1. 概念理解2. Tab栏切换 完整实例代码 vue实现tab栏功能描述 选项卡切换选中状态 实现效果 vue实现tab栏实现步骤 1. 概念理解 了解vue的基础指令 代码含义v-on绑定事件,可以简写为:事件名“执行体”。…

【读书笔记】华为《从偶然到必然》

note 华为的成功并非偶然,而是通过IPD体系、投资组合管理、平台战略等系统性工具,将研发投资转化为可持续的商业竞争力。书中强调的“管理即内部因素”理念,揭示了企业规模扩张与管理能力匹配的深层规律,为高科技企业提供了可借鉴…

表达式树和编译原理【10道经典面试题】(中英对照)

表达式树(Expression Tree) 是一种用于表示数学表达式的二叉树结构。它在编译器设计、数学计算引擎、符号计算等领域有着广泛的应用(《表达式树(Expression Tree)在编译器中的应用》)。理解表达式树的构建、…

【redis】主从复制:单点问题、配置详解、特点详解

文章目录 单点问题什么是主从复制主从模式能解决的问题并发量有限可用性问题 配置建立复制通过配置文件来指定端口配置主从查看集群结构 断开复制 特点安全性只读传输延迟 单点问题 分布式系统中,涉及到一个非常关键的问题:单点问题 某个服务器程序&…

VSCode 生成HTML 基本骨架

在VSCode 新建html文件中敲一个英文感叹号 ! <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><titl…

STM32定时器-01定时器概述

内容概述 定时器是STM32中功能最强大、结构最复杂的一个外设&#xff0c;分为四部分&#xff1a; 一部分&#xff1a;定时中断功能 二部分&#xff1a;定时器输出比较&#xff0c;常见的用途&#xff1a;产生PWM波形&#xff0c;驱动电机&#xff08;如驱动舵机和直流电机&…

在 Ubuntu 中用 Docker 安装 RAGFlow

一、安装 1.前提条件 CPU > 4 核 RAM > 16 GB Disk > 50 GB Docker > 24.0.0 & Docker Compose > v2.26.1 安装docker&#xff1a;在Ubuntu中安装Docker并配置国内镜像 2.设置 vm.max_map_count #设置 vm.max_map_count 不小于 262144# 查看 sysctl vm.…

17153 班级活动

17153 班级活动 ⭐️难度&#xff1a;简单 &#x1f31f;考点&#xff1a;2023、思维、国赛 &#x1f4d6; &#x1f4da; import java.util.Arrays; import java.util.LinkedList; import java.util.Queue; import java.util.Scanner;public class Main {static int N 10…