NRF52832在OTA基础上,同时支持UART升级(自定义串口协议、可远程升级)
NRF52832的程序升级,即DFU,有通过无线方式(OTA)升级,也有通过UART,USB等硬件接口进行升级,目前资料最多的是通过无线方式进行升级,大家可以参考“青风带你学蓝牙”、“[艾克姆科技]nRF52832开发指南”等系列资料。
本篇文章主要记录利用UART和自定义协议如何进行设备的固件升级。对于UART,相信大家都很清楚,那么什么叫自定义协议升级呢?就是指传输新固件的时候用自己定义的协议,不用管NRF官方的的传输协议。
本文记录的方法是在支持OTA升级(Dual Bank Flash)的基础上修改的,使用此方法前可先了解OTA方式升级,所以使用此方法即可保证OTA不受影响,又能利用有线方式进行升级。此方法还有一个用处就是,如果用UART搭载4G模块,便可实现远程升级。
本文将升级分为四步讲解:
目录
1.得到新固件
2.传输新固件(远程传输)
3.存储新固件
4.使新固件骗过BootLoader,让BootLoader认为新固件有效
1.得到新固件
使用OTA升级时,我们会用boot.hex、SDK.hex、APP.hex以及一些命令去生成一个压缩包文件,然后用nRF Connect手机App升级时,选择用此压缩包进行升级。当我们用解压工具解压此压缩包是会得到三个文件:app.bin;app.dat;manifest.json。没错,app.bin就是我们需要传输的新固件。
2.传输新固件(远程传输)
我们得到新固件app.bin后,可以利用串口去传输它到NRF52832中,为防止传输过程中出现数据丢包和数据错误的情况,最好自己定义一个协议,将新固件打包传输,在NRF52832中按照协议解析,当解析出错时,进行固件重传。
如何进行远程传输?可用4G模块或者其他可远程传输数据的模块,连接到NRF52832上,例如使用4G模块EC20,将EC20用串口UART和NRF52832相连,EC20连接到你自己的远程服务器上,在服务器上开一个TCPserver,服务器上使用TCP发送固件,EC20接收到后通过串口将固件透传给NRF52832。
我们可以在应用程序中或者boot loader中添加传输新固件的代码。
3.存储新固件
NRF52832使用OTA升级时,NRF52832应用程序存储区分为bank0、bank1两个区,bank0存储的是当前正在运行的固件,bank1存储的是新固件。通过调试发现bank0的起始地址是固定的0x26000,bank1的起始地址是=bank0的起始地址+bank0的app大小并页对齐,boot loader中也提供了相应的计算函数:
uint32_t nrf_dfu_bank1_start_addr(void)
{uint32_t bank0_addr = nrf_dfu_bank0_start_addr;return ALIGN_TO_PAGE(bank0_addr + s_dfu_settings.bank_0.image_size);
}
4.使新固件骗过BootLoader,让BootLoader认为新固件有效
我们将新固件已经存到了bank1区域,但是bank0才是当前程序运行区域,也就是还需要将程序copy到bank0,在OTA的bootloader中,已经有这部分代码了,只是要让BootLoader检测到bank1的新固件合法有效才会去执行这步操作。
怎么让BootLoader认为我们bank1的新固件合法有效呢?其中最重要的就是s_dfu_settings这个结构体,它的值是在BootLoader启动时,从flash中获取并通过校验的,对应BootLoader中的函数是
void nrf_dfu_settings_reinit(void)
所以,我们要使bank1中的固件能通过BootLoader的校验,就需要更改s_dfu_settings的值,它是一个结构体变量,包含了bank0、bank1存储的固件大小,CRC校验,以及自身数据的校验值等等,当BootLoader检测到s_dfu_settings的检验数据不正确时,还有一个备份s_dfu_settings数据的flash区,会从备份区域给s_dfu_settings赋值并更新原s_dfu_settings存储区的值。
接下来就是如何更改s_dfu_settings?更改s_dfu_settings数据,可以在BootLoader从flash读取到数据以后再更改,也可以在读取之前去将要更改的数据存到相应flash中(如果此段flash可以用app读写,则用此方法实现升级可以不用修改BootLoader代码,完全由APP实现)。
为区分OTA和UART升级,在UART传输完成后,需要设置一个标志位,标志位符合UART升级事件再执行修改s_dfu_settings的操作。修改数据在“void nrf_dfu_settings_reinit(void)”函数中完成。
修改s_dfu_settings数据:
1>s_dfu_settings.progressv.update_start_address 新固件的起始存储地址,对于我而言固定为0x3E000,也可以利用上面的函数去计算;
2>s_dfu_settings.bank_1.image_size 新固件大小;
3>s_dfu_settings.bank_1.image_crc 新固件CRC检验值,此值可用BootLoader提供的现有函数"crc32_compute()"计算而得;
4>s_dfu_settings.bank_1.bank_code 更改为“NRF_DFU_BANK_VALID_APP”,表示有效的APP;
5>s_dfu_settings.crc “s_dfu_settings“的校验值,因为我们已经把s_dfu_settings中的数据改了,所以CRC就和之前不同,应该重新计算后赋值,利用BootLoader现有的函数”settings_crc_get“去计算此值;
6>s_dfu_settings.boot_validation_app.bytes 将s_dfu_settings.bank_1.image_crc复制给它;
7>修改完成后,还需要把这些数据更新到相应flash中,以便下次重启后通过检验,用到的函数是“”nrf_dfu_settings_write";
8>修改备份s_dfu_settings区域数据有效性判断条件,如果有效,则会把备份区的数据重新赋值给s_dfu_settings,以上工作就做了无用功,所以判断用于区分OTA和UART升级的标志位,在UART升级时,不要用备份区数据去覆盖已经修改过的s_dfu_settings数据;
9>清除用于区分OTA和UART升级的标志位。
我修改后的代码展示
void nrf_dfu_settings_reinit(void)
{bool settings_valid = settings_crc_ok();//校验flash中的s_dfu_settings数据bool settings_backup_valid = settings_backup_crc_ok();//校验flash中备份的s_dfu_settings数据if (settings_valid)//如果flash中的s_dfu_settings数据校验有效{NRF_LOG_DEBUG("Using settings page.");memcpy(&s_dfu_settings, m_dfu_settings_buffer, sizeof(nrf_dfu_settings_t));//将flash中的数据复制给s_dfu_settings/**************UART升级更改s_dfu_settings数据***************/uint32_t new_firmware_init=0x69000;//app中新固件传输完成,我将标志位和新固件大小写到此flashuint8_t new_firmware_flag[8]={0};nrf_dfu_flash_read(new_firmware_init, new_firmware_flag, 8);//读取标志位,次函数自己根据原有的读flash修改的,BootLoader中没有,自己稍微修改一下或者用原来的,功能没有区别,只是为了更方便使用if(new_firmware_flag[0]==0x01){s_dfu_settings.progress.update_start_address = 0x3E000;//bank1起始位置s_dfu_settings.bank1.image_size = ;/*新固件大小*/s_dfu_settings.bank1.image_crc = crc32_compute((uint8_t*)(s_dfu_settings.progress.update_start_address),s_dfu_settings.bank1.image_size,NULL);//计算新固件crcs_dfu_settings.bank1.bank_code = NRF_DFU_BANK_VALID_APP;//新固件有效s_dfu_settings.crc = settings_crc_get(&s_dfu_settings);//重新计算s_dfu_settings的crcmemcpy(s_dfu_settings.boot_validation_app.bytes, &s_dfu_settings.bank1.image_crc, 4);//也是存储新固件crc的位置ret_code_t err_code = nrf_dfu_settings_write(NULL);//将s_dfu_settings的值更新到flash中if(err_code != NRF_SUCCESS) return;nrf_dfu_flash_erase(new_firmware_init, 1, NULL);//清除UART升级标志位}else if (settings_backup_valid)//如果flash中备份的数据有效/***********************************************************/{NRF_LOG_DEBUG("Copying forbidden parts from backup page.");settings_forbidden_parts_copy_from_backup((uint8_t *)&s_dfu_settings);}}/*以下程序未修改,此处展示时省略*/
}
到此,升级需要修改的代码就完成了。更改s_dfu_settings数据后,BootLoader检测带新固件有效就会去从bank1 copy新固件到bank0,并自动更新其他相关的数据和写flash,比如备份s_dfu_settings数据的flash会自动被跟新,不需要我们去更改。然后BootLoader跳转到app中,此时的app就是升级后的app。
本文重点是第4步,理解之后就能运用了。如果能用蓝牙去广播新固件,用此方法是不是可以实现批量升级?如果可以用蓝牙广播固件,丢包、传输速度又是问题,如何提高升级的效率?
NRF52832在OTA基础上,同时支持UART升级(自定义串口协议、可远程升级)相关推荐
- 在JEECG-boot代码生成的基础上修改list页面(结合自定义的组件)
先上效果图: 1.在后端创建接口,获取树节点.测试通过后即可. 2.创建前端组件 两个method的全部代码为: methods: {onLoadData(selectedNode) {let tha ...
- 乐鑫esp8266学习rtos3.0笔记:仅1M flash 的安信可 ESP-01S 模块,如何二次开发?如何对其 OTA 远程升级固件!
本系列博客学习由非官方人员 半颗心脏 潜心所力所写,不做开发板.仅仅做个人技术交流分享,不做任何商业用途.如有不对之处,请留言,本人及时更改. 1. Esp8266之 搭建开发环境,开始一个" ...
- 支持自定义的离线语音模块WT516P6Core 串口协议使用说明
很多开发爱好者在应用启明云端的WT516P6Core自定义离线语音模块时,遇到最多的就是串口问题:接好线没反应,串口数据没有等等 ,这里为大家整理了一份串口协议使用说明文档供大家参考! 离线语音-支持 ...
- 国泰君安国际携手蔚来与宁德时代,助力新能源汽车电池产业创新发展做优、做强基础上突破发展,以金融支持实体经济
香港--(美国商业资讯)--国泰君安国际控股有限公司(「国泰君安国际」或「公司」,与其附属公司称为「集团」,股份代号:1788.HK)宣布,集团将携手蔚来汽车(「蔚来」).宁德时代新能源科技股份有限公 ...
- 【跟随万一老师的足迹】查找目录下文件,在万一老师的基础上升级下,支持多文件查找 - 文件操作(一)
看了万一老师的"遍历某个文件的文件及子文件",经过层层优化,结合实际需要,在万一老师代码的基础上,增加了多文件查找的功能 //sysGetFileList(List,'c:\',' ...
- 【BLE】OTA基础知识详解
[BLE]OTA基础知识详解 一. 概念 1. 缩写 BIM Boot Image Manager , the software bootloader CRC cyclic redundancy ch ...
- 我们为什么不能只相信建立在深度学习基础上的人工智能系统
来源:简书 本文摘自: https://www.jianshu.com/p/55e1abcd896d Gary Marcus介绍了如何实现通用智能以及为什么通用智能可能会让机器更安全. 加里•马库斯( ...
- android自定义滚轴选择器_Android自定义滚动式时间选择器(在他人基础上修改)...
尽管Android给我们提供了时间选择控件DatePicker和TimePicker(它们的使用方法可以参考我的这篇文章Android之日期时间选择控件DatePicker和TimePicker),但 ...
- 机器学习:SVM代码实现,朴素实现基础上的优化
SVM代码实现,朴素实现基础上的优化: 因为二次凸优化已经把解析结果明白表现出来了,所以优化只能体现在两个变量的选择上,或者说是两个样本的选择上: 1.第一个变量的选择:这次实现也并不是选择最不满足K ...
最新文章
- TCP服务端收到syn但是不回复syn ack问题分析
- How to apply for the PG studies as a UG
- hashCode()方法的性能优化
- 关于mysql启动错误
- Data Collection
- OpenJudge NOI 1.5 25:求特殊自然数
- 57 - 算法 -贪心算法 - 区间不相交问题
- VMware 安装Ubuntu 无法进入安装界面
- apk 反编译 - 最新版图文教程
- Android 百度图像识别(详细步骤+源码)
- URL和Socket
- .NET面试宝典130道经典面试真题及答案
- cad中tk什么意思_cad图纸中各种字母是什么意思
- 元器件_封装库_命名规范
- 微软C2030服务器,联想支持Windows 10系统升级机型列表
- 装机软件测试工资,实际性能测试及总结_DIY攒机装机不求人-中关村在线
- 我是如何学习Java的~标志寄存器及其应用
- Gogs搭建教程-极易搭建的自助 Git 服务
- uniapp生成商品分享海报
- 机器学习其他常用技术