stm32 - stm32L476 - 擦除闪存
问题描述
L4 系列使用页(或存储区,如果您进行完全擦除)来擦除闪存。但是我在擦除页面后遇到了一些问题,我不知道为什么。
只是为了概述目标,我从 0x08080000(第 256 页)开始存储 6 个值,然后我存储从 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,这并不完全有帮助。
我不确定有什么区别,但我希望另一组对我的擦除的关注可能会揭示这个问题。
谢谢!
解决方案
此问题似乎与闪存快速编程有关,并非所有 STM32 型号都提供此功能。
根据参考手册 (RM0351),在使用快速编程之前,必须对闪存进行批量擦除。否则会发生编程序列错误,并且寄存器PGSERR
中的位FLASH_SR
将被设置。请参阅快速编程/编程错误部分中的3.3.7 闪存主存储器编程序列和位 7 PGSERR下的3.7.5 闪存状态寄存器 (FLASH_SR)。
RM0351 第 9 版,3.3.7 闪存主存储器编程序列,第 106 页:
Fast programming
(...)
1. Perform a mass erase of the bank to program. If not, PGSERR is set.
2. (...)
RM0351 第 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()
orFLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, ...)
代替。
相关源文件:stm32l4xx_hal_flash.h、stm32l4xx_hal_flash.c
相关文章:STM32——读写闪存
推荐阅读
- ios - 使用自定义消息 Swift 4 打开消息
- javascript - 使用 fs.watch('dir', fn) 的通配模式
- ruby - 符号和字符串之间的转换
- android - Admob 集成无法正常工作或 admob 的某些实现最近发生了变化?
- c++ - 在具有可调用对象的线程中生成线程
- node.js - 无法将 SSL 客户端证书从 Nodejs/MQRC_KEY_REPOSITORY_ERROR/MQRC_SSL_INITIALIZATION_ERROR 传递给 IBM MQ
- reactjs - 如何为 Spacemacs 中的每个 js 文件设置 rjsx 模式?
- apache-spark-sql - 为什么 Presto 比 Spark SQL 快
- html - 画布中的脉冲动画
- java - 如何修改 CAS 5.x 以使用 rest api 检查用户的登录名和密码