当前位置: 首页 > article >正文

使用__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.kler.cn/a/598132.html

相关文章:

  • Scikit-learn 学习思维导图
  • 深度解析 Android Matrix 变换(二):组合变换 pre、post
  • 资金管理策略思路
  • 数据结构之双链表
  • 解码未来:DeepSeek开源FlashMLA,推理加速核心技术,引领AI变革
  • 高项第十四章——项目沟通管理
  • SAP SD学习笔记35 - ATP(可用性检查)的各种Pattern
  • 基于springboot的“衣依”服装销售平台(043)
  • 第43章:企业级密钥管理:Vault与Kubernetes集成
  • 运行时智控:PanLang 开发者指南(一)运行时系统核心模块实现——PanLang 原型全栈设计方案与实验性探索5
  • 使用OpenCV进行图像处理:边界填充、阈值处理
  • 第16章:基于CNN和Transformer对心脏左心室的实验分析及改进策略
  • Centos7搭建Zabbix4.x监控HCL模拟网络设备:zabbix-server搭建及监控基础04
  • 【第13届蓝桥杯】软件赛CB组省赛
  • Trie树(字典树)/(前缀树)
  • JVM 学习前置知识
  • 12、Python 异常处理与调试技巧
  • 《Java到Go的平滑转型指南》
  • 轻松认识 SQL 关键字,打开数据库操作大门
  • Java-SpringBootWeb入门、Spring官方脚手架连接不上解决方法