stm32L476 - 擦除闪存

Posted

技术标签:

【中文标题】stm32L476 - 擦除闪存【英文标题】:stm32L476 - erasing flash 【发布时间】:2021-09-28 02:13:20 【问题描述】:

L4 系列使用页(或存储区,如果您进行完全擦除)来擦除闪存。 但是我在擦除页面后遇到了一些问题,我不知道为什么。

只是为了概述目标,我从 0x08080000 开始存储 6 个值(第 256 页) 然后我存储更多的值,从 0x08080800)(第 257 页)到 0x08085800(第 267 页)

我使用一个函数来擦除/写入第 256 页的值:

void write_bias_flash(int16_t biases[]) 
    uint16_t *flash_biases = (uint16_t*) (ADDR_FLASH_PAGE_256);
    static FLASH_EraseInitTypeDef EraseInitStruct;
    Address = ADDR_FLASH_PAGE_256;

    /* Fill EraseInit structure*/
    EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
    EraseInitStruct.Page = 0;
    EraseInitStruct.Banks = FLASH_BANK_2;
    EraseInitStruct.NbPages = 1;

    HAL_FLASH_Unlock();
    if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK) 
        serprintf("Error erasing biases at address: 0x%x", Address);
    
    for (int8_t bias = 0; bias < 6; bias++) 
         if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD,
                Address + bias * sizeof(uint64_t), (uint64_t) biases[bias])
                != HAL_OK)
            serprintf("Error writing biases to flash.");
     
    HAL_FLASH_Lock();
    serprintf("Biases stored in flash.");

这项工作很棒。没有问题。

我有两个函数用于擦除/写入从 0x08080800 开始的数据)(第 257 页):

void Erase_TM_Flash() 
    uint8_t *flash = (uint8_t*) (FLASH_USER_START_ADDR);
    uint8_t *b = (uint16_t*) (ADDR_FLASH_PAGE_256);
    static FLASH_EraseInitTypeDef EraseInitStruct;
    Address = FLASH_USER_START_ADDR;

    /* Fill EraseInit structure*/
    EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
    EraseInitStruct.Page = 1;
    EraseInitStruct.NbPages = 255;
    EraseInitStruct.Banks = FLASH_BANK_2;

    HAL_FLASH_Unlock();
    if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK) 
        serprintf("Error erasing biases at address: 0x%x", Address);
    

    HAL_FLASH_Lock();

    for (uint16_t i = 0; i< (FLASH_ROW_SIZE * sizeof(uint64_t))*255; i++)
    
        if ((uint16_t) *(flash+i) != 255) 
            serprintf("0x%x is not erased (%i)", flash+i, (uint16_t) *(flash+i));
        

    


void Save_to_Flash(uint32_t *data) 

    uint32_t src_addr = (uint32_t) data;
    Erase_TM_Flash();
    serprintf("Saving to flash...");
    HAL_StatusTypeDef HAL_STATUS;

    HAL_FLASH_Unlock();
    Address = FLASH_USER_START_ADDR;
    while (Address < (FLASH_USER_END_ADDR - (FLASH_ROW_SIZE * sizeof(uint64_t)))) 
        HAL_STATUS = HAL_FLASH_Program(FLASH_TYPEPROGRAM_FAST, Address, (uint64_t) src_addr);
        if (HAL_STATUS == HAL_OK) 
          Address = Addres+ (FLASH_ROW_SIZE * sizeof(uint64_t));
            src_addr = src_addr + (FLASH_ROW_SIZE * sizeof(uint64_t));
             else 
                serprintf("Error writing flash at address 0x%x. (%i)", Address, HAL_STATUS);
                Address = Address + (FLASH_ROW_SIZE * sizeof(uint64_t));
                src_addr = src_addr + (FLASH_ROW_SIZE * sizeof(uint64_t));
            
    
    HAL_FLASH_Lock();
    serprintf("Done");
    

擦除工作正常。我验证调试器中的值(并在代码中检查未擦除的页面)。但是当保存发生时:

Error writing flash at address 0x8080800. (1)
Error writing flash at address 0x8080900. (1)
Error writing flash at address 0x8080a00. (1)
Error writing flash at address 0x8080b00. (1)

以此类推,遍历所有剩余的页面。

但是,如果我擦除整个闪存:

void Erase_Flash() 
    serprintf("Erasing flash...");
    HAL_FLASH_Unlock();
    /* Clear OPTVERR bit set on virgin samples */
    __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR);

    /* Fill EraseInit structure*/
    EraseInitStruct.TypeErase = FLASH_TYPEERASE_MASSERASE;
    EraseInitStruct.Banks = FLASH_BANK_2;

    if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK) 
        serprintf("Error erasing flash.");
    
    HAL_FLASH_Lock();
    serprintf("Done.");

然后写作就像一个魅力。 HAL_STATUS = 1,根据我找到的代码是HAL_ERROR = 0x01U,这并不完全有用。

我不确定有什么区别,但我希望对我的擦除有另一种看法,可能会发现问题。

谢谢!

【问题讨论】:

【参考方案1】:

此问题似乎与闪存快速编程有关,并非所有 STM32 型号都提供此功能。

根据Reference Manual (RM0351),在使用快速编程之前必须对闪存进行批量擦除。否则会发生编程顺序错误FLASH_SR 寄存器中的PGSERR 位将被设置。请参阅快速编程/编程错误部分中的3.3.7 Flash 主存储器编程序列3.7.5 Flash 状态寄存器(FLASH_SR) Bit 7 PGSERR 下。

RM0351 Rev 9,3.3.7 闪存主存储器编程序列,第 106 页:

Fast programming
(...)
1. Perform a mass erase of the bank to program. If not, PGSERR is set.
2. (...)

RM0351 Rev 9,3.3.7 闪存主存储器编程序列,第 107 页:

Programming errors
(...)
PGSERR: Programming Sequence Error
PGSERR is set if one of the following conditions occurs:
– (...)
– In the fast programming sequence: the Mass erase is not performed before setting 
  FSTPG bit.
– (...)

因此,观察到的行为符合预期。 - 所以你可以替换你的Erase_TM_Flash()函数并使用Erase_Flash()首先批量擦除整个闪存库。或者,完全避免使用闪存快速编程,而改用FLASH_Program_DoubleWord()FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, ...)

相关源文件:stm32l4xx_hal_flash.h、stm32l4xx_hal_flash.c

相关帖子:STM32 - writing and reading flash

【讨论】:

谢谢!我已经出城了,无法对此进行评论。但它是有道理的,你已经呈现它的方式。我将不得不重新组织一些事情。

以上是关于stm32L476 - 擦除闪存的主要内容,如果未能解决你的问题,请参考以下文章

使用 STM32L476RG 时出现 UART 溢出错误

STM32L476 和 CubeMX 上带有 DMA 的 SD 卡没有中断

STM32L476应用开发之一:初次使用

STM32L476的RTC使用问题记录

STM32L476应用开发之二:模拟量数据采集

最终启动序列中的错误 - STM32L476 的 Eclipse 系统工作台调试