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

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*)&current_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*)&current_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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 01:04:55