#ifndef __OTA_CONFIG_H #define __OTA_CONFIG_H #include #include #define OTA_PAGE_SIZE 256UL /* Flash 页大小(硬件固定 256B,任何模式通用)*/ /* ════════════════════════════════════════════════════════════════ * OTA 模式配置 — 客户唯一配置入口 * * 本文件被 APP(Core/ota_ab.c)与 Bootloader(boot_main.c)共用, * 修改后需重新编译两个工程。 * * 只需改 ① OTA_BACKUP_MODE(备份模式)。其余配置均由 #if 条件 * 编译保护,自动只编译生效模式需要的部分: * ① OTA_BACKUP_MODE = SINGLE / AB 备份模式(唯一必选) * ② OTA_SWAP_STRATEGY = SCRATCH / RAM 仅 AB 模式生效 * ③ OTA_SCRATCH_* 仅 AB+SCRATCH 生效 * 结构体 ota_param_t 的 seq/progress/phase 仅 AB 模式存在, * OTA_STATE_SWAPPING 仅 AB 模式存在(单备份下不编译)。 * * ┌─ 三种模式优缺点速查 ─────────────────────────────────────────┐ * │ SINGLE(单备份) │ * │ 优:最简单;最省 Flash(主区+BAK 各 58K,无需额外区) │ * │ 缺:升级失败/变砖只能整片重烧,无自动回滚 │ * │ AB + RAM(双备份 + RAM 缓冲交换) │ * │ 优:新固件崩溃可自动回滚旧固件;不预留 scratch; │ * │ 无 scratch 擦写磨损;占 Flash = A/B 各 58K │ * │ 缺:升级耗时较长(~7~12s,逐页 RAM 缓冲交换); │ * │ 固件需 2× Flash(A、B 两份) │ * │ AB + SCRATCH(双备份 + Flash 暂存区交换) │ * │ 优:升级最快(~1~3s);掉电恢复最稳 │ * │ 缺:需预留 scratch 区(暂存区,仅 1 页); │ * │ scratch 固定页反复擦写有磨损(固件越大页数越多、 │ * │ 磨损越快);固件需 2× Flash(A、B 两份) │ * │ 注:双备份两策略都需 2× 固件 Flash,scratch 仅多 1 页缓冲; │ * │ 128K 芯片上固件 > ~57K 时 2× 放不下,需外部 SPI Flash。 │ * └────────────────────────────────────────────────────────────┘ * ════════════════════════════════════════════════════════════════ */ /* ① 备份模式 ----------------------------------------------------- */ #define OTA_MODE_SINGLE 0 /* 单备份:BAK 下载→校验→拷贝覆盖主区(同 AppVersion)*/ #define OTA_MODE_AB 1 /* 双备份:A/B 区交换(新固件崩溃可回滚旧固件)*/ #define OTA_BACKUP_MODE OTA_MODE_SINGLE /* 默认单备份:最省 Flash、最简单、无磨损 */ /* ═══════ 以下 ②③ 配置仅 OTA_BACKUP_MODE == OTA_MODE_AB 时生效 ═══════ */ #if (OTA_BACKUP_MODE == OTA_MODE_AB) /* ② 双备份交换策略 ----------------------------------------------- */ #define OTA_SWAP_SCRATCH 0 /* Flash 暂存区交换:升级快、掉电恢复最稳(需预留暂存区)*/ #define OTA_SWAP_RAM 1 /* RAM 缓冲交换:不预留暂存区,A/B 保持 55K */ #define OTA_SWAP_STRATEGY OTA_SWAP_SCRATCH /* ③ 暂存区参数(仅 OTA_SWAP_STRATEGY == OTA_SWAP_SCRATCH 生效) --- */ #if (OTA_SWAP_STRATEGY == OTA_SWAP_SCRATCH) #define OTA_SCRATCH_ADDR 0x0801F800UL /* 暂存区起始地址:放在 Flash 最底部(必须页对齐)*/ #define OTA_SCRATCH_SIZE OTA_PAGE_SIZE /* 暂存区只需 1 页:交换时每次仅暂存 1 页(256B), 故大小=1 页即可;Bootloader 每次也只擦这 1 页, 避免原 1KB 整块擦除的 4 倍磨损浪费 */ #endif /* OTA_SWAP_STRATEGY == SCRATCH */ #endif /* OTA_BACKUP_MODE == AB */ /* ════════════════════════════════════════════════════════════════ * 布局宏自动联动(以下由上面配置推导,勿手工修改) * ════════════════════════════════════════════════════════════════ */ #define OTA_PARAM_ADDR_BASE 0x08002C00UL /* OTA 状态区,1KB(固定):Bootloader 11K 后 */ #define OTA_PARAM_MAX_SIZE (1UL * 1024) #if (OTA_BACKUP_MODE == OTA_MODE_AB) && (OTA_SWAP_STRATEGY == OTA_SWAP_SCRATCH) /* 双备份 + 暂存区:A/B 各 57KB(128K-12K固定-256B暂存区 ≈ 57K/份), B 区收尾于 0x0801F800,scratch(1页)紧接其后放在 Flash 最底部 0x0801F800 */ #define OTA_RUN_ADDR_BASE 0x08003000UL /* A 区 = 运行区(固件链接地址)*/ #define OTA_BAK_ADDR_BASE 0x08011400UL /* B 区 = 备份区 */ #define OTA_SLOT_MAX_SIZE (57UL * 1024) #else /* 单备份(主区+BAK) 或 双备份+RAM(A/B 各 58K):布局相同,A+B 正好填满 128K */ #define OTA_RUN_ADDR_BASE 0x08003000UL /* 主区/A 区 = 运行区 */ #define OTA_BAK_ADDR_BASE 0x08011800UL /* BAK/B 区 */ #define OTA_SLOT_MAX_SIZE (58UL * 1024) #endif #define OTA_SLOT_PAGE_NB (OTA_SLOT_MAX_SIZE / OTA_PAGE_SIZE) /* ════════════════════════════════════════════════════════════════ * OTA 状态机(APP 与 Bootloader 共用) * * 单备份:IDLE → PENDING →(Bootloader 拷贝主区)→ 运行,无回滚 * 双备份:IDLE → PENDING →(Bootloader 交换)→ BOOT_NEW →(APP 确认)→ IDLE * SWAPPING = 交换掉电中断,下次启动续做 * 新固件崩溃(IWDG复位):BOOT_NEW 未确认 → 反向交换回滚 → IDLE * ════════════════════════════════════════════════════════════════ */ #define OTA_MAGIC 0xA55A #define OTA_STATE_IDLE 0x00 /* 正常运行 */ #define OTA_STATE_PENDING 0x01 /* 新固件已下载,待 Bootloader 校验/拷贝/交换 */ #if (OTA_BACKUP_MODE == OTA_MODE_AB) #define OTA_STATE_SWAPPING 0x02 /* 双备份:交换进行中(掉电恢复入口)*/ #endif #define OTA_STATE_BOOT_NEW 0x03 /* 已切到新固件,等待 APP 确认(未确认=回滚)*/ /* ════════════════════════════════════════════════════════════════ * OTA 状态结构(APP 与 Bootloader 共用,flash.c 负责读写) * * seq / progress / phase 仅双备份需要(4 页轮换判新、交换掉电恢复), * 由 #if 保护 —— 单备份模式下字段不存在,结构体更小(20B vs 28B)。 * ════════════════════════════════════════════════════════════════ */ typedef struct { #if (OTA_BACKUP_MODE == OTA_MODE_AB) uint32_t seq; /* 写入序号:4 页轮换判新(参与 CRC16 保护)*/ #endif uint16_t magic; /* OTA_MAGIC,有效标志 */ uint8_t state; /* IDLE / PENDING / [SWAPPING] / BOOT_NEW */ uint8_t rsv; uint32_t fw_size; /* 新固件长度(字节) */ uint32_t fw_crc32; /* 新固件 CRC32 */ uint32_t fw_version; /* 新固件版本(透传,可留 0) */ #if (OTA_BACKUP_MODE == OTA_MODE_AB) uint16_t progress; /* 双备份:交换已完成页数(掉电恢复) */ uint8_t phase; /* 双备份:交换阶段标志(掉电恢复) */ #endif uint8_t rsv2; uint16_t crc16; /* 结构体自身 CRC16(CRC-16/CCITT)保护 */ } ota_param_t; #define OTA_PARAM_SIZE ((uint16_t)sizeof(ota_param_t)) #endif /* __OTA_CONFIG_H */