STM32中Flash的读写(HAL库)

  1. 1. STM32的Flash
  2. 2. 如何读写Flash
    1. 2.1. 写入Flash
    2. 2.2. 读取Flash

在以前的电路中,常常会用到EEPROM (Electrically Erasable Programmable read only memory, 带电可擦可编程只读存储器),EEPROM在掉电后储存的信息不会丢失,一般用于存储设备的设置。

但现在更常用的是Flash(闪存),Flash的特点是结构简单,同样工艺和同样晶元面积下可以得到更高容量且大数据量下的操作速度更快,但Flash每次擦除只能以扇区(Page)为单位操作,而EEPROM可以以字节(Byte)为单位操作。相比EEPROM,FLASH操作过程麻烦,特别是在小数据量反复重写时,所以在MCU中Flash结构适于不需频繁改写的程序存储器

STM32的Flash

STM32(这里以STM32F103C8T6为例)中,就带有64KB的Flash,用于存储可执行的代码。根据参考手册可知,Flash的起始地址为0x0800 0000,一共有64 Pages(64KB),每个Page的大小为1KB

image-20200617175413513

如何读写Flash

注意:在读写Flash之前,一定要规划好扇区,避免读写Flash时修改程序代码。

写入Flash

首先讲讲写操作。对Flash进行写入之前,为了确保最终的数据正确,要先进行擦除,因为对Flash进行编程只能将1变成0,而不能将0变成1,而擦除的操作就是将Flash的某个扇区全部写入1。擦除完毕后,就是对Flash进行编程。具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/**
* @brief 编程Flash(需提前擦除Flash)
*
* @param Address 地址
* @param Data 要写入的数据
* @return 执行结果,成功返回0
*/
HAL_StatusTypeDef ProgramFlash(uint32_t Address, uint32_t Data) {
HAL_StatusTypeDef _status;
/* 解锁Flash操作寄存器 */
HAL_FLASH_Unlock();
/**
* FLASH_TYPEPROGRAM_WORD表示以字(32bit)为单位进行写入,除此之外,还有HALFWORLD, DOUBLEWORLD
**/
_status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Address, Data);
HAL_FLASH_Lock();
return _status;
}

/**
* @brief 擦除Flash
*
* @param PageAddress Page地址
* @param NumberPage 要擦除的Page数量
* @return 擦除失败的地址,成功返回0xFFFFFFFF
*/
uint32_t EraseFlash(uint32_t PageAddress, uint32_t NumberPage) {
FLASH_EraseInitTypeDef herase;
uint32_t _pageError;

herase.TypeErase = FLASH_TYPEERASE_PAGES; // 按页擦除
herase.NbPages = NumberPage; // 从起始地址开始,要擦除的页数
herase.PageAddress = PageAddress; // 页的起始地址

HAL_FLASH_Unlock();
HAL_FLASHEx_Erase(&herase, &_pageError); // PageError为擦除失败时的地址,成功返回0xFFFFFFFF
HAL_FLASH_Lock();
return _pageError;
}

如我要对扇区10的首地址进行写入一个uint32_t类型的变量:

1
2
3
4
5
6
7
8
9
10
11
12
13
#define PAGE_START_ADDRESS (0x08000000 + 0x400 * 10)

uint32_t count = 0;

if ((pageError = EraseFlash(PAGE_START_ADDRESS, 1)) == 0xFFFFFFFF) {
if (ProgramFlash(PAGE_START_ADDRESS, count) == HAL_OK) {
printf("Program success: %d\n", count);
} else {
printf("Program failed...\n");
}
} else {
printf("Erase error: %x\n", (int)pageError);
}

顺带提一下,STM32为小端模式,即数据的低位放在内存的低地址,高位放在高地址,使用时需注意。

如果需要对扇区的某字节进行修改,则需将整个扇区读取到内存中进行修改,然后对扇区进行擦除,再将数据写回到扇区,是不是很麻烦😑?

STM32的Flash的擦写寿命最少是10k次,如果Flash损坏的话就变成只读的了,所以如果是需要频繁修改的数据,可以存在内存中,在掉电时再写入Flash。

读取Flash

从Flash中读取就简单多了,直接用指针即可。

1
2
3
4
5
6
7
/**
* @brief 读取lash
*
* @param Address 要读取的地址
* @return uint32_t 读取的数据
*/
uint32_t ReadFlash(uint32_t Address) { return *(uint32_t *)Address; }
本网站所有文章除特别声明外,均采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。