一种有趣的 OTA 升级思路(基于 LoRa 通信的 OTA 固件升级的调试记录)

news2024/11/27 9:49:49

文章目录

  • 1 概述
  • 2 调试之路
    • 2.1 想法
    • 2.2 函数和变量定义在绝对地址的实现
      • 2.2.1 IAR的扩展关键字
      • 2.2.2 函数的绝对定位
      • 2.2.3 变量的绝对定位
      • 2.2.4 常量的绝对定位
      • 2.2.4 .c文件的绝对定位
    • 2.3 Bootload 共有函数的实现
    • 2.4 APP 共有函数的使用
  • 3 注意事项
  • 4 调试坎坷之路
  • 5 补充

1 概述

  采用 LoRa 技术进行无线通讯,考虑到产品的实际需求,增加了产品的 OTA 固件升级的功能。因为 LoRa 通讯速度较慢,合理的减小 APP 区域固件的大小加快固件升级的速度变的尤为重要,于是就开启了优化调整 APP 区域固件大小之旅。
  代码中使用到了 STM32_Cryptographic_Library、STM32_Std_Library 和 LoRa 驱动库,这些库编译之后的体积较大,猜想能不能将所有的这些库文件放在 Bootload 进行固化,然后封装好接口供 APP 调用,顺着这个思路开启了优化之路。

2 调试之路

2.1 想法

  常见的固件升级是将片内 Flash 分为 Bootload 区域和 APP 区域(如下图所示),由 APP 区域接收新固件存储在片内或者片外 Flash,然后置升级的标志位并跳转到 Bootload,在 Bootload 完成新固件的更新工作。这样实现比较常规,但是由于 APP 中包含了多种库导致目标文件比较大,LoRa 通讯速率又不高会使整个升级时间很长。
screenshot_image.png
  为了减小 APP 的大小,考虑将使用到库文件都固化在 Bootload 内,将片内 Flash 分为三个区域(如下图所示),增加一个共有函数区域,用于存放 Bootload 中封装好的接口。在函数调用时,如果 APP 调用的是共有函数,那么首先去共有函数区域找到函数在 Flash 中的地址,然后到 Bootload 中的对应位置执行相应的代码,再讲执行结果返回给 APP 区域,整个调用过程如下所示。
screenshot_image.png

2.2 函数和变量定义在绝对地址的实现

  有了上面的想法,首先需要验证的是如何将函数和变量放置在 Flash 的固定位置处,这样每次在调用固定位置处的接口就能找到 Bootload 中固化的代码接口。查阅相关资料,了解到 IAR 中的具体实现如下:

2.2.1 IAR的扩展关键字

  @ 用于函数变量的绝对地址定位,将函数变量等放到指定的 section
  __no_init禁止系统启动时初始化变量
  __root 保证没有使用的函数或者变量也能够包含在目标代码中

2.2.2 函数的绝对定位

  要将函数定义在绝对位置,需要在函数定义时后面加上 @".section_name",例如:

void fun1(int a, int b) @".MY_SECTION"
{
    ...  // 函数内容
}

  然后在链接文件 .icf 中添加如下内容。其中 0x08010000 表示在 Flash 中的地址,.MY_SECTION 必须与函数 @ 后面双引号中内容一致

place at address mem:0x08010000 { readonly section .MY_SECTION};

2.2.3 变量的绝对定位

  示例如下,变量绝对定位,无须修改 .icf 链接文件,直接指定具体位置即可。

__no_init char array1[100]@0x2000B000;

2.2.4 常量的绝对定位

  常量的绝对定位示例如下:

__root const int str1[4]@".MYSEG" = {1, 2, 3, 4};

  常量绝对定位,需要改.icf文件,示例如下:

place at address mem:0x08018500 { readonly section .MYSEG};

2.2.4 .c文件的绝对定位

  要将 test.c 文件定位到 Flash 的绝对地址,那么在 .icf文件中应该按照如下格式添加:

place at address mem:0x08018000 { section .text object test.o };

  编译完成后整个 test.c 文件的所有函数,都在 0x08018000 之后。

2.3 Bootload 共有函数的实现

  考虑到在初期编写代码时共有函数是可能发生变化的,如果按照上述的方法一个一个将函数放在固定的位置不是很方便,因此采用数组的方式将所有的共有函数放置在一起,如下所示:

__root const uint32_t func_table[]@".COMMON_FUNC_SEG" = {
    (uint32_t)&fun1,  /** 00 */
    (uint32_t)&fun2,  /** 01 */
    (uint32_t)&fun3,  /** 02 */
}

  按照上面数组的方式将所有共有函数集合在一起,然后再 .icf 链接文件中将该数组放置在固定位置处,这样在 0x08010000 位置处依次就能找到定义的所有共有函数(每个成员是函数对象的地址,占 4 个字节)。

/** 将数组放置在固定位置 */
place at address mem:0x08010000 { readonly section .COMMON_FUNC_SEG};

2.4 APP 共有函数的使用

  按照上述的方法可以将所有的库函数封装好并固化在 Bootload 中,并且实现了将所有的共有函数接口放置在固定的位置,在 APP 区可以使用函数指针的方式进行访问,示例如下:

/** 1. 声明 */
typedef int (*app_fun1)(int a, int b);
typedef void (*app_fun2)(void);
typedef char *(*app_fun3)(char *p);

/** 2. 定义函数指针类型的变量 */
app_fun1 fun1;
app_fun2 fun2;
app_fun1 fun3;

/** 3. 共有函数的重定义 */
#define FUNC_TABLE_ADDR (0x08010000)  /** 共有函数的首地址 */
void redefine_common_function(void)
{
    uint32_t *func_table_addr = (uint32_t *)FUNC_TABLE_ADDR;

    fun1 = (app_fun1)func_table_addr[0];    /* 00 */
    fun2 = (app_fun2)func_table_addr[1];    /* 01 */
    fun3 = (app_fun3)func_table_addr[2];    /* 02 */
}

  通过上面的方式就能在 APP 区域调用 Bootload 中固化的接口了,不过要注意这种方式调试起来不是很方便,需要前期验证好 Bootload 中封装的接口有没有问题。

3 注意事项

  按照上述的方法操作时有一些注意事项如下:
  1. 固件更新区的绝对定位的函数,不能随意调用其他库函数,那些被调用的函数也必须是绝对定位的。
  2. 绝对定位的函数,如果要使用常量,那么被使用的常量也必须是绝对定位的。
  3. 绝对定位的函数,如果要使用全局变量,那么被使用的常量也必须是绝对定位的,而局部变量则不受此限制。

4 调试坎坷之路

  上面的想法很有新意,在调试时自己封装的接口文件也经过了验证,但是在 APP 调用共有函数时程序还是跑飞了,经过不断的分析现实线现象,找到了问题的根源所在。STM32 标准库在进行时钟配置时定义了两个全局的数组如下,由于开始没有注意到这两个全局数组,而这两个全局数组是在 Bootload 区域定义的,跳转到 APP 区域后会对栈空间重新初始化,原本放这两个数组的位置就被初始化其他数值了,到时时钟配置出错。

/** stm32f10x_rcc.c */
static __I uint8_t APBAHBPrescTable[16] = {0, 0, 0, 0, 1, 2, 3, 4, 1, 2, 3, 4, 6, 7, 8, 9};
static __I uint8_t ADCPrescTable[4] = {2, 4, 6, 8};

  分析后的解决办法如下,因为这两个全局数据需要在 Bootload 区域中使用,而 Bootload 需要进行固化,所以需要将这两个数组放置固定的位置,这样每次使用到该数组时就回去固定的位置找,就不会出现被误修改的情况了。修改方式如下:

__root const uint8_t APBAHBPrescTable[16]@".AHBAPB_PRESC_TABLE"={0, 0, 0, 0, 1, 2, 3, 4, 1, 2, 3, 4, 6, 7, 8, 9};
__root const uint8_t ADCPrescTable[4]@".ADC_PRESC_TABLE"={2, 4, 6, 8};

/** 对应的修改 .icf 文件 */
place at address mem:0x08010000 { readonly section .AHBAPB_PRESC_TABLE};
place at address mem:0x08010010 { readonly section .ADC_PRESC_TABLE};

5 补充

  上述讲解了在 Bootload 和 APP 中共有函数的定义和使用,怎么验证是不是将其定义在绝对地址了呢?我们可以查看编译后生成的 map 文件,如下所示,可以看到在 map 文件中可以找到定义的 section。

screenshot_image.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/793849.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

学习React(四)

学习React(四) componentWillMount(被放弃使用)rendercomponentDidMountshouldComponentUpdatecomponentWillUpdate(被放弃使用)componentDidUpdatecomponentWillReceiveProps(被放弃使用&#…

idea连接远程服务器上传war包文件

idea连接远程服务器&上传war包 文章目录 idea连接远程服务器&上传war包1. 连接服务器2.上传war包 1. 连接服务器 选择Tools -> Start SSH Session 添加配置 连接成功 2.上传war包 Tools -> Deployment -> Browse Remote Host 点击右侧标签,点击&…

【二开】JeecgBoot-vue3二次开发 前端 扩展online表单js增强等-在表单里拿到列表上下文onlineTableContext

【二开】JeecgBoot-vue3二次开发 前端 扩展online表单js增强等-在表单里拿到列表上下文 onlineTableContext 对应的属性方法 acceptHrefParams"<p> 跳转时获取的参数信息"currentPage"<p> 当前页数"currentTableName"<p> 当前表…

读取有重复section的ini格式文件最新的几个不同section

文件内容示例如下 可以看到文件并不是标准的 ini 配置文件的格式&#xff0c;存在很多重复的 section&#xff08;中括号里的就是section&#xff09; &#xff0c; 我的任务是读取文件末尾最新的四个不同 section&#xff0c;并发送出去。 按照读取 ini 文件那样读取显然是不…

常用API学习08(Java)

格式化 格式化指的是将数据按照指定的规则转化为指定的形式 。 那么为什么需要格式化&#xff1f;格式化有什么用&#xff1f; 以数字类为例&#xff0c;假设有一个比分牌&#xff0c;在无人得分的时候我们希望以&#xff1a;“00&#xff1a;00”的形式存在&#xff0c;那么…

睡眠健康数据分析

项目背景 背景描述 本数据集涵盖了与睡眠和日常习惯有关的诸多变量。如性别、年龄、职业、睡眠时间、睡眠质量、身体活动水平、压力水平、BMI类别、血压、心率、每日步数、以及是否有睡眠障碍等细节。 数据集的主要特征&#xff1a; 综合睡眠指标&#xff1a; 探索睡眠持续时…

Gitlab服务器备份恢复及系统升级

居安思危&#xff0c;思则有备&#xff0c;有备无患。 基于此&#xff0c;申请了一个测试服务器&#xff0c;准备先安装同版本服务器&#xff0c;按照最新的数据进行恢复&#xff0c;然后再将现在的服务器升级到Gitlab的最新版本&#xff0c;记录一下完整的过程&#xff0c;以…

文件上传漏洞总结2

文件上传的大体都已经学习过了 这个假期在给他强化一下 什么是webshell webshell是web入侵的脚本攻击工具。webshell就是一个asp或php木马后门&#xff0c;黑客在入侵了一个网站后&#xff0c;常常在将这些asp或php木马后门文件放置在网站服务器的web目录中&#xff0c;与正常…

C++初阶之一篇文章让你掌握string类(了解和使用)

string类及其模拟实现 1.我们为什么要学习string类2. 标准库中的string类2.1 string类的实例化标准2.2 了解string 3.string类的常用接口说明3.1 string类对象的常见构造3.2 string类对象的容量操作3.3 string类对象的元素访问3.4 string类对象的Iterators&#xff08;迭代器&a…

Websocket协议-http协议-tcp协议区别和相同点

通讯形式 单工通讯-数据只能单向传送一方来发送数据&#xff0c;另一方来接收数据 半双工通讯-数据能双向传送但不能同时双向传送 全双工通讯-数据能够同时双向传送和接受 注&#xff1a;http的通讯方式是分版本 http1.0&#xff1a;单工。因为是短连接&#xff0c;客户端…

C++笔记之对指针类型的变量进行+1操作

C笔记之对指针类型的变量进行1操作 在C中&#xff0c;对指针类型的变量进行"1"操作会根据指针的数据类型而有所不同。这涉及到指针的算术运算&#xff0c;C中的指针算术运算是根据指针所指向的数据类型的大小来进行的。 code review! 文章目录 C笔记之对指针类型的…

扫地机语音提示芯片,智能家居语音交互首选方案,WT588F02B-8S

智能家居已经成为现代家庭不可或缺的一部分&#xff0c;而语音交互技术正是智能家居的核心。在智能家居设备中&#xff0c;扫地机无疑是最受欢迎的产品之一。然而&#xff0c;要实现一个更智能的扫地机&#xff0c;需要一颗语音提示芯片&#xff0c;以提供高质量的语音交互体验…

【iOS】—— 持久化

文章目录 数据持久化的目的iOS中数据持久化方案数据持久化方式分类内存缓存磁盘缓存 沙盒机制获取应用程序的沙盒路径沙盒目录的获取方式 持久化数据存储方式XML属性列表Preferences偏好设置&#xff08;UserDefaults&#xff09;数据库存储什么是序列化和反序列化&#xff0c;…

构建外卖系统小程序,订单管理功能实现步骤详解

外卖系统小程序是近年来越来越受欢迎的一种订餐方式&#xff0c;方便快捷&#xff0c;并且可以减少人与人之间的接触&#xff0c;更加卫生安全。为了搭建一个完善的外卖系统小程序&#xff0c;订单管理功能是必不可少的一部分。在本文中&#xff0c;我们将详细介绍如何实现订单…

java 支持jsonschema

入参校验产品化 schema_xsd可视化编辑器_个人渣记录仅为自己搜索用的博客-CSDN博客 jsonchema的生成 支持v4的jackson-jsonSchema GitHub - mbknor/mbknor-jackson-jsonSchema: Generate JSON Schema with Polymorphism using Jackson annotations jackson-module-jsonSchema …

三、函数-4.日期函数

一、常见函数 二、示例 -- 返回当前日期current date 2023-07-26 select curdate();-- 返回当前时间current time 15:21:14 select curtime();-- 返回当前日期和时间 2023-07-26 15:21:33 select now();-- 获取指定data的年份 2023 select year(now());-- 获取指…

C++教程 从0开始

0基础C教程 从0开始 课堂现在开始 如需学习 请订阅该标签 什么是C&#xff1f; 这个不是太重要 自行查看该链接即可 C_百度百科C&#xff08;c plus plus&#xff09;是一种计算机高级程序设计语言&#xff0c;由C语言扩展升级而产生&#xff0c;最早于1979年由本贾尼斯特劳…

SpringBoot2为什么默认使用CGLib不再使用JDK动态代理

SpringBoot2为什么默认使用CGLib不再使用JDK动态代理 CGLib和JDK动态代理对比1. 不需要实现接口2. 性能3. 代理对象的创建4. 调用方法 2. CGLib使用 CGLib和JDK动态代理对比 1. 不需要实现接口 JDK动态代理类要求目标类必须实现接口,而CGLib动态代理可以直接代理普通类(非接口…

【大数据运维-ambari】自定义fair-scheduler.xml配置文件导致ambari-server启动失败

将自定义fair-scheduler.xml放到 /var/lib/ambari-server/resources/stacks/HDP/3.0/services/YARN/configuration目录下&#xff0c;重启ambari-server失败&#xff1a; 日志显示&#xff1a; 进ambari数据库查看发现数据应该是对的。 删掉之前自定义的文件fair-scheduler.x…

Visual Studio2022报错 无法打开 源 文件 “openssl/conf.h“解决方式

目录 问题起因问题解决临时解决方案 问题起因 近一段时间有了解到Boost 1.82.0新添加了MySQL库&#xff0c;最近一直蠢蠢欲动想要试一下这个库 所以就下载了源码并进行了编译&#xff08;过程比较简单&#xff0c;有文档的&#xff09; 然后在VS2022中引入了Boost环境&#xf…