跳转至

CH582M Flash 存储与 SNV 详解

芯片型号:CH582M / CH583 / CH592 等 CH58x 系列
主题:片上 Flash 分区地图、BLE SNV 配对绑定机制、外接存储扩展方案
学习状态:🚧 原理已整理,待代码验证
更新日期:2026年7月18日


⚠️ 这是踩坑重灾区,也是 CH58x 系列最核心的"非直观"设计之一。建议通读本节后再动手写 Flash 相关代码。


1. 整片 Flash 地址映射总览

CH582M / CH583M 的 Flash 总容量为 512 KB(0x00000000 ~ 0x0007FFFF),物理上就是同一块 Flash,沁恒通过地址划分人为定义了 4 个功能区域:

地址范围 区域名称 容量 用途 用户可读写?
0x00000000 ~ 0x0006FFFF CodeFlash 448 KB 用户程序 + 蓝牙 LIB ✅ 程序读写(带加解密)
0x00070000 ~ 0x00077FFF DataFlash 32 KB 用户非易失数据 ✅ 直接读写(无加密)
0x00078000 ~ 0x0007DFFF BootLoader 24 KB 系统引导程序(ISP/IAP) ❌ 用户不可写
0x0007E000 ~ 0x0007FFFF InfoFlash 8 KB 系统配置信息(校准参数、MAC 等) ❌ 用户不可写

📌 关键认知:CodeFlash 和 DataFlash 只是同一物理 Flash 的不同地址段,不是两块独立的芯片。它们的差异是沁恒在 SDK 里做了不同的接口封装(CodeFlash 带内核加解密,DataFlash 不加)。


2. CodeFlash 内部分区(BLE 例程视角)

在官方 BLE 例程中,CodeFlash 的 448 KB 并非全给用户程序,实际被划分如下:

子区域 容量 地址范围(相对) 用途
启动区 4 KB 0x0000 ~ 0x0FFF 中断向量表、启动代码
imageA (APP) 152 KB 0x1000 ~ 0x26FFF 用户主程序
imageA (OTA) 152 KB 0x27000 ~ 0x4DFFF OTA 升级固件备份区
imageA (IAP) 4 KB 0x4E000 ~ 0x4EFFF IAP 跳转程序
BLE LIB 136 KB 0x4F000 ~ 0x6FFFF 蓝牙协议栈库(只读)
合计 448 KB

💡 这意味着:如果你不需要 OTA 功能,理论上可以把 imageA (OTA) 这 152 KB 腾出来给主程序或数据存储。但注意——这涉及到修改链接脚本和启动文件,不是开箱即用。


3. DataFlash 内部细分手册(避坑用)

DataFlash 只有 32 KB(0x70000 ~ 0x77FFF),但 BLE 协议栈会自动占用尾部区域,用户可用的其实更少:

DataFlash 偏移 占用长度 对应宏定义 用途
0x0000 12 KB CONFIG_MESH_NVS_ADDR_DEF MESH 网络信息存储
0x3000 用户可用空间
0x7000 4 字节 OTA_DATAFLASH_ADD OTA 升级标志位
0x7E00 512 B BLE_SNV_ADDR BLE 配对绑定信息
0x7FFF DataFlash 边界

⚠️ 血泪教训:如果你往 0x7E00 之后写自己的数据,会导致 BLE 配对信息丢失,下次连接手机需要重新配对!


4. CodeFlash vs DataFlash 操作差异

特性 CodeFlash DataFlash
基地址 0x00000000 0x00070000
最小擦除单位 4 KB(块擦) 256 B(页擦)或 4 KB(块擦)
读写接口 带内核加解密 无加解密,直接操作
擦除后读前 4 字节 显示为"乱码"(正常,因加密) 正常显示
ISP 工具读取 可读出完整固件 可单独读出 DataFlash
RAM 缓冲区对齐 必须 4 字节对齐 必须 4 字节对齐
写前操作 必须先擦除 必须先擦除

5. Flash 擦写寿命与时间开销

参数 数值
擦写寿命(常温 5~45°C) 10 万次(典型值)
擦写寿命(全温 -40~85°C) 5 万次(典型值)
数据保持 20 年
单块(4KB)擦除时间 6 ~ 30 ms(典型 16 ms)
单字编程时间 1 ~ 4 ms(典型 2 ms)

实测:擦 1 字节和擦 4 KB 耗时几乎一样(都是 ~17 ms),因为最小擦除单位是 4 KB。写 1 字节也要 ~2 ms。所以 Flash 操作要尽量批量、减少擦写次数


6. BLE SNV — 配对绑定信息存储(避坑重点)

SNV(Secure Non-Volatile) 是 BLE 协议栈用来保存配对绑定(Pairing & Bonding)信息的关键区域。这块区域躲藏在 DataFlash 尾部,新手很容易误写进去导致连接异常。

6.1 什么是配对绑定?

概念 含义 类比
配对(Pairing) 首次连接时交换密钥、建立安全链路 初次见面,交换名片
绑定(Bonding) 把配对得到的密钥保存下来,下次自动重连 把名片存通讯录,下次直接打电话

CH582M 的 BLE 协议栈在首次配对成功后,会把密钥信息(LTK、IRK、设备地址等)写入 SNV 区域。如果 SNV 被擦除或覆盖,下次手机连接时会拒绝重连(错误码 0x13:主机拒绝配对),必须删除手机端的配对记录重新配对。

6.2 SNV 在 DataFlash 中的位置

根据官方 EVT 包中的 CONFIG.h 定义:

#define BLE_SNV_ADDR    0x00077000   // 实质 Flash 地址
#define BLE_SNV_SIZE    0x00001000   // 分配大小 4 KB(注意:实际有效约 512 B ~ 1 KB)

但这里有个坑——0x77000 是实质地址,DataFlash 的接口函数使用的是偏移地址(减去 0x70000),所以偏移地址是 0x7000

更常见的 EVT 版本实际使用:

#define BLE_SNV_ADDR    0x00077E00   // 实质地址,对应偏移 0x7E00
参数 数值(典型版本) 说明
实质 Flash 地址 0x00077E00 在 DataFlash 范围内
DataFlash 偏移 0x7E00 使用 EEPROM_WRITE 时传这个偏移
占用长度 512 B(实际 ~224 B/次配对) 一次配对密钥约 224 B,按 256 B 对齐
配对次数上限 约 2 ~ 4 次(取决于具体实现) 超出需覆盖旧记录或扩 SNV 区

⚠️ 血泪教训:不同版本的 EVT 包、不同芯片型号(CH582/CH583/CH592),SNV 地址可能不同。务必以你当前工程 CONFIG.happ_mesh_config.h 中的宏定义为准!

6.3 一次配对实际占用多少字节?

实测(从 DataFlash 写入记录推算):

  • 单次配对成功后的密钥数据约 224 B
  • BLE 协议栈按 256 B 块 对齐存储
  • 所以 BLE_SNV_SIZE = 0x1000 (4 KB) 看似很多,实际可能支持 8~16 次配对记录,或用于不同用途分区

如果你需要连接多台主机并回连(比如一个蓝牙键盘要连 3 台电脑),可以动态切换 SNV 地址实现——每次切换广播 MAC 地址时,同时切换对应的 SNV 存储区,每台主机的配对信息互不干扰。

6.4 SNV 相关操作禁忌

操作 后果
0x7E00 偏移之后写用户数据 BLE 配对信息丢失,需重新配对
擦除 DataFlash 时未保护 SNV 区 所有绑定设备失效
更换 BLE 例程版本未核对 SNV 宏 可能新例程的 SNV 地址和旧版不同,导致数据冲突
关闭 BLE 配对功能却保留 SNV 宏 浪费 4 KB DataFlash,其实可释放

6.5 释放 SNV 空间的方法

如果你不需要 BLE 配对功能(比如广播传感器数据,任何手机都能连,不做安全认证):

  1. CONFIG.h 中查找配对使能宏,如 BLE_BONDING_ENABLESNV_ENABLE
  2. 关闭后,SNV 区域变为普通 DataFlash 可用空间
  3. 但注意:关闭配对后,BLE 连接将没有加密,在敏感场景(如键鼠)不建议

💡 一句话:SNV 是 BLE 的"通讯录",别乱动。要动之前先确认你的配对策略,再决定要不要释放这块空间。

6.6 SNV 绑定设备数量上限 — 128 个的真相

来自论坛官方技术支持(WCH TECH_Lpc)的确认:

CH592 的 BLE_SNV_NUM 最大值为 32 × 4 = 128 个,改宏与 BLE_SNV_ADDR 配合使用,每 256 字节可以多存放一个设备

算术验证

参数 计算 结果
单个设备占用 256 B(协议栈按块对齐) 256 B
128 个设备总需求 128 × 256 B 32,768 B = 32 KB
CH582/CH592 DataFlash 总容量 32 KB

结论:128 个绑定的理论上限是 32 KB DataFlash 全部给 SNV 用时实现的。

但"理论上"不等于"实际工程可用"

场景 占用 DataFlash 剩余用户空间 可行性
默认 1 个绑定 256 B ~31.7 KB ✅ 正常
6 个绑定 1,536 B ~30.5 KB ✅ 正常
128 个绑定(理论极限) 32 KB 0 KB ⚠️ 前提:不开 MESH、不用 OTA 标志、不存任何用户数据
128 绑定 + MESH(12 KB) 44 KB -12 KB 溢出,编译报错 / 运行崩溃

实际工程建议

你的需求 建议 SNV 数量 配置要点
普通 BLE 从机(连 1~2 台手机) 1 ~ 4 默认即可,改 BLE_SNV_NUM
蓝牙键盘(连 3 台电脑切换) 3 ~ 6 BLE_SNV_NUM=6,确保 BLE_SNV_ADDR 后有足够空间
需要配对很多设备(如门禁系统) 10 ~ 32 需要关闭 MESH,释放前 12 KB
超过 32 个绑定 不推荐用 CH582M 考虑改用 Nordic nRF 系列(NVS 存储更灵活)或外接 SPI Flash 存配对信息

📌 核心认知:Deepseek 说的"理论上最多 128 个"数字本身是对的,但隐含的"全占 DataFlash"条件必须明确。实际工程中,128 个绑定 = 放弃 MESH、放弃 OTA DataFlash 标志、放弃所有用户数据存储——绝大多数场景下做不到。按需调整 BLE_SNV_NUM,不要盲从理论上限。


7. 能扩展 Flash 容量吗?

问题 答案 说明
CodeFlash 能扩展吗? ❌ 不能 物理上限 448 KB,改不了
DataFlash 能扩展吗? ❌ 不能 物理上限 32 KB,改不了
总 Flash 能扩展吗? ❌ 不能 512 KB 是芯片物理容量
但可以通过重新分区释放空间吗? ✅ 可以 不需要 OTA 时,可释放 152 KB OTA 区
外接存储扩展可行吗? ✅ 推荐 通过 SPI 外接 Flash/EEPROM/SD 卡

实用策略

  1. CodeFlash 不够:如果程序超过 152 KB(APP 区),要么换 CH585(128 KB SRAM,但 CodeFlash 也是 448 KB),要么优化代码、关闭不需要的 BLE 功能,或者外接 SPI Flash 存储大资源(如字库、图片)。
  2. DataFlash 不够:32 KB 对于配置参数、历史数据很快会满。推荐做法:
  3. 频繁变化的数据 → 外接 SPI Flash(如 W25Q128,16 MB)
  4. 小量配置参数 → 用 DataFlash 的 0x3000 ~ 0x6FFF 区域(约 16 KB 可用)
  5. 极简配置 → 直接复用 OTA 标志位附近的空闲区(谨慎)
  6. RAM 不够:32 KB SRAM 跑 BLE 协议栈后只剩约 10~15 KB 给用户。如果不够,直接升级 CH585(128 KB SRAM)或 CH592(26 KB SRAM,反而更小)。

8. 外接存储扩展方案

既然片上 Flash 和 DataFlash 都受限于物理容量,外接存储芯片就成了扩展的核心手段。CH582M 有 1 组 SPI 和 4 组 UART,可以通过 SPI 接口挂载各种存储器。

8.1 三种主流外接存储方案对比

特性 EEPROM(AT24C 系列) SPI Flash(W25Q 系列) FRAM(FM25L 系列)
接口 I2C(CH582M 无原生 I2C,需软模拟或外挂) SPI(硬件支持) SPI(硬件支持)
典型容量 1 KB ~ 1 MB 512 KB ~ 256 MB 4 KB ~ 1 MB
擦写单位 字节级(可单字节改写) 4 KB 扇区(必须整块擦) 字节级(直接覆盖,无需擦除)
写入速度 慢(~5 ms / 字节) 中等(~100 µs / 页,但擦除 ~16 ms) 极快(~150 ns / 字节)
擦写寿命 10 万 ~ 100 万次 10 万次 10 亿次(10¹⁴)
数据保持 10 年 @ 85°C 20 年 @ 85°C 45 年以上
功耗(写) ~3 mA ~15 mA ~150 µA
典型单价 ¥0.5 ~ 2(小容量) ¥1 ~ 5(常用 8 MB) ¥10 ~ 50(较贵)
最佳场景 配置参数、密码、校准值 固件、字库、图片、日志、大数据 高频事件记录、医疗数据、实时日志

📌 核心差异:EEPROM 和 FRAM 都是字节可改写,不用先擦除;Flash 必须先擦 4 KB 再写。FRAM 的寿命和速度碾压前两者,但价格也贵。

8.2 选型决策树

需要存什么?
├── 配置参数(几十 ~ 几百字节)
│   ├── 更新频率低(一天几次)  →  DataFlash 或 AT24C02
│   └── 更新频率高(一秒几次)  →  FRAM(FM25L256)
├── 日志/历史数据(KB ~ MB 级)
│   ├── 只追加、不频繁擦写       →  SPI Flash(W25Q64)
│   └── 频繁覆盖、循环记录       →  SPI Flash + 磨损均衡算法
├── 字库/图片/音频资源(MB 级)
│   └── 只读、偶尔更新           →  SPI Flash(W25Q128)
└── 固件备份/OTA 包
    └── 大容量、一次性写入       →  SPI Flash(W25Q64 / W25Q128)

8.3 与 CH582M 的接口对接建议

外接芯片 接口方式 CH582M 连接 注意点
W25Q64(8 MB SPI Flash) SPI 硬件 MOSI→PA12, MISO→PA13, SCK→PA14, CS→任意 GPIO SPI 速率可达半主频(40 MHz @ 80 MHz),读写极快
AT24C02(256 B I2C EEPROM) GPIO 模拟 I2C 任意 GPIO 软模拟 速率低(~100 kHz),但省引脚
FM25W256(32 KB FRAM) SPI 硬件 同 W25Q64 写操作无需等待,可像 RAM 一样随机写
SD 卡(microSD) SPI 模式 同 SPI Flash FAT 文件系统可用 FatFs,适合大容量日志

8.4 实用策略:分级存储架构

最成熟的方案是把存储按访问频率和重要性分层:

层级 存储介质 存放内容 访问策略
L1 片上 DataFlash BLE 配对信息、设备 ID、校准参数 开机加载,运行时只读
L2 外接小容量 EEPROM / FRAM 用户设置、运行配置、实时计数器 按需读写,频繁更新
L3 外接大容量 SPI Flash / SD 卡 日志、字库、图片、音频、OTA 包 批量读写,顺序/追加为主

💡 示例:一个 BLE 温湿度传感器 - DataFlash:存设备名称、广播间隔、配对密钥 - 外接 W25Q64:存 30 天的温湿度历史数据(每 10 分钟一条) - 如果需要 1 秒级高频记录 → 换 FRAM,或做 RAM 缓冲 + 定期批量写入 Flash

8.5 关于"扩展"的最终总结

问题 答案
片上 Flash 能物理扩展吗? ❌ 不能,448 KB CodeFlash + 32 KB DataFlash 是硬上限
程序代码超过 152 KB 怎么办? ① 关闭 OTA 释放 152 KB;② 精简代码;③ 换 CH585(也是 448 KB,但 RAM 大)
用户数据超过 32 KB 怎么办? 外接 SPI Flash(W25Q64/W25Q128),性价比高,最常用
频繁写入的参数怎么存? 外接 EEPROM(AT24C)FRAM(FM25L),按擦写频率和预算选
日志类大数据怎么存? 外接 SPI Flash + 环形缓冲区/日志文件系统,做好磨损均衡

🔑 核心心法:CH582M 的片上存储是"精打细算型",用 DataFlash 存关键的、掉电必须保的少量配置;用外接存储兜底大容量和频繁写入。不要试图把所有东西塞进 32 KB DataFlash 里——那是给自己找不痛快。


参考文献

本文内容基于以下资料整理与验证:

来源 标题/说明 关键信息
WCH 产品页 沁恒 CH583/CH582 产品页 核心规格、外设参数
WCH 下载中心 CH583DS1.PDF 数据手册 Flash 分区、地址映射、擦写参数
WCH 社区论坛 【SNV】BLE_SNV 相关问题 官方确认:CH592 的 BLE_SNV_NUM 最大值为 128 个,每 256 字节多存一个设备
WCH 社区论坛 ch571 Peripheral dataflash 问题 DataFlash 中蓝牙库保存了数据,需避开系统区域
WCH 社区论坛 ch582 dataflash 讨论 蓝牙绑定占用 DataFlash 最后 256 字节,操作接口说明
WCH 社区论坛 CH582 BLE MESH DataFlash 问题 MESH 默认使用 DataFlash 前 12 KB,修改扇区配置
CSDN 博客 沁恒 RISC-V 蓝牙芯片 Flash 分区优化 Flash 地图、SNV 位置、分区数据
CSDN 博客 【沁恒蓝牙 mesh】CH58x flash 分区与数据存储管理 DataFlash 偏移地址、MESH 存储区域、SNV 地址
博客园 CH573/571/CH583/582/CH592/591 内部 flash 和 eeprom 的读写 CodeFlash / DataFlash 地址范围、读写接口说明
立创商城 CH582M 商品参数 工作电压、ADC 位数、GPIO 数量等