打印
[STM32F1]

FLASH 模拟 EEPROM

[复制链接]
2842|38
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
iyoum|  楼主 | 2024-2-28 23:32 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
STM32 本身没有自带 EEPROM,但是 STM32 具有在应用编程(IAP:In Application Programming)功能,可以把它的 FLASH 当成 EEPROM 来使用。


该部分用来存放代码和数据常数(如 const 类型的数据)。对于大容量产品,其被划分为 256 页,每页 2K 字节。**注意:**小容量和中容量产品则每页只有 1K 字节。从上图可以看出主存储器的起始地址就是 0X08000000, B0、 B1 (BOOT0、BOOT1)都接 GND 的时候,就是从 0X08000000开始运行代码的。

1.2 信息块:
1.3 闪存存储器接口寄存器:
2. 闪存读取
闪存等待时间:

等待周期体现了系统时钟(SYSCLK)频率与闪存访问时间的关系:
0等待周期 0 < SYSCLK < 24MHz
2等待周期 48MHz < SYSCLK ≤ 72MHz
要从地址 addr,读取一个半字(半字为 16 为,字为 32 位),可以通过如下的语句读取:
将 addr 强制转换为 vu16 指针,然后取该指针所指向的地址的值,即得到了 addr 地址的值。类似的,将上面的 vu16 改为 vu8,即可读取指定地址的一个字节。
3. 闪存的编程和擦除
3.1 FPEC 键寄存器(FLASH_KEYR)
STM32 复位后, FPEC 模块是被保护的,不能写入 FLASH_CR 寄存器;通过写入特定的序列到 FLASH_KEYR 寄存器可以打开 FPEC 模块(即写入 KEY1 和 KEY2),只有在写保护被解除后,我们才能操作相关寄存器。

STM32 闪存的编程每次必须写入 16 位(不能单纯的写入 8 位数据!), 当 FLASH_CR 寄存器的 PG 位为’ 1’时,在一个闪存地址写入一个半字将启动一次编程;写入任何非半字的数据, FPEC 都会产生总线错误。在编程过程中(BSY 位为’ 1’ ),任何读写闪存的操作都会使 CPU暂停,直到此次闪存编程结束。同样, STM32 的 FLASH 在编程的时候,也必须要求其写入地址的 FLASH 是被擦除了的(也就是其值必须是 0XFFFF),否则无法写入, 在 FLASH_SR 寄存器的 PGERR 位将得到一个警告。

(1)检查 FLASH_CR 的 LOCK 是否解锁,如果没有则先解锁;
(3)设置 FLASH_CR 寄存器的 PG 位为’ 1’;
(4) 等待 BSY 位变为’ 0’;

在 STM32 的 FLASH 编程的时候,要先判断缩写地址是否被擦除了。 STM32 的闪存擦除分为两种:页擦除和整片擦除。

(2)检查 FLASH_SR 寄存器的 BSY 位,以确认没有其他正在进行的闪存操作;
(4) 用 FLASH_AR 寄存器选择要擦除的页;
(6) 等待 BSY 位变为’ 0’;

(1)PEC 键寄存器: FLASH_KEYR

寄存器主要用来解锁 FPEC,必须在该寄存器写入特定的序列(KEY1 和 KEY2)解锁后,才能对 FLASH_CR 寄存器进行写操作。


STRT 位:用于开始一次擦除操作。在该位写入 1 , 将执行一次擦除操作。
PG 位:用于选择编程操作,在往 FLASH 写数据的时候,该位需要置 1。


(4)存地址寄存器: FLASH_AR

4. 软件实现
#ifndef __STMFLASH_H__
#include "sys.h"
#define STM32_FLASH_WREN 1              //使能FLASH写入(0,不使能;1,使能)

#define STM32_FLASH_BASE 0x08000000 //STM32 FLASH的起始地址

void STMFLASH_WriteLenByte(u32 WriteAddr,u32 DataToWrite,u16 Len); //指定地址开始写入指定长度的数据
void STMFLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite); //从指定地址开始写入指定长度的数据
//测试写入
#endif

//faddr:读地址(此地址必须为2的倍数!!)
u16 STMFLASH_ReadHalfWord(u32 faddr)
return *(vu16*)faddr;
#if STM32_FLASH_WREN //如果使能了写   
//WriteAddr:起始地址
//NumToWrite:半字(16位)数   
{  
for(i=0;i<numtowrite;i++)</numtowrite;i++)
FLASH_ProgramHalfWord(WriteAddr,pBuffer);
}  
//从指定地址开始写入指定长度的数据
//pBuffer:数据指针
#if STM32_FLASH_SIZE<256
#else
#endif

void STMFLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)
u32 secpos;    //扇区地址
u16 secremain; //扇区内剩余地址(16位字计算)   
u32 offaddr;   //去掉0X08000000后的地址

return;//非法地址
offaddr = WriteAddr - STM32_FLASH_BASE; //实际偏移地址.
secoff = (offaddr % STM_SECTOR_SIZE)/2; //在扇区内的偏移(2个字节为基本单位.)
if(NumToWrite<=secremain)
while(1)
STMFLASH_Read(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//读出整个扇区的内容
{
}
{
for(i=0;i<secremain;i++) 复制
STMFLASH_BUF[i+secoff]=pBuffer;   
STMFLASH_Write_NoCheck(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//写入整个扇区  
else
if(NumToWrite==secremain)
else//写入未结束
secpos ++; //扇区地址增1
    pBuffer += secremain;  //指针偏移
    NumToWrite -= secremain; //字节(16位)数递减
secremain = STM_SECTOR_SIZE/2;//下一个扇区还是写不完
secremain=NumToWrite;//下一个扇区可以写完了
};
}


//从指定地址开始读出指定长度的数据
//pBuffer:数据指针
void STMFLASH_Read(u32 ReadAddr,u16 *pBuffer,u16 NumToRead)   
u16 i;
{
ReadAddr+=2;//偏移2个字节.
}

//WriteAddr:起始地址
void Test_Write(u32 WriteAddr,u16 WriteData)   
STMFLASH_Write(WriteAddr,&WriteData,1);//写入一个字
4.2 测试

测试实现就是想 FLASH 特定的地址写入一定长度的数据,再读出来,类似 SPI 读取外部 FLASH 的操作。


读取的数据为:u8 TEXT_Buffer[]={“STM32 FLASH TEST”};

使用特权

评论回复
沙发
可怜的小弗朗士| | 2024-2-29 10:29 | 只看该作者
FLASH模拟EEPROM可以节省成本

使用特权

评论回复
板凳
digit0| | 2024-2-29 11:17 | 只看该作者
Flash 模拟 EEPROM 是一种在嵌入式系统中常见的数据存储策略,尤其在那些没有内置 EEPROM 或者为了节省成本和空间而选择不使用外部 EEPROM 的场合。

使用特权

评论回复
地板
理想阳| | 2024-2-29 11:18 | 只看该作者
从 Flash 中预留一部分空间作为模拟 EEPROM 区域,通常会根据需要存储的数据大小来分配合适的 Flash 扇区。

使用特权

评论回复
5
狄克爱老虎油| | 2024-2-29 17:53 | 只看该作者
这个存储少量运行数据时候很方便

使用特权

评论回复
6
heisexingqisi| | 2024-2-29 22:10 | 只看该作者
使用多余的Flash,节约成本啊。

使用特权

评论回复
7
dspmana| | 2024-3-1 20:03 | 只看该作者
Flash存储器有写入次数的限制,通常比EEPROM要少。因此,频繁地写入和擦除同一个位置可能会降低Flash的寿命。

使用特权

评论回复
8
wengh2016| | 2024-3-1 20:32 | 只看该作者
STM32的Flash存储器由主存储器、信息块和Flash存储器接口寄存器等部分组成。在将Flash用作EEPROM时,您需要考虑如何有效地管理这些存储区域,并确保您的代码能够正确地执行Flash的擦除和写入操作。

使用特权

评论回复
9
bestwell| | 2024-3-2 01:13 | 只看该作者
Flash存储器通常有更大的擦除单元,并且在写入前需要先擦除。此外,Flash的读写速度可能不如EEPROM快,因此在某些实时性要求较高的场合中可能需要权衡。

使用特权

评论回复
10
jkl21| | 2024-3-2 07:33 | 只看该作者
为了在STM32上实现Flash的EEPROM功能,开发者需要编写软件来管理Flash存储器的擦除和写入操作。这通常涉及到使用STM32的HAL库或标准外设库中的Flash API。

使用特权

评论回复
11
robertesth| | 2024-3-2 19:45 | 只看该作者
STM32本身没有自带EEPROM,但是它具有IAP(In Application Programming)功能,可以把它的FLASH当成EEPROM来使用。

使用特权

评论回复
12
pixhw| | 2024-3-2 22:53 | 只看该作者
能够将STM32的内部Flash存储器的一部分当作EEPROM来使用。通过IAP功能,可以在程序运行时对Flash存储器进行编程和擦除操作。

使用特权

评论回复
13
macpherson| | 2024-3-3 08:57 | 只看该作者
与EEPROM相比,Flash的擦除和写入操作可能会比较慢,尤其是在写入大量数据时。

使用特权

评论回复
14
modesty3jonah| | 2024-3-3 12:42 | 只看该作者
使用STM32的IAP功能,您可以将数据存储在FLASH的一个特定区域,这个区域被划分成多个小的存储块,每个块可以独立地编程和擦除。

使用特权

评论回复
15
lzbf| | 2024-3-3 15:19 | 只看该作者
可以在软件层面模拟出EEPROM的读写操作,以此来保存需要掉电保持的小容量非易失性数据。

使用特权

评论回复
16
uptown| | 2024-3-3 17:13 | 只看该作者
需要考虑FLASH的寿命和编程次数限制

使用特权

评论回复
17
tabmone| | 2024-3-3 20:13 | 只看该作者
#include "stm32fxx_hal.h"

// 定义需要写入的数据
uint8_t data_to_write[256] = {0};

// 定义FLASH操作的地址
uint32_t flash_address = 0x08000000;

// 初始化FLASH操作所需的变量
FLASH_EraseInitTypeDef erase_init;
HAL_FLASHEx_Erase(&erase_init, &flash_address);

// 将数据写入FLASH
for (uint32_t i = 0; i < 256; i++)
{
    HAL_FLASH_Program(FLASH_TYPEPROGRAM_DATA, flash_address + i * 4, data_to_write[i]);
}

使用特权

评论回复
18
uiint| | 2024-3-4 14:25 | 只看该作者
Bootloader通常通过ISP方式烧录到微控制器内,并为其预留一定的Flash空间。

使用特权

评论回复
19
qiufengsd| | 2024-3-5 16:33 | 只看该作者
Flash存储器在掉电后能够保持数据,因此它适合作为非易失性存储器使用。

使用特权

评论回复
20
wangdezhi| | 2024-3-7 13:20 | 只看该作者
可以在程序运行过程中对FLASH进行读写操作,从而实现类似EEPROM的功能

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

29

主题

3277

帖子

1

粉丝