嵌入式微控制器应用中的无线更新:设计权衡和经验教训

描述

作者:Benjamin Bucklin Brown

许多嵌入式系统部署在人类操作员难以或不切实际的地方。对于物联网 (IoT) 应用尤其如此,这些应用通常部署量较大且电池寿命有限。一些例子是监控人或机器健康状况的嵌入式系统。这些挑战,加上快速的软件生命周期,导致许多系统需要支持无线 (OTA) 更新。OTA 更新将嵌入式系统的微控制器或微处理器上的软件替换为新软件。虽然许多人非常熟悉移动设备上的 OTA 更新,但在资源受限的系统上进行设计和实施会带来许多不同的挑战。在本文中,我们将介绍 OTA 更新的几种不同软件设计,并讨论它们的权衡。我们将了解如何在OTA更新软件中利用两个超低功耗微控制器的硬件特性。

积木

服务器和客户端

OTA 更新将设备上的当前软件替换为新软件,并以无线方式下载新软件。在嵌入式系统中,运行此软件的设备通常是微控制器。微控制器是一种小型计算设备,内存、速度和功耗有限。微控制器通常包含一个微处理器(内核)以及用于特定操作的数字硬件模块(外设)。超低功耗微控制器在活动模式下通常消耗30 μA/MHz至40 μA/MHz,非常适合此类应用。在这些微控制器上使用特定的硬件外设并将其置于低功耗模式是OTA更新软件设计的重要组成部分。可能需要 OTA 更新的嵌入式系统示例如图 1 所示。在这里,我们看到一个与无线电和传感器连接的微控制器,该微控制器可用于物联网应用程序,该应用程序使用传感器收集有关环境的数据,并使用无线电定期报告。系统的这一部分称为边缘节点或客户端,是 OTA 更新的目标。系统的另一部分称为云或服务器,是新软件的提供商。服务器和客户端使用收发器(无线电)通过无线连接进行通信。

嵌入式

图1.嵌入式系统中的示例中的服务器/客户端体系结构。

是什么造就了软件应用程序?

大部分 OTA 更新过程都是将新软件从服务器传输到客户端的行为。软件从源格式转换为二进制格式后,将作为字节序列传输。转换过程编译源代码文件(例如,c,cpp),将它们链接在一起到可执行文件中(例如,exe,elf),然后将可执行文件转换为可移植的二进制文件格式(例如,bin,hex)。在高级别上,这些文件格式包含属于微控制器中特定内存地址的字节序列。通常,我们将通过无线链接发送的信息概念化为数据,例如更改系统状态的命令或系统收集的传感器数据。在OTA更新的情况下,数据是二进制格式的新软件。在许多情况下,二进制文件太大,无法从服务器到客户端的单次传输中发送,这意味着二进制文件需要放入单独的数据包中,该过程称为打包。为了更好地可视化此过程,图 2 演示了不同版本的软件将如何生成不同的二进制文件,从而在 OTA 更新期间发送不同的数据包。在这个简单的示例中,每个数据包包含 8 个字节的数据,前 4 个字节表示客户端内存中的地址,用于存储接下来的 4 个字节。

嵌入式

图2.软件应用程序的二进制转换和数据包化过程。

主要挑战

基于对 OTA 更新过程的高级描述,OTA 更新解决方案必须解决的三个主要挑战。第一个挑战与记忆有关。软件解决方案必须将新的软件应用程序组织到客户端设备的易失性或非易失性存储器中,以便在更新过程完成时可以执行。解决方案必须确保将以前版本的软件保留为备用应用程序,以防新软件出现问题。此外,我们必须在重置和电源周期之间保留客户端设备的状态,例如我们当前正在运行的软件版本以及它在内存中的位置。第二个主要挑战是沟通。 新软件必须以离散数据包的形式从服务器发送到客户端,每个数据包都针对客户端内存中的特定地址。数据包化方案、数据包结构和用于传输数据的协议都必须在软件设计中考虑在内。最后一个主要挑战是安全。随着新软件从服务器无线发送到客户端,我们必须确保服务器是受信任的一方。此安全质询称为身份验证。我们还必须确保新软件对任何观察者进行混淆,因为它可能包含敏感信息。此安全挑战称为机密性。 安全性的最后一个要素是完整性,确保新软件在无线发送时不会损坏。

第二阶段引导加载程序 (SSBL)

了解引导顺序

主引导加载程序是一个软件应用程序,永久驻留在微控制器的只读存储器中。主引导加载程序所在的内存区域称为信息空间,有时用户无法访问。每次发生重置时,此应用程序都会执行,通常执行一些基本的硬件初始化,并可能将用户软件加载到内存中。但是,如果微控制器包含片上非易失性存储器(如闪存),则引导加载程序不需要执行任何加载,只需将控制权转移到闪存中的程序即可。如果主引导加载程序不支持 OTA 更新,则必须具有第二阶段引导加载程序。与主引导加载程序一样,SSBL 将在每次重置发生时运行,但将实现 OTA 更新过程的一部分。此启动顺序如图 3 所示。在本节中,我们将描述为什么需要第二阶段引导加载程序,并描述指定此应用程序的角色如何成为关键的设计权衡。

嵌入式

图3.使用 SSBL 的内存映射和引导流的示例。

经验教训:始终拥有SSBL

从概念上讲,省略 SSBL 并将所有 OTA 更新功能放入用户应用程序中似乎更简单,因为它将允许将现有的软件框架、操作系统和设备驱动程序无缝用于 OTA 流程。选择这种方法的系统的内存映射和引导顺序如图 4 所示。

嵌入式

图4.没有 SSBL 的内存映射和引导流程示例

应用程序A是部署在现场微控制器上的原始应用程序。此应用程序包含与 OTA 更新相关的软件,当服务器请求时,该软件可用于下载应用程序 B。完成此下载并验证应用程序 B 后,应用程序 A 将通过对应用程序 B 的重置处理程序执行分支指令将控制权转移到应用程序 B。重置处理程序是一小段代码,是软件应用程序的入口点,并在重置时运行。在这种情况下,重置是通过执行分支来模拟的,这相当于函数调用。此方法存在两个主要问题:

许多嵌入式软件应用程序采用实时操作系统(RTOS),它允许将软件拆分为并发任务,每个任务在系统中具有不同的职责。例如,图1所示的应用可能具有RTOS任务,用于读取传感器、对传感器数据运行算法以及与无线电接口。RTOS 本身始终处于活动状态,并负责根据异步事件或特定的基于时间的延迟在这些任务之间切换。因此,从RTOS任务分支到新程序是不安全的,因为其他任务将继续在后台运行。使用实时操作系统终止程序的唯一安全方法是通过重置。

根据图 4,前一个问题的解决方案是将主引导加载程序分支到应用程序 B,而不是应用程序 A。但是,在某些微控制器上,主引导加载程序始终运行具有中断向量表 (IVT) 的程序,IVT 是描述中断处理功能的应用程序的关键部分,位于地址 0。这意味着需要某种形式的IVT重新定位才能将重置映射到应用程序B。如果在此 IVT 重新定位期间发生电源循环,则可能会使系统处于永久损坏状态。

通过将 SSBL 固定在地址 0 可以缓解这些问题,如图 3 所示。由于SSBL是一个非RTOS程序,它可以安全地分支到新的应用程序。无需担心电源循环会使系统处于灾难性状态,因为地址为 0 的 SSBL 的 IVT 永远不会重新定位。

设计权衡:SSBL的作用

我们花了很多时间讨论SSBL及其与应用软件的关系,但是这个SSBL程序有什么作用呢?至少,程序必须确定当前应用程序是什么(它开始的位置),然后分支到该地址。各种应用在微控制器存储器中的位置通常保存在目录(ToC)中,如图3所示。这是持久内存的共享区域,SSBL 和应用程序软件都使用它来相互通信。OTA 更新过程完成后,将使用新的应用程序信息更新 ToC。部分 OTA 更新功能也可以推送到 SSBL。在开发 OTA 更新软件时,确定哪些部分是一项重要的设计决策。上面描述的最小 SSBL 将非常简单、易于验证,并且很可能在应用程序的生命周期内不需要修改。但是,这意味着每个应用程序必须负责下载和验证下一个应用程序。这可能会导致无线电堆栈、设备固件和 OTA 更新软件方面的代码重复。另一方面,我们可以选择将整个OTA更新过程推送到SSBL。在此方案中,应用程序只需在 ToC 中设置一个标志以请求更新,然后执行重置。然后,SSBL 执行下载顺序和验证过程。这将最大限度地减少代码重复并简化特定于应用程序的软件。但是,这带来了可能必须更新 SSBL 本身(即更新更新代码)的新挑战。最后,决定在 SSBL 中放置哪些功能将取决于客户端设备的内存限制、下载的应用程序之间的相似性以及 OTA 更新软件的可移植性。

设计权衡:缓存和压缩

OTA 更新软件的另一个关键设计决策是如何在 OTA 更新过程中在内存中组织传入的应用程序。微控制器上通常有两种类型的存储器:非易失性存储器(例如闪存)和易失性存储器(例如SRAM)。闪存将用于存储应用程序的程序代码和只读数据,以及其他系统级数据,如 ToC 和事件日志。SRAM将用于存储软件应用程序的可修改部分,例如非常量全局变量和堆栈。图2所示的软件应用程序二进制文件仅包含程序中驻留在非易失性存储器中的部分。应用程序将在启动例程期间初始化属于易失性内存的部分。

在OTA更新过程中,每次客户端设备从服务器收到包含二进制文件一部分的数据包时,该数据包都将存储在SRAM中。此数据包可以是压缩的,也可以是未压缩的。压缩应用程序二进制文件的好处是它的尺寸更小,允许发送更少的数据包,并且在下载过程中SRAM中存储它们所需的空间更少。这种方法的缺点是压缩和解压缩会增加更新过程的额外处理时间,并且必须在 OTA 更新软件中捆绑与压缩相关的代码。

由于新的应用软件属于闪存,但在更新过程中到达SRAM,因此OTA更新软件需要在更新过程中的某个时刻对闪存执行写入操作。将新应用程序临时存储在 SRAM 中称为缓存。在高级别上,OTA 更新软件可以采用三种不同的方法来缓存。

无缓存:每次数据包到达时,包含新应用程序的一部分,将其写入闪存中的目标。该方案非常简单,将最大限度地减少OTA更新软件中的逻辑量,但它要求完全擦除新应用程序的闪存区域。此方法会磨损闪存并增加开销。

部分缓存:保留一个 SRAM 区域用于缓存,并在新数据包到达时将它们存储在该区域中。当区域填满时,将数据写入闪存来清空它。如果数据包无序到达或新应用程序二进制文件中存在间隙,这可能会变得复杂,因为需要将SRAM地址映射到闪存地址的方法。一种策略是让缓存充当闪存部分的镜像。闪存被划分为称为页面的小区域,这是擦除的最小分区。由于这种自然划分,一个好的方法是在SRAM中缓存一页闪存,当它填满或下一个数据包属于不同的页面时,通过写入该页面闪存来刷新缓存。

完全缓存:在OTA更新过程中将整个新应用程序存储在SRAM中,并且仅在从服务器完全下载后将其写入闪存。这种方法克服了以前方法的缺点,最大限度地减少了对闪存的写入次数,并避免了OTA更新软件中复杂的缓存逻辑。但是,这将限制正在下载的新应用程序的大小,因为系统上的可用SRAM量通常远小于可用闪存量。

嵌入式

图5.使用SRAM到一页缓存闪存。

OTA 更新期间的第二种部分缓存方案如图 5 所示,其中图 3 和图 4 中应用程序 A 的闪存部分被放大,并显示了 SSBL SRAM 的功能存储器图。显示了 2 kB 的 Flash 页面大小示例。最终,此设计决策将根据新应用程序的大小和 OTA 更新软件的允许复杂性来确定。

安全与通信

设计权衡:软件与协议

OTA 更新解决方案还必须解决安全和通信问题。许多系统(如图 1 所示)都将在硬件和软件中实现通信协议,以实现正常(与 OTA 更新无关)的系统行为,例如交换传感器数据。这意味着在服务器和客户端之间已经建立了一种(可能是安全的)无线通信方法。如图1所示的嵌入式系统可能使用的通信协议是低功耗蓝牙(BLE)或6LoWPAN。有时,这些协议支持安全性和数据交换,OTA 更新软件可以在 OTA 更新过程中利用这些安全性和数据交换。®

OTA更新软件中必须内置的通信功能量最终将取决于现有通信协议提供的抽象程度。现有的通信协议具有在服务器和客户端之间发送和接收文件的功能,OTA 更新软件可以简单地利用这些工具进行下载过程。但是,如果通信协议更原始并且只有用于发送原始数据的工具,则 OTA 更新软件可能需要执行数据包化并提供元数据以及新的应用程序二进制文件。这也适用于安全挑战。如果通信协议不支持,OTA 更新软件可能有责任解密通过无线发送的字节以确保机密性。

总之,将自定义数据包结构、服务器/客户端同步、加密和密钥交换等设施构建到 OTA 更新软件中将根据系统的通信协议提供的内容以及对安全性和鲁棒性的要求来确定。在下一节中,我们将提出一个完整的安全解决方案,以解决前面介绍的所有挑战,并将展示如何在此解决方案中利用微控制器的加密硬件外设。

解决安全挑战

我们的安全解决方案需要对无线发送的新应用程序保密,检测新应用程序中的任何损坏,并验证新应用程序是从受信任的服务器而不是恶意方发送的。这些挑战可以使用加密(加密)操作来解决。具体而言,可以在安全解决方案中使用称为加密和哈希的两种加密操作。加密将使用客户端和服务器之间的共享密钥(密码)来混淆无线发送的数据。微控制器的加密硬件加速器可能支持的特定类型的加密称为 AES-128 或 AES-256,具体取决于密钥大小。除了加密的数据,服务器还可以发送摘要以确保没有损坏。摘要是通过对数据包进行哈希处理生成的,数据包是一种生成唯一代码的不可逆数学函数。如果在服务器创建消息或摘要后修改了消息或摘要的任何部分,例如在无线通信期间翻转了位,则客户端在对数据包执行相同的哈希函数并比较摘要时会注意到此修改。微控制器的加密硬件加速器可能支持的一种特定类型的哈希是 SHA-256。图 6 显示了微控制器中加密硬件外设的框图,其中 OTA 更新软件位于 Cortex-M4 应用层。此图还显示了外围设备中对受保护密钥存储的支持,可以在 OTA 更新软件解决方案中利用它来安全地存储客户端的密钥。®

嵌入式

图6.ADuCM4050加密加速器的硬件框图

解决身份验证的最终挑战的常用技术是使用非对称加密。对于此操作,服务器将生成公钥-私钥对。私钥只有服务器知道,公钥由客户端知道。使用私钥,服务器可以生成给定数据块的签名,例如将通过无线发送的数据包摘要。签名将发送给客户端,客户端可以使用公钥验证签名。这使客户端能够确认消息是从服务器而不是恶意第三方发送的。该序列如图 7 所示,实心箭头表示函数输入/输出,虚线箭头表示通过无线发送的信息。

嵌入式

图7.使用非对称加密对消息进行身份验证。

大多数微控制器没有用于这些非对称加密操作的硬件加速器,但它们可以使用Micro-ECC等软件库来实现,Micro-ECC专门针对资源受限的设备。该库需要用户定义的随机数生成功能,该功能可以使用微控制器上的真随机数生成器硬件外设来实现。虽然这些非对称加密操作解决了 OTA 更新期间的信任挑战,但它们在处理时间方面成本高昂,并且需要随数据一起发送签名,这会增加数据包大小。我们可以在下载结束时使用最终数据包的摘要或整个新软件应用程序的摘要执行一次此检查,但这将允许第三方将不受信任的软件下载到客户端,这并不理想。理想情况下,我们希望验证我们收到的每个数据包是否来自我们受信任的服务器,而每次都没有签名的开销。这可以使用哈希链来实现。

哈希链将我们在本节中讨论的加密概念合并到一系列数据包中,以在数学上将它们绑定在一起。如图 8 所示,第一个数据包(编号 0)包含下一个数据包的摘要。第一个数据包的有效载荷不是实际的软件应用程序数据,而是签名。第二个数据包(编号 1)有效负载包含二进制文件的一部分,以及第三个数据包(编号 2)的摘要。客户端验证第一个数据包中的签名,并缓存摘要 H0 供以后使用。当第二个数据包到达时,客户端对有效负载进行哈希处理并将其与 H0 进行比较。如果它们匹配,则客户端可以确定此后续数据包来自受信任的服务器,而无需执行签名检查的所有开销。生成此链的昂贵任务留给服务器,客户端必须在每个数据包到达时简单地缓存和哈希,以确保数据包到达时未损坏、完整性和经过身份验证。

嵌入式

图8.将哈希链应用于数据包序列。

实验设置

解决本文所述存储器、通信和安全设计挑战的超低功耗微控制器是ADuCM3029和ADuCM4050。这些微控制器包含整篇文章中讨论的用于 OTA 更新的硬件外设,例如闪存、SRAM、加密加速器和真随机数生成器。这些微控制器的器件系列包 (DFP) 为在这些器件上构建 OTA 更新解决方案提供软件支持。DFP 包含外围驱动程序,这些驱动程序为使用硬件提供简单、灵活的接口。

硬件配置

为了验证和验证本文讨论的概念,使用ADuCM4050创建了一个OTA更新软件参考设计。对于客户端,ADuCM4050 EZ-KIT使用收发器子板马蹄形连接器连接到ADF7242。客户端设备如图 9 左侧所示。对于服务器,开发了一个在Windows PC上运行的Python应用程序。Python应用程序通过串行端口与另一个ADuCM4050 EZ-KIT通信,该模块也以与客户端相同的排列方式连接了ADF7242。但是,图9中的右侧EZ-KIT不执行OTA更新逻辑,只是将从ADF7242接收的数据包中继到Python应用。®

嵌入式

图9.实验性硬件设置。

软件组件

软件参考设计对客户端设备的闪存进行分区,如图3所示。主客户端应用程序被设计为非常可移植和可配置,以便可以在其他安排或其他硬件平台上利用它。图 10 显示了客户端设备的软件体系结构。请注意,虽然我们有时将整个应用程序称为 SSBL,但在图 10 中,从现在开始,我们在逻辑上将真正的 SSBL 部分(蓝色)与 OTA 更新部分(红色)分开,因为后者不一定需要在前面讨论的同一应用程序中完全实现。图 10 中所示的硬件抽象层使 OTA 客户端软件保持可移植性,并且独立于任何底层库(以橙色显示)。

嵌入式

图 10.客户端软件体系结构。

软件应用程序实现了图 3 中的引导顺序、用于从服务器下载新应用程序的简单通信协议以及哈希链。通信协议中的每个数据包都有一个 12 字节元数据标头、64 字节有效负载和 32 字节摘要。此外,它还具有以下功能:

缓存:支持无缓存或缓存一页闪存,具体取决于用户配置。

目录:ToC 设计为仅容纳两个应用程序,并且新应用程序始终下载到最旧的位置,以保留回退应用程序。这称为 A/B 更新方案。

消息传递:支持ADF7242或UART进行消息传递,具体取决于用户配置。使用 UART 进行消息传递消除了图 9 中的左侧 EZ-KIT,将套件留在右侧供客户端使用。这种在线更新方案对于初始系统启动和调试非常有用。

结果

除了满足功能要求和通过各种测试外,软件的性能对于确定项目成功也至关重要。通常用于衡量嵌入式软件性能的两个指标是占用空间和周期。占用空间是指软件应用程序在易失性 (SRAM) 和非易失性(闪存)存储器中占用的空间。周期是指软件用于执行特定任务的微处理器时钟周期数。虽然与软件运行时类似,但它解释了这样一个事实,即软件在执行 OTA 更新时可能会进入低功耗模式,其中微处理器处于非活动状态,并且不消耗任何周期。虽然软件参考设计没有针对这两个指标进行优化,但它们对于对程序进行基准测试和比较设计权衡非常有用。

图11和图12显示了在ADuCM4050上实现的无缓存OTA更新软件参考设计的尺寸。这些图根据图 10 中所示的组件进行分区。如图 11 所示,整个应用使用大约 15 kB 的闪存。 考虑到ADuCM4050包含512 kB闪存,这是相当小的。真正的应用软件(为OTA更新过程开发的软件)只需要大约1.5 kB,其余的用于DFP、Micro-ECC和ADF7242堆栈等库。这些结果有助于说明SSBL在系统中应具有什么角色的设计权衡。15 kB 占用空间的大部分用于更新过程。SSBL 本身仅占用大约 500 字节的占用空间,还有额外的 1 kB 到 2 kB 的 DFP 代码用于设备访问,如闪存驱动程序。

嵌入式

图 11.闪存占用空间(字节)。

嵌入式

图 12.SRAM 占用空间(字节)。

为了评估软件的开销,我们在每次收到数据包时执行周期计数,然后查看每个数据包消耗的平均周期数。每个数据包都需要 AES-128 解密、SHA-256 哈希、写入闪存和一些数据包元数据验证。数据包有效负载大小为 64 字节且无缓存,处理单个数据包的开销为 7409 个周期。使用 26 MHz 内核时钟,这大约是 285 微秒的处理时间。该值是使用ADuCM4050 DFP(未调整周期)中的周期计数驱动程序计算得出的,是100 kB二进制下载(约1500个数据包)期间的平均值。每个数据包的最小开销可归因于DFP中的驱动器在执行总线事务时利用ADuCM4050上的直接存储器访问(DMA)硬件外设,以及驱动程序在每次事务期间将处理器置于低功耗睡眠状态。如果我们禁用 DFP 中的低功耗休眠并将总线事务更改为不使用 DMA,则每个数据包的开销将增加到 17,297 个周期。这说明了有效使用设备驱动程序对嵌入式软件应用程序的影响。虽然每个数据包的数据字节数较少也保持较低开销,但将每个数据包的数据字节数加倍到 128 个只会产生周期的小幅增加,导致同一实验的周期为 8362 个。

周期和占用空间还说明了前面讨论的缓存数据包数据而不是每次都写入闪存的权衡。启用一页闪存缓存后,每个数据包的开销从 7409 个周期减少到 5904 个周期。这 20% 的减少来自于能够跳过大多数数据包的闪存写入,并且仅在缓存已满时执行闪存写入。这种减少是以SRAM占用空间为代价的。如果没有缓存,HAL 只需要 336 字节的 SRAM,如图 12 所示。但是,当使用缓存时,我们必须保留等于一整页闪存的空间,这会将SRAM利用率增加到2388字节。由于确定何时必须刷新缓存所需的额外代码,HAL 的闪存利用率也会略有增加。

这些结果表明,设计决策将对软件性能产生切实影响。没有放之四海而皆准的解决方案——每个系统都有不同的要求和约束,需要调整 OTA 更新软件以解决这些问题。希望本文能够阐明在设计、实施和验证 OTA 更新软件解决方案时面临的常见问题和权衡。

审核编辑:郭婷

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分