升级相关
📎 原始文档:https://www.kdocs.cn/l/cqfnKL2xsDQG ota升级相关
概述:
按照有线无线分为两种升级方式:
- OTA升级:通过无线方式升级的,统称为OTA升级,如wifi/蓝牙
- 本地升级:通过有线方式升级的,统称为本地升级,如uart,usb,sd卡
按照固件覆盖方式分为两种模式:
- 单备份升级 优点:flash资源占用较少 缺点:升级过程中断,固件只能待在loader代码,或新固件有异常,设备运行异常。
- 双备份升级 优点:升级出现异常仍有一块正常运行的代码块 缺点:flash资源占用多
按照用户体验感分为两种下载: - 后台式下载 需要双备份升级方式
- 非后台下载 单双备份升级方式均可以实现
graph TD;
A[准备升级固件和上位机软件] --> B[连接串口设备与电脑];
B --> C[打开上位机软件,选择串口和升级文件];
C --> D[发送升级指令];
D --> E[设备进入升级模式,擦除原固件存储区];
E --> F[通过串口接收新固件数据并写入存储区];
F --> G[校验新固件的完整性和有效性];
G --> H{校验是否成功};
H -->|是| I[更新引导程序,指向新固件];
H -->|否| J[提示升级失败,可选择重新升级];
I --> K[重启设备,运行新固件];
目前杰理支持以下升级方式(可以在编译完成后的构建记录中查看)
需要支持的升级,需要满足两个条件,1、VM区空间大小大于升级代码,2、代码中开启相应的升级方式
注意:VM区域空间大小在 cpu\brxx\tools\isd_config.ini 中查看,soundbox系列SDK默认给32K空间大小。
ota.bin
ota.bin包含各种方式的升级代码(loader代码)
一、跳转升级维持IO电平
AC695&AC696音箱SDK
维持电平的IO必须是ROM后的IO(用户手册资料有标哪些IO是ROM后的IO)
具体修改
- 打开跳转升级的宏定义DEV_UPDATE_SUPPORT_JUMP
#if (defined(CONFIG_CPU_BR23) || defined(CONFIG_CPU_BR25))
//升级IO保持使能
#define DEV_UPDATE_SUPPORT_JUMP //目前只有br23\\br25支持
#endif
- isd_config.ini文件中打开跳转升级
UPDATE_JUMP=1;
注意:打印为跳转升级 3. 如果出现SD卡跳转升级时软件复位(正常应该是电源复位)导致40ms左右的电平被拉低问题。 解决方法:
修改update.c文件的这两处位置
相关补丁以及问题修复补丁
- AC695N_soundbox_sdk_release_3.1.0
- 注意 update_close_hw调用方法update_close_hw("null");
- dmeo
701音箱 维持(锁住)IO状态 SD、U盘升级
注:测试sdk为jl701n_soundbox_release_v1.2.0
- 所需文件下载
- 开启CONFIG_UPDATE_JUMP_TO_MASK宏
维持的IO口要在此处前配置
- SD卡需要设置维持(锁住)io,U盘不需要设置
SD_LATCH_IO = PB02_PB08_USBDP; //SD卡升级需要锁住的io,最大限制10个io,
//如包含T卡升级功能,需要维持SDPG脚和MOS管的维持脚位
4. SD卡有升级文件上电死机 
701音箱 维持(锁住)IO状态 OTA升级
注:测试sdk为jl701n_soundbox_release_v1.4.2,维持(锁住)IO状态 SD、U盘升级只需修改下面第一点开启CONFIG_UPDATE_JUMP_TO_MASK宏即可;
软件修改
- 开启CONFIG_UPDATE_JUMP_TO_MASK宏

- 维持的IO口要在此处前配置

- 软件添加代码如下图

- 升级完之后没有播放升级成功提示音,如果下修改


695音箱 维持(锁住)IO状态 OTA升级
- 默认SDK使用的是 cpu_reset(); 进行复位,所以会导致IO口无法维持 修改方法:
static void rcsp_update_before_jump_handle(int type)
update_close_hw();
ram_protect_close();
save_spi_port();
printf("update jump to mask...\n");
二、串口升级
- 696/695升级流程
详细命令说明可以查看下面文档
杰理串口升级规范.pdf
AC696N串口升级说明.pdf
升级相关说明.pdf
备注:部分芯片串口升级流程:跳转到loader前是没有stop命令回复上位机。蓝牙设备加载完loader会直接发start,此时上位机可以不必等待stop命令 - 实现代码 使能 USER_UART_UPDATE_ENABLE 的宏定义及 配置串口升级的角色
#define USER_UART_UPDATE_ENABLE 1//用于客户开发上位机或者多MCU串口升级方案
#define UART_UPDATE_SLAVE 0
#define UART_UPDATE_MASTER 1
//配置串口升级的角色
#define UART_UPDATE_ROLE UART_UPDATE_SLAVE
- demo 从机
【金山文档】 串口升级(从机)_AC695N_soundbox_sdk_release_2.0.0 https://kdocs.cn/l/cmuzJNKZbqia
【金山文档】 串口升级(从机)_AC695N_soundbox_sdk_release_3.0.0 https://kdocs.cn/l/cdVfTSHfqSyp
【金山文档】 串口升级(从机)_AC695N_soundbox_sdk_release_3.1.0. https://kdocs.cn/l/cqnQzOwQebWl
【金山文档】 串口升级(从机)_ac696n_soundbox_sdk_v1.7.0 串口升级(从机)_ac696n_soundbox_sdk_v1.7.0.7z
703 串口从机升级
JL703N音箱问题整理.otl
706串口从机升级
PC串口升级工具SerialUpdateDemo-20260716.exe
设置普通io为串口主从升级功能
主机
- 升级流程一致,主机代码可以通用
- 主从串口接好线之后,把ufw升级文件放入U盘,U盘插入主机即可升级从机 【金山文档】 串口升级(主机)_AC695N_soundbox_sdk_release_2.0.0(通用)
https://kdocs.cn/l/cmk8ITK4f1Lt
使用的IO
.rx = IO_PORTA_02,
.tx = IO_PORTA_03,
703 串口主
JL703N音箱问题整理.otl
相关补丁文件
- AC695N_soundbox_sdk_release_3.0.0~AC695N_soundbox_sdk_release_3.1.0 更新dev_update.c uart_update.c update.c文件,链接如下:
【金山文档】 串口升级(从机)_AC695N_soundbox_sdk_release_3.0.0~3.1.0修改文件.zip
- AC692/AC690串口升级说明 【金山文档】 AC690AC692-UART串口升级协议
AC690AC692-UART串口升级协议.pdf
【金山文档】 串口升级(主机)_AC695N_soundbox_sdk_release_2.0.0(通用)
使用参考:README.TXT
注意:AC692X/AC690X 串口升级调式时,请先使用SDK中配置的默认串口组。调式完整之后,若需要更换串口组,再联系我们修改uboot提供
三、测试盒升级
1、无线升级报空间错误
A、报错误码 01 升级文件大小错误
1、该报错的原因是编译生成的 (jl_isd.bin + VM区 + 蓝牙配置区)大于或等于 flash 空间大小引起。 需要压缩空间处理。
以下是查看jl_isd.bin 、VM区 、蓝牙配置区 大小的地方(以下是以AC700X 为例,其他系列基本一致):

备注:也可以用强制升级工具,通过USB线,编译工程下载程序到样机中。用于判断烧录文件大小是否达到要求。如果能正常下载,则说明烧录文件大小没有超flash空间。如果下载失败,提flash大小问题,则说明烧录文件大小已经超过flash 空间:
2、压缩代码空间常见的几种方法:
a、检查代码工程,把用不到的功能都关掉,打印也要关掉。占用空间比较大的解码和编码格式,用不到的要关掉。
AC695X 解码格式(能关则关,这里以AC695X 为例,其他系列雷同):
AC695X 编码格式(能关则关,这里以AC695X 为例,其他系列雷同):
b、把用不到的提示音都去掉、选用低音质提示音编码格式(如果客户要求高音质提示音,可以沟通将一些常播放的提示音选择为中、高音质,其他提示音选择为低音质)

c、可以根据实际应用需求,可以适当把VM区压缩。注意:压缩VM区会影响测试盒无线升级,如果是带卡或U盘,会影响到断点保存,因此修改之后请做好测试,达到需求再进行量产。
(以下是AC697X 修改的地方)
有的系列IC工程,VM区修改是在代码中的global_build 配置文件中修改的。所以请自行区分,以下是AC700X为例:

d、提示音前后部分静音部分删掉:
B、报错误码 02 update loader大小错误
1、该报错是由于测试盒OTA无线升级需要VM区做数据缓存,VM区不够大引起的报错。需要调大VM区大小处理。
(VM区大小修改请参考以上“A、报错误码 01 升级文件大小错误”部分处理)
2、若出现同一份程序部分机子升级出现报错 02 update loader大小错误,其他机子可以正常升级的情况。其原因是芯片封装的flash 有4K block擦除的,也有256 byte擦除的。针对4K擦除的芯片,要支持测试盒无线升级的话,需要更多的VM缓存,导致了这个差异。
处理方法只能是,将程序都统一做强制擦除4K,以达到一致性。(这个修改并不是使4K擦除的样机能正常OTA升级,而统一用4K擦除计算,让256 byte 擦除的机子也无法OTA升级。之后加大VM区大小处理,若加大VM区后,发现烧录文件超过flash 空间,请参考以上“A、报错误码 01 升级文件大小错误”部分处理)

SPECIAL_OPT=0;
FORCE_4K_ALIGN=YES;
3、如何查看,测试盒无线升级需要多大的VM空间:用强制升级工具,通过USB线下载程序到样机,然后查看下载界面信息:
备注:若下载界面没有这个信息,则需要更换以下isd_download.exe 文件:
【金山文档】 下载程序时能否显示测试盒无线升级需要多少VM空间的isd_download文件
https://kdocs.cn/l/cu3k4pakK5iY
2、696音箱SDK测试盒串口升级失败
按下图修改:
四、手机OTA升级(BLE RCSP升级)
关键字:OTA升级;OTA;手机OTA升级
1、固件端程序设置
(AC697X、AC700X、AC695X、AC696X基本一致)
AC700X (参考):


AC697X (参考):

demo 程序:
【金山文档】 AC700N_earphone_release_V1.3.0(手机OTA升级测试OK)
https://kdocs.cn/l/cnsncL3EGl4e
【金山文档】 jl701n_soundbox_release_v1.4.1_BLE_RCSP升级
jl701n_soundbox_release_v1.4.1_BLE_RCSP升级.zip
jl701n_soundbox_v1.4.3beta2-OTA-双备份-维持io.7z
AC695双备份升级demo:
695_310_sdk_dual_update_250701.rar
2、APP端说明
SDK仅支持OTA功能,可更新附件OTA的APK来测试功能和开发接入。用于本地测试,或者接客户自己服务器。请发给有需要的客户。
安卓开发仓库路径:珠海杰理科技/Android-JL_OTA (gitee.com)
apk下载:https://www.pgyer.com/otaJ
IOS 开发仓库路径:珠海杰理科技/iOS-JL_OTA (gitee.com)
apk下载:appstore
【金山文档】 iOS杰理OTA升级开发资料v2.0.0https://kdocs.cn/l/cvwG5KTbXLxn【金山文档】 jl_bt_ota_V1.6.0开发资料https://kdocs.cn/l/cg8hmAhuTwrF
五、双备份升级
A.双备份存储结构介绍
| uboot | |
|---|---|
| code0 | |
| code1 | |
| VM(VMIF) | |
| 蓝牙配置区(BTIF) | |
| 其他预留区(可有可无) | 自定义区域1 |
| 自定义区域2 | |
| ...... | |
| 4K预留区 |
- 双备份存储结构有两个app code区域
- 当运行app code 0时,升级时将新固件写入app code 1区域,反之亦然
- 升级时对app code N区域数据校验成功后,更新启动标志,复位后即可运行app code N代码
- 当升级中断或者新写入固件校验不成功,不会影响原来app code 的运行
- 杰理双备份升级有两种方式实现
- 设备主动升级(由设备端主动向远端获取升级数据,通信协议需要能支持文件内容获取能力)
- 设备被动升级(由远端主动推送升级数据,设备端被动写入的方式,远端可控制升级流程)\
B.双备份升级流程
- 双备份设备主动升级流程图

- 双备份设备被动升级流程图

C.sdk相关配置
- 在app_config.h定义
#define CONFIG_DOUBLE_BANK_ENABLE 1
开启后需要注意此处是否也有使能,没使能的话注意加一下头文件!
- isd_config.ini需要加入如下配置
[EXTRA_CFG_PARAM]
BR22_TWS_DB=YES; //dual bank flash framework enable(only valid for dual_bank)
FLASH_SIZE=1M; //flash_size cfg (only valid for dual_bank)
BR22_TWS_VERSION=0; //default fw version(only valid for dual_bank)
DB_UPDATE_DATA=YES; //generate db_update_data.bin(only valid for dual_bank)
SPECIAL_OPT=0; //special cfg : single bin generating(only valid for dual_bank)
FORCE_4K_ALIGN=YES; // force aligin with 4k bytes(only valid for dual_bank)
#NEW_FLASH_FS=YES; //enable single bank flash framework (only valid for single_bank)
例如:
- 设备主动升级流程采用tools目录下的*.ufw文件作为升级文件,设备被动升级采用db_update_data.bin作为升级文件
D.API接口说明
- 设备主动升级API (update_loader_download.h)
/* *****************************************************************************/
/**
* \Brief : initializes the active update module v1
*
* \Param : update_type - which meida for getting update data
* \Param : result_cbk - callback for update result handle
* \Param : cbk_priv - priv param for callback func
* \Param : p_op_api - remote file operation APIs
*/
/* *****************************************************************************/
void app_update_loader_downloader_init(
int update_type,
void (*result_cbk)(void *priv, u8 type, u8 cmd),
void *cbk_priv,
update_op_api_t *p_op_api);
typedef struct _update_mode_info_t {
s32 type; //update type
void (*state_cbk)(int type, u32 status, void *priv); //callback for update state handle
const update_op_api_t *p_op_api; //remote file operation APIs
u8 task_en; //enable/disable to create update task
} update_mode_info_t;
/* *****************************************************************************/
/**
* \Brief : initializes the active update module v2
*
* \Param : info - active update info structure
*
* \Return :
*/
/* *****************************************************************************/
int app_active_update_task_init(update_mode_info_t *info);
- 设备被动升级API(dual_bank_passive_update.h)
/* @brief:Api for getting the buffer size for temporary storage
*/
u32 get_dual_bank_passive_update_max_buf(void);
/* @brief:Initializes the update task,and setting the crc value and file size of new fw;
* @param fw_crc:crc value of new fw file
* @param fw_size:total size of new fw file
* @param priv:reserved
* @param max_ptk_len: Supported maxium length of every programming,it decides the max size of programming every time
* @return: if dual_bank_init ok will return 0, memory no enough will return -2, can't find target info will return -3;
*/
u32 dual_bank_passive_update_init(u16 fw_crc, u32 fw_size, u16 max_pkt_len, void *priv);
/* @brief:exit the update task
* @param priv:reserved
*/
u32 dual_bank_passive_update_exit(void *priv);
/* @brief:Judge whether enough space for new fw file
* @note: it should be called after dual_bank_passive_update_init(...);
* @param fw_size:fw size of new fw file
* @return: if check ok will return 0, dual_bank no init will return -1, flash area no enough will return -2
*/
u32 dual_bank_update_allow_check(u32 fw_size);
/* @brief:copy the data to temporary buffer and notify task to write non-volatile storage
* @param data:the pointer to download data
* @param len:the length to download data
* @param write_complete_cb:callback for programming done,return 0 if no err occurred
* @return: write without error will return 0, dual_bank no init will return -1, write len > buf_size will return -3
*/
u32 dual_bank_update_write(void *data, u16 len, int (*write_complete_cb)(void *priv));
/* @brief: caculate all the data had flashed,and compare with the cre value intializeed when update init;
* @crc_init_hdl:if it equals NULL,use internal implementation(CRC16-CCITT Standard);otherwise,use user's customization;
* @crc_calc_hdl:if it equals NULL,use internal implementation(CRC16-CCITT Standard);otherwise,use user's customization;
* @verify_result_hdl:when the verification completed,this callback for result notification;
* if crc_res equals 1,crc verification passed,if 0,the verification failed.
*/
u32 dual_bank_update_verify(void (*crc_init_hdl)(void), u16(*crc_calc_hdl)(u16 init_crc, u8 *data, u32 len), int (*verify_result_hdl)(int crc_res));
/* @brief:After the new fw verification succeed,call this api to program the new boot info for new fw
* @param burn_boot_info_result_hdl:this callback for error notification
* if err equals 0,the operate to burn boot info succeed,other value means to fail.
*/
u32 dual_bank_update_burn_boot_info(int (*burn_boot_info_result_hdl)(int err));
enum {
CLEAR_APP_RUNNING_BANK = 0,
CLEAR_APP_UPDATE_BANK,
};
/* @brief:this api for erasing the boot info of specific bank,it should be called much carefully
* @param type:it decides which bank's boot info would be erased;
* clean the boot info of running bank and call system_reset,system will run the other bank if available;
*/
int flash_update_clr_boot_info(u8 type);
- demo程序 被动升级流程图

#include "dual_bank_updata_api.h"
typedef struct {
u32 file_size;
u32 file_crc;
u16 max_pkt_len;
}dual_bank_start_info;
int dual_bank_write_complete_cb(void *priv){
//rsp app current buffer write complete, can send next buffer (need user implement api to response app)
}
void dual_bank_cpu_reset(void *priv){
cpu_reset();
}
int burn_boot_info_result_hdl(int err){
if(err == 0){
//boot_info write ok, and rsp app update success (need user implement api to response app)
sys_timeout_add(NULL, dual_bank_cpu_reset, 2000);
} else {
//boot_info write failed, rsp app update failed (need user implement api to response app)
dual_bank_update_exit(NULL);
}
}
int dual_bank_verify_result_hdl(int res){
if(res){
//flash verify success, write boot info
dual_bank_update_burn_boot_info(burn_boot_info_result_hdl);
} else{
//rsp app flash verify failed
dual_bank_update_exit(NULL);
}
}
void dual_bank_update_deal(u8 msg_type, u8 *data, u32 len){
switch(msg_type){
case DUAL_BANK_UPDATE_START:
dual_bank_start_info *info = (dual_bank_start_info *)data;
if(dual_bank_passive_update_init(info->file_crc, info->file_size, info->max_pkt_len, NULL) == 0){
if(dual_bank_update_allow_check(info->file_size) == 0){
//alloc_check ok, rsp app can update (need user implement api to response app)
} else {
//alloc_check error ,rsp app flash size no enough (need user implement api to response app)
dual_bank_update_exit(NULL);
}
}else{
//cpu resource no enough and rsp app can not update (need user implement api to response app)
dual_bank_update_exit(NULL);
}
break;
case DUAL_BANK_UPDATE_DATA:
dual_bank_update_write(data, len, dual_bank_write_complete_cb);
break;
case DUAL_BANK_UPDATE_VERIFY:
//if app calculate crc no use CRC16-CCITT Standard, then user should implement crc_init_hdl and crc_calc_hdl functions
dual_bank_update_verify(NULL, NULL, dual_bank_verify_result_hdl);
break;
}
}
被动升级参考:
使用前请先阅读文档内的readme.txt:
被动升级流程参考.rar
被动升级问题处理:
- 部分SDK,带KEY后会导致无法升级成功,不带KEY可以升级成功。 异常时打印:
问题原因:
升级时需要解除对FLASH的保护。
处理方法:
E.查看代码空间是否足够
由于使用双备份升级方式,flash会被分成两个APP区域,编译器会在下载的时候检测时候有足够空间(需要去除不必要功能、提示音等来减小程序大小),如下图:
F.补丁
因后需SDK均有添加EOFFSET偏移,双备份代码没有相应更新,所以需要相应更新以下补丁:
百度网盘链接:
https://pan.baidu.com/s/1PRT2cyK7jWSvZ4pUntrRyQ 提取码:8888
补丁升级(20251118):AC695N_soundbox_sdk_release_3.1.0 版本sdk ,使用涂鸦APP双备份被动升级(添加EOFFSET偏移的前提下),在接收完设升级文件后跳转报CRC_ERR 错误,需要更换最新的update.a:
问题点:CRC重入的问题,就是之前用的CRC如果被其他地方使用了,CRC里面的初值就变了,导致线程切回来就有问题了
补丁:update(AC695N_soundbox_sdk_release_3.1.0_tuya_ota_crc_err).rar
六、各系列升级相关最新版-OTA-bin文件
AC695N&AC696N&AC608N
AC695N&AC696N&AC608N音箱问题整理.otl
七、外置flash挂载fatfs升级
- 目前只支持AC695 3.1.0 SDK AC695 3.1.0 SDK —— ac695x_使用外置flash挂载fatfs升级_2022-7-23
八、外置flash升级
九、下载工具升级(一般用于调音程序升级,不能生产使用)
跟调音一致的接线方式,程序配置CDC串口功能,连接电脑能出端口
打开配置工具文件


打开串行设备

打开ufw文件,路径一定要正确

如果程序带key文件,需要使用license文件
licence由key文件生成,一般找代理商提供
点击升级,等待升级成功


十、实现升级 比较升级内容,如果选择则相同升级文件不升级
添加以下内容:到update_loader_download.h的最后的endif之前一句
// 升级配置属性
typedef enum {
= BIT(0), // 是否比较升级内容,如果选择则相同升级文件不升级
} UPDATE_FEATURE_CONFIG;
/**
* @method 设置升级配置属性
* @param update_feature_config 填入UPDATE_FEATURE_CONFIG的枚举选项,如果有多个使用|填入,没有则填入0
**/
void set_update_feature_config(u32 update_feature_config);
- 替换库文件
696 0.2.5sdk :【金山文档】 patch_比较升级内容如果选择则相同升级文件不升级_AC696_音箱025update —— https://kdocs.cn/l/cpEwHtCk6AWU
FAQ
1、升级报空间错误
demo1: AC697X测试盒无线升级部分机子报空间错误问题分析
【金山文档】 AC697X测试盒无线升级部分机子报空间错误问题分析处理报告
AC697X测试盒无线升级部分机子报空间错误问题分析处理.doc
demo2:提示升级文件大小错误
【金山文档】 OTA升级错误
OTA升级错误.otl
2、升级时配置是否擦VM和蓝牙配置区
1、无线升级、U/卡升级或串口升级时是可以配置是否擦VM配置区和蓝牙配置区的。但是否起作用,要看升级进去的代码量相对于样机中的代码量相差多少,是否会多出或减少一个扇区(扇区擦除,详看以上第三大点“测试盒升级”)。若代码修改后,代码多出或减少一个扇区量则配置会不起作用(会被覆盖)。所以要以实际测试为准。
设置升级是否擦VM或蓝牙配置区的demo:
AC695X demo:
AC700X demo:

3、杰理之家单备份OTA,VM数据是否保留

4、测试盒升级失败,如何抓取debug信息
- 替换debug的bin

- 配置ota、uboot的打印口

本文档为保密信息,未经授权,请勿转发或告知第三方。非常感谢!
This electronic documentation and any attachments are confidential and may be legally privileged or otherwise protected from disclosure. If you are not the intended recipient, please do not disclose the contents to anyone。
Thank you for your cooperation!
解析权归杰理所有!
The analysis right belongs to JieLi Technology Co., Ltd.
https://www.kdocs.cn/l/csczbvOSXxbB?linkname=r3rJlorDIK
https://www.kdocs.cn/l/csczbvOSXxbB?linkname=r3rJlorDIK