mOTA v2.0

2024-08-23 06:44
文章标签 v2.0 mota

本文主要是介绍mOTA v2.0,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

mOTA_logo

mOTA v2.0

一、简介

  本开源工程是一款专为 32 位 MCU 开发的 OTA 组件,组件包含了 bootloader 、固件打包器 (Firmware_Packager) 、固件发送器 三部分,并提供了基于多款 MCU (STM32F1 / STM32F407 / STM32F411 / STM32L4) 和 YModem-1K 协议的案例。基于此,本工程提供了基于 YModem-1K 协议的固件发送器 YModem_Sender ,example 文件夹放置了案例工程,包含使用 SPI Flash 和 QSPI Flash 存放固件的案例。

  mOTA 中的 m 可意为 mini, micro, MCU (Microcontroller Unit),而 OTA (Over-the-Air Technology),即空中下载技术,根据维基百科的定义, OTA 是一种为设备分发新软件、配置,乃至更新加密密钥(为例如移动电话、数字视频转换盒或安全语音通信设备——加密的双向无线电)的方法。 OTA 的一项重要特征是,一个中心位置可以向所有用户发送更新,其不能拒绝、破坏或改变该更新,并且该更新为立即应用到频道上的每个人。用户有可能“拒绝” OTA 更新,但频道管理者也可以将其踢出频道。由此可得出 OTA 技术几个主要的特性:

  1. 一个中心可向多个设备分发更新资料(固件);
  2. 更新资料一旦发送便不可被更改;
  3. 设备可以拒绝更新;
  4. 中心可以排除指定的设备,使其不会接收到更新资料。

  本工程仅实现 OTA 更新资料的部分技术,即上文列出的 OTA 技术几个主要的特性,而不关心中心分发资料中间采用何种传输技术。


二、实现的功能

  MCU 设备上的 OTA 升级可理解为 IAP (In Application Programming) 技术, MCU 通过外设接口(如 UART, IIC, SPI, CAN, USB 等接口),连接具备联网能力的模块、器件、设备(以下统称上位机)。上位机从服务器上拉取固件包,再将固件包以约定的通讯协议,经由通讯接口发送至 MCU ,由 MCU 负责固件的解析、解密、存储、更新等操作,以完成设备固件更新的功能。需要注意的是, example 提供的案例不基于文件系统,而是通过对 Flash 划分为不同的功能区域完成固件的更新。

:tw-1f535:

 本组件实现了以下功能:

  1. 固件包完整性检查: 自动检测固件 CRC 值,验证固件数据的准确性。
  2. 固件加密: 支持 AES256 加密算法,提高固件的安全性。
  3. APP 完整性检查: 支持在 APP 运行前进行完整性检查,以确认可运行的固件通过数据校验。
  4. 断电保护: 当固件更新过程中(含下载、解密、更新等过程),任何一个环节断电,设备再次上电时,依然能确保有可用的固件。(需在 bootloader_config.h 中配置为双分区或三分区)
  5. 固件水印检查: 可检测下载的固件包是否携带了特殊的水印,用于确认非第三方或非匹配的固件包,防止错误更新。
  6. 固件自动更新: 当 download 或 factory 分区有可用的固件,且 APP 分区为空或 APP 分区不是最新版本的固件时,可配置为自动开始更新。
  7. 恢复出厂设置: factory 分区设计用于存放稳定版的固件,当设备需要恢复出厂设置时,该固件会被更新至 APP 分区。
  8. 无须 deinit : 我们知道,固件更新完毕后从 bootloader 跳转至 APP 前需对所用的外设 deinit ,以使外设恢复至上电时的初始状态。本组件的 bootloader 包含了下载器的功能,当使用复杂的外设收取固件包时, deinit 也将变得复杂,甚至很难排除对 APP 的影响。为此,本组件采用了再入 bootloader 的方式,给 APP 提供一个相当于刚上电的外设环境,免去了 deinit 的代码。
  9. 功能可裁剪: 本组件通过功能裁剪(bootloader_config.h)可实现单分区、双分区、三分区的方案切换、是否配置解密组件、是否自动更新 APP 、是否检查 APP 完整性、 是否使用 SPI Flash 等功能。
  10. 固件存放至 SPI flash : 本组件可通过 bootloader_config.h 配置 download 分区和 factory 分区的所在位置为片内 flash 或 SPI flash ,使用了 SFUD (Serial Flash Universal Driver) 作为 SPI flash 的底层驱动库。若使用的 SPI flash 支持 SFDP (Serial Flash Discovable Parameters) ,则可在不修改任何源代码的情况下更换其它品牌型号的 SPI flash 。若不支持 SFDP ,SFUD 中已有对应 SPI flash 参数表的,也可做到在不修改任何源代码的情况下更换其它品牌型号的 SPI flash 。


三、 bootloader 架构

(一)软件架构

bootloader软件架构

  • 硬件层描述的是运算器件和逻辑器件,如 CPU、ADC、TIMER、各类 IC 等,是所有软件组件的硬件基础,是软件逻辑的最终底层实现。
  • 硬件抽象层是位于驱动与硬件电路之间的接口层,将硬件抽象化。它隐藏了特定平台的硬件接口细节,为驱动层提供抽象化的硬件接口,使其具有硬件无关性。
  • 驱动层通过调用硬件抽象层的开放接口,实现一定的逻辑功能后封装,提供给上层软件调用。
  • 数据传输层负责收发数据,对外开放的是数据发送与接收相关的接口,屏蔽了通讯接口的逻辑代码,使其易于修改为其他类型的通讯接口。
  • 协议析构层将调用数据传输层的数据收发接口进行封包发送与收包解析,通过实现公有协议或自定义的协议,完成对数据的构造和解析。
  • 应用层负责业务逻辑代码的实现,通过调用其他层封装的接口,完成顶层逻辑功能。

(二)文件架构
├─ document                 设计和原理性文档
├─ example                  示例工程
├─ image                    图片资源
├─ source                   mOTA 组件的源码
│  ├─ bootloader            mOTA 组件的 bootloader 部分
│  │  ├─ Component          第三方库
│  │  ├─ Config             bootloader 配置文件
│  │  ├─ Core               核心源码
│  │  │  ├─ Module          代码模块(可移植部分)
│  ├─ BSP                   BSP(板级支持包)
├─ tools                    mOTA 组件的工具部分
│  ├─ firmware_packager     固件打包工具
│  ├─ YModem_Sender         基于 YModem-1K 协议的发送工具
├─ README.md                说明文件
├─ LICENSE                  Apache-2.0 开源许可
(三)文件描述
文件功能描述
main.c由 STM32CubeMX 自动生成,负责外设的初始化
bootloader_config.h用户配置文件,用于裁剪 OTA 组件的功能
app_config.h应用配置文件,配置代码工程的一些运行选项
user.h同上,为了避免误解为 APP 的配置文件,bootloader 的应用层命名为 user
app.c应用层,负责业务逻辑代码的实现
user.c同上,为了避免误解为 APP 的文件,bootloader 的应用层命名为 user
bootloader.c实现 bootloader 的核心功能
bootloader.hbootloader 的公共头文件
bootloader_port.cbootloader 的非核心和可移植的部分,主要是通信和协议部分的代码
firmware_manage.c固件的管理接口层,提供了固件的所有操作接口
firmware_manage.c固件的管理接口层,提供了固件的所有操作接口
protocol_parser.c协议析构层,实现协议的解包和封包
data_transfer.c数据传输层,对外提供数据发送和接收的接口
data_transfer_port.c数据传输层的移植位置,便于修改为其它通讯接口
bsp_config.hBSP 层的配置文件
bsp_common.hBSP 层的公共头文件
bsp_board.c实现板卡的一些自定义的初始化代码
bsp_key.c通用的按键驱动库
bsp_timer.c通用的 timer 驱动库
bsp_flash.cflash 的分区操作抽象接口
bsp_uart.c通用的 UART 驱动库
bsp_uart_stm32.cUART 的接口移植文件,此处是 STM32
bsp_uart_stm32.hUART 的定义文件,此处是 STM32
bsp_gpio_stm32.cGPIO 的驱动库,此处是 STM32
bsp_gpio_stm32.hGPIO 的驱动库头文件,此处是 STM32
fal_xxx_flash.cxxx 芯片的片内 flash 的写入、读取和擦除的抽象接口
sfud_port.cSFUD 的移植接口


四、 bootloader 的设计思路

  整个 bootloader 设计思路的内容较多,本设计思路也以 PDF 文档的形式提供,详见《bootloader程序设计思路》。 

bootloader的程序设计思路(YModem)


五、固件更新流程

  根据配置的分区方案不同,固件的更新流程会有些不同,此处仅展示简要的更新流程,便于快速理解固件更新的流程,因此屏蔽了很多细节,更详细的内容,请阅读《bootloader程序设计思路》文档和源代码。

  本组件的目的是最大程度的减少 APP 的改动量以实现 OTA 的功能,从下图可知, bootloader 完成了固件的下载、存放、校验、解密、更新等所有操作, APP 部分所需要做的有以下三件事。

  1. 根据 bootloader 占用的大小和 flash 的最小擦除单位,重新设置 APP 的起始位置和中断向量表。( bootloader 默认进行 __disable_irq(); 因此设置完向量表后要执行 __enable_irq(); )
  2. 增加触发系统软复位(进入 bootloader )以开始固件更新的方式。(如:接收来自上位机的更新指令或者按键等)
  3. 设置一个更新标志位,且这个标志位在 APP 进行系统软复位进入 bootloader 时仍能被读取到。(当固件更新的方式为上位机指令控制时,不需要此步骤)

   一般来说,通知 bootloader 进行固件更新的方式有以下两种:

  1. 采用上位机指令控制的方式,优点是 APP 无须设置更新标志位,即便设备在收到更新指令后断电,也可以照常更新。缺点是设备在上电后, bootloader 需要等待几秒的时间(时间长短由通讯协议和上位机决定),以确认是否有来自上位机的更新指令,从而决定进入固件更新模式亦或跳转至 APP 。

  2. APP 在软复位进入 bootloader 之前设置一个特殊的标志位,可以放置在 RAM 、备份寄存器或者外部的非易失性存储介质中(如:EEPROM)。此方式的优点是设备上电时 bootloader 无须等待和验证是否有固件更新的指令,通过标志位便可决定是否进入固件更新模式亦或跳转至 APP ,且利用再入 bootloader 的机制,可以给 APP 提供一个干净的外设环境。缺点则是 APP 和 bootloader 要有一个存放更新标志位的地址空间,且该地址空间不能被挪作他用,不能被意外修改,更不能被编译器初始化。相较于上个方案多了要专门指定该变量的地址并且不被初始化的步骤。若使用的是 RAM 作为记录标志位的介质,则还有断电后更新标志信息丢失的问题。

   综上所述,没有完美的方案。本组件支持上述方案二选一,根据实际需求选择即可。

由于案例采用了 YModem-1K 协议,而本组件开始固件更新的方式是通过上位机发送指令开始的,因此测试时若设备正在运行 APP ,需要有个进入 bootloader 的条件,为了便于展示,案例使用了板卡上的功能按键作为触发条件,上位机向设备发送更新指令的方式可参考执行部分的代码,详见案例的使用说明。

固件更新流程图


六、固件检测与处理机制

  之所以单独列出固件的检测与处理机制,是为了方便理解代码逻辑,此部分也以 PDF 文档的形式提供,详见《固件检测与处理机制》。 

固件检测与处理机制


七、所需的工具

  1. Firmware_Packager 此工具是必选项,负责打包 bin 固件,并为 bin 固件添加一个最小 96 byte 的表头,最终生成为 fpk (Firmware Package) 固件包。关于 96 byte 表头的具体内容,详见《fpk固件包表头信息》。为了便于 bootloader 解包,本工具提供了表头尺寸的选项,当移植为其它协议时,需根据协议的包大小选择表头尺寸,确保 fpk 的表头是单独成一帧发送的。

需要注意的是,本案例选择了 YModem-1K 协议,因此若直接采用或测试 example 中的案例,固件打包器的表头尺寸需要选择 1024 byte。若采用其它包大小的 YModem 协议,需根据 YModem 包大小选择符合的表头尺寸。

  1. YModem_Sender 本工程的 example 采用广泛使用且公开的 YModem-1K 通讯协议,因此也提供了一个基于 YModem-1K 协议的发送器。由于固件发送器和通讯协议是绑定的,实际使用时,不必绑定此工具,本工程仅为了方便测试而提供。

注:以上的工具是基于 Qt6 开发的,YModem_Sender 依赖 Qt 的 serial_port 库,自行编译时需添加。以上工具作为 OTA 组件的一部分,自然也是开源的。运行平台是 windows ,目前仅在 win10 和 win11 上测试过。若需要修改和编译工程,需要自行安装 Qt ,请自行搜索安装教程。


八、组件占用的空间

  此处使用了开源的存储器用量可视化的工具用于分析,推荐使用 keil-build-viewer
  本组件的案例是基于 YModem-1K 协议及 UART 作为 MCU 与外部的数据传输媒介,因此不是仅计算核心代码部分的占用空间情况,而是整个可用工程。此数据才更有参考意义。以下是几种方案配置占用的 flash 和 RAM 的大小。

  1. 最小占用(单分区) 

    STM32F1_单分区

RAM:   8.7 KB
flash: 8.3 KB
  1. 一般占用(单分区 + 解密组件) 

    STM32F1_单分区_解密组件

RAM:   8.9 KB
flash: 9.5 KB
  1. 一般占用(三分区) 

    STM32F1_三分区

RAM:   8.7 KB
flash: 9.4 KB
  1. 一般占用(三分区 + 解密组件) 

    STM32F1_三分区_解密组件

RAM:    9.0 KB
flash: 10.8 KB
  1. 最大占用(三分区 + 解密组件 + QSPI flash)

    STM32L4_三分区_解密组件_QSPI

RAM:   10.2 KB
flash: 25.5 KB

  代码和编译器不同,实际数据会有偏差,仅供参考。因双分区和三分区的占用尺寸相差较小,因此不单独列出双分区的占用情况。本组件已尽量压缩尺寸,但由于固件数据的处理需要一定的 RAM 开销,此部分除非修改每个分包的最小处理单位(目前是 4096 byte ),否则已经很难进一步压缩,请按实际需求选择。


九、移植说明

  由于写教程工作量较大,本开源工程暂不提供详细的移植说明文档。代码已分层设计,具备一定的移植性,有经验的工程师看 example 中的示例代码和本说明基本都能自行移植到别的芯片平台。这里仅做几点说明。

挖个坑,后续有时间再录个移植视频。

  1. bootloader 部分的核心代码都在 source 目录下,是移植的必需文件。
  2. source/bootloader/Component 和 source/BSP 目录下的组件库非移植的必选项,根据功能需要进行裁剪。
  3. 固件经过 固件打包器 打包后会包含一个 96 byte 的表头,bootloader 将固件写入的 flash 分区的方式与通讯协议是强相关的。若采用其他协议时,需要注意固件表头的大小一定要设置为一帧数据的尺寸。例如通讯协议一帧能传输 128 byte 的数据,那么要在 固件打包器 中选择表头尺寸为 128 byte,以使 bootloader 能正确解包。本工程的案例采用 YModem-1K 协议,需使用 固件打包器 指定表头为 1024 byte )。
  4. 除表头部分,固件的每个切包不能超过 4096 byte ,且 4096 除以每个切包大小后必须是整数(如常见的128、256、512、1024、2048等),否则将修改源码。
  5. 单分区方案虽然节省了 flash 空间,但本组件的很多功能和安全相关的特性都无法使用,除非 flash 实在受限,否则建议至少使用双分区的方案。

  以下是移植的基本步骤

(一)bootloader 部分

参考 example 中的案例进行移植。

  1. 创建一个代码工程,并确保这个工程可以正常运行(如:控制一个 LED 闪烁)
  2. 将 source 目录下的文件放到工程目录下,可随意放置和命名
    • source/Component 目录下的 config 和 port 文件夹分别表示配置和移植文件,一般一个工程对应一个,这点可在 example 中的案例了解到
  3. 添加 bootloader.c 进工程中
  4. 添加 bootloader_port.c 进工程中,若此部分逻辑有不同,则按实际情况进行修改
  5. 添加 firmware_manage.c 进工程中
  6. 添加 protocol_parser.c 进工程并实现内部的公共函数,若与案例一致,则无需修改
  7. 添加 data_transfer.c 进工程中
  8. 添加 data_transfer_port.c 进工程并实现内部的公共函数,若与案例一致,则无需修改
  9. 若使用了 spi flash ,则添加 fal 库 和 sfud 库进工程
    • 根据芯片添加对应的 fal_xxx_flash.c 进工程中,如 fal_stm32f1_flash.c ,若提供的案例中无适配的芯片,则需基于 fal_xxx_flash.c 修改适配
    • 添加 fal_flash_sfud_port.c 进工程中
    • 添加 sfud_port.c 进工程中,并参考案例按实际使用的外设进行适配
  10. 在你工程的业务逻辑部分代码中调用 main.c 或 app.c 或 user.c 中调用 Bootloader_Init() 函数和 Bootloader_Loop() 函数。Bootloader_Loop() 函数需要不间断的循环调用。
  11. 尝试编译并解决编译器报错的问题(若提示缺失部分文件,可在 example 目录中寻找并添加进工程)
  12. 按需求设置好 bootloader_config.h 文件,请仔细阅读文件内的说明
  13. 若 USING_IS_NEED_UPDATE_PROJECT 配置为USING_APP_SET_FLAG_UPDATE(否则忽略此步骤),且标志位放置在 RAM ,则需要配置标志位 update_flag 所在的 RAM 地址,并且配置 IDE 或分散加载文件不对其进行初始化。 IDE 配置的方式参考如下图所示。( 需包含 common.h ) 其中,宏 FIRMWARE_UPDATE_VAR_ADDR 在 bootloader_config.h 中配置,本案例是 0x20000000 。注意,提供给 update_flag 的 RAM 区域一定是 NoInit 的,否则会导致 bootloader 无法正常跳转
/* 固件更新的标志位,该标志位不能被清零 */
#if (USING_IS_NEED_UPDATE_PROJECT == USING_APP_SET_FLAG_UPDATE)#if defined(__IS_COMPILER_ARM_COMPILER_5__)volatile uint64_t update_flag __attribute__((at(FIRMWARE_UPDATE_VAR_ADDR), zero_init));#elif defined(__IS_COMPILER_ARM_COMPILER_6__)#define __INT_TO_STR(x)     #x#define INT_TO_STR(x)       __INT_TO_STR(x)volatile uint64_t update_flag __attribute__((section(".bss.ARM.__at_" INT_TO_STR(FIRMWARE_UPDATE_VAR_ADDR))));#else#error "variable placement not supported for this compiler."#endif
#endif

update_flag的定义

 

IDE配置RAM

  1. 工程配置建议选择 AC6 (虽然本组件也支持 AC5 ,除非不得已,否则建议使用 AC6),选择 C99 (如果使用了 perf_counter ,则至少需要选择 gnu99 ) ,优化根据需要选择即可,建议按下图所示配置。 

    AC6的配置

  2. 尝试再次编译并解决编译器提示的问题。

  3. 若 USING_IS_NEED_UPDATE_PROJECT 配置为USING_APP_SET_FLAG_UPDATE (否则忽略此步骤),编译通过后,查看 map 文件是否新增了一个 Region ,并且地址正确, Type 为 Zero ,该区域为 UNINIT ,若全部符合,则移植成功。 

    bootloader的map

(二)APP 部分

APP 部分的移植相对简单,可直接参考 example 中的案例。

  1. 创建一个代码工程,并确保这个工程可以正常运行。(如:控制一个 LED 闪烁)
  2. 确定 APP 在 flash 中的地址,需结合 bootloader 的大小(不能和 bootloader 有地址冲突),中断向量表一般对地址是有要求的,如必须是 0x200 的整数倍。还要考虑 flash 的擦除粒度(因 flash 擦除时是以扇区为单位的)。 需要注意的是, APP 的地址一定要和 bootloader 的 bootloader_config.h 中配置的一致,否则可能导致 APP 无法运行。
  3. 在外设初始化前修改中断向量表, keil 可采用下图的方式修改,一劳永逸。其他编译器直接给 SCB->VTOR 寄存器赋值即可。其他非 ARM 内核的芯片需要自行搜索资料。
/* 设置中断向量表后,开启总中断 */
__IRQ_SAFE 
{extern int Image$$ER_IROM1$$Base;SCB->VTOR = (uint32_t)&Image$$ER_IROM1$$Base;
}
__enable_irq();

设置中断向量表

 

IDE设置ROM地址

__IRQ_SAFE 是 perf_counter 库的一个功能宏,若不想使用,可采用下面的方式。

/* 设置中断向量表后,开启总中断 */
__disable_irq();
extern int Image$$ER_IROM1$$Base;
SCB->VTOR = (uint32_t)&Image$$ER_IROM1$$Base;
__enable_irq();
  1. 同 bootloader 部分的步骤 13 一致。

  2. 增加需要进行固件更新时系统复位进入 bootloader 的代码,如上位机发送固件更新的指令。(测试时可通过按键模拟上位机发送固件更新指令)

  3. 在执行固件更新的指令的代码处,添加设置 update_flag 标志位的值和系统复位的代码,如下图所示。其中, FIRMWARE_UPDATE_MAGIC_WORD 的值是 0xA5A5A5A5 , 注意此值要和 bootloader 保持一致 。
    若需要通过标志位使用“恢复出厂固件”的功能,也是同理,对应的宏则是 FIRMWARE_RECOVERY_MAGIC_WORD ,值为 0x5A5A5A5A 。
    若 USING_IS_NEED_UPDATE_PROJECT 配置为 USING_HOST_CMD_UPDATE ,则忽略此步骤

update_flag = FIRMWARE_UPDATE_MAGIC_WORD;
HAL_NVIC_SystemReset();
  1. 尝试再次编译并解决编译器提示的问题。
  2. 同 bootloader 部分的步骤 16 一致。


十、一些问题的解答

  1. 为什么不使用 RTOS ?

为了最大程度的减少 bootloader 占用的 flash 空间,体积越小,组件的适用范围就越广。当然,本组件是开源的,想在 bootloader 里增加 RTOS 或者其它代码也是可以的。

  1. 为什么要将 bootloader 设计在 flash 的首地址?

我们知道, bootloader 的运行环境最理想的情况是未经使用任何外设的。有些设计会将 APP 放置在 flash 首地址, bootloader 放置在其它地址,优点是 APP 无须设置 APP 的起始位置和中断向量表,改动量最少,缺点是这种方式很难做到通用,需要在 bootloader 或 APP 中 deinit 所使用的外设,否则固件更新时可能会出现各式各样的异常。实际上,每个设备每个产品所使用的外设都是不确定的,为了做到通用,本组件选择了 bootloader 设计在 flash 的首地址的方案。

  1. 为什么要设计成单分区、双分区和三分区?

现实情况是,并非所有设备的 flash 空间都有比较大的富余。有些设备,无法使用多个分区, bootloader + APP 分区已经是极限。而 bootloader 分区方案不同时,其占用的 flash 大小也不同,为了尽可能的减小 bootloader 的体积,而将分区设计成可配置的方式。

  1. 什么是 fpk ?

fpk 是 mOTA 组件的固件打包器生成的一种文件,基于 bin 文件,在其头部增加了一个 96 byte 表头后合成的一个新文件,后缀是 .fpk 。fpk 取自英文词语 Firmware Package 的缩写,意为固件程序包,本组件统称为固件包,而提及固件时,一般指的是 bin 文件。

  1. 我可以不用固件打包器(Firmware_Packager),直接用 bin 文件进行更新吗?

目前是不能的。 本组件提供的功能和安全特性是基于 fpk 表头和多分区的方式实现的,因此需要固件打包器打包固件,生成 fpk 固件包。为了最大程度的使用这些功能和安全特性, bootloader 的更新流程是基于含有表头的固件包开发的,暂时不考虑增加不含表头的更新流程。当然,不排除因为要求的人多了,我就开搞了。

:tw-1f60b:


十一、引用的第三方库

  本开源工程使用了或将使用以下的第三方库,感谢以下优秀的代码库(按编写时使用时间排序)。

  1. fal (Flash Abstraction Layer) ,RT-Thread 团队的开发的库,是对 Flash 及基于 Flash 的分区进行管理、操作的抽象库。
  2. SFUD (Serial Flash Universal Driver) 一款使用 JEDEC SFDP 标准的串行 (SPI) Flash 通用驱动库。
  3. crc-lib-c 为本工程的 CRC32 验算提供了基础。
  4. tinyAES 这是一个用 C 编写的 AES 、 ECB 、 CTR 和 CBC 加密算法的小型可移植的库。
  5. SEGGER RTT SEGGER's Real Time Transfer (RTT) is the proven technology for system monitoring and interactive user I/O in embedded applications. It combines the advantages of SWO and semihosting at very high performance.
  6. perf_counter 该库利用 SysTick 实现了代码的运行时间测量和通用的 ms 及 us 的延时函数,且不影响原有的 SysTick 功能和逻辑,若使用的是 AC5 或 AC6 ,可以做到无感使用,即只需将 perf_counter 库添加进代码工程后即可直接使用,无需调用 init 之类的任何函数。


十二、参考例程

案例贡献者
GD32L233_SPI_Flashwade任
STM32F1Dino侯巽杰
STM32F1_SPI_FlashDino侯巽杰
STM32F407Dino侯巽杰
STM32F411Dino侯巽杰
STM32L4Dino侯巽杰
STM32L4_QSPI_FlashDino侯巽杰


说明

由于从 v2.0 开始改动较大,已与 v1.0 核心代码部分基本互不兼容,因此将 v1.0 封包在发行版中。建议使用最新版本。

这篇关于mOTA v2.0的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1098649

相关文章

若依库存管理 ruoyi-wms V2.0发布:升级到jdk17和vue3,支持一物一码

开源地址 https://gitee.com/zccbbg/wms-ruoyi 项目代码、文档 均开源免费可商用 遵循开源协议在项目中保留开源协议文件即可 活到老写到老 为兴趣而开源 为学习而开源 为让大家真正可以学到技术而开源 若依wms是一套基于若依的wms仓库管理系统,支持lodop和网页打印入库单、出库单。毫无保留给个人及企业免费使用。 前端采用Vue、Element UI。

财务记账管理系统V2.0.4

单人记账、多人共同记账(高级授权)、个人中心轮播图、记账分类管理、小程序等 V2.0.4优化调整 修复统计BUG收入和支出反了的问题

2021/11月最新H5盲盒交友系统V2.0.1版本源码_其他站长亲测

搭建了下,简单的测试了下前台各个功能(存取纸条),正常使用。 支付没看。 感兴趣的可以自己下载下来看下。 下载地址:http://www.yuenos.cchttp://www.yuenos.cc

terminal_layout 命令行ui布局管理器 V2.0.0 发布

terminal_layout 是一个命令行布的局管理器,支持Windows,Linux,OSX。 Github: https://github.com/gojuukaze/terminal_layout文档:https://doc.ikaze.cn/terminal_layout/   V2.0更新内容 增加自动刷新功能增加渐进显示字符的函数 delay_set_text()find_v

DeerU v2.0.0 发布,开源博客系统

DeerU v2.0.0 更新了多处细节,同时修改了项目之后的开发方向,主要细节有: 一、修改项目定位     DeerU从2.0开始定位为可供二次开发的博客系统,基于此定位,此项目将为有django、前端经验开发者提供可自行扩展博客系统。DeerU今后将只提供博客基础功能更新、安全性更新、可扩展性更新,除此之外的功能(比如主题、上传cdn等)需要开发者自行开发。 二、功能及BUG更新 a

销售预测数据挖掘实战V2.0

1、概述 沃尔玛全年都会举办几次促销减价活动。这些减价活动都是在重要节假日之前进行的,其中最大的四个节假日是超级碗、劳动节、感恩节和圣诞节。包括这些节假日在内的几周在评估中的权重是非节假日周的五倍。在缺乏完整/理想历史数据的情况下,对这些节假日周的降价影响进行建模,是此次竞争所面临的部分挑战。我们提供了位于不同地区的 45 家沃尔玛商店的历史销售数据。 数据集信息 这是 2010-02-05

植物大战僵尸杂交版 v2.0.88 mac版 Plants vs. Zombies 杂交版下载

特别注意:该游戏最低系统要求为macOS Sonoma 14.X,低于此系统版本的请勿下载! 游戏介绍 植物大战僵尸杂交版是由B站UP主“潜艇伟伟迷”制作的一款结合了《植物大战僵尸》原有元素与创新玩法的游戏。这款游戏以其独特的“杂交”植物概念在B站上迅速走红,吸引了大量玩家的关注和讨论。 游戏的由来与特色: 游戏的灵感来源于UP主将《植物大战僵尸》中的植物进行创意结合,创造出了具有两种植物

QT串口调试助手V2.0(源码全开源)--上位机+多通道波形显示+数据保存(优化波形显示控件)

首先关于Qt的安装和基本配置这里就不做重复说明了,注:本文在Qt5.14基础上完成 完整的项目开源仓库链接在文章末尾 图形控件——qcustomplot QCustomPlot是一个基于Qt框架的开源绘图库,用于创建高质量的二维图表和数据可视化。 QCustomPlot的主要功能: 绘制多种图表类型:包括折线图、散点图、柱状图、面积图 交互性:支持图表的缩放、平移、数据点选择等交互操作 多轴

浔川画板v2.0——浔川python社

系列文章目录 浔川画板v2.0——浔川python社 文章目录 系列文章目录前言总结 前言 浔川画板v2.0——浔川python社 正式代码: # -*- coding: utf-8 -*-import tkinter as tkimport tkinter.messageboximport pickleimport random# 窗口wind

软件测试自学指南---从入门到精通V2.0

本系列是在之前的基础上进行了修改更新,原来的内容显得过于简单,但都是重点,这次对于过于简单部分增加了更详细的内容。         目前国内越来越重视软件测试,人才的缺口也是比较大的,为了帮助大家快速的学习测试知识来找到满意的工作,特此来分享本系列的课程。本教程的重点是黑盒测试基础知识和数据库部分的内容,其他部分也会介绍一些。 学习方法 软件测试自学指南 软件测试工程师修