云计算百科
云计算领域专业知识百科平台

【嵌入式外设精学】Day17|Flash:页擦写、参数保存、掉电安全

【嵌入式外设精学】Day17|Flash:页擦写、参数保存、掉电安全

今天解决:为什么不能像 RAM 随便写?参数怎样存才抗掉电?


目录

  • 问题 2. 原理 3. 代码 4. 误区 5. 自测 6. 答案

  • 1. 问题

    • 存参数偶发坏
    • 写得很勤后来整片变砖

    2. 原理

    2.1 擦和写是两回事

    操作粒度意思
    擦 页/扇区 整块变“空白”
    写 字/半字 往空白里写

    改一个字节,往往也要先擦整页再写回。

    2.2 寿命有限

    每块能擦写的次数有限(常见万级到十万级,看器件)。 不能每 10ms 存一次 PID。

    2.3 掉电安全(双份 A/B)

    A 页 / B 页,都带“序号 + 校验”
    保存:写到“不是当前有效”的那一份
    上电:两份都读,取校验过且序号大的

    这样写到一半掉电,旧那份仍可用。


    3. 代码示例

    #include <stdint.h>
    #include <stdbool.h>
    #include <string.h>

    #define MAGIC 0x5041524Du

    typedef struct {
    float kp, ki, kd;
    } par_t;

    typedef struct {
    uint32_t magic;
    uint16_t ver;
    uint16_t seq;
    par_t p;
    uint32_t crc;
    } blob_t;

    /* 平台相关:擦页、写、读、CRC */
    void flash_erase_page(uint32_t page);
    void flash_write(uint32_t addr, const void *d, uint32_t n);
    void flash_read(uint32_t addr, void *d, uint32_t n);
    uint32_t page_addr(uint32_t page);
    uint32_t crc32_calc(const uint8_t *d, uint32_t n);

    static void seal(blob_t *b)
    {
    b->magic = MAGIC;
    b->crc = crc32_calc((const uint8_t *)b, (uint32_t)(sizeof(*b) – 4u));
    }

    static bool ok(const blob_t *b)
    {
    return b->magic == MAGIC &&
    b->crc == crc32_calc((const uint8_t *)b, (uint32_t)(sizeof(*b) – 4u));
    }

    int param_save(uint16_t *seq, const par_t *in, uint32_t page)
    {
    blob_t b;
    memset(&b, 0, sizeof(b));
    b.seq = (uint16_t)(*seq + 1u);
    b.p = *in;
    seal(&b);

    flash_erase_page(page);
    flash_write(page_addr(page), &b, sizeof(b));
    *seq = b.seq;
    return 0;
    }

    bool param_load(par_t *out, uint16_t *seq, uint32_t page_a, uint32_t page_b)
    {
    blob_t a, b;
    flash_read(page_addr(page_a), &a, sizeof(a));
    flash_read(page_addr(page_b), &b, sizeof(b));

    if (ok(&a) && ok(&b)) {
    const blob_t *sel = ((int16_t)(a.seq – b.seq) > 0) ? &a : &b;
    *out = sel->p; *seq = sel->seq;
    return true;
    }
    if (ok(&a)) { *out = a.p; *seq = a.seq; return true; }
    if (ok(&b)) { *out = b.p; *seq = b.seq; return true; }
    return false;
    }

    保存时机:按钮“保存参数”、关机前、模式切换——不要高频定时写。


    4. 常见误区

    误区正解
    Flash 当 EEPROM 随便改 要擦写策略和寿命意识
    只存一份 掉电可能半新半旧
    不加校验 坏数据当参数用
    运行中频繁写 寿命和掉电风险都大

    5. 自测

  • 双份 A/B 的好处?
  • 为什么不能每圈都存 PID?

  • 6. 答案

  • 写挂了还有旧有效数据;取“校验过且更新”的那份。
  • 寿命不够,且掉电时容易写坏;应在明确“保存”时刻写。

  • 作者:shuifanyu 标签:Flash 掉电 参数存储

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 【嵌入式外设精学】Day17|Flash:页擦写、参数保存、掉电安全
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!