关于VM、蓝牙配置区和4K预留区
📎 原始文档:https://www.kdocs.cn/l/ciXKzmpZQUMy 关于VM、蓝牙配置区和4K预留区
- VM、蓝牙配置区和4K预留区在flash中的分布 各区域配置由isd_config_rule.c或者isd_config.ini文件决定
- 单备份
| uboot | |
|---|---|
| code | |
| VM(VMIF) | |
| 蓝牙配置区(BTIF) | |
| 其他预留区(可有可无) | 自定义区域1 |
| 自定义区域2 | |
| ...... | |
| 4K预留区 |
- 双备份
| uboot | |
|---|---|
| code1 | |
| code2 | |
| VM(VMIF) | |
| 蓝牙配置区(BTIF) | |
| 其他预留区(可有可无) | 自定义区域1 |
| 自定义区域2 | |
| ...... | |
| 4K预留区 |
- VM 在代码中,VM的地址、大小配置,最终由isd_config_rule.c或者isd_config.ini文件决定

VM_ADR
此项的值表示VM区的起始地址,此项的值为0时,表示VM地址由程序自动分配,否则VM地址固定为指定地址(按照flash物理地址来分配,例如flash 8Mbit,想要把VM区放在flash倒数第4个4K的位置,则可配置为0xfc000),但要注意指定的地址不能与其他区域冲突或者超过flash大小。
双备份的代码结构下,建议固定地址,避免空间浪费,还能避免代码空间变化导致VM被擦除,常用的地址为0xfc000(flash 8Mbit,下面的VM_LEN=8K)。
VM_LEN
此项的值表示VM区的最小值,当VM_ADR=0时,实际VM大小可能会大于VM_LEN,单备份代码需要测试盒无线升级时,VM_LEN要大于等于32K,双备份时可调整为8K节约空间。
VM_OPT
此项的值表示每次升级代码时需要对VM进行什么操作,为0时表示擦除VM,为1时表示不操作VM(但是当代码大小变动影响到VM地址或者VM大小时,VM也会被擦除),为2时表示保护VM(一般不用)。
该配置的作用范围是所有普通升级方式:强制升级工具升级、测试盒串口升级、测试盒蓝牙无线升级、杰理之家OTA;而第三方被动式双备份升级时不操作VM(使用db_update_data.bin文件升级的方式),比如涂鸦OTA。
3. 蓝牙配置区 
BTIF_ADR
此项的值表示蓝牙配置区的地址,此项值不要改动,默认为AUTO,由程序自动分配。
BTIF_LEN
此项的值表示蓝牙配置区的大小,此项值不要改动。
BTIF_OPT
此项的值表示每次升级代码时需要对蓝牙配置区进行什么操作,为0时表示擦除蓝牙配置区,为1时表示不操作蓝牙配置区(因为蓝牙配置区始终排在VM后面,在无自定义区域的情况下,蓝牙配置区的地址会被固定在flash倒数第二个4K的位置,配置为1不会存在擦除蓝牙配置区的情况),为2时表示保护蓝牙配置区(一般不用)。
该配置的作用范围是所有普通升级方式:强制升级工具升级、测试盒串口升级、测试盒蓝牙无线升级、杰理之家OTA;而第三方被动式双备份升级时不操作蓝牙配置区(使用db_update_data.bin文件升级的方式),比如涂鸦OTA。
4. 4K预留区 4K预留区是大部分芯片SDK默认预留的flash空间,大小为4K,固定在flash最后4K的位置,用于存放一拖二、一拖八烧录的蓝牙地址、认证码等信息。
该区域一般只有在一拖二、一拖八烧录时才会被擦除。
5. ANC区域 SDK开启ANC功能后,会默认开辟存放anc参数的区域,不同的flash大小需要使用不同的anc区域地址,否则会报空间异常,具体修改isd_config_rule.c或者isd_config.ini中的ANCIF_ADR和ANCIF1_ADR
6. 自定义区域 用户可以自己在flash中开辟一块区域存放数据
新增自定义区域:修改isd_config_rule.c或者isd_config.ini,划一块区域使用,如需在区域中默认放一个文件,使用FILE配置
USER_FILE = user.bin //如需在区域中默认放一个文件,参考此配置
USER_ADR = 0x1f1000;
USER_LEN = 32K;
USER_OPT = 1;
读写demo(需要在apps\earphone\sdk_used_list.c中打开sdfile_vfs_ops):
RESFILE *file = resfile_open("flash/app/USER");
if(file){
printf("file open suss\n");
int ret = resfile_seek(file, 0, SEEK_SET);
printf("file seek %d\n", ret);
u8 data_w[32];
for (int i = 0; i < 32; i++)
{
data_w[i] = rand32()%255;
}
struct resfile_attrs file_attrs = {0};
ret = resfile_get_attrs(file, &file_attrs);
printf("file attrs %d %d %d\n", ret, file_attrs.fsize, file_attrs.sclust);
//擦除开始==================================================================
u32 file_flash_addr = sdfile_cpu_addr2flash_addr(file_attrs.sclust);
u32 erase_unit = 4096;
u32 erase_size = 0;
u32 total_size = file_attrs.fsize;
u32 erase_cmd = IOCTL_ERASE_SECTOR;
#include "boot.h"
if (boot_info.vm.align == 1) {
erase_unit = 256;
erase_cmd = IOCTL_ERASE_PAGE;
}
do {
int ret = norflash_ioctl(NULL, erase_cmd, file_flash_addr);
printf("norflash_ioctl ret %d , 0x%x, %d, %d", ret, file_flash_addr, erase_size, total_size);
file_flash_addr += erase_unit;
erase_size += erase_unit;
} while (erase_size < total_size);
//擦除结束==================================================================
ret = resfile_write(file, data_w, 32);//写入
printf("file write %d\n", ret);
u8 data_r[32];
memset(data_r, 0, 32);
ret = resfile_seek(file, 0, SEEK_SET);
ret = resfile_read(file, data_r, 32);//读取
printf("file read %d\n", ret);
put_buf(data_r, 32);
resfile_close(file);
}
else{
printf("file open fail\n");
}
特殊情况的处理
部分SDK对 [RESERVED_CONFIG] 的数量有限制,不能超过6个,如果超过6个会不开机,这个时候需要将用户自定义区域增加在 [RESERVED_EXPAND_CONFIG] 下,文件路径使用"flash/EXT_RESERVED/区域名"。
如果开了ANC,还需要把ANCIF的区域往前挪(自定义区域多大, ANCIF_ADR和 ANCIF1_ADR就往前挪多少)。
7. 查看各个区域实际地址和大小 
单备份
-----------------------------------FLASH INFO------------------------------------
| FLASH_BIN_SIZE : 0xb9000 |
| FLASH_NEED_SIZE : 0xff000 |
| FLASH_REAL_SIZE : UNLIMITED |
| VM_REAL_SIZE : 0x45000 |VM区的实际大小
| VM_START_ADDR : 0xb9000 |VM区的起始地址
| VM_END_ADDR : 0xfe000 |VM区的结束地址
| BTIF_SIZE : 0x1000 |蓝牙配置区的大小
| BTIF_START_ADDR : 0xfe000 |蓝牙配置区的起始地址
| BTIF_END_ADDR : 0xff000 |蓝牙配置区的结束地址
| LAVE_SIZE : 0x3b000 |剩余未分配使用的空间
| ENTRY_ADDR : 0x6000100 |
| ERASE MODE : NONE |
| UBOOT VERSION : 2025-10-09 13:57:27,uboot-$-@20251009-$589b1b3 |
| OTA VERSION : 2025-07-25 11:44:50,OTA_LOADER-$-@20250725-$79186ddc |
代码区空间计算:
代码区空间 = VM_START_ADDR - UBOOT大小(4K对齐)
代码区剩余空间 = VM_START_ADDR - jl_isd.bin大小(含UBOOT)
双备份
---------------------------------FLASH INFO----------------------------------
| PID : AC700N |
| VID : 0.01 |
| FLASH_BIN_SIZE : 0x6a000 |
| FLASH_NEED_SIZE : 0xff000 |
| FLASH_REAL_SIZE : 0x100000 |
| VM_REAL_SIZE : 0x8000 |VM区的实际大小
| VM_START_ADDR : 0xf6000 |VM区的起始地址
| VM_END_ADDR : 0xfe000 |VM区的结束地址
| BTIF_RESERVED_START : 0xfe000 |蓝牙配置区的起始地址
| BTIF_RESERVED_END : 0xff000 |蓝牙配置区的结束地址
| CODE_BOUNDARY_LINE : 0x7b000 |双备份代码区code1和code2的分界线(双备 份才有)
| LAVE_SIZE : 0x11000 |剩余未分配使用的空间
| ENTRY_ADDR : 0x1e00100 |
| ERASE MODE : NONE |
| UBOOT VERSION : 2023-01-06 18:58:49,UBOOT-$-@20230106-$a547aba |
|---|
| 代码区空间计算: |
| 代码区空间 = CODE_BOUNDARY_LINE - UBOOT大小(4K对齐) |
| 代码区剩余空间 = 代码区空间 - db_update_data.bin大小(不含UBOOT) |
| jl_isd.bin ≈ db_update_data.bin + UBOOT |
- 第三方配置文件 需要在代码区中加入第三方配置文件,使用download.bat打包。
读取demo
#define RES_CUSTOM_CFG_FILE FLASH_RES_PATH"user.bin"
void res_file_read_demo(void)
{
RESFILE *fp = NULL;
fp = resfile_open(RES_CUSTOM_CFG_FILE);
if (!fp) {
puts("file open fail");
return;
}
u8 buf[512];
fseek(fp, SEEK_SET, 0);
int r_len = resfile_read(fp, (void *)buf, sizeof(buf));
if (r_len != sizeof(buf)) {
puts("file read cfg head fail\n");
resfile_close(fp);
return;
}
resfile_close(fp);
}