ST意法半导体
直播中

张娟

8年用户 2248经验值
私信 关注
[问答]

STM32H743一个扇区128K,扇区中间地址写数据,地址前后的数据内容不变,怎么解决?

扇区128K,写数据要擦除整个扇区,扇区的其他数据页被擦除掉了,怎么不改变扇区其他地址的数据不变

回帖(2)

胡丹

2025-3-14 16:17:28
由于FLASH 结构的原理限制,须按照手册规定的方式擦和写。


如果只是想修改中间部分数据的话,那么就将这个sectors 的数据拷贝到RAM中并修改后,擦除后一并写入。

毕竟FLASH的目的主要是为了保存程序,顺带考虑保存数据。

FLASH的擦写寿命有限,如果经常保存数据建议还是使用片外的EEPROM,好用不贵。
举报

郭大

2025-3-21 17:53:12

在STM32H743中,由于Flash存储器的物理特性,擦除操作的最小单位是128KB的扇区,而写入操作需要确保目标区域已被擦除(即全为0xFF)。因此,在扇区中间写入数据时,必须采取特定策略来保留其他数据。以下是详细的解决方案:




解决方案步骤


1. 备份原始数据到RAM



  • 读取整个扇区数据:在擦除前,将整个128KB扇区的数据读取到RAM缓冲区。
    #define SECTOR_SIZE  (128 * 1024)
    uint8_t buffer[SECTOR_SIZE];
    memcpy(buffer, (void*)SECTOR_START_ADDR, SECTOR_SIZE);

  • 修改目标数据:在缓冲区中更新需要写入的地址内容。
    uint32_t target_offset = 0x2000; // 中间地址示例
    memcpy(buffer + target_offset, new_data, new_data_size);


2. 执行擦除操作




  • 使用HAL库擦除目标扇区:


    FLASH_EraseInitTypeDef erase;
    erase.TypeErase = FLASH_TYPEERASE_SECTORS;
    erase.Banks = FLASH_BANK_1; // 根据实际使用的Bank选择
    erase.Sector = SECTOR_NUMBER;
    erase.NbSectors = 1;

    uint32_t sector_error;
    HAL_FLASH_Unlock();
    HAL_FLASHEx_Erase(&erase, §or_error);
    HAL_FLASH_Lock();



3. 将缓冲区数据写回Flash



  • 逐块写入:Flash写入通常需要按64位(8字节)对齐,使用HAL_FLASH_Program函数:
    HAL_FLASH_Unlock();
    for (uint32_t i = 0; i < SECTOR_SIZE; i += 8) {
      uint64_t data = *(uint64_t*)(buffer + i);
      HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, SECTOR_START_ADDR + i, data);
    }
    HAL_FLASH_Lock();




优化与注意事项


1. 断电保护机制



  • 使用双扇区备份:维护两个扇区(A和B),每次写入新数据到B扇区,完成后将指针切换到B,下次擦除A。这避免单扇区操作时断电导致数据丢失。

  • 写入校验:在数据写回后,校验Flash内容与缓冲区是否一致,确保完整性。


2. 数据存储结构优化



  • 分块管理:将频繁修改的数据独立存储在小扇区(若可用)或使用外部EEPROM/FRAM。

  • 日志式更新:记录变更日志到其他存储区,积累一定量后再合并写入,减少擦除次数。


3. 磨损均衡(Wear Leveling)



  • 动态分配数据到不同扇区,平衡擦写次数。例如,使用索引表记录数据位置,每次更新选择不同扇区。


4. 关键代码保护



  • 操作期间禁用中断:避免擦写过程被中断,导致操作失败。
    __disable_irq();
    // 执行Flash操作
    __enable_irq();




示例代码片段


void update_flash_sector(uint32_t sector_addr, uint32_t offset, uint8_t *data, uint32_t size) {
    // 备份原始数据
    uint8_t backup[SECTOR_SIZE];
    memcpy(backup, (void*)sector_addr, SECTOR_SIZE);

    // 修改备份数据
    memcpy(backup + offset, data, size);

    // 擦除扇区
    FLASH_EraseInitTypeDef erase = {0};
    erase.TypeErase = FLASH_TYPEERASE_SECTORS;
    erase.Sector = GET_SECTOR_NUMBER(sector_addr); // 根据地址获取扇区号
    erase.NbSectors = 1;
    uint32_t sector_error;

    HAL_FLASH_Unlock();
    if (HAL_FLASHEx_Erase(&erase, §or_error) != HAL_OK) {
        // 处理错误
    }

    // 写回数据
    for (uint32_t i = 0; i < SECTOR_SIZE; i += 8) {
        uint64_t word = *(uint64_t*)(backup + i);
        if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, sector_addr + i, word) != HAL_OK) {
            // 处理错误
        }
    }
    HAL_FLASH_Lock();
}



结论


在STM32H743中,由于Flash擦除的最小单位为128KB扇区,局部更新数据必须通过备份-修改-擦除-写回的流程实现。虽然无法绕过物理擦除限制,但通过合理的软件设计和数据管理策略(如双缓冲、磨损均衡),可以有效减少数据丢失风险并延长Flash寿命。对于频繁更新的场景,建议结合外部存储器或优化存储结构以提升系统鲁棒性。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分