嵌入式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
相关产品推荐
相关产品推荐

