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升级(自定义串口协议、可远程升级)相关推荐

  1. 在JEECG-boot代码生成的基础上修改list页面(结合自定义的组件)

    先上效果图: 1.在后端创建接口,获取树节点.测试通过后即可. 2.创建前端组件 两个method的全部代码为: methods: {onLoadData(selectedNode) {let tha ...

  2. 乐鑫esp8266学习rtos3.0笔记:仅1M flash 的安信可 ESP-01S 模块,如何二次开发?如何对其 OTA 远程升级固件!

    本系列博客学习由非官方人员 半颗心脏 潜心所力所写,不做开发板.仅仅做个人技术交流分享,不做任何商业用途.如有不对之处,请留言,本人及时更改. 1. Esp8266之 搭建开发环境,开始一个" ...

  3. 支持自定义的离线语音模块WT516P6Core 串口协议使用说明

    很多开发爱好者在应用启明云端的WT516P6Core自定义离线语音模块时,遇到最多的就是串口问题:接好线没反应,串口数据没有等等 ,这里为大家整理了一份串口协议使用说明文档供大家参考! 离线语音-支持 ...

  4. 国泰君安国际携手蔚来与宁德时代,助力新能源汽车电池产业创新发展做优、做强基础上突破发展,以金融支持实体经济

    香港--(美国商业资讯)--国泰君安国际控股有限公司(「国泰君安国际」或「公司」,与其附属公司称为「集团」,股份代号:1788.HK)宣布,集团将携手蔚来汽车(「蔚来」).宁德时代新能源科技股份有限公 ...

  5. 【跟随万一老师的足迹】查找目录下文件,在万一老师的基础上升级下,支持多文件查找 - 文件操作(一)

    看了万一老师的"遍历某个文件的文件及子文件",经过层层优化,结合实际需要,在万一老师代码的基础上,增加了多文件查找的功能 //sysGetFileList(List,'c:\',' ...

  6. 【BLE】OTA基础知识详解

    [BLE]OTA基础知识详解 一. 概念 1. 缩写 BIM Boot Image Manager , the software bootloader CRC cyclic redundancy ch ...

  7. 我们为什么不能只相信建立在深度学习基础上的人工智能系统

    来源:简书 本文摘自: https://www.jianshu.com/p/55e1abcd896d Gary Marcus介绍了如何实现通用智能以及为什么通用智能可能会让机器更安全. 加里•马库斯( ...

  8. android自定义滚轴选择器_Android自定义滚动式时间选择器(在他人基础上修改)...

    尽管Android给我们提供了时间选择控件DatePicker和TimePicker(它们的使用方法可以参考我的这篇文章Android之日期时间选择控件DatePicker和TimePicker),但 ...

  9. 机器学习:SVM代码实现,朴素实现基础上的优化

    SVM代码实现,朴素实现基础上的优化: 因为二次凸优化已经把解析结果明白表现出来了,所以优化只能体现在两个变量的选择上,或者说是两个样本的选择上: 1.第一个变量的选择:这次实现也并不是选择最不满足K ...

最新文章

  1. TCP服务端收到syn但是不回复syn ack问题分析
  2. How to apply for the PG studies as a UG
  3. hashCode()方法的性能优化
  4. 关于mysql启动错误
  5. Data Collection
  6. OpenJudge NOI 1.5 25:求特殊自然数
  7. 57 - 算法 -贪心算法 - 区间不相交问题
  8. VMware 安装Ubuntu 无法进入安装界面
  9. apk 反编译 - 最新版图文教程
  10. Android 百度图像识别(详细步骤+源码)
  11. URL和Socket
  12. .NET面试宝典130道经典面试真题及答案
  13. cad中tk什么意思_cad图纸中各种字母是什么意思
  14. 元器件_封装库_命名规范
  15. 微软C2030服务器,联想支持Windows 10系统升级机型列表
  16. 装机软件测试工资,实际性能测试及总结_DIY攒机装机不求人-中关村在线
  17. 我是如何学习Java的~标志寄存器及其应用
  18. Gogs搭建教程-极易搭建的自助 Git 服务
  19. uniapp生成商品分享海报
  20. 机器学习其他常用技术

热门文章

  1. 电压比较器工作原理及应用
  2. 智能交通系统计算机技术应用,计算机技术在智能交通系统中的应用研究
  3. set 集合 拷贝的操作
  4. 简单对比discuz phpwind phpBB
  5. the beginning
  6. SpringCloud01
  7. linux svn 自动更新,Linux(Ubuntu) svn 自动更新设置 hooks(post-commit)
  8. 如何用浏览器调试网页前端代码?
  9. 透视软件,好骚啊!!!
  10. 兴业银行企业网银预处理软件