FLASH介绍
FLASH是常用的,用于存储数据的半导体器件,它具有容量大,可重复擦写,按“扇区/块”擦除、掉电后数据可继续保存的特性。
常见的FLASH有NOR FLASH和NAND FLASH。
NOR和NAND是两种数字门电路,可以简单地认为FLASH内部存储单元使用哪种门作存储单元就是哪种类型的FLASH。
U盘,SSD,eMMC等为NAND型,而NOR FLASH则根据设计需要灵活应用于各类PCB上,如BIOS,手机等。
FLASH有一个物理特性:只能写0,不能写1,写1全靠擦除。
NOR 与 NAND 在数据写入前都需要有擦除操作,但实际上 NOR FLASH 的一个 bit 可以从 1 变成 0,而要从 0 变 1 就要擦除后再写入。
擦除的最小单位是“扇区/块”,这意味着有时候即使只写一字节的数据,这个“扇区/块”上之前的数据都可能会被擦除。
NOR FLASH的地址线和数据线分开,它可以按“字节”读写数据,符合CPU的指令译码执行要求,所以假如NOR FLASH上存储了代码指令,CPU给NOR FLASH一个地址,NOR FLASH就能向CPU返回一个数据让CPU执行。
中间不需要额外的处理操作,这体现于XIP特性(eXecute In Place)。因此可以用NOR FLASH直接作为嵌入式MCU的程序存储空间。
NAND的数据和地址共用,只能按块读写数据,假如 NAND 上存储了代码指令,CPU 给 NAND 地址后,它无法直接返回该地址的数据,所以不符合指令译码要求。
若代码存储在 NAND 上,可以把它先加载到 RAM 存储器上,再有 CPU 执行。所以在功能上可以认为 NOR 是一种断电后数据不丢失的 RAM,但它的擦除单位与 RAM 有区别,且读写速度比 RAM 要慢得多。
NOR FLASH基于字节读写。
STM32内部 FLASH组成
内部FLASH用于保存要运行的代码和常量。
外部FLASH用于存储需要掉电保护的用户数据。
STM32内部FLASH简介
在STM32芯片内部有一个FLASH存储器,主要用于存储代码。
闪存的读取
直接在通用地址空间直接寻址,任何32位数据的读操作都能访问闪存模块的内容并得到相对应的数据。
CPU通过ICode指令总线访问FLASH指令。
通过DCode数据总线访问FLASH数据。
CPU运行速度比FLASH快得多,STM32F103的FLASH最快访问速度≤24MHz,CPU频率超过这个速度,得加入等待时间,否则读写FLASH可能出错,导致死机等情况。
正确设置好等待周期后,利用指针读取数据。
从地址addr,读取数据(字节为8位,半字为16位,字为32位)。
将addr强制转换为uintx_t指针,然后取该指针所指向的地址的值。
在进行写或擦除操作时,不能进行代码或数据的读取操作。
闪存的写入
闪存编程是由FPEC(闪存编程和擦除控制器)模块处理的。
写操作有4步:
- 解锁
- 擦除:FLASH物理特性(只能写0,不能写1),所以写FLASH之前需要擦除,将要写入的区域变为0xFFFF。擦除操作分为:页擦除和批量擦除。
- 写数据:可以向FLASH写数据,每次只能以16位方式写入。
- 上锁
FLASH相关HAL库函数简介
- HAL_FLASH_Unlock():关联寄存器FLASH_KEYR,用于解锁FLASH_CR的访问。
- HAL_FLASH_Lock():关联寄存器FLASH_KEYR,用于锁定FLASH_CR的访问。
- HAL_FLASH_PROGRAM():用于FLASH的写入。
- HAL_FLASHEx_Erase():用于大量擦除或擦除指定的内存扇区
- FLASH_WaitForLastOperation():等待操作完成
C语言中用static修饰函数作用
限制函数作用域
当static用于修饰函数时,它将限制该函数的作用域仅限于当前源文件。这样,其它源文件无法访问该函数,即使它们包含了相同名称的函数。这有助于防止函数名称冲突和提高代码的模块化性。
保留函数的静态存储(Internal Linkage): 在C语言中,未被修饰的函数默认具有外部链接性(external linkage),这意味着它们可以在其他源文件中使用。但是,当使用static修饰函数时,它将具有内部链接性(internal linkage),只能在当前源文件中使用。这也有助于提高程序的安全性和减少命名空间污染。
静态函数只在当前源文件中可见,但它仍然可以被当前文件内的其他函数调用。这种方式有助于将相关的函数组织在一起,但限制了可见性。
/* 静态函数(仅限stmflash.c调用) */
static void stmflash_unlock(void); /* 解锁STM32 内部FLASH */
static void stmflash_lock(void); /* 锁定STM32 内部FLASH */
static uint8_t stmflash_get_error_status(void); /* 获取FLASH错误状态 */
static uint8_t stmflash_wait_done(uint32_t time); /* 等待操作完成 */
static uint8_t stmflash_erase_sector(uint32_t saddr); /* 擦除扇区 */
static uint8_t stmflash_write_halfword(uint32_t faddr, uint16_t data); /* FLASH写半字 */