STM32F4至STM32L4R9I的Flash代码迁移:写入逻辑正确性验证
STM32L4R9I Flash字节写入适配问题分析
原STM32F4 Flash写入函数
static void hal_flash_bank_stm32_write(void * context, int bank, uint32_t offset, const uint8_t * data, uint32_t size) { hal_flash_bank_stm32_t * self = (hal_flash_bank_stm32_t *) context; if (bank > 1) return; if (offset > self->sector_size) return; if ((offset + size) > self->sector_size) return; unsigned int i; HAL_FLASH_Unlock(); for (i = 0; i < size; i++) { HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, self->banks[bank] + offset + i, data[i]); } HAL_FLASH_Lock(); }
用户的适配尝试(针对STM32L4R9I)
由于STM32L4R9I仅支持FLASH_TYPEPROGRAM_DOUBLEWORD,不支持字节写入,用户尝试了以下代码:
uint64_t dword = 0; for (i = 0; i < size; i++) { dword = (dword << 8) | data[i]; if (i > 0 && i % 8 == 0) { uint32_t addr = self->banks[bank] + offset + i; HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, addr, dword); dword = 0; } }
逻辑问题分析
你的适配代码存在几处关键疏漏:
- 地址偏移错误:当你在
i%8==0时写入,此时计算的地址是self->banks[bank] + offset + i,但第0-7个字节对应的起始地址应该是offset + i - 8,比如i=8时,写入的是前8个字节(0-7),对应的地址应该是起始地址+offset,而不是offset+8。 - 字节顺序错误:你用
dword = (dword << 8) | data[i]的方式,会把第一个字节放在双字的最高位(比如data[0]变成dword的第57-63位),但STM32的Flash是小端存储,实际应该让data[0]对应双字的最低字节(第0-7位),否则写入的数据字节序会反转。 - 剩余字节未处理:如果size不是8的整数倍,循环结束后剩下的1-7个字节没有写入,这部分数据会丢失。
- 地址对齐问题:STM32L4的Flash双字写入要求地址必须是8字节对齐,原函数中的
offset可能不是8对齐的,需要先处理起始部分的非对齐字节(如果有的话),或者确保写入起始地址对齐。
修正后的适配代码示例
HAL_FLASH_Unlock(); uint32_t start_addr = self->banks[bank] + offset; const uint8_t* p_data = data; uint32_t remaining = size; // 处理起始非8对齐的部分(如果需要) uint32_t misalign = (uint32_t)start_addr % 8; if (misalign != 0 && remaining > 0) { uint8_t fill_bytes = 8 - misalign; if (fill_bytes > remaining) fill_bytes = remaining; // 读取当前地址的双字数据,只修改需要写入的字节,再写入 uint64_t current_dword = *(uint64_t*)(start_addr - misalign); for (uint32_t i = 0; i < fill_bytes; i++) { ((uint8_t*)¤t_dword)[misalign + i] = p_data[i]; } HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, start_addr - misalign, current_dword); start_addr += fill_bytes; p_data += fill_bytes; remaining -= fill_bytes; } // 处理整双字部分 while (remaining >= 8) { uint64_t dword = 0; // 按小端顺序组装双字:data[0]是最低字节 for (uint32_t i = 0; i < 8; i++) { ((uint8_t*)&dword)[i] = p_data[i]; } HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, start_addr, dword); start_addr += 8; p_data += 8; remaining -= 8; } // 处理剩余不足8字节的部分 if (remaining > 0) { uint64_t current_dword = *(uint64_t*)start_addr; for (uint32_t i = 0; i < remaining; i++) { ((uint8_t*)¤t_dword)[i] = p_data[i]; } HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, start_addr, current_dword); } HAL_FLASH_Lock();
额外注意事项
- STM32 Flash写入前必须确保对应扇区已经被擦除,否则写入会失败,原函数假设扇区已擦除,适配后也要保持这个前提。
- 双字写入的地址必须严格8字节对齐,否则
HAL_FLASH_Program会返回错误码,建议在代码中添加错误检查(比如判断返回值是否为HAL_OK)。
内容的提问来源于stack exchange,提问作者atta
相关产品推荐
相关产品推荐

