perf(vd960DBN): OTA RAM 优化 — union 复用块缓冲 + 命令分支数组改 static

MRS 编译 RAM 90.02% (44248/48KB) 逼近历史 .bss 挤栈红线, 减负:
- ota_srv.c: _chunk_buf[256] + _fs_frame[254] 合并为 union (下载/校验与刷写帧
  互斥复用, 省 ~260B static); ota_send_9f 组帧直接用 union 缓冲 (省 254B 栈)
- iot_mqtt_srv.c: 6 个 ota_* 分支 resp[256~400] + ota_data hexbuf[513] 局部栈
  数组改 static (栈峰值 → BSS, 防运行时栈溢出; RAM 总量不变但运行时安全)

验证: gcc 隔离单测 9/9 全过; 语法 0 新增错误
This commit is contained in:
wangfq
2026-08-20 13:41:33 +08:00
parent 49736c341c
commit 0b51d84a9b
2 changed files with 28 additions and 27 deletions
@@ -710,7 +710,7 @@ static void iot_handle_publish(const char *topic, uint8_t *payload, int payload_
} else if (strcmp(cmd_str, "ota_begin") == 0) { } else if (strcmp(cmd_str, "ota_begin") == 0) {
/* V1.08: 开启 OTA 会话 / 断点续传定位 (Loop MCU 远程 OTA, 先存后刷) */ /* V1.08: 开启 OTA 会话 / 断点续传定位 (Loop MCU 远程 OTA, 先存后刷) */
char resp[400]; static char resp[400]; /* static: RAM 90% 下防栈峰值 (历史 .bss 挤栈事故) */
uint32_t size = 0, crc32 = 0; uint32_t size = 0, crc32 = 0;
char version[16] = {0}; char version[16] = {0};
uint8_t force = 0; uint8_t force = 0;
@@ -750,8 +750,8 @@ static void iot_handle_publish(const char *topic, uint8_t *payload, int payload_
} else if (strcmp(cmd_str, "ota_data") == 0) { } else if (strcmp(cmd_str, "ota_data") == 0) {
/* V1.08: 分片下发 (256B/片, 单片 CRC32; 重复片幂等, 乱序拒收指示续传) */ /* V1.08: 分片下发 (256B/片, 单片 CRC32; 重复片幂等, 乱序拒收指示续传) */
char resp[400]; static char resp[400];
char hexbuf[512 + 1]; static char hexbuf[512 + 1]; /* 512 hex 最大, static 防栈峰值 */
const char *hp; const char *hp;
uint32_t offset = 0, crc32 = 0; uint32_t offset = 0, crc32 = 0;
int rc; int rc;
@@ -793,7 +793,7 @@ static void iot_handle_publish(const char *topic, uint8_t *payload, int payload_
} else if (strcmp(cmd_str, "ota_end") == 0) { } else if (strcmp(cmd_str, "ota_end") == 0) {
/* V1.08: 结束下载, 全镜像 CRC32 复核 */ /* V1.08: 结束下载, 全镜像 CRC32 复核 */
char resp[300]; static char resp[300];
uint32_t crc32 = 0; uint32_t crc32 = 0;
int rc; int rc;
memset(tmp, 0, sizeof(tmp)); memset(tmp, 0, sizeof(tmp));
@@ -827,7 +827,7 @@ static void iot_handle_publish(const char *topic, uint8_t *payload, int payload_
} else if (strcmp(cmd_str, "ota_abort") == 0) { } else if (strcmp(cmd_str, "ota_abort") == 0) {
/* V1.08: 中止会话, 释放暂存 */ /* V1.08: 中止会话, 释放暂存 */
char resp[256]; static char resp[256];
int rc = ota_cmd_abort(); int rc = ota_cmd_abort();
snprintf(resp, sizeof(resp), snprintf(resp, sizeof(resp),
"{\"msg_id\":%lu,\"cmd\":\"ota_abort\",\"ts\":%lu,\"code\":%d,\"msg\":\"%s\"}", "{\"msg_id\":%lu,\"cmd\":\"ota_abort\",\"ts\":%lu,\"code\":%d,\"msg\":\"%s\"}",
@@ -837,7 +837,7 @@ static void iot_handle_publish(const char *topic, uint8_t *payload, int payload_
} else if (strcmp(cmd_str, "ota_flash") == 0) { } else if (strcmp(cmd_str, "ota_flash") == 0) {
/* V1.08: 触发本地 ISP 刷写 (同步安全检查 → 异步执行) */ /* V1.08: 触发本地 ISP 刷写 (同步安全检查 → 异步执行) */
char resp[300]; static char resp[300];
char slot_buf[8] = {0}; char slot_buf[8] = {0};
uint8_t slot = 0, force = 0; uint8_t slot = 0, force = 0;
int rc; int rc;
@@ -868,7 +868,7 @@ static void iot_handle_publish(const char *topic, uint8_t *payload, int payload_
} else if (strcmp(cmd_str, "ota_status") == 0) { } else if (strcmp(cmd_str, "ota_status") == 0) {
/* V1.08: 查询 OTA 状态 (含刷写进度) */ /* V1.08: 查询 OTA 状态 (含刷写进度) */
char resp[400]; static char resp[400];
const OtaMeta *m = ota_meta(); const OtaMeta *m = ota_meta();
snprintf(resp, sizeof(resp), snprintf(resp, sizeof(resp),
"{\"msg_id\":%lu,\"cmd\":\"ota_status\",\"ts\":%lu,\"code\":0,\"msg\":\"success\"," "{\"msg_id\":%lu,\"cmd\":\"ota_status\",\"ts\":%lu,\"code\":0,\"msg\":\"success\","
@@ -46,9 +46,11 @@ static uint32_t _fs_block_crc; /* 当前块 CRC (调试/审计) */
uint8_t g_ota_flash_active = 0; /* 本地刷写进行中 → uart_srv 把 ACK 交给 ota_srv */ uint8_t g_ota_flash_active = 0; /* 本地刷写进行中 → uart_srv 把 ACK 交给 ota_srv */
/* 块缓冲 (static: 栈紧张教训) */ /* 块缓冲 (static: 栈紧张教训; union: 下载片 256B 与 A7 帧 254B 互斥复用, 省 ~260B RAM) */
static uint8_t _chunk_buf[OTA_CHUNK_SIZE]; /* 下载片缓冲 */ static union {
static uint8_t _fs_frame[5 + OTA_FLASH_BLOCK + 1]; /* A7 帧: 9F+SubL+SubH+LEN+CMD+DATA+CHECK */ uint8_t chunk[OTA_CHUNK_SIZE]; /* 下载片缓冲 / 校验读缓冲 */
uint8_t frame[5 + OTA_FLASH_BLOCK + 1]; /* A7 帧: 9F+SubL+SubH+LEN+CMD+DATA+CHECK */
} _ota_buf;
/*=========================================================================== /*===========================================================================
* CRC-32/ISO-HDLC (协议 §4.19.1; 逐位实现, 零查表 RAM) * CRC-32/ISO-HDLC (协议 §4.19.1; 逐位实现, 零查表 RAM)
@@ -275,15 +277,15 @@ int ota_cmd_data(uint32_t offset, uint32_t crc32, const char *hex)
clen = _meta.size - offset; clen = _meta.size - offset;
if (clen > OTA_CHUNK_SIZE) clen = OTA_CHUNK_SIZE; if (clen > OTA_CHUNK_SIZE) clen = OTA_CHUNK_SIZE;
if (ota_hex_decode(hex, _chunk_buf, clen) != 0) { if (ota_hex_decode(hex, _ota_buf.chunk, clen) != 0) {
return 1; /* hex 格式错误 */ return 1; /* hex 格式错误 */
} }
if (ota_crc32(_chunk_buf, clen) != crc32) { if (ota_crc32(_ota_buf.chunk, clen) != crc32) {
return 1; /* 单片 CRC 失败 */ return 1; /* 单片 CRC 失败 */
} }
/* 落盘: SPI_Flash_Write 自带"目标区非 0xFF 则读-改-写擦扇区" (256B 页对齐) */ /* 落盘: SPI_Flash_Write 自带"目标区非 0xFF 则读-改-写擦扇区" (256B 页对齐) */
SPI_Flash_Write(_chunk_buf, _slot_base + offset, (uint16_t)clen); SPI_Flash_Write(_ota_buf.chunk, _slot_base + offset, (uint16_t)clen);
_meta.received = offset + clen; _meta.received = offset + clen;
ota_meta_flush(); ota_meta_flush();
PRINT("OTA: data@%lu crc_ok received=%lu\n", PRINT("OTA: data@%lu crc_ok received=%lu\n",
@@ -313,8 +315,8 @@ int ota_cmd_end(uint32_t crc32)
while (i < _meta.size) { while (i < _meta.size) {
uint32_t n = _meta.size - i; uint32_t n = _meta.size - i;
if (n > OTA_CHUNK_SIZE) n = OTA_CHUNK_SIZE; if (n > OTA_CHUNK_SIZE) n = OTA_CHUNK_SIZE;
SPI_Flash_Read(_chunk_buf, _slot_base + i, (uint16_t)n); SPI_Flash_Read(_ota_buf.chunk, _slot_base + i, (uint16_t)n);
total = ota_crc32_update(total, _chunk_buf, n); total = ota_crc32_update(total, _ota_buf.chunk, n);
i += n; i += n;
} }
total ^= 0xFFFFFFFFu; total ^= 0xFFFFFFFFu;
@@ -407,18 +409,17 @@ int ota_cmd_flash(uint8_t slot, uint8_t force)
static void ota_send_9f(uint8_t sub_l, uint8_t sub_h, uint8_t cmd, static void ota_send_9f(uint8_t sub_l, uint8_t sub_h, uint8_t cmd,
const uint8_t *data, uint16_t datalen) const uint8_t *data, uint16_t datalen)
{ {
uint8_t frame[5 + OTA_FLASH_BLOCK + 1];
uint16_t i; uint16_t i;
uint8_t sum = 0; uint8_t sum = 0;
frame[0] = 0x9F; _ota_buf.frame[0] = 0x9F;
frame[1] = sub_l; _ota_buf.frame[1] = sub_l;
frame[2] = sub_h; _ota_buf.frame[2] = sub_h;
frame[3] = (uint8_t)(1 + datalen); /* LEN 含 CMD */ _ota_buf.frame[3] = (uint8_t)(1 + datalen); /* LEN 含 CMD */
frame[4] = cmd; _ota_buf.frame[4] = cmd;
if (data && datalen) memcpy(&frame[5], data, datalen); if (data && datalen) memcpy(&_ota_buf.frame[5], data, datalen);
for (i = 1; i < 5 + datalen; i++) sum += frame[i]; /* SubL..DATA */ for (i = 1; i < 5 + datalen; i++) sum += _ota_buf.frame[i]; /* SubL..DATA */
frame[5 + datalen] = sum; _ota_buf.frame[5 + datalen] = sum;
UART2_SendString(frame, (uint16_t)(5 + datalen + 1)); UART2_SendString(_ota_buf.frame, (uint16_t)(5 + datalen + 1));
} }
/* 刷写失败收尾: 状态落盘 + event_report 告警 + 恢复 0x7F 模式 */ /* 刷写失败收尾: 状态落盘 + event_report 告警 + 恢复 0x7F 模式 */
@@ -566,9 +567,9 @@ void ota_poll(void)
uint32_t read_off = _fs_sent; uint32_t read_off = _fs_sent;
uint32_t remain = _meta.size - read_off; uint32_t remain = _meta.size - read_off;
uint16_t datalen = (remain > OTA_FLASH_BLOCK) ? OTA_FLASH_BLOCK : (uint16_t)remain; uint16_t datalen = (remain > OTA_FLASH_BLOCK) ? OTA_FLASH_BLOCK : (uint16_t)remain;
SPI_Flash_Read(_fs_frame + 5, _slot_base + read_off, datalen); SPI_Flash_Read(_ota_buf.frame + 5, _slot_base + read_off, datalen);
ota_send_9f((uint8_t)(_fs_sub & 0xFF), (uint8_t)(_fs_sub >> 8), 0xA7, ota_send_9f((uint8_t)(_fs_sub & 0xFF), (uint8_t)(_fs_sub >> 8), 0xA7,
_fs_frame + 5, datalen); _ota_buf.frame + 5, datalen);
_fs = OTA_FLASH_WAIT_ACK; _fs = OTA_FLASH_WAIT_ACK;
_fs_start_ms = now; _fs_start_ms = now;
PRINT("OTA: sent A7 sub=%u off=%lu datalen=%u\n", PRINT("OTA: sent A7 sub=%u off=%lu datalen=%u\n",