• 回复
  • 收藏
  • 点赞
  • 分享
  • 发新帖

看STM32FLASH模拟EEPROM的虚拟地址

先看一下falsh模拟eeprom的流程

首先

1、在ST 的网站上下载 AN2594 及例程。

2、在例程中src目录中找到eeprom.c 及inc目录中找到eeprom.h拷贝到自己的工程目录中。

3.、在工程中添加这个eeprom.c

4、在工程中的外设库里添加 stm32f10x_flash.c

5、在eeprom.c 文件中包含 #include "stm32f10x_flash.h"

6、main.c中包含include "eeprom.h"

7、添加数据,在 AN2594中,存入到FLASH的数据是以16位的方式存的。每个数据包含数据本身,还需要存16位的虚拟地址。所以在main.c中需要定义虚地址。:

/* Virtual address defined by the user: 0xFFFF value is prohibited */

uint16_t VirtAddVarTab[NumbOfVar] = {0x5555, 0x6666, 0x7777};

需要多少个16位的数据,将定义在 eeprom.h 中的将NumbOfVar修改成需要的个数。虚地址需要是16位,非0xFFFF,互不重复就可以。

定义数据,如果实际的数据不是16位的,可以定义一个联合来解决。

union {

uint16_t SeatStorage[NumbOfVar+1];

uint8_t SeatByte[NumbOfVar * 2+2];

}Seat;

8、使用时,先初始化

EE_Init();

读出数据

if((0 == EE_ReadVariable(VirtAddVarTab[0], &Seat.SeatStorage[0])) &&

(0 == EE_ReadVariable(VirtAddVarTab[1], &Seat.SeatStorage[1])) &&

(0 == EE_ReadVariable(VirtAddVarTab[2], &Seat.SeatStorage[2])))

// 可以用EE_ReadVariable的返回值是否为0判断FLASH中存储的数据是否有效。

全部回复(8)
正序查看
倒序查看
lingyan
LV.8
2
2019-01-28 19:35
学习
0
回复
2019-02-11 10:36
@lingyan
学习

这里主要用到虚拟地址

如果理解文档中的图3,你就明白什么是虚拟地址。
对于EPPROM,读取数据是通过I2C的,传入的是Addr,读出的是数据。这里地址就是物理地址。
对于FLASH模拟EPPROM,我们假设FLASH里面的一块区域0x10000000-0x10001000这4K空间用来模拟,其中数据结构都是
typedef Struct
{
   UINT16 data; 
   UINT16 Address;
}STRUCT_EPPROM;
若在0x10000000处的数据为{0x0001, 0x5555}
这里面0x10000000就是物理地址,
结合一些逻辑和接口,就可以通过0x5555(结构体中的Address)这个地址找到数/数组,也就是被称为虚拟地址的原因
data就是内部存储的数据。


如 果 变 量 是 16 位,则每个变量都占用 32 位( 16 位数据加 16 位虚拟地址),这意味着每次 写入新数据时,各个变量分别使用 4 字节的 Flash 。也就是每个变量实际占用四个物理地址,每个 1 KB 页在变满之前可执行 256 次 变量写入

0
回复
2019-02-11 12:11
@lihui710884923
这里主要用到虚拟地址对于EPPROM,读取数据是通过I2C的,传入的是Addr,读出的是数据。这里地址就是物理地址。typedefStruct  UINT16data; }STRUCT_EPPROM;这里面0x10000000就是物理地址,data就是内部存储的数据。如果变量是16位,则每个变量都占用32位(16位数据加16位虚拟地址),这意味着每次写入新数据时,各个变量分别使用4字节的Flash。也就是每个变量实际占用四个物理地址,每个1KB页在变满之前可执行256次变量写入

我们在103c8中,64K的flash

程序中我i们选择后4k作为物理地址来存储数据

#define EEPROM_START_ADDRESS    ((uint32_t)0x0800F000) /* EEPROM emulation start address:
                                                  after 4KByte of used Flash memory */


结束地址就是0x0800FFFF,就是4k的空间

0
回复
dianda341
LV.4
5
2019-02-18 16:27
0
回复
2019-02-19 14:35
@dianda341
[图片]
看看有啥问题没?
0
回复
2020-05-04 08:28
@lihui710884923
我们在103c8中,64K的flash程序中我i们选择后4k作为物理地址来存储数据#defineEEPROM_START_ADDRESS  ((uint32_t)0x0800F000)/*EEPROMemulationstartaddress:                         after4KByteofusedFlashmemory*/结束地址就是0x0800FFFF,就是4k的空间

举个实例

在EEPROM.H中

修改
/* Variables' number */
#define NumbOfVar               ((uint8_t)0x03) 定义要写的 halfword 数量。

用的时候需要定义一个数组
/* Virtual address defined by the user: 0xFFFF value is prohibited */
uint16_t VirtAddVarTab[NumbOfVar];

需初始化
  for(u16 i=0;i
  {
    VirtAddVarTab = i; //就是为每个变量分配一个地址,这个地址是虚的,只要不重复就可以。

  }
  FLASH_Unlock();
  EE_Init();          //检测模拟EEPROM是否第一次或数据损坏,如果是就格式化一下
  FLASH_Lock();


使用:
uint16_t EE_ReadVariable(uint16_t VirtAddress, uint16_t* Data); //读

这个函数返回的是虚拟地址所对应的数据,虚拟地址是作为一个参数被传送的。只有最后更新的被读取。这个函数进入的时候是一个循环,在这个循环内读变量目录到最后一个。如果找不到该地址,读状态变量将返回1,否则就重置表明变量已经被发现并且变量值被返回到Data变量。
uint16_t EE_WriteVariable(uint16_t VirtAddress, uint16_t Data); //写

VirtAddress 取VirtAddVarTab中内容

相当于编号为0至NumbOfVar-1个数据写入模拟EEPROM中,
写入时写入数据紧跟后面写入虚地址VirtAddVarTab(0<=i
相同地址再次写入时不会把上次写的擦掉,而是在模拟EEPROM区尾部未写过的地方再次写入数据、虚地址,
读的时候是从尾部开始匹配地址,也就是读取最后一次写的内容。

模拟EEPROM区分为2页,如果一页满了把这一页内地址不重复的数据复制到另一页后擦除,2页交替使用。

0
回复
2020-05-04 08:32
@lihui710884923
看看有啥问题没?
懒惰不会让你一下子跌倒, 但会在不知不觉中减少你的收获; 勤奋也不会让你一夜成功 但会在不知不觉中积累你的成果 越努力,越幸运。
0
回复
2020-05-04 11:35
@lihui710884923
举个实例在EEPROM.H中修改/*Variables'number*/#defineNumbOfVar          ((uint8_t)0x03)定义要写的halfword数量。用的时候需要定义一个数组/*Virtualaddressdefinedbytheuser:0xFFFFvalueisprohibited*/uint16_tVirtAddVarTab[NumbOfVar];需初始化  for(u16i=0;i

再对FLASH读部分详细分析

uint16_t EE_ReadVariable(uint16_t VirtAddress, uint16_t* Data)
{
  uint16_t ValidPage = PAGE0;
  uint16_t AddressValue = 0x5555, ReadStatus = 1;
  uint32_t Address = 0, PageStartAddress = 0;
 
  /* Get active Page for read operation */
  ValidPage = EE_FindValidPage(READ_FROM_VALID_PAGE);
 
  /* Check if there is no valid page */
  if (ValidPage == NO_VALID_PAGE)
  {
    return  NO_VALID_PAGE;
  }
 
  /* Get the valid Page start Address */
  PageStartAddress = (uint32_t)(EEPROM_START_ADDRESS + (uint32_t)(ValidPage * PAGE_SIZE));
 
  /* Get the valid Page end Address */
  Address = (uint32_t)((EEPROM_START_ADDRESS - 2) + (uint32_t)((1 + ValidPage) * PAGE_SIZE));
 
  /* Check each active page address starting from end */
  while (Address > (PageStartAddress + 2))
  {
    /* Get the current location content to be compared with virtual address */
    AddressValue = (*(__IO uint16_t*)Address);
 
    /* Compare the read address with the virtual address */
    if (AddressValue == VirtAddress)
    {
      /* Get content of Address-2 which is variable value */
      *Data = (*(__IO uint16_t*)(Address - 2));
 
      /* In case variable value is read, reset ReadStatus flag */
      ReadStatus = 0;
 
      break;
    }
    else
    {
      /* Next address location */
      Address = Address - 4;
    }
  }/* Return ReadStatus value: (0: variable exist, 1: variable doesn't exist) */

return ReadStatus;

}

1.程序找到存储的有效页面.页面从后面开始检索数据,为什么反着找,是因为写的是顺序写的,最新的时候在最后面。

一个数据包含是两个字节的有效数据+两个字节的虚拟地址,这个虚拟地址表示存储的ID。

读取数据每个页面最前面两个是页面的标记位,所以这个两个位不是存储的。

为什么是虚拟地址在后面有效数据在前面,这样设计,设想一下如果数据断电,刚好存储的数据写了,但是虚拟地址没有写,

那么这个数据也是没有效的。

不同的MCU可能在断电写的数据不正常,不排除可能写的是其他有效虚拟地址,所以开机读取数据还是需要做数据合法性检测。

虽然这样的概率很低。

0
回复