1. 为什么需要内部Flash存储数据
在实际项目中,我们经常会遇到需要保存一些关键数据的情况,比如设备的配置参数、运行日志、用户设置等。这些数据需要在设备断电后仍然能够保留,下次上电时还能读取使用。最直接的想法是外接一个EEPROM或者Flash芯片,但有时候板子已经设计好了,没有预留这些外设,或者为了节省成本不想增加额外硬件。这时候,STM32芯片内部的Flash就派上用场了。
我最近就遇到了这样一个项目,板子已经量产,没有外接存储芯片,但需要保存一些校准参数。于是我就研究了如何使用STM32内部的Flash来实现掉电数据保存。实测下来,这个方案非常稳定可靠,而且几乎零成本,毕竟Flash空间是芯片自带的,不用白不用。
STM32的内部Flash主要用来存储程序代码,但通常都会有一些剩余空间。比如我用的STM32L031G6u6有32KB的Flash,实际程序只用了20KB左右,剩下的12KB就可以用来存储数据。不过要注意的是,不同型号的STM32芯片,其Flash大小和分页方式可能不同,所以在编写代码时需要根据具体型号进行调整。
2. STM32内部Flash的基本结构
要操作内部Flash,首先得了解它的结构。STM32的内部Flash可以分为几个主要部分:主存储块、系统存储器和选项字节。对我们来说,最重要的是主存储块,因为程序就存储在这里,剩余的空间也可以用来存数据。
Flash的起始地址通常是0x0800 0000,这个地址是程序开始执行的地方。Flash的大小因芯片型号而异,比如STM32F103C8T6有64KB,而STM32F407VET6有512KB。要知道具体型号的Flash大小,可以查看芯片的数据手册或者参考手册。
STM32的Flash是按页或扇区组织的。对于小容量产品(小于等于32KB),每页大小是1KB;中容量产品(64KB到128KB)也是每页1KB;大容量产品(大于128KB)则是每页2KB。这个分页信息很重要,因为擦除操作是以页为单位进行的。
我以STM32L031G6u6为例,这款芯片是32KB的小容量产品,所以每页大小是1KB,总共32页。地址从0x0800 0000开始,第一页是0x0800 0000到0x0800 03FF,第二页是0x0800 0400到0x0800 07FF,依此类推,最后一页是0x0800 7C00到0x0800 7FFF。
除了主存储块,系统存储器存储了ST的Bootloader程序,这个区域是只读的,我们不能修改。选项字节则用于配置Flash的读写保护、看门狗等功能,一般不需要动它。
3. Flash操作的核心原理与注意事项
Flash操作和我们平时操作内存有很大不同,它有以下几个特点需要注意:
首先,Flash的写操作只能将bit从1变为0,而不能从0变为1。如果想要将某个bit从0变为1,必须先进行擦除操作,擦除会将整个页的所有bit都变为1。这就是为什么在写入数据之前必须先擦除。
其次,Flash的擦除是以页为单位的。即使你只想修改一个字节,也需要擦除整个页。这就要求我们在设计存储方案时,要尽量避免频繁擦写,因为Flash的擦写次数是有限的,通常为1万次左右。如果频繁擦写同一个页,很容易导致该页损坏。
另外,Flash的读写速度相对较慢,尤其是擦除操作,可能需要几毫甚至几十毫秒。在这期间,最好避免被打断,否则可能导致操作失败。
为了安全起见,STM32的Flash默认是上锁状态,防止意外修改。在进行擦除或写入操作前,需要先解锁,操作完成后再上锁。解锁过程需要按顺序写入两个特定的密钥值:0x45670123和0xCDEF89AB。
还有一个重要点是操作位数。STM32支持按8位、16位、32位甚至64位操作Flash,这取决于电源电压。在3.3V供电时,通常使用32位操作。不同系列的STM32支持的操作位数可能不同,需要查看具体型号的参考手册。
我在实际项目中就遇到过一个问题,一开始没有注意操作位数,导致写入的数据不正确。后来仔细阅读参考手册才发现,我用的STM32L0系列在3.0V电压下建议使用16位操作。所以大家一定要根据自己使用的芯片型号和供电电压来选择正确的操作位数。
4. HAL库Flash操作函数详解
STM32的HAL库提供了一套完整的Flash操作函数,大大简化了我们的工作。这些函数主要包括解锁/上锁、擦除和编程(写入)三大功能。
先来看看解锁和上锁函数:
HAL_StatusTypeDef HAL_FLASH_Unlock(void);
HAL_StatusTypeDef HAL_FLASH_Lock(void);
这两个函数很简单,HAL_FLASH_Unlock()用于解锁Flash,允许进行擦除和写入操作;HAL_FLASH_Lock()则用于操作完成后重新上锁,防止意外修改。
擦除操作稍微复杂一些,HAL库提供了HAL_FLASHEx_Erase()函数:
HAL_StatusTypeDef HAL_FLASHEx_Erase(

749

被折叠的 条评论
为什么被折叠?



