2541 OTA固件升级。

第一步:OTA升级原理解释

TI官方WIKI详细介绍

http://processors.wiki.ti.com/index.php/OAD

 1       解释:
 2       第一步:红色方框 1 Boot就像PC的BIOS,负责选择要运行的Image,是Image-A,还是Image-B.就像PC装了双系统,选择启动哪一个系统。Boot程序需要额外烧录。
 3
 4       第二步:红色方框 2Boot会首先判断Image-B是否存在,如果存在则直接运行Image-B,绿色圆圈 5;如果不存在,红色方框 3检测ImageA是否存在,如果存在,则直接运行Image-A,绿色圆圈5;
 5
 6       第三步:如果都不存在,则进入PM3模式,也即休眠模式。
 7
 8        伪代码实现如下:
 9          unsigned char image = boot_get_image_Type();
10          if(image == ‘B‘)
11          {
12             Jump(B);
13          }
14          else if(image == ‘A‘)
15        {
16             Jump(A);
17          }
18          else
19          {
20            Jump(PM3);
21          }


第二步:校验源码分析

(注:协议栈版本 v1.4,需要懂BLE相关知识)

OAD升级的关键就是获取目前正在运行的是Image,然后升级不同的Image.这一步就是固件校验部分。

***如果正在运行的是Image-A,则升级Image-B;

***如果正在运行的是Image-B,则升级Image-A//协议栈Oad_target.c文件源码

//主机在升级之前,需要发送要升级固件的"版本" "类型"和"大小(其实是固定的124k,后面会讲到)"。BLE外设收到数据会回调到下面的函数
static bStatus_t oadImgIdentifyWrite( uint16 connHandle, uint8 *pValue )
{
  img_hdr_t rxHdr;。//存储要升级固件的数据
  img_hdr_t ImgHdr;//存储目前运行固件的信息
 //前两个字节的数据是要升级固件的版本号和类型。Byte2和Byte3是要升级固件的大小(124k)
  rxHdr.ver = BUILD_UINT16( pValue[0], pValue[1] );
  rxHdr.len = BUILD_UINT16( pValue[2], pValue[3] );

  (void)osal_memcpy(rxHdr.uid, pValue+4, sizeof(rxHdr.uid));

  //读取Flash中目前运行固件的信息  HalFlashRead(OAD_IMG_R_PAGE, OAD_IMG_HDR_OSET, (uint8 *)&ImgHdr, sizeof(img_hdr_t));
 //OAD 16个Byte为一块,算出一共要升级多少块数据,这个数据非常有用,因为下面升级的时候,会做二次校验
  oadBlkTot = rxHdr.len / (OAD_BLOCK_SIZE / HAL_FLASH_WORD_SIZE);
 //#define OAD_IMG_ID( ver )    ( (ver) & 0x01 )// OAD_IMG_VER( OAD_IMAGE_VERSION ), // 15-bit Version #, left-shifted 1; OR with Image-B/Not-A bit.//上面的代码是从源码中复制的,注意阴影部分说的很清楚,高15bit位版本号,最后一位是判断Image-A还是Image-B
  if ( (OAD_IMG_ID( ImgHdr.ver ) != OAD_IMG_ID( rxHdr.ver )) && // TBD: add customer criteria for initiating OAD here.
       (oadBlkTot <= OAD_BLOCK_MAX) &&
       (oadBlkTot != 0) )
  {//只针对Image做了判断,只要不是相同的Image,并且升级的块不等于0,小于最大的升级块就可以
    oadBlkNum = 0;
    oadImgBlockReq(connHandle, 0);   //当通过校验,就会发个0给数据传输通道,同时0也表示请求发送第0块要升级的数据
  }
  else
  {
    oadImgIdentifyReq(connHandle, &ImgHdr);   //如果没有通过校验,那么会发送当前运行固件的信息,
  }

  return ( SUCCESS );
}

结论:1.TI官方软件的升级也是必须要经过以上的校验,至于如何做的,不再介绍,串口打日志是可以得到结果的。2.如果我们写自己的App,我的想法是发送0xffffffff,给要升级的固件,此时由于是错误的升级信息,那么BLE外设一定会回复目前正在运行固件的信息,我们获得正在运行固件的信息,就可以做出相应的选择了。3.如果不想让TI官方的App升级我们的固件,只需要加一些判断标志位即可。

第三步:升级源码分析

当数据传输通道收到数据0,则证明通过校验,也表示可以发送第0帧要升级的数据,数据升级的回调函数如下。

升级是以序列块的形式发送的,App每次需要发送18字节的数据,前两个字节的数据是序列,后16字节的是要升级的数据。

 1 static bStatus_t oadImgBlockWrite( uint16 connHandle, uint8 *pValue )
 2 {     //收到数据的序列,取前两个字节
 3   uint16 blkNum = BUILD_UINT16( pValue[0], pValue[1] );
 4
 5   // make sure this is the image we‘re expecting
 6   if ( blkNum == 0 )
 7   {//第一块数据非常关键,要说明的是数据的序列是程序里手动加上的,而数据则是直接读取bin文件获得的。bin文件里面保存了字节 的一些信息,这些信息被2541收到之后,会做二次校验
 8     img_hdr_t ImgHdr;
 9     uint16 ver = BUILD_UINT16( pValue[6], pValue[7] );
10     uint16 blkTot = BUILD_UINT16( pValue[8], pValue[9] ) / (OAD_BLOCK_SIZE / HAL_FLASH_WORD_SIZE);
11            //再次读取Flash中存储的信息,
12     HalFlashRead(OAD_IMG_R_PAGE, OAD_IMG_HDR_OSET, (uint8 *)&ImgHdr, sizeof(img_hdr_t));
13     //对比第二步存储的数据和从Flash中读取的数据,如果错误,就返回
14     if ( ( oadBlkNum != blkNum ) ||
15          ( oadBlkTot != blkTot ) ||
16          ( OAD_IMG_ID( ImgHdr.ver ) == OAD_IMG_ID( ver ) ) )
17     {//
18       return ( ATT_ERR_WRITE_NOT_PERMITTED );
19     }
20   }
21   //如果收到的序列是对的,就是说我要升级第三块数据,那么收到的就是第三块数据
22   if (oadBlkNum == blkNum)
23   {
24     uint16 addr = oadBlkNum * (OAD_BLOCK_SIZE / HAL_FLASH_WORD_SIZE) +
25                               (OAD_IMG_D_PAGE * OAD_FLASH_PAGE_MULT);
26     oadBlkNum++;
27
28 #if defined FEATURE_OAD_SECURE
29     if (blkNum == 0)
30     {
31       // Stop attack with crc0==crc1 by forcing crc1=0xffff.
32       pValue[4] = 0xFF;
33       pValue[5] = 0xFF;
34     }
35 #endif
36
37 #if defined HAL_IMAGE_B
38     // Skip the Image-B area which lies between the lower & upper Image-A parts.
39     if (addr >= (OAD_IMG_B_PAGE * OAD_FLASH_PAGE_MULT))
40     {
41       addr += OAD_IMG_B_AREA * OAD_FLASH_PAGE_MULT;
42     }
43 #endif
44     if ((addr % OAD_FLASH_PAGE_MULT) == 0)
45     {
46       HalFlashErase(addr / OAD_FLASH_PAGE_MULT);
47     }
48     //将要升级的数据写入Flash
49     HalFlashWrite(addr, pValue+2, (OAD_BLOCK_SIZE / HAL_FLASH_WORD_SIZE));
50   }
51     //如果数据升级完成,就是说所有的块都发完了
52   if (oadBlkNum == oadBlkTot)  // If the OAD Image is complete.
53   {
54 #if defined FEATURE_OAD_SECURE
55     HAL_SYSTEM_RESET();  // Only the secure OAD boot loader has the security key to decrypt.
56 #else//校验数据
57     if (checkDL())
58     {
59 #if !defined HAL_IMAGE_A
60       // The BIM always checks for a valid Image-B before Image-A,
61       // so Image-A never has to invalidate itself.
62       uint16 crc[2] = { 0x0000, 0xFFFF };
63       uint16 addr = OAD_IMG_R_PAGE * OAD_FLASH_PAGE_MULT + OAD_IMG_CRC_OSET / HAL_FLASH_WORD_SIZE;
64       HalFlashWrite(addr, (uint8 *)crc, 1);
65 #endif//重启
66       HAL_SYSTEM_RESET();
67     }
68 #endif
69   }
70   else  // Request the next OAD Image block.
71   {      //上面的注释写到很清楚,发送要升级数据块的序列
72     oadImgBlockReq(connHandle, oadBlkNum);
73   }
74
75   return ( SUCCESS );
76 }

结论:    1.由于已经通过身份校验,App直接读取要升级的bin文件即可,在这里要注意的是,固件类型Image-A还是Image-B,以及升级固件的大小一定不可以搞错。    2.在写数据到Flash涉及到更加底层的操作,具体的就不在说明。    

第四步:bin文件分析

所有生成的bin文件的大小都是124k,如下图,

第一个问题,在上面的第三步会对第0块数据做判断,那么第0块数据里面都有什么数据呢?

打开bin文件

第三步代码中的第9行
uint16 ver = BUILD_UINT16( pValue[6], pValue[7] );如果去掉加的序列,那么 0000 就是版本号和类型,007C就是要发送块的大小

第二个问题,bin文件的内容是我全部的应用的数据吗?答案:否,非应用的数据全部用FFFF填充。但是我们升级的时候,还是要升级124数据的

数据块大小:124K * 1024 /(16字节) = 7936块数据,下面的截图也印证了这一点。


到此,所有的分析都已经完成了,下面是我总结BLE升级时候的流程图和一些数据。

 一:通信UUID:

二:OTA升级流程图

   主要分为两个部分:

1.身份校验,APP要发送要升级古剑的大小和类型;

2.传输要升级的数据.

 

时间: 2024-08-05 21:34:47

2541 OTA固件升级。的相关文章

Python爬取CSDN博客文章

之前解析出问题,刚刚看到,这次仔细审查了 0 url :http://blog.csdn.net/youyou1543724847/article/details/52818339Redis一点基础的东西目录 1.基础底层数据结构 2.windows下环境搭建 3.java里连接redis数据库 4.关于认证 5.redis高级功能总结1.基础底层数据结构1.1.简单动态字符串SDS定义: ...47分钟前1 url :http://blog.csdn.net/youyou1543724847/

OTA制作及升级过程笔记【转】

本文转载自:http://www.it610.com/article/5752570.htm 1.概述 1.1   文档概要 前段时间学习了AndroidRecovery模式及OTA升级过程,为加深理解和防止以后遗忘,所以写这篇文档进行一个总结和梳理,以便日后查阅回顾.文档主要包括两部分,第一部分为OTA升级包的制作过程分析,第二部分为Recovery模式下OTA升级包安装过程的分析,其中包括Recovery模式分析及服务流程. 1.2   参考文献 <Recovery 开发指导> <A

OTA升级详解(一)

不积跬步,无以至千里: 不积小流,无以成江海. 出自荀子<劝学篇> 1.概念解释 OTA是何物? 英文解释为 Over The Air,既空中下载的意思,具体指远程无线方式,OTA 技术可以理解为一种远程无线升级技术: FOTA:Firmware OverThe Air/固件空中升级,通过云端为具有连网功能的设备:例如手机.平板电脑.移动互联网设备等提供固件升级服务,手机中的固件升级即可称为 FOTA: 在3G.4G网络普遍的今天,很多时候还是要考虑流量限制,如果步入5G时代,虽然流量已不在是

ESA2GJK1DH1K升级篇: 阿里云物联网平台 OTA: 关于阿里云物联网平台 OTA 的升级流程

前言 鉴于有些用户直接想使用现成的物联网平台实现 OTA 远程升级 我就写一写这系列的文章 注意:首先大家必须把我自建服务器是如何实现的看明白! 我看了下阿里云提供的,实际上流程和咱自建实现的差别不大 https://help.aliyun.com/document_detail/85700.html?spm=a2c4g.11186623.6.699.6292740d5hzKl6 首先控制升级获取当前程序的版本号等走的还是MQTT 设备端首先通过MQTT获取云端的版本信息,还有程序固件的http

基于 arduino开发的esp8266 通过阿里云实现固件升级

简介: 既然是固件升级那么要求我们必须要每个固件指定一个版本,当然这个东西还不能只有你自己知道,你还要将这个版本信息通过 发布PUB 的方式让别人知道:然后再说说更新这回事,其实就是阿里云那边为你准备一个固件的下载链接,你要做的就是通过他所指定的方法获取该固件的URL,再通过你系统只带的 HttpUpdate 的方式,进行升级就可以了,这时候要注意的就是版本号咯,版本号也是要跟着改变的撒. 代码实现: 第一步:指定版本号,及 device/inform 这个 Topic #define ALIN

【STM32H7教程】第69章 STM32H7的系统bootloader之串口IAP固件升级

完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第69章       STM32H7的系统bootloader之串口IAP固件升级 本章节为大家讲解使用系统bootloader做程序升级的方法,即使不依赖外部boot引脚也可以方便升级. IAP的全称是In Application Programming,即在线应用编程. 69.1 初学者重要提示 69.2 跳转到系统bootloader的程序设计 69.3 STM

NB-IOT的OTA测试(功率、灵敏度测试)

2017年7月25日新益技术实现了NB-IoT终端系统测试,在OTA暗室中完成了NB-IoT终端系统总辐射功率TRP(TotalRadiated Power)和总全向灵敏度TIS(Total Isotropic Sensitivity)测试.测试得到的360度全方位辐射和接收性能参数,为NB-IoT产品推向市场提供重要的参考数据. 关于NB-IoT通常一项通信技术从诞生到发展成熟需要4~5年的发展周期,NB-IoT从15年下半年到现在只经过两年就得到业界普遍认可,在国内更是涌现出芯片,模组和终端

固件空中升级(OTA)与固件二次引导的原理和设计

蓝牙固件空中升级(OTA)涉及到蓝牙无线通信.固件外存分布.固件内存分布(定制链接脚本).固件二次引导等技术,须要开发者深入理解蓝牙单芯片的存储架构.启动引导流程.外存设备驱动和产品电路设计等领域知识.完整和完美地设计和实现OTA,是一名嵌入式物联网软件project师最好的技术体现. 本文以Dialog公司研发的号称全球最低功耗蓝牙单芯片DA14580平台为基础进行分析和设计,但设计思想能够推广到其它蓝牙单芯片平台,甚至也适用于wifi固件空中升级. 一.OTA意义 固件空中升级是如此重要,在

2541 幂运算

2541 幂运算 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 查看运行结果 题目描述 Description 从m开始,我们只需要6次运算就可以计算出m31: m2=m×m,m4=m2×m2,m8=m4×m4,m16=m8×m8,m32=m16×m16,m31=m32÷m. 请你找出从m开始,计算mn的最少运算次数.在运算的每一步,都应该是m的正整数次方,换句话说,类似m-3是不允许出现的. 输入描述 Input Description 输入为一