沁恒 RISC-V 蓝牙芯片 FLASH 操作以及分区管理 ...... 矜辰所致
前言
要合理使用一块芯片,熟悉其内部 Flash 的分区管理是必不可少的。
本文我们说明一下沁恒 RISC-V 蓝牙芯片 Flash 的分区以及读写操作。
我是矜辰所致,全网同名,尽量用心写好每一系列文章,不浮夸,不将就,认真对待学知识的我们,矜辰所致,金石为开!
目录
- 前言
- [一、 Flash 分区](#一、 Flash 分区)
-
- [1.1 基本分区介绍](#1.1 基本分区介绍)
- [1.2 BLE 应用使用区域](#1.2 BLE 应用使用区域)
- [二、 FLASH 读写](#二、 FLASH 读写)
-
- [2.1 函数说明](#2.1 函数说明)
- [2.2 Flash 操作注意事项](#2.2 Flash 操作注意事项)
- [2.3 擦写时间和寿命](#2.3 擦写时间和寿命)
- [三、 补充说明(部分型号特殊性说明)](#三、 补充说明(部分型号特殊性说明))
- 结语
一、 Flash 分区
本文以 CH585 芯片为例,其他芯片都可根据手册和代码确定,方法在文中会有说明。
1.1 基本分区介绍
在官方的芯片手册《CH585DS1》文档中,第一页芯片介绍的时候就有说明:

在文档第 2 章《系统结构及存储器》 2.3 小结也有表格说明:

本文我们讨论的是 Flash 存储器区域,对应的映射地址是:0x0000 0000 ------ 0x0007 FFFF 的部分。
其他系列的芯片手册也有明显的标注,可以自行查看。
针对上面的的官方说明,我绘制了一张图示说明:

目前来说 CH585 在沁恒微 32 位 RISC-V 里面此系列芯片中 Flash 和 SRAM 是最大的了,除了另一个带以太网接口的 CH32V208 系列达到 480K Flash。
InfoFlash 区域保存了一些出场信息,类似 芯片 ID 、RF 频偏、LDO 校准等等信息,不建议改(虽然手册上提示部分区域可以配置)。
BootLoader 区域官方的 BootLoader 主要用来做产品 ISP 下载升级的工作,产品能够 USB 下载,串口下载,串口免按键下载全靠它了。
DataFlash 和 CodeFlash 就是官方帮客户区分好的 Flash 区域,一个区域用来放代码,一个区域用来放掉电保存的数据。在工程中对两个区域操作的函数也不一样,这个在本文后面会有测试说明。
要明确知道的是,它们和上面两块区域本质上是都是同一块 Flash 区域,只是官方为了方便应用,自己划分了开了不同的区域。 理论上,用户是可以自己区分的,只不过官方的示例和很多软件是配合了这个分区开发使用的,这里并不建议开发者胡来。
1.2 BLE 应用使用区域
应用区域即便是同一芯片不同版本的 EVT 可能会有调整,随着系列芯片的不断推出,需要做一些兼容,以官网最新为例,在应用上用户是可以自行修改的。
上面的0x0007 0000 ~ 0x 0007 8000 区,即 DataFlash 区是留给客户保存数据的部分,但是如果使用蓝牙应用,蓝牙配对,Mesh 组网,OTA 升级等的数据也被保存在这部分区域,用户需要注意一下如果使用到对应的部分功能自己的数据不要和这些数据重叠了,当然用户也可以自己修改地址存放,直接在程序中修改宏定义即可 。
这里我们也用一张示意图来说明一下:
再次提醒一下,下图区域为 Flash 的0x0007 0000 ~ 0x 0007 8000 区域。不同芯片的地址可能有区别,具体的可查看代码中的定义。

上面这些区域的划分在代码中都有体现的,只是刚学习的时候,很容易搞不清楚。
大家可以自己打开工程查看,比如在主机工程中的CONFIG.h 文件中(这个文件怎么快速找到,通过某些通用的宏定义跳转就过来了,比如#if(defined(BLE_MAC)) && (BLE_MAC == TRUE) 中的 BLE_MAC),有关于 BLE 配对绑定信息存储区域的宏定义如下:

如果使用蓝牙 Mesh,在配网发起者例程provisioner_vendor 中的app_mesh_config.h 中有关于 Mesh 网络信息存储区域的宏定义如下:

在带有 OTA 功能的工程中 ota.h 中有 OTA 标志位存放的地址:

这里特别说明,上面 BLE_SNV_ADDR 和OTA_DATAFLASH_ADD 重复了,是因为确实博主目前手头的 EVT 包就是这样的,写错了,已经和沁恒微工程师反馈确认。 但为什么我上面写出图表说明,是因为和沁恒微工程师请教过,默认 DataFlash 应用就是上图那么区分。只是后来出了不同的芯片做兼容,可能一下忽略了,但是沁恒微的 FAE 响应速度还是很快的, 相信很快就能改正 。
二、 FLASH 读写
那了解了 Flash 的分区,我们来学习一下 Flash 的读写操作。
这个官方提供了现成的示例:

先跑一遍示例,再来看后面,读写数据太简单了,大家自己过一遍即可。
2.1 函数说明
库函数把操作 DataFlash 和 CodeFlash 的函数做了区分。
DataFlash 操作(带 EEPROM 名字):
- 读
EEPROM_READ(StartAddr,Buffer,Length) - 擦除
EEPROM_ERASE(uint32_t StartAddr, uint32_t Length) - 写
EEPROM_WRITE(StartAddr,Buffer,Length)
CodeFlash 操作(带 FLASH_ROM 名字):
- 读
FLASH_ROM_READ(uint32_t StartAddr, void *Buffer, uint32_t len) - 擦除
FLASH_ROM_ERASE(StartAddr,Length) - 写
FLASH_ROM_WRITE(StartAddr,Buffer,Length) - 校验
FLASH_ROM_VERIFY(StartAddr,Buffer,Length)
2.2 Flash 操作注意事项
-
首先是大家跑示例会发现读取 Codeflash ,擦除后读出来并不是 0xFF,这是正常的,MCU内核有加解密。

-
Codeflash 最小擦除单位为 4096字节。
-
DataFlash 操作函数的地址参数都是基于
0x70000的 基地址的偏移,比如EEPROM_READ(0, TestBuf, 500);就是从Flash 地址为0x70000的位置读取数据。 -
DataFlash 最小擦除单位为 256字节(CH585)。
-
操作 Flash 的函数,在库中已包含失能/恢复中断 ,无需应用层代码再添加。
-
写 Flash之前一定要擦除,不论是 DataFlash 还是 CodeFlash
-
操作 CodeFlash ,地址,长度,
buffer长度,都按 4 字节的整数倍!!!不按照4字节出问题的情况太多了= =!
-
操作 DataFlash 相对要求没那么严格,在 CH585 上是可以 1 字节操作的,我做了个测试:

但是官方建议4字节对齐,考虑到通用性和移植, 地址还是建议 4 字节对齐。
根据官方的宏,列了个表格:
| 概念 | 官方宏 | 数值 | 分区 | 备注 |
|---|---|---|---|---|
| Page(页) | EEPROM_PAGE_SIZE |
256 B | ||
| Block(块) | EEPROM_BLOCK_SIZE |
4096 B | ||
| Data-Flash 最小擦除 | EEPROM_MIN_ER_SIZE |
256 B | Data 区 | 可单页擦,也可整块擦 (CH585) |
| Code-Flash 最小擦除 | 注释里说明 | 4096 B | Code 区 | 只能用4 KB (页)擦 |
| 最小写粒度 | EEPROM_MIN_WR_SIZE |
1 B | Data 区 | 实际硬件仍 4 B 对齐,库自动补 |
| 最小写粒度 | FLASH_MIN_WR_SIZE |
4 B | Code 区 | 必须 4 B 倍数,否则 HardFault |
2.3 擦写时间和寿命
这部分直接在官方芯片手册的最后 参数 章节里有说明,沁恒 RISC-V内核的 CH5Xx 蓝牙 MCU 此处参数相差不大。

注: 上面文字中的 "扇区" 即为 Block(块)4096 字节。
三、 补充说明(部分型号特殊性说明)
本小节作为补充内容,记录一下一些特别型号的说明,保持持续更新...
- CH592A 和 CH584X 的 Dataflash 和 CodeFlash 擦除单位都为 4K !
所以他们的 DataFlash 中 Ble 配对绑定数据存储地址为0x7 7000,偏移0x7000。
结语
本文主要给大家介绍了 CH585 芯片的内存分布,读写操作。
东西并不复杂,但是切记要牢记注意事项,这里建议大家在以后应用中,只要是 Flash 写操作都按照 4 字节对齐来操作,避免不必要的麻烦。
好了,本文就到这里。谢谢大家!