# ota_app **Repository Path**: xuedejin/ota_app ## Basic Information - **Project Name**: ota_app - **Description**: No description available - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-10-11 - **Last Updated**: 2026-10-11 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # STM32 OTA 应用程序 这是与本仓库配套的 STM32 OTA 用户应用,面向 STM32F103C8T6(Blue Pill / C8T6)。应用通过 ESP8266 接入 Wi-Fi 和 MQTT 服务,接收固件元数据并按块下载新固件,将镜像写入非活动应用槽;下载及校验成功后设置 Bootloader 的 pending 状态并重启,由 Bootloader 启动新镜像。 本项目不是 Bootloader。它必须以 Slot A 或 Slot B 的地址分别链接,并与负责启动、镜像校验和回滚的 Bootloader 配合使用。 ## 1. 功能概览 - 支持 Slot A / Slot B 两种链接地址,单个镜像槽容量为 24 KB - 使用 ESP8266 AT 固件连接 Wi-Fi,并通过 MQTT 连接 OTA 服务 - 订阅 OTA 元数据,按 256 字节一块请求固件 - 对每个写入块进行 CRC32 校验,并对整份镜像做 CRC32 和向量表校验 - 将固件写入当前活动槽以外的备用槽,不覆盖当前活动镜像 - 校验成功后调用 `Boot_SetPending()` 设置待启动槽,并通过系统复位进入 Bootloader 更新启动流程 - 在应用启动时检查并确认当前 pending 槽 - USART1 输出应用及 OTA 状态日志;LED 周期闪烁表示主循环运行 ## 2. 硬件与 Flash 布局 目标器件为 STM32F103C8T6,配置按 64 KB Flash、20 KB SRAM 编译。应用与配套 Bootloader 使用相同的 Flash 分区: | 区域 | 起始地址 | 大小 | 说明 | | --- | --- | --- | --- | | Bootloader | `0x08000000` | 8 KB | 引导程序 | | App Slot A | `0x08002000` | 24 KB | A 槽应用镜像 | | App Slot B | `0x08008000` | 24 KB | B 槽应用镜像 | | OTA Flag | `0x0800E000` | 4 KB | 双页 OTA 状态记录 | | Reserve | `0x0800F000` | 4 KB | 预留区 | 应用槽地址和容量定义见 [Modules/Inc/boot.h](Modules/Inc/boot.h),链接器脚本分别为 [linker/app_slot_a.ld](linker/app_slot_a.ld) 和 [linker/app_slot_b.ld](linker/app_slot_b.ld)。应用启动时将 VTOR 设置为当前镜像的向量表地址,因此烧录到 Bootloader 时必须选择匹配的 A 或 B 镜像。 ## 3. 主要模块 ### 3.1 应用入口与运行循环 [Core/Src/main.c](Core/Src/main.c) 完成 HAL、时钟、GPIO、DMA、定时器和 USART 初始化,随后初始化串口日志及 ESP8266,确认 pending 镜像并连接 MQTT。主循环周期性闪烁 LED,并在收到 OTA 元数据后执行固件下载。 ### 3.2 OTA 状态与 Flash 操作 [Modules/Src/boot.c](Modules/Src/boot.c) 提供与配套 Bootloader 一致的状态记录和 Flash 操作接口,包括读取/初始化状态、擦除与编程应用槽、镜像 CRC32/向量表校验、设置 pending 及确认 pending。应用侧 OTA 主流程位于 [Modules/Src/mqtt.c](Modules/Src/mqtt.c)。 ### 3.3 ESP8266 与 MQTT - [Modules/Src/esp8266.c](Modules/Src/esp8266.c):ESP8266 AT 命令、Wi-Fi 连接及 MQTT 操作 - [Modules/Src/mqtt.c](Modules/Src/mqtt.c):服务连接、元数据解析、固件分块接收和下载状态管理 - [Modules/Src/json_parser.c](Modules/Src/json_parser.c):OTA 元数据 JSON 字段解析 - [Modules/Src/serial.c](Modules/Src/serial.c):USART 接收缓冲和日志输出 ## 4. OTA 工作流程 1. 应用从 ESP8266 连接 Wi-Fi,再连接 MQTT 服务并订阅 OTA 元数据及固件分块响应主题。 2. 收到元数据后检查固件标题、版本、大小和校验和;相同版本或超出槽容量的镜像不会开始下载。 3. 应用读取 Bootloader 状态,要求当前 VTOR 对应有效槽、状态中的活动槽与当前运行槽一致,且没有另一个 pending 更新。 4. 应用擦除非活动槽,随后通过 MQTT 逐块请求固件并写入备用槽。每块请求大小最多为 256 字节,单块等待超时为 20 秒。 5. 每个数据块写入后进行 CRC32 对比;全部接收后再进行整包 CRC32 和镜像向量表校验。 6. 所有检查通过后调用 `Boot_SetPending()`,然后 MCU 软件复位。 7. Bootloader 根据持久化状态尝试启动 pending 镜像。当前应用会在初始化阶段调用 `App_ConfirmIfPending()`:如果启动地址对应 pending 槽,便立即调用 `Boot_ConfirmPending()` 将其确认为活动槽。 **注意:**目前应用是在启动初始化阶段立即确认 pending 镜像,尚未等待联网成功、设备自检或用户确认后再提交。因此当前“预览”窗口很短;如果需要以运行健康检查结果决定是否确认,应调整 `App_ConfirmIfPending()` 的调用时机,并保留 Bootloader 的启动次数回滚机制。 如果下载过程中失败,活动槽不会被改写,应用也不会设置 pending 或主动重启。备用槽可能留下未完成数据,下次 OTA 开始时会重新擦除目标槽。 ## 5. MQTT OTA 对接 默认连接配置和主题定义见 [Modules/Src/mqtt.c](Modules/Src/mqtt.c) 与 [Modules/Inc/mqtt.h](Modules/Inc/mqtt.h): | 用途 | 主题 | | --- | --- | | 设备控制命令订阅 | `v1/devices/me/rpc/request/+` | | OTA 元数据订阅 | `v1/devices/me/attributes` | | 固件分块响应订阅 | `v2/fw/response/+/chunk/#` | | 固件分块请求 | `v2/fw/request/{request_id}/chunk/{chunk_id}` | 固件元数据需包含以下字段: | 字段 | 类型 | 说明 | | --- | --- | --- | | `fw_title` | 字符串 | 固件标题 | | `fw_version` | 字符串 | 固件版本;与当前 `APP_VERSION` 相同则跳过升级 | | `fw_size` | 整数 | 固件二进制长度,范围为 8 字节至 24 KB | | `fw_checksum` | 字符串 | 8 位十六进制 CRC32;其表示需与代码中的 CRC 字节序转换方式一致 | 每个分块请求的主题携带 request ID 和 chunk ID,消息负载为请求字节数;当前请求最多 256 字节。服务端须按对应响应主题返回请求长度及原始二进制数据。CRC32 使用 IEEE CRC-32(多项式 `0xEDB88320`);`fw_checksum` 的字节序应与应用解析实现一致。 应用订阅了设备控制命令主题,但当前代码只实现 OTA 元数据及固件分块处理,没有实现通用 RPC 命令的业务处理逻辑。 ## 6. 配置 Wi-Fi 与 MQTT 凭据 凭据头文件 [Modules/Inc/secretkey.h](Modules/Inc/secretkey.h) 被 `.gitignore` 忽略,不应将真实凭据提交到版本库。可从 [Modules/Inc/secretkey.example.h](Modules/Inc/secretkey.example.h) 复制一份为 `secretkey.h`,并填写: - `WIFI_SSID`、`WIFI_PASSWORD` - `MQTT_CLIENT_ID`、`MQTT_USERNAME`、`MQTT_PASSWORD` 当前 MQTT 服务地址和端口在 [Modules/Src/mqtt.c](Modules/Src/mqtt.c) 中设置为 `xthings.cloud:1883`。更换服务端时,应同时确认设备认证方式、主题、元数据字段及固件分块响应格式与服务端实现相匹配。 ## 7. 构建 项目使用 CMake、Ninja 和 ST ARM Clang 工具链。可以在 VS Code 中使用已安装的 STM32Cube 工具包,也可以使用仓库提供的 PowerShell 脚本构建。脚本从 `%LOCALAPPDATA%\stm32cube\bundles` 中查找 CMake、Ninja 和 ST ARM Clang。 在项目根目录运行: ```powershell .\build-app.ps1 ``` 默认以 Release 配置同时构建 A、B 两个槽,版本号默认为 `dev`。也可以指定目标槽、构建类型和固件版本: ```powershell .\build-app.ps1 -Slot A -Configuration Debug -Version v1.2.0 .\build-app.ps1 -Slot B -Configuration Release -Version v1.2.0 .\build-app.ps1 -Slot Both -Configuration Release -Version v1.2.0 ``` 脚本会分别使用 `slot-a` 和 `slot-b` CMake preset 配置链接地址,产物位于对应的 `build` 子目录: - `build/slot-a/ota_app-v1.2.0-slot-a.bin` - `build/slot-b/ota_app-v1.2.0-slot-b.bin` - 同目录下的 `ota_app.elf` 用于调试 版本字符串也会编译为应用内的 `APP_VERSION`,用于启动日志和 OTA 版本比较。OTA 发布时应使用与目标槽相符的 `.bin`,并让元数据中的版本、文件大小和 CRC32 与该二进制文件匹配。 也可直接选择 `CMakePresets.json` 中的 `slot-a` / `slot-b` 预设进行配置和构建。未显式指定 `APP_SLOT` 时默认链接到 Slot A;不要将 A 槽镜像当作 B 槽镜像使用。 ## 8. VS Code 按 F5 调试 项目的 [.vscode/launch.json](.vscode/launch.json) 配置了 `STM32Cube: Launch ST-Link GDB Server`,通过 STM32 扩展的构建命令预构建,并从当前项目上下文获取 ELF 文件。 1. 使用 VS Code 打开项目根目录,并安装/启用配置所需的 STM32Cube 调试扩展及其工具包,包括 Cube CMake、ST ARM Clang 和 ST-Link GDB Server。 2. 连接目标板与 ST-Link,确认扩展已识别当前工程及要调试的 A 或 B 槽构建。 3. 在“运行和调试”中选择 `STM32Cube: Launch ST-Link GDB Server`,按 **F5**。 若构建或连接失败,查看 VS Code 的“输出”面板和调试控制台。命令行构建则需要本机安装并配置对应的 CMake、Ninja 和 ST ARM Clang 工具链;PowerShell 中无法识别相关命令通常表示工具包路径未配置,不代表 F5 工作流不可用。 ## 9. 串口与板载 IO | 外设 | 引脚 | 用途 | 参数 | | --- | --- | --- | --- | | USART1 | PA9 / PA10 | 应用调试日志 | 115200、8N1 | | USART3 | PB10 / PB11 | ESP8266 AT 通信 | 115200、8N1 | | LED1 | PB9 | Slot A 主循环状态指示 | 周期闪烁 | | LED2 | PB8 | Slot B 主循环状态指示 | 周期闪烁 | USART1 可连接 USB 转串口适配器观察启动、MQTT 连接及 OTA 下载日志。串口日志与 ST-Link 下载/调试相互独立。 ## 10. 目录结构 ```text . ├── CMakeLists.txt ├── CMakePresets.json ├── build-app.ps1 ├── linker/ │ ├── app_slot_a.ld │ └── app_slot_b.ld ├── Core/ │ ├── Inc/ # CubeMX 生成的外设和 HAL 配置头文件 │ └── Src/ # 应用入口、GPIO、DMA、定时器和 USART ├── Modules/ │ ├── Inc/ # Boot、ESP8266、MQTT、串口及 JSON 接口 │ └── Src/ # OTA 状态/Flash、ESP8266、MQTT 等实现 ├── Drivers/ # STM32 HAL 和 CMSIS ├── cmake/ # 工具链及 STM32CubeMX CMake 配置 └── startup_stm32f103xb.s ``` ## 11. 注意事项 - 必须先确保 Bootloader 已烧录到 `0x08000000`,并与本应用的 Flash 分区及 OTA 状态记录格式兼容。 - 初次部署时,需使用匹配的槽镜像,并确保 Bootloader 已有有效的活动槽状态;应用在没有可读取状态记录时会尝试初始化当前运行槽状态。 - 应用镜像大小不能超过 24 KB,构建后应确认 ELF/二进制大小适合对应槽位。 - OTA 依赖 ESP8266 固件支持当前使用的 AT 与 MQTT 命令;网络参数、服务端认证和分块响应格式需与服务端配置一致。 - Flash 擦写期间应保证供电稳定。该实现使用 CRC32 检测传输/镜像完整性,不等同于加密签名或来源认证。 - 该应用本身不能代替 Bootloader 直接从复位向量运行;应通过 Bootloader 启动对应槽内镜像。