抽象
许多嵌入式系统部署在人类操作员难以访问或不切实际的地方。对于物联网 (IoT) 应用尤其如此,这些应用通常以较大数量部署且电池寿命有限。一些例子是监视人或机器健康状况的嵌入式系统。这些挑战,加上快速的软件生命周期,导致许多系统需要支持无线(OTA)更新。OTA更新将嵌入式系统的微控制器或微处理器上的软件替换为新软件。虽然许多人非常熟悉移动设备上的OTA更新,但在资源受限的系统上进行设计和实施会带来许多不同的挑战。在本文中,我们将介绍用于OTA更新的几种不同的软件设计,并讨论它们的权衡。我们将看到如何在OTA更新软件中利用两个超低功耗微控制器的硬件功能。
积木
服务器和客户端
OTA 更新将设备上的当前软件替换为新软件,新软件将以无线方式下载。在嵌入式系统中,运行此软件的设备通常是微控制器。微控制器是一种小型计算设备,具有有限的内存、速度和功耗。微控制器通常包含一个微处理器(内核)以及用于特定操作(外设)的数字硬件模块。在有源模式下,功耗通常为30 μA/MHz至40 μA/MHz的超低功耗微控制器非常适合此类应用。在这些微控制器上使用特定的硬件外设并将其置于低功耗模式是OTA更新软件设计的重要组成部分。图 1 显示了可能需要 OTA 更新的嵌入式系统示例。在这里,我们看到一个与无线电和传感器连接的微控制器,该微控制器可用于物联网应用,该应用使用传感器收集有关环境的数据,并使用无线电定期报告。系统的这一部分称为边缘节点或客户端,是 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 是非实时操作系统程序,因此它可以安全地分支到新的应用程序。无需担心电源循环会将系统置于灾难性状态,因为地址 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到一页高速缓存闪存。
图5说明了OTA更新期间部分缓存的第二种方案,其中放大了图3和图4中应用A的闪存部分,并说明了SSBL的SRAM的功能存储器图。图中显示了一个 2 kB 的闪存页面大小示例。最终,此设计决策将根据新应用程序的大小和 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等软件库来实现,这些软件库专门针对资源受限的设备。该库需要用户定义的随机数生成函数,该函数可以使用微控制器上的真随机数生成器硬件外设来实现。虽然这些非对称加密操作解决了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通信,该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.内存占用空间(字节)。
为了评估软件的开销,我们在每次收到数据包时执行周期计数,然后查看每个数据包消耗的平均周期数。每个数据包都需要 AES-128 解密、SHA-256 哈希、闪存写入和一些数据包元数据验证。数据包有效负载大小为 64 字节且无缓存的情况下,处理单个数据包的开销为 7409 个周期。使用26 MHz内核时钟,这大约是285微秒的处理时间。该值是使用位于ADuCM4050 DFP(未调整周期)中的周期计数驱动程序计算的,是100 kB二进制下载(约1500个数据包)期间获得的平均值。每个数据包的最小开销可归因于DFP中的驱动程序在执行总线事务时利用ADuCM4050上的直接存储器访问(DMA)硬件外设,以及驱动程序在每个事务期间将处理器置于低功耗休眠状态。如果我们在 DFP 中禁用低功耗休眠,并将总线事务更改为不使用 DMA,则每个数据包的开销将增加到 17,297 个周期。这说明了有效使用设备驱动程序对嵌入式软件应用程序的影响。虽然每个数据包具有少量的数据字节也保持了较低的开销,但将每个数据包的数据字节增加一倍到128只会产生周期的小幅增加 - 导致同一实验的8,362个周期。
周期和占用空间还说明了前面讨论的缓存数据包数据而不是每次都写入闪存的权衡。启用一页闪存缓存后,每个数据包的开销从 7,409 个周期减少到 5,904 个周期。这 20% 的减少来自跳过大多数数据包的闪存写入功能,并且仅在缓存已满时才执行闪存写入。这种减少是以SRAM占位面积为代价的。如果不进行缓存,HAL 只需要 336 字节的 SRAM,如图 12 所示。但是,当使用缓存时,我们必须保留相当于整页闪存的空间,这会将SRAM利用率增加到2,388字节。HAL的闪存利用率也增加了一小部分,因为确定何时必须刷新缓存需要额外的代码。
这些结果表明,设计决策将对软件性能产生切实的影响。没有放之四海而皆准的解决方案——每个系统都有不同的要求和约束,OTA更新软件需要进行调整才能解决这些问题。希望本文能够阐明在设计、实现和验证 OTA 更新软件解决方案时遇到的常见问题和权衡。
审核编辑:郭婷
全部0条评论
快来发表一下你的评论吧 !