RAM 缓冲区
1. OTA 中的缓冲区职责
OTA 通常采用“接收一小块、校验一小块、写入存储”的流式处理方式,不会把整个固件一次性放进 RAM。
| 概念 | 位置 | 作用 |
|---|---|---|
| RAM 双缓冲 | MCU 内部 RAM | 在串口接收和 Flash 写任务之间传递数据 |
| Flash A/B 区 | 外部或内部 Flash | 保存升级包、备份镜像和回滚数据 |
RAM 双缓冲不是 Flash 的 A/B 升级分区:前者解决任务间的数据暂存和吞吐,后者解决掉电保护、版本切换和回滚。
2. 当前工程的数据链路
串口 / Ymodem
↓
1030 字节接收缓冲区
↓ memcpy
双缓冲槽 s_slots[2]
↓ 队列传递槽指针
Flash 写任务
↓
4 KB 缓冲区
↓
写入外部 W25Q64 的 A 区这里还有一个ymodem实在是程序设计问题了,到时候如果是OTA应该不要这个ymodem的缓存,而是直接写到flash的双缓存里去
4. 小型工程:固定块内存池
下面的思路来自OTA 内存池复盘中的面试复盘对话。
门锁、门禁等小型工程可以用一个大数组划分固定大小的块,再用简单的单向空闲链表管理这些块:
大数组(静态分配)
├─ 128B 块 0
├─ 128B 块 1
├─ 128B 块 2
└─ ...
空闲链表:
[块 0 | next] → [块 1 | next] → [块 2 | next] → ...如果数组是静态定义并初始化为 0,例如:
static uint8_t g_pool[POOL_BLOCK_COUNT][POOL_BLOCK_SIZE] = {0};它通常进入 .bss 段(具体仍以编译器、链接脚本和初始化方式为准)。数组本身保存实际存储空间,空闲链表只保存每个块的首地址和 next 关系:
static uint8_t g_pool[16][128] = {0};因为每个元素较小,需要多个元素才能组成一个OTA的缓冲区,但是内存池是供给所有任务的,他肯定会不连续,所以需要用链表的方式,找到下一个内存块的位置,这里链表可以直接用freertos的list.h,也可自己写,这样可以省一些空间,因为只需要单向的链表就好了