You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

嵌入式C固件下载:64字节Flash页打包写入问题求助

解决嵌入式Flash分块写入的缓冲区打包问题

看起来你的核心需求是把不定长的下载数据包凑成64字节的完整块,再写入Flash存储器。你的现有代码逻辑方向是对的,但在剩余数据处理、地址计算上存在几个小问题,导致rmdBuff出现异常。我们一步步来梳理和修正:

原代码的关键问题

  • 剩余数据复制的地址错误:当rmdBuff被填满后,你尝试把当前数据包剩下的内容复制到rmdBuff时,源地址多写了+1,这会导致丢字节,进而破坏缓冲区数据。
  • 缺少文件大小累加:received_file_size没有在每次处理数据包时更新,后续可能无法正确判断下载是否完成。
  • 最后不足64字节的块未处理:当前代码只处理凑满64字节的情况,下载结束后剩余的不足64字节的数据没有写入Flash(这部分大概率是你还没实现,但需要纳入逻辑)。
  • 变量命名可读性差:比如rmdBuff、rmd_indx这类缩写可以更清晰,便于后续维护。

修正后的完整代码

先调整全局变量的命名(可选,但推荐提升可读性),然后修正核心逻辑:

// 全局变量:语义化命名,降低维护成本
uint8_t flashWriteBuffer[64]; // 凑满64字节后写入Flash的缓冲区
uint8_t remainingBuffer[64];  // 存放未凑满的剩余数据
uint8_t remainingIdx = 0;     // remainingBuffer的当前写入位置
uint32_t receivedFileSize = 0;// 已接收的总字节数

然后是修正后的store_file_packet函数:

void store_file_packet(char *data, uint32_t length) {
    // 参数合法性检查
    if ((data == NULL) || (length < 1)) {
        return;
    }

    // 第一次接收数据包时初始化下载状态
    if (!is_state_set(DOWNLOADING)) {
        printf("********* Initial Start of Download **************\n\r");
        receivedFileSize = 0;
        add_state(DOWNLOADING);
        remainingIdx = 0;
        memset(remainingBuffer, 0, sizeof(remainingBuffer)); // 确保初始状态干净
    }

    receivedFileSize += length; // 累加已接收字节数
    uint8_t *dataPtr = (uint8_t *)data; // 转成uint8_t指针,避免char的符号扩展问题

    // 1. 先填充剩余缓冲区,尝试凑满64字节
    if (remainingIdx > 0) {
        uint8_t availableSpace = 64 - remainingIdx;
        // 计算当前数据包能填充剩余缓冲区的字节数
        uint8_t copyLen = (length <= availableSpace) ? length : availableSpace;
        
        memcpy(&remainingBuffer[remainingIdx], dataPtr, copyLen);
        remainingIdx += copyLen;
        dataPtr += copyLen;
        length -= copyLen;

        // 剩余缓冲区已满,写入Flash
        if (remainingIdx == 64) {
            write_flash_page(remainingBuffer); // 替换成你的Flash写入函数
            memset(remainingBuffer, 0, sizeof(remainingBuffer));
            remainingIdx = 0;
        }
    }

    // 2. 处理当前数据包中剩余的完整64字节块
    while (length >= 64) {
        memcpy(flashWriteBuffer, dataPtr, 64);
        write_flash_page(flashWriteBuffer);
        dataPtr += 64;
        length -= 64;
    }

    // 3. 把最后不足64字节的内容存入剩余缓冲区
    if (length > 0) {
        memcpy(remainingBuffer, dataPtr, length);
        remainingIdx = length;
    }
}

// 补充:下载完成后调用,处理最后不足64字节的块(适配Flash写满页的要求)
void finish_download() {
    if (is_state_set(DOWNLOADING) && remainingIdx > 0) {
        // 如果Flash要求必须写满64字节,就补0;若允许写不满,直接写remainingIdx字节即可
        memset(&remainingBuffer[remainingIdx], 0, 64 - remainingIdx);
        write_flash_page(remainingBuffer);
        remainingIdx = 0;
        remove_state(DOWNLOADING);
        printf("********* Download Completed, Total Size: %lu bytes **************\n\r", receivedFileSize);
    }
}

关键改进点说明

  • 地址计算修正:移除了原代码中错误的+1偏移,改用指针移动的方式处理数据,更直观且不易出错。
  • 分阶段处理逻辑:把整个流程拆成三个清晰的步骤:填充剩余缓冲区、处理完整64字节块、保存剩余不足部分,逻辑更线性,降低出错概率。
  • 符号安全:将char*转为uint8_t*,避免因char的有符号属性导致的数据异常。
  • 下载收尾处理:补充finish_download函数,专门处理最后不足64字节的情况,符合Flash写入的硬件要求。
  • 命名优化:用语义化名称代替缩写,后续维护时能快速理解变量用途。

额外建议

  • 避免在函数内频繁调用memset,比如flashWriteBuffer每次都会被新数据覆盖,无需提前清空。
  • Flash写入前记得对应页的擦除操作(如果你的Flash硬件要求先擦除再写入,原代码未体现这部分,需要根据硬件手册补充)。
  • 可以添加Flash写入的错误检查,比如捕获写入失败的情况并做重试或日志记录。

内容的提问来源于stack exchange,提问作者PhillyNJ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:48:03