单片机基础核心知识点汇总(三十)

目录

前言

[一、Flash 基础核心特性](#一、Flash 基础核心特性)

[二、Flash 分区规划(IAP 必备)](#二、Flash 分区规划(IAP 必备))

[三、Flash 基础读写代码](#三、Flash 基础读写代码)

四、参数掉电存储工程方案

[五、IAP 固件升级 Flash 操作逻辑](#五、IAP 固件升级 Flash 操作逻辑)

[六、Flash 开发高频坑点](#六、Flash 开发高频坑点)

[七、Flash 寿命优化策略](#七、Flash 寿命优化策略)

小结


前言

本篇我们攻克嵌入式量产开发核心存储能力 ------ 片内 Flash 操作。

几乎所有量产设备都离不开 Flash 应用:设备参数掉电保存、校准数据存储、日志记录、OTA 固件升级、开机配置固化。

很多新手对 Flash 认知只有简单读写,实际项目中频繁遇到各种疑难问题: 直接写 Flash 不擦除导致写入失败;频繁擦写损耗 Flash 寿命;跨扇区存储数据异常;IAP 分区规划不合理引发固件覆盖;程序运行时擦 Flash 造成卡死。

Flash 有一条铁则:只能将 bit1 改成 bit0,不能直接把 bit0 改成 bit1;想要恢复 bit1,必须执行扇区擦除。

一、Flash 基础核心特性

  1. 存储单元最小操作:按半字 / 字 / 双字写入,按扇区擦除
  2. 擦除后扇区所有数据为 0xFF
  3. 擦写次数有上限,STM32 片内 Flash 一般万次级别
  4. 程序运行时,可读写同芯片 Flash,但擦写期间禁止访问被操作扇区代码
  5. 掉电瞬间操作 Flash,极易造成存储数据损坏

二、Flash 分区规划(IAP 必备)

以 512KB Flash 芯片举例

  • 0x08000000 ~ 0x08002FFF:Bootloader 分区,IAP 升级引导程序
  • 0x08003000 ~ 0x0800BFFF:App 分区,设备业务主程序
  • 0x0800C000 ~ 0x0800CFFF:参数存储分区,保存配置、校准参数
    业务代码和参数分区物理隔离,升级固件不会覆盖设备配置

三、Flash 基础读写代码

复制代码
#include "stm32f10x.h"

//Flash擦除单个扇区
uint32_t Flash_EraseSector(uint32_t addr)
{
    FLASH_Unlock();
    FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
    uint32_t ret = FLASH_ErasePage(addr);
    FLASH_Lock();
    return ret;
}

//写入半字(2字节)
uint32_t Flash_WriteHalfWord(uint32_t addr, uint16_t data)
{
    FLASH_Unlock();
    FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
    uint32_t ret = FLASH_ProgramHalfWord(addr, data);
    FLASH_Lock();
    return ret;
}

//批量写入多字节数据
uint32_t Flash_WriteBuf(uint32_t start_addr, uint8_t *buf, uint16_t len)
{
    uint16_t i = 0;
    uint32_t res;
    if(len % 2 != 0) return 1;
    while(i < len)
    {
        uint16_t temp = (buf[i+1] << 8) | buf[i];
        res = Flash_WriteHalfWord(start_addr + i, temp);
        if(res != FLASH_COMPLETE) return res;
        i += 2;
    }
    return FLASH_COMPLETE;
}

//读取Flash数据,直接指针访问
uint8_t Flash_ReadByte(uint32_t addr)
{
    return *(volatile uint8_t*)addr;
}

四、参数掉电存储工程方案

不要每次修改参数就擦写 Flash,频繁擦写快速损耗寿命。

方案:内存缓存参数,定时保存 / 修改确认后再写入 Flash。

复制代码
#define PARAM_ADDR 0x0800C000
typedef struct
{
    uint16_t para1;
    uint16_t para2;
    uint32_t crc;
}param_t;

param_t g_param_cache;

//保存参数到Flash
void Param_Save(void)
{
    Flash_EraseSector(PARAM_ADDR);
    g_param_cache.crc = crc16_calc((uint8_t*)&g_param_cache, sizeof(param_t)-4);
    Flash_WriteBuf(PARAM_ADDR, (uint8_t*)&g_param_cache, sizeof(param_t));
}

//开机加载参数
void Param_Load(void)
{
    param_t *p = (param_t *)PARAM_ADDR;
    uint16_t crc_check = crc16_calc((uint8_t*)p, sizeof(param_t)-4);
    if(crc_check == p->crc)
    {
        memcpy(&g_param_cache, p, sizeof(param_t));
    }
    else
    {
        //校验失败,加载默认参数
        g_param_cache.para1 = 100;
        g_param_cache.para2 = 200;
    }
}

增加 CRC 校验,防止掉电半写导致参数损坏。

五、IAP 固件升级 Flash 操作逻辑

  1. Bootloader 运行,检测是否存在新固件
  2. 将收到的固件包写入 App 备份 Flash 分区
  3. 固件全部接收完成,校验整个固件 CRC
  4. 校验通过,擦除原 App 分区,将备份固件拷贝到 App 区域
  5. 跳转 App 程序;校验失败,保留旧程序,不执行覆盖

六、Flash 开发高频坑点

  1. 忘记解锁 Flash,直接擦写,操作全部失败
  2. 不做 CRC 校验,掉电中断写入,参数变成乱码
  3. 循环频繁擦写同一扇区,Flash 提前磨损失效
  4. 擦写 Flash 时,代码在当前扇区运行,程序直接 HardFault
  5. 地址没有对齐,写入半字 / 字时报错
  6. 分区规划重叠,升级时误擦除 Bootloader,设备变砖

七、Flash 寿命优化策略

  1. 减少擦除次数,参数改动批量一次性写入
  2. 循环轮换多个备份扇区,分散擦写压力
  3. 重要参数做双备份,A 扇区主存,B 扇区备用
  4. 禁止在循环内反复执行 Flash 擦写

小结

片内 Flash 操作核心就三点:遵守硬件读写规则、合理分区、增加校验与备份机制。

单纯读写只是基础,量产项目重点在于保护数据安全、控制擦写损耗,避免设备变砖与参数丢失。

相关推荐
不悔哥4 天前
开源OV-Watch:怎么做一个智能手表
单片机·开源·嵌入式
XiHongShi20164 天前
STM32F407 RTC定时器例程,建议保存
stm32·单片机·学习
深圳老胡4 天前
STM32F407 控制 L6470 步进电机驱动 —— 控制过程简介
笔记·stm32·单片机·嵌入式硬件·代码规范
女神下凡4 天前
嵌入式设计的各种存储芯片的硬件/软件设计规范,非常全面。
arm开发·单片机·嵌入式硬件
梅梅9664 天前
一款mipi转lvds的lcd调试(LT8912B)
单片机·计算机外设·电脑·显示器·pd芯片
开发笔记-阿牛4 天前
蓝牙音乐灯拆解,又一次拆到蓝牙音乐灯芯片CK6865L
人工智能·单片机·嵌入式硬件·音视频·音频
从零开始的嵌入式之旅4 天前
day47
arm开发·经验分享·笔记·嵌入式硬件
恒锐丰科技林技术员4 天前
EG1164 高压大电流升压同步整流芯片解析
经验分享·嵌入式硬件·硬件工程
CHENKONG_CK4 天前
破解制鞋打磨痛点:RFID赋能去毛刺工序自动化升级
网络·单片机·嵌入式硬件·网络协议·tcp/ip
祖力554 天前
ARM时钟
嵌入式硬件·arm·时钟·imx6ull