如何在STM32H743XIH6的Cube IDE中向Flash写入变量
在STM32H743XIH6 Cube IDE中实现Flash变量掉电保存(C语言)
核心思路
STM32的Flash是只读存储,无法直接赋值修改,必须先擦除对应扇区,再写入数据。我们需要通过自定义Linker段将变量固定到Flash的空闲区域,再配合HAL库的Flash操作API完成读写。
步骤1:确定可用Flash区域
STM32H743XIH6的Flash总容量2MB,分为两个Bank:
- Bank1:
0x08000000 - 0x080FFFFF(通常用于存储程序代码) - Bank2:
0x08100000 - 0x081FFFFF(默认未被程序占用,可用于存储非易失变量)
推荐选择Bank2的扇区24(起始地址0x08100000,大小128KB),可通过STM32H7参考手册RM0433确认扇区划分。
步骤2:修改Linker Script
在Cube IDE的项目中,打开STM32H743XIHx_FLASH.ld链接脚本,添加自定义段用于存放非易失变量:
/* 自定义非易失变量段 */ .nv_vars : { . = ALIGN(4); // 按4字节对齐 *(.nv_vars) // 匹配所有标记为.nv_vars的变量 . = ALIGN(4); } >FLASH AT>FLASH // 指定段存放于Flash区域
确认MEMORY区块中的FLASH范围包含Bank2地址(默认配置已覆盖0x08000000到0x081FFFFF,无需额外修改)。
步骤3:声明Flash变量
使用__attribute__((section(".nv_vars")))将变量指定到自定义Flash段:
#include <stdint.h> // 初始值会被烧录到Flash中,上电后直接读取 __attribute__((section(".nv_vars"))) int nv_int = 0; __attribute__((section(".nv_vars"))) unsigned char nv_uchar = 0; __attribute__((section(".nv_vars"))) uint8_t nv_uint8 = 0; // 可选:用结构体统一管理所有非易失变量(更便于批量读写) typedef struct { int nv_int; unsigned char nv_uchar; uint8_t nv_uint8; } NV_Vars_t; __attribute__((section(".nv_vars"))) NV_Vars_t nv_vars = {0, 0, 0};
步骤4:实现Flash操作函数
4.1 扇区擦除函数
Flash写入前必须先擦除对应扇区,擦除会清除整个扇区的数据:
#include "stm32h7xx_hal.h" HAL_StatusTypeDef Flash_Erase_Bank2_Sector(uint32_t sector) { FLASH_EraseInitTypeDef erase_init = {0}; uint32_t sector_error = 0; erase_init.TypeErase = FLASH_TYPEERASE_SECTORS; erase_init.Banks = FLASH_BANK_2; // 指定操作Bank2 erase_init.Sector = sector; erase_init.NbSectors = 1; erase_init.VoltageRange = FLASH_VOLTAGE_RANGE_3; // 适配2.7V-3.6V电源(根据板子调整) HAL_FLASH_Unlock(); // 解锁Flash HAL_StatusTypeDef status = HAL_FLASHEx_Erase(&erase_init, §or_error); HAL_FLASH_Lock(); // 操作完成后锁定Flash return status; }
4.2 变量写入函数
Flash写入最小单位为32位(字),对于字节类型变量,需结合扇区擦除+批量写入避免数据丢失:
// 写入int类型变量 HAL_StatusTypeDef Flash_Write_Int(uint32_t flash_addr, int value) { HAL_FLASH_Unlock(); HAL_StatusTypeDef status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, flash_addr, (uint32_t)value); HAL_FLASH_Lock(); return status; } // 更新uint8_t变量(需先保存其他变量值,擦除后重新写入) void Update_NV_Uint8(uint8_t new_value) { // 1. 保存当前扇区内的所有变量 NV_Vars_t temp_vars = nv_vars; temp_vars.nv_uint8 = new_value; // 2. 擦除目标扇区 if (Flash_Erase_Bank2_Sector(FLASH_SECTOR_24) != HAL_OK) { // 处理擦除错误(如打印日志、触发指示灯) return; } // 3. 重新写入所有变量 Flash_Write_Int((uint32_t)&nv_vars, *(uint32_t*)&temp_vars); // 若结构体大于4字节,需分多次写入,或使用FLASH_TYPEPROGRAM_DOUBLEWORD写入64位数据 }
步骤5:读取变量
直接通过变量名读取即可,编译器会自动从Flash地址加载数据:
int current_int = nv_int; uint8_t current_uint8 = nv_vars.nv_uint8;
关键注意事项
- Flash擦除寿命:Flash擦写次数约10万次,避免频繁写入(如每秒写入)。
- 解锁/锁定Flash:所有写操作前必须解锁,完成后立即锁定,防止误操作。
- 扇区占用检查:通过Cube IDE的
Map文件确认自定义段未占用程序代码区域。 - 电源稳定性:Flash写入/擦除过程中不能掉电,否则会导致Flash损坏。
参考资料
- ST官方STM32H743xx参考手册(RM0433):详细说明Flash控制器的寄存器配置与操作流程。
- STM32Cube HAL库文档:查看
FLASH模块的API参数与使用示例。 - Cube IDE用户指南:了解链接脚本的结构与自定义段配置方法。
内容的提问来源于stack exchange,提问作者spino
相关产品推荐
相关产品推荐

