你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32F103与F407的EEPROM仿真及其应用层扩展

[复制链接]
STMCU小助手 发布时间:2022-4-13 17:00
说明
在工业应用中经常使用 EEPROM(电可擦除可编程只读存储器)来存储可更新的数据。EEPROM 是用在复杂系统(例如计算机)和其它电子器件中的一种永久(非易失)存储器存储系统,它可以在电源故障时存储和保留少量数据。

由于STM32的单片机支持IAP功能,因此可以通过读写Flash的某个特定区域来实现对EEPROM的模拟。STM32F103与F407的EEPROM仿真主要参考了意法半导体公司官方应用笔记:

STM32F101xx和STM32F103xx微控制器中的EEPROM仿真(AN2594)
STM32F40x/STM32F41x微控制器中的EEPROM仿真(AN3969)
笔者在EEPROM仿真库的基础上,进一步封装了应用层的扩展库。利用此扩展库,可以直接声明和定义一个StorableData类型的变量。该变量可以利用扩展库提供的接口方便的实现掉电存储、上电加载、重置默认等功能。

需要特别说明的是:
笔者提供的EEPROM仿真库源码与官方提供的源码相比,稍作了修改以使其能更好的配合应用层扩展库使用。
由于STM32F103与STM32F407的标准外设库函数中对flash的操作API不同,因此EEPROM仿真库针对不同单片机平台的函数实现(源文件)是有所不同的。
应用层扩展是基于EEPROM仿真库实现的,利用了EEPROM仿真库统一的接口,因此可以兼容不同的单片机平台。

EEPROM仿真
框架介绍

EEPROM 是许多需要非易失性数据存储的嵌入式应用的关键组件,它在运行期间以字节或字为粒度。这些系统中使用的微控制器通常是基于嵌入式 Flash 存储器的。为了避免使用这些组件、节约 PCB 空间并降低系统成本,可使用 STM32的Flash代替外部 EEPOM,模拟代码和数据的存储。但是与 Flash 不同的是,外部 EEPROM 在重写数据之前并不需要执行擦除操作来释放空间。要将数据存储到嵌入式 Flash 中,需要执行特殊的软件管理。

官方提供的应用笔记介绍了使用 STM32F103/STM32F407 器件的片上 Flash 通过仿真 EEPROM 机制来取代独立 EEPROM 的软件解决方案。由于Flash的可采写次数较少(1万次),因此EEPROM仿真库采用了耗损均衡算法以增加Flash可擦写次数。

源码
容量设置

根据项目需要可以修改头文件与源文件中的相关内容,设置一个合适的16位数据可存储的数量。

在头文件中指定了16位数据可存储的数量为128个,如果都以32位的浮点数类型来保存数据的话,保存的浮点数数量为64个。
头文件中相关内容:

  1. /* Variables' number */
  2. #define EEPROM_NumbOfVar                128
  3. extern uint16_t EEPROM_VirtAddVarTab[EEPROM_NumbOfVar];
复制代码

源文件中相关内容:

  1. /* Virtual address defined by the user: 0xFFFF value is prohibited */
  2. uint16_t EEPROM_VirtAddVarTab[EEPROM_NumbOfVar] =
  3. {
  4.         0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
  5.         0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, 0x0010,
  6.         0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018,
  7.         0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, 0x0020,
  8.         0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
  9.         0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, 0x0030,
  10.         0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
  11.         0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, 0x0040,
  12.         0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
  13.         0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050,
  14.         0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
  15.         0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, 0x0060,
  16.         0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068,
  17.         0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070,
  18.         0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078,
  19.         0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, 0x0080,
  20. };
复制代码

在头文件中指定了16位数据可存储的数量为256个,如果都以32位的浮点数类型来保存数据的话,保存的浮点数数量为128个。
头文件中相关内容:

  1. /* Variables' number */
  2. #define EEPROM_NumbOfVar                256
  3. extern uint16_t EEPROM_VirtAddVarTab[EEPROM_NumbOfVar];
复制代码

源文件中相关内容:

  1. /* Virtual address defined by the user: 0xFFFF value is prohibited */
  2. uint16_t EEPROM_VirtAddVarTab[EEPROM_NumbOfVar] =
  3. {
  4.         0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
  5.         0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, 0x0010,
  6.         0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018,
  7.         0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, 0x0020,
  8.         0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
  9.         0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, 0x0030,
  10.         0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
  11.         0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, 0x0040,
  12.         0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
  13.         0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050,
  14.         0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
  15.         0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, 0x0060,
  16.         0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068,
  17.         0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070,
  18.         0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078,
  19.         0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, 0x0080,

  20.         0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088,
  21.         0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, 0x0090,
  22.         0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098,
  23.         0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, 0x00A0,
  24.         0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8,
  25.         0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, 0x00B0,
  26.         0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8,
  27.         0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, 0x00C0,
  28.         0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, 0x00C8,
  29.         0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, 0x00D0,
  30.         0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00D8,
  31.         0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, 0x00E0,
  32.         0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8,
  33.         0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, 0x00F0,
  34.         0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8,
  35.         0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF, 0x0100,
  36. };
复制代码

STM32F103
头文件

  1. /**
  2.   ******************************************************************************
  3.   * @file    EEPROM_Emulation/inc/eeprom.h
  4.   * @author  MCD Application Team
  5.   * @version V3.1.0
  6.   * @date    07/27/2009
  7.   * @brief   This file contains all the functions prototypes for the EEPROM
  8.   *          emulation firmware library.
  9.   ******************************************************************************
  10.   * @copy
  11.   *
  12.   * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
  13.   * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
  14.   * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
  15.   * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
  16.   * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
  17.   * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
  18.   *
  19.   * <h2><center>© COPYRIGHT 2009 STMicroelectronics</center></h2>
  20.   */

  21. /* Define to prevent recursive inclusion -------------------------------------*/
  22. #ifndef __EEPROM_H
  23. #define __EEPROM_H

  24. /* Includes ------------------------------------------------------------------*/
  25. #include "stm32f10x.h"
  26. #include "stm32f10x_conf.h"

  27. /* Exported constants --------------------------------------------------------*/
  28. /* Define the STM32F10Xxx Flash page size depending on the used STM32 device */
  29. #if defined (STM32F10X_LD) || defined (STM32F10X_MD)
  30.   #define PAGE_SIZE  (uint16_t)0x400  /* Page size = 1KByte */
  31.   #define FLASH_END_ADDRESS 0x08010000

  32. #elif defined (STM32F10X_HD) || defined (STM32F10X_CL)
  33.   #define PAGE_SIZE  (uint16_t)0x800  /* Page size = 2KByte */
  34.   #define FLASH_END_ADDRESS 0x08040000

  35. #endif

  36. /* EEPROM start address in Flash */
  37. #define EEPROM_START_ADDRESS    ((uint32_t)(FLASH_END_ADDRESS - 2 * PAGE_SIZE))


  38. /* Pages 0 and 1 base and end addresses */
  39. #define PAGE0_BASE_ADDRESS      ((uint32_t)(EEPROM_START_ADDRESS + 0x000))
  40. #define PAGE0_END_ADDRESS       ((uint32_t)(EEPROM_START_ADDRESS + (PAGE_SIZE - 1)))

  41. #define PAGE1_BASE_ADDRESS      ((uint32_t)(EEPROM_START_ADDRESS + PAGE_SIZE))
  42. #define PAGE1_END_ADDRESS       ((uint32_t)(EEPROM_START_ADDRESS + (2 * PAGE_SIZE - 1)))

  43. /* Used Flash pages for EEPROM emulation */
  44. #define PAGE0                   ((uint16_t)0x0000)
  45. #define PAGE1                   ((uint16_t)0x0001)

  46. /* No valid page define */
  47. #define NO_VALID_PAGE           ((uint16_t)0x00AB)

  48. /* Page status definitions */
  49. #define ERASED                  ((uint16_t)0xFFFF)     /* PAGE is empty */
  50. #define RECEIVE_DATA            ((uint16_t)0xEEEE)     /* PAGE is marked to receive data */
  51. #define VALID_PAGE              ((uint16_t)0x0000)     /* PAGE containing valid data */

  52. /* Valid pages in read and write defines */
  53. #define READ_FROM_VALID_PAGE    ((uint8_t)0x00)
  54. #define WRITE_IN_VALID_PAGE     ((uint8_t)0x01)

  55. /* Page full define */
  56. #define PAGE_FULL               ((uint8_t)0x80)

  57. /* Variables' number */
  58. //#define EEPROM_NumbOfVar               ((uint8_t)STORABLE_DATA_COUNT * 2)
  59. #define EEPROM_NumbOfVar                128

  60. extern uint16_t EEPROM_VirtAddVarTab[EEPROM_NumbOfVar];

  61. /* Exported types ------------------------------------------------------------*/
  62. /* Exported macro ------------------------------------------------------------*/
  63. /* Exported functions ------------------------------------------------------- */
  64. uint16_t EE_Init(void);
  65. uint16_t EE_ReadVariable(uint16_t VirtAddress, uint16_t* Data);
  66. uint16_t EE_WriteVariable(uint16_t VirtAddress, uint16_t Data);

  67. #endif /* __EEPROM_H */

  68. /******************* (C) COPYRIGHT 2009 STMicroelectronics *****END OF FILE****/
复制代码

源文件
  1. /**
  2. ******************************************************************************
  3. * @file    EEPROM_Emulation/src/eeprom.c
  4. * @author  MCD Application Team
  5. * @version V3.1.0
  6. * @date    07/27/2009
  7. * @brief   This file provides all the EEPROM emulation firmware functions.
  8. ******************************************************************************
  9. * @copy
  10. *
  11. * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
  12. * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
  13. * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
  14. * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
  15. * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
  16. * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
  17. *
  18. * <h2><center>© COPYRIGHT 2009 STMicroelectronics</center></h2>
  19. */
  20. /** @addtogroup EEPROM_Emulation
  21. * @{
  22. */

  23. /* Includes ------------------------------------------------------------------*/
  24. #include "eeprom.h"

  25. /* Private typedef -----------------------------------------------------------*/
  26. /* Private define ------------------------------------------------------------*/
  27. /* Private macro -------------------------------------------------------------*/
  28. /* Private variables ---------------------------------------------------------*/

  29. /* Global variable used to store variable value in read sequence */
  30. static uint16_t DataVar = 0;

  31. /* Virtual address defined by the user: 0xFFFF value is prohibited */
  32. uint16_t EEPROM_VirtAddVarTab[EEPROM_NumbOfVar] =
  33. {
  34.         0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
  35.         0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, 0x0010,
  36.         0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018,
  37.         0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, 0x0020,
  38.         0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
  39.         0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, 0x0030,
  40.         0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
  41.         0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, 0x0040,
  42.         0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
  43.         0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050,
  44.         0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
  45.         0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, 0x0060,
  46.         0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068,
  47.         0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070,
  48.         0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078,
  49.         0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, 0x0080,
  50. };

  51. /* Private function prototypes -----------------------------------------------*/
  52. /* Private functions ---------------------------------------------------------*/
  53. static FLASH_Status EE_Format(void);
  54. static uint16_t EE_FindValidPage(uint8_t Operation);
  55. static uint16_t EE_VerifyPageFullWriteVariable(uint16_t VirtAddress, uint16_t Data);
  56. static uint16_t EE_PageTransfer(uint16_t VirtAddress, uint16_t Data);

  57. /**
  58. * @brief  Restore the pages to a known good state in case of page's status
  59. *   corruption after a power loss.
  60. * @param  None.
  61. * @retval - Flash error code: on write Flash error
  62. *         - FLASH_COMPLETE: on success
  63. */
  64. uint16_t EE_Init(void)
  65. {
  66.         uint16_t PageStatus0 = 6, PageStatus1 = 6;
  67.         uint16_t VarIdx = 0;
  68.         uint16_t EepromStatus = 0, ReadStatus = 0;
  69.         int16_t x = -1;
  70.         uint16_t FlashStatus;

  71.         /* Get Page0 status */
  72.         PageStatus0 = (*(__IO uint16_t*) PAGE0_BASE_ADDRESS);
  73.         /* Get Page1 status */
  74.         PageStatus1 = (*(__IO uint16_t*) PAGE1_BASE_ADDRESS);

  75.         /* Check for invalid header states and repair if necessary */
  76.         switch (PageStatus0)
  77.         {
  78.         case ERASED:
  79.                 if (PageStatus1 == VALID_PAGE) /* Page0 erased, Page1 valid */
  80.                 {
  81.                         /* Erase Page0 */
  82.                         FlashStatus = FLASH_ErasePage(PAGE0_BASE_ADDRESS);
  83.                         /* If erase operation was failed, a Flash error code is returned */
  84.                         if (FlashStatus != FLASH_COMPLETE)
  85.                         {
  86.                                 return FlashStatus;
  87.                         }
  88.                 }
  89.                 else if (PageStatus1 == RECEIVE_DATA) /* Page0 erased, Page1 receive */
  90.                 {
  91.                         /* Erase Page0 */
  92.                         FlashStatus = FLASH_ErasePage(PAGE0_BASE_ADDRESS);
  93.                         /* If erase operation was failed, a Flash error code is returned */
  94.                         if (FlashStatus != FLASH_COMPLETE)
  95.                         {
  96.                                 return FlashStatus;
  97.                         }
  98.                         /* Mark Page1 as valid */
  99.                         FlashStatus = FLASH_ProgramHalfWord(PAGE1_BASE_ADDRESS, VALID_PAGE);
  100.                         /* If program operation was failed, a Flash error code is returned */
  101.                         if (FlashStatus != FLASH_COMPLETE)
  102.                         {
  103.                                 return FlashStatus;
  104.                         }
  105.                 }
  106.                 else /* First EEPROM access (Page0&1 are erased) or invalid state -> format EEPROM */
  107.                 {
  108.                         /* Erase both Page0 and Page1 and set Page0 as valid page */
  109.                         FlashStatus = EE_Format();
  110.                         /* If erase/program operation was failed, a Flash error code is returned */
  111.                         if (FlashStatus != FLASH_COMPLETE)
  112.                         {
  113.                                 return FlashStatus;
  114.                         }
  115.                 }
  116.                 break;

  117.         case RECEIVE_DATA:
  118.                 if (PageStatus1 == VALID_PAGE) /* Page0 receive, Page1 valid */
  119.                 {
  120.                         /* Transfer data from Page1 to Page0 */
  121.                         for (VarIdx = 0; VarIdx < EEPROM_NumbOfVar; VarIdx++)
  122.                         {
  123.                                 if ((*(__IO uint16_t*) (PAGE0_BASE_ADDRESS + 6))
  124.                                                 == EEPROM_VirtAddVarTab[VarIdx])
  125.                                 {
  126.                                         x = VarIdx;
  127.                                 }
  128.                                 if (VarIdx != x)
  129.                                 {
  130.                                         /* Read the last variables' updates */
  131.                                         ReadStatus = EE_ReadVariable(EEPROM_VirtAddVarTab[VarIdx],
  132.                                                         &DataVar);
  133.                                         /* In case variable corresponding to the virtual address was found */
  134.                                         if (ReadStatus != 0x1)
  135.                                         {
  136.                                                 /* Transfer the variable to the Page0 */
  137.                                                 EepromStatus = EE_VerifyPageFullWriteVariable(
  138.                                                                 EEPROM_VirtAddVarTab[VarIdx], DataVar);
  139.                                                 /* If program operation was failed, a Flash error code is returned */
  140.                                                 if (EepromStatus != FLASH_COMPLETE)
  141.                                                 {
  142.                                                         return EepromStatus;
  143.                                                 }
  144.                                         }
  145.                                 }
  146.                         }
  147.                         /* Mark Page0 as valid */
  148.                         FlashStatus = FLASH_ProgramHalfWord(PAGE0_BASE_ADDRESS, VALID_PAGE);
  149.                         /* If program operation was failed, a Flash error code is returned */
  150.                         if (FlashStatus != FLASH_COMPLETE)
  151.                         {
  152.                                 return FlashStatus;
  153.                         }
  154.                         /* Erase Page1 */
  155.                         FlashStatus = FLASH_ErasePage(PAGE1_BASE_ADDRESS);
  156.                         /* If erase operation was failed, a Flash error code is returned */
  157.                         if (FlashStatus != FLASH_COMPLETE)
  158.                         {
  159.                                 return FlashStatus;
  160.                         }
  161.                 }
  162.                 else if (PageStatus1 == ERASED) /* Page0 receive, Page1 erased */
  163.                 {
  164.                         /* Erase Page1 */
  165.                         FlashStatus = FLASH_ErasePage(PAGE1_BASE_ADDRESS);
  166.                         /* If erase operation was failed, a Flash error code is returned */
  167.                         if (FlashStatus != FLASH_COMPLETE)
  168.                         {
  169.                                 return FlashStatus;
  170.                         }
  171.                         /* Mark Page0 as valid */
  172.                         FlashStatus = FLASH_ProgramHalfWord(PAGE0_BASE_ADDRESS, VALID_PAGE);
  173.                         /* If program operation was failed, a Flash error code is returned */
  174.                         if (FlashStatus != FLASH_COMPLETE)
  175.                         {
  176.                                 return FlashStatus;
  177.                         }
  178.                 }
  179.                 else /* Invalid state -> format eeprom */
  180.                 {
  181.                         /* Erase both Page0 and Page1 and set Page0 as valid page */
  182.                         FlashStatus = EE_Format();
  183.                         /* If erase/program operation was failed, a Flash error code is returned */
  184.                         if (FlashStatus != FLASH_COMPLETE)
  185.                         {
  186.                                 return FlashStatus;
  187.                         }
  188.                 }
  189.                 break;

  190.         case VALID_PAGE:
  191.                 if (PageStatus1 == VALID_PAGE) /* Invalid state -> format eeprom */
  192.                 {
  193.                         /* Erase both Page0 and Page1 and set Page0 as valid page */
  194.                         FlashStatus = EE_Format();
  195.                         /* If erase/program operation was failed, a Flash error code is returned */
  196.                         if (FlashStatus != FLASH_COMPLETE)
  197.                         {
  198.                                 return FlashStatus;
  199.                         }
  200.                 }
  201.                 else if (PageStatus1 == ERASED) /* Page0 valid, Page1 erased */
  202.                 {
  203.                         /* Erase Page1 */
  204.                         FlashStatus = FLASH_ErasePage(PAGE1_BASE_ADDRESS);
  205.                         /* If erase operation was failed, a Flash error code is returned */
  206.                         if (FlashStatus != FLASH_COMPLETE)
  207.                         {
  208.                                 return FlashStatus;
  209.                         }
  210.                 }
  211.                 else /* Page0 valid, Page1 receive */
  212.                 {
  213.                         /* Transfer data from Page0 to Page1 */
  214.                         for (VarIdx = 0; VarIdx < EEPROM_NumbOfVar; VarIdx++)
  215.                         {
  216.                                 if ((*(__IO uint16_t*) (PAGE1_BASE_ADDRESS + 6))
  217.                                                 == EEPROM_VirtAddVarTab[VarIdx])
  218.                                 {
  219.                                         x = VarIdx;
  220.                                 }
  221.                                 if (VarIdx != x)
  222.                                 {
  223.                                         /* Read the last variables' updates */
  224.                                         ReadStatus = EE_ReadVariable(EEPROM_VirtAddVarTab[VarIdx],
  225.                                                         &DataVar);
  226.                                         /* In case variable corresponding to the virtual address was found */
  227.                                         if (ReadStatus != 0x1)
  228.                                         {
  229.                                                 /* Transfer the variable to the Page1 */
  230.                                                 EepromStatus = EE_VerifyPageFullWriteVariable(
  231.                                                                 EEPROM_VirtAddVarTab[VarIdx], DataVar);
  232.                                                 /* If program operation was failed, a Flash error code is returned */
  233.                                                 if (EepromStatus != FLASH_COMPLETE)
  234.                                                 {
  235.                                                         return EepromStatus;
  236.                                                 }
  237.                                         }
  238.                                 }
  239.                         }
  240.                         /* Mark Page1 as valid */
  241.                         FlashStatus = FLASH_ProgramHalfWord(PAGE1_BASE_ADDRESS, VALID_PAGE);
  242.                         /* If program operation was failed, a Flash error code is returned */
  243.                         if (FlashStatus != FLASH_COMPLETE)
  244.                         {
  245.                                 return FlashStatus;
  246.                         }
  247.                         /* Erase Page0 */
  248.                         FlashStatus = FLASH_ErasePage(PAGE0_BASE_ADDRESS);
  249.                         /* If erase operation was failed, a Flash error code is returned */
  250.                         if (FlashStatus != FLASH_COMPLETE)
  251.                         {
  252.                                 return FlashStatus;
  253.                         }
  254.                 }
  255.                 break;

  256.         default: /* Any other state -> format eeprom */
  257.                 /* Erase both Page0 and Page1 and set Page0 as valid page */
  258.                 FlashStatus = EE_Format();
  259.                 /* If erase/program operation was failed, a Flash error code is returned */
  260.                 if (FlashStatus != FLASH_COMPLETE)
  261.                 {
  262.                         return FlashStatus;
  263.                 }
  264.                 break;
  265.         }

  266.         return FLASH_COMPLETE;
  267. }

  268. /**
  269. * @brief  Returns the last stored variable data, if found, which correspond to
  270. *   the passed virtual address
  271. * @param  VirtAddress: Variable virtual address
  272. * @param  Data: Global variable contains the read variable value
  273. * @retval Success or error status:
  274. *           - 0: if variable was found
  275. *           - 1: if the variable was not found
  276. *           - NO_VALID_PAGE: if no valid page was found.
  277. */
  278. uint16_t EE_ReadVariable(uint16_t VirtAddress, uint16_t* Data)
  279. {
  280.         uint16_t ValidPage = PAGE0;
  281.         uint16_t AddressValue = 0x5555, ReadStatus = 1;
  282.         uint32_t Address = 0x08010000, PageStartAddress = 0x08010000;

  283.         /* Get active Page for read operation */
  284.         ValidPage = EE_FindValidPage(READ_FROM_VALID_PAGE);

  285.         /* Check if there is no valid page */
  286.         if (ValidPage == NO_VALID_PAGE)
  287.         {
  288.                 return NO_VALID_PAGE;
  289.         }

  290.         /* Get the valid Page start Address */
  291.         PageStartAddress = (uint32_t) (EEPROM_START_ADDRESS
  292.                         + (uint32_t) (ValidPage * PAGE_SIZE ));

  293.         /* Get the valid Page end Address */
  294.         Address = (uint32_t) ((EEPROM_START_ADDRESS - 2)
  295.                         + (uint32_t) ((1 + ValidPage) * PAGE_SIZE ));

  296.         /* Check each active page address starting from end */
  297.         while (Address > (PageStartAddress + 2))
  298.         {
  299.                 /* Get the current location content to be compared with virtual address */
  300.                 AddressValue = (*(__IO uint16_t*) Address);

  301.                 /* Compare the read address with the virtual address */
  302.                 if (AddressValue == VirtAddress)
  303.                 {
  304.                         /* Get content of Address-2 which is variable value */
  305.                         *Data = (*(__IO uint16_t*) (Address - 2));

  306.                         /* In case variable value is read, reset ReadStatus flag */
  307.                         ReadStatus = 0;

  308.                         break;
  309.                 }
  310.                 else
  311.                 {
  312.                         /* Next address location */
  313.                         Address = Address - 4;
  314.                 }
  315.         }

  316.         /* Return ReadStatus value: (0: variable exist, 1: variable doesn't exist) */
  317.         return ReadStatus;
  318. }

  319. /**
  320. * @brief  Writes/upadtes variable data in EEPROM.
  321. * @param  VirtAddress: Variable virtual address
  322. * @param  Data: 16 bit data to be written
  323. * @retval Success or error status:
  324. *           - FLASH_COMPLETE: on success
  325. *           - PAGE_FULL: if valid page is full
  326. *           - NO_VALID_PAGE: if no valid page was found
  327. *           - Flash error code: on write Flash error
  328. */
  329. uint16_t EE_WriteVariable(uint16_t VirtAddress, uint16_t Data)
  330. {
  331.         uint16_t Status = 0;

  332.         /* Write the variable virtual address and value in the EEPROM */
  333.         Status = EE_VerifyPageFullWriteVariable(VirtAddress, Data);

  334.         /* In case the EEPROM active page is full */
  335.         if (Status == PAGE_FULL)
  336.         {
  337.                 /* Perform Page transfer */
  338.                 Status = EE_PageTransfer(VirtAddress, Data);
  339.         }

  340.         /* Return last operation status */
  341.         return Status;
  342. }

  343. /**
  344. * @brief  Erases PAGE0 and PAGE1 and writes VALID_PAGE header to PAGE0
  345. * @param  None
  346. * @retval Status of the last operation (Flash write or erase) done during
  347. *         EEPROM formating
  348. */
  349. static FLASH_Status EE_Format(void)
  350. {
  351.         FLASH_Status FlashStatus = FLASH_COMPLETE;

  352.         /* Erase Page0 */
  353.         FlashStatus = FLASH_ErasePage(PAGE0_BASE_ADDRESS);

  354.         /* If erase operation was failed, a Flash error code is returned */
  355.         if (FlashStatus != FLASH_COMPLETE)
  356.         {
  357.                 return FlashStatus;
  358.         }

  359.         /* Set Page0 as valid page: Write VALID_PAGE at Page0 base address */
  360.         FlashStatus = FLASH_ProgramHalfWord(PAGE0_BASE_ADDRESS, VALID_PAGE);

  361.         /* If program operation was failed, a Flash error code is returned */
  362.         if (FlashStatus != FLASH_COMPLETE)
  363.         {
  364.                 return FlashStatus;
  365.         }

  366.         /* Erase Page1 */
  367.         FlashStatus = FLASH_ErasePage(PAGE1_BASE_ADDRESS);

  368.         /* Return Page1 erase operation status */
  369.         return FlashStatus;
  370. }

  371. /**
  372. * @brief  Find valid Page for write or read operation
  373. * @param  Operation: operation to achieve on the valid page.
  374. *   This parameter can be one of the following values:
  375. *     @arg READ_FROM_VALID_PAGE: read operation from valid page
  376. *     @arg WRITE_IN_VALID_PAGE: write operation from valid page
  377. * @retval Valid page number (PAGE0 or PAGE1) or NO_VALID_PAGE in case
  378. *   of no valid page was found
  379. */
  380. static uint16_t EE_FindValidPage(uint8_t Operation)
  381. {
  382.         uint16_t PageStatus0 = 6, PageStatus1 = 6;

  383.         /* Get Page0 actual status */
  384.         PageStatus0 = (*(__IO uint16_t*) PAGE0_BASE_ADDRESS);

  385.         /* Get Page1 actual status */
  386.         PageStatus1 = (*(__IO uint16_t*) PAGE1_BASE_ADDRESS);

  387.         /* Write or read operation */
  388.         switch (Operation)
  389.         {
  390.         case WRITE_IN_VALID_PAGE: /* ---- Write operation ---- */
  391.                 if (PageStatus1 == VALID_PAGE)
  392.                 {
  393.                         /* Page0 receiving data */
  394.                         if (PageStatus0 == RECEIVE_DATA)
  395.                         {
  396.                                 return PAGE0; /* Page0 valid */
  397.                         }
  398.                         else
  399.                         {
  400.                                 return PAGE1; /* Page1 valid */
  401.                         }
  402.                 }
  403.                 else if (PageStatus0 == VALID_PAGE)
  404.                 {
  405.                         /* Page1 receiving data */
  406.                         if (PageStatus1 == RECEIVE_DATA)
  407.                         {
  408.                                 return PAGE1; /* Page1 valid */
  409.                         }
  410.                         else
  411.                         {
  412.                                 return PAGE0; /* Page0 valid */
  413.                         }
  414.                 }
  415.                 else
  416.                 {
  417.                         return NO_VALID_PAGE; /* No valid Page */
  418.                 }

  419.         case READ_FROM_VALID_PAGE: /* ---- Read operation ---- */
  420.                 if (PageStatus0 == VALID_PAGE)
  421.                 {
  422.                         return PAGE0; /* Page0 valid */
  423.                 }
  424.                 else if (PageStatus1 == VALID_PAGE)
  425.                 {
  426.                         return PAGE1; /* Page1 valid */
  427.                 }
  428.                 else
  429.                 {
  430.                         return NO_VALID_PAGE; /* No valid Page */
  431.                 }

  432.         default:
  433.                 return PAGE0; /* Page0 valid */
  434.         }
  435. }

  436. /**
  437. * @brief  Verify if active page is full and Writes variable in EEPROM.
  438. * @param  VirtAddress: 16 bit virtual address of the variable
  439. * @param  Data: 16 bit data to be written as variable value
  440. * @retval Success or error status:
  441. *           - FLASH_COMPLETE: on success
  442. *           - PAGE_FULL: if valid page is full
  443. *           - NO_VALID_PAGE: if no valid page was found
  444. *           - Flash error code: on write Flash error
  445. */
  446. static uint16_t EE_VerifyPageFullWriteVariable(uint16_t VirtAddress,
  447.                 uint16_t Data)
  448. {
  449.         FLASH_Status FlashStatus = FLASH_COMPLETE;
  450.         uint16_t ValidPage = PAGE0;
  451.         uint32_t Address = 0x08010000, PageEndAddress = 0x080107FF;

  452.         /* Get valid Page for write operation */
  453.         ValidPage = EE_FindValidPage(WRITE_IN_VALID_PAGE);

  454.         /* Check if there is no valid page */
  455.         if (ValidPage == NO_VALID_PAGE)
  456.         {
  457.                 return NO_VALID_PAGE;
  458.         }

  459.         /* Get the valid Page start Address */
  460.         Address = (uint32_t) (EEPROM_START_ADDRESS
  461.                         + (uint32_t) (ValidPage * PAGE_SIZE ));

  462.         /* Get the valid Page end Address */
  463.         PageEndAddress = (uint32_t) ((EEPROM_START_ADDRESS - 2)
  464.                         + (uint32_t) ((1 + ValidPage) * PAGE_SIZE ));

  465.         /* Check each active page address starting from begining */
  466.         while (Address < PageEndAddress)
  467.         {
  468.                 /* Verify if Address and Address+2 contents are 0xFFFFFFFF */
  469.                 if ((*(__IO uint32_t*) Address) == 0xFFFFFFFF)
  470.                 {
  471.                         /* Set variable data */
  472.                         FlashStatus = FLASH_ProgramHalfWord(Address, Data);
  473.                         /* If program operation was failed, a Flash error code is returned */
  474.                         if (FlashStatus != FLASH_COMPLETE)
  475.                         {
  476.                                 return FlashStatus;
  477.                         }
  478.                         /* Set variable virtual address */
  479.                         FlashStatus = FLASH_ProgramHalfWord(Address + 2, VirtAddress);
  480.                         /* Return program operation status */
  481.                         return FlashStatus;
  482.                 }
  483.                 else
  484.                 {
  485.                         /* Next address location */
  486.                         Address = Address + 4;
  487.                 }
  488.         }

  489.         /* Return PAGE_FULL in case the valid page is full */
  490.         return PAGE_FULL;
  491. }

  492. /**
  493. * @brief  Transfers last updated variables data from the full Page to
  494. *   an empty one.
  495. * @param  VirtAddress: 16 bit virtual address of the variable
  496. * @param  Data: 16 bit data to be written as variable value
  497. * @retval Success or error status:
  498. *           - FLASH_COMPLETE: on success
  499. *           - PAGE_FULL: if valid page is full
  500. *           - NO_VALID_PAGE: if no valid page was found
  501. *           - Flash error code: on write Flash error
  502. */
  503. static uint16_t EE_PageTransfer(uint16_t VirtAddress, uint16_t Data)
  504. {
  505.         FLASH_Status FlashStatus = FLASH_COMPLETE;
  506.         uint32_t NewPageAddress = 0x080103FF, OldPageAddress = 0x08010000;
  507.         uint16_t ValidPage = PAGE0, VarIdx = 0;
  508.         uint16_t EepromStatus = 0, ReadStatus = 0;

  509.         /* Get active Page for read operation */
  510.         ValidPage = EE_FindValidPage(READ_FROM_VALID_PAGE);

  511.         if (ValidPage == PAGE1) /* Page1 valid */
  512.         {
  513.                 /* New page address where variable will be moved to */
  514.                 NewPageAddress = PAGE0_BASE_ADDRESS;

  515.                 /* Old page address where variable will be taken from */
  516.                 OldPageAddress = PAGE1_BASE_ADDRESS;
  517.         }
  518.         else if (ValidPage == PAGE0) /* Page0 valid */
  519.         {
  520.                 /* New page address where variable will be moved to */
  521.                 NewPageAddress = PAGE1_BASE_ADDRESS;

  522.                 /* Old page address where variable will be taken from */
  523.                 OldPageAddress = PAGE0_BASE_ADDRESS;
  524.         }
  525.         else
  526.         {
  527.                 return NO_VALID_PAGE; /* No valid Page */
  528.         }

  529.         /* Set the new Page status to RECEIVE_DATA status */
  530.         FlashStatus = FLASH_ProgramHalfWord(NewPageAddress, RECEIVE_DATA);
  531.         /* If program operation was failed, a Flash error code is returned */
  532.         if (FlashStatus != FLASH_COMPLETE)
  533.         {
  534.                 return FlashStatus;
  535.         }

  536.         /* Write the variable passed as parameter in the new active page */
  537.         EepromStatus = EE_VerifyPageFullWriteVariable(VirtAddress, Data);
  538.         /* If program operation was failed, a Flash error code is returned */
  539.         if (EepromStatus != FLASH_COMPLETE)
  540.         {
  541.                 return EepromStatus;
  542.         }

  543.         /* Transfer process: transfer variables from old to the new active page */
  544.         for (VarIdx = 0; VarIdx < EEPROM_NumbOfVar; VarIdx++)
  545.         {
  546.                 if (EEPROM_VirtAddVarTab[VarIdx] != VirtAddress) /* Check each variable except the one passed as parameter */
  547.                 {
  548.                         /* Read the other last variable updates */
  549.                         ReadStatus = EE_ReadVariable(EEPROM_VirtAddVarTab[VarIdx], &DataVar);
  550.                         /* In case variable corresponding to the virtual address was found */
  551.                         if (ReadStatus != 0x1)
  552.                         {
  553.                                 /* Transfer the variable to the new active page */
  554.                                 EepromStatus = EE_VerifyPageFullWriteVariable(
  555.                                                 EEPROM_VirtAddVarTab[VarIdx], DataVar);
  556.                                 /* If program operation was failed, a Flash error code is returned */
  557.                                 if (EepromStatus != FLASH_COMPLETE)
  558.                                 {
  559.                                         return EepromStatus;
  560.                                 }
  561.                         }
  562.                 }
  563.         }

  564.         /* Erase the old Page: Set old Page status to ERASED status */
  565.         FlashStatus = FLASH_ErasePage(OldPageAddress);
  566.         /* If erase operation was failed, a Flash error code is returned */
  567.         if (FlashStatus != FLASH_COMPLETE)
  568.         {
  569.                 return FlashStatus;
  570.         }

  571.         /* Set new Page status to VALID_PAGE status */
  572.         FlashStatus = FLASH_ProgramHalfWord(NewPageAddress, VALID_PAGE);
  573.         /* If program operation was failed, a Flash error code is returned */
  574.         if (FlashStatus != FLASH_COMPLETE)
  575.         {
  576.                 return FlashStatus;
  577.         }

  578.         /* Return last operation flash status */
  579.         return FlashStatus;
  580. }

  581. /**
  582. * @}
  583. */

  584. /******************* (C) COPYRIGHT 2009 STMicroelectronics *****END OF FILE****/
复制代码

STM32F407
头文件

  1. /**
  2.   ******************************************************************************
  3.   * @file    EEPROM_Emulation/inc/eeprom.h
  4.   * @author  MCD Application Team
  5.    * @version V1.0.0
  6.   * @date    10-October-2011
  7.   * @brief   This file contains all the functions prototypes for the EEPROM
  8.   *          emulation firmware library.
  9.   ******************************************************************************
  10.   * @attention
  11.   *
  12.   * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
  13.   * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
  14.   * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
  15.   * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
  16.   * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
  17.   * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
  18.   *
  19.   * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
  20.   ******************************************************************************
  21.   */

  22. /* Define to prevent recursive inclusion -------------------------------------*/
  23. #ifndef __EEPROM_H
  24. #define __EEPROM_H

  25. /* Includes ------------------------------------------------------------------*/
  26. #include "stm32f4xx.h"

  27. /* Exported constants --------------------------------------------------------*/

  28. #define ADDR_FLASH_SECTOR_0                        ((uint32_t) 0x08000000)
  29. #define ADDR_FLASH_SECTOR_1                        ((uint32_t) 0x08004000)
  30. #define ADDR_FLASH_SECTOR_2                        ((uint32_t) 0x08008000)
  31. #define ADDR_FLASH_SECTOR_3                        ((uint32_t) 0x0800C000)
  32. #define ADDR_FLASH_SECTOR_4                        ((uint32_t) 0x08010000)
  33. #define ADDR_FLASH_SECTOR_5                        ((uint32_t) 0x08020000)
  34. #define ADDR_FLASH_SECTOR_6                        ((uint32_t) 0x08040000)
  35. #define ADDR_FLASH_SECTOR_7                        ((uint32_t) 0x08060000)
  36. #define ADDR_FLASH_SECTOR_8                        ((uint32_t) 0x08080000)
  37. #define ADDR_FLASH_SECTOR_9                        ((uint32_t) 0x080A0000)
  38. #define ADDR_FLASH_SECTOR_10                        ((uint32_t) 0x080C0000)
  39. #define ADDR_FLASH_SECTOR_11                        ((uint32_t) 0x080E0000)

  40. #define ADDR_FLASH_SECTOR_12                        ((uint32_t) 0x08100000)
  41. #define ADDR_FLASH_SECTOR_13                        ((uint32_t) 0x08104000)
  42. #define ADDR_FLASH_SECTOR_14                        ((uint32_t) 0x08108000)
  43. #define ADDR_FLASH_SECTOR_15                        ((uint32_t) 0x0810C000)
  44. #define ADDR_FLASH_SECTOR_16                        ((uint32_t) 0x08110000)
  45. #define ADDR_FLASH_SECTOR_17                        ((uint32_t) 0x08120000)
  46. #define ADDR_FLASH_SECTOR_18                        ((uint32_t) 0x08140000)
  47. #define ADDR_FLASH_SECTOR_19                        ((uint32_t) 0x08160000)
  48. #define ADDR_FLASH_SECTOR_20                ((uint32_t) 0x08180000)
  49. #define ADDR_FLASH_SECTOR_21                        ((uint32_t) 0x081A0000)
  50. #define ADDR_FLASH_SECTOR_22                ((uint32_t) 0x081C0000)
  51. #define ADDR_FLASH_SECTOR_23                ((uint32_t) 0x081E0000)

  52. /*Bootload占用了Flash的0~1扇区,模拟EEPROM占用2~3扇区,用户APP从4扇区开始启动*/

  53. /* Define the size of the sectors to be used */
  54. #define PAGE_SIZE               (uint32_t)0x4000  /* Page size = 16KByte */

  55. /* Device voltage range supposed to be [2.7V to 3.6V], the operation will
  56.    be done by word  */
  57. #define VOLTAGE_RANGE           (uint8_t)VoltageRange_3

  58. /* EEPROM start address in Flash */
  59. /* EEPROM emulation start address: from sector2 : after 16KByte of usedFlash memory */
  60. #define EEPROM_START_ADDRESS  ADDR_FLASH_SECTOR_2

  61. /* Pages 0 and 1 base and end addresses */
  62. #define PAGE0_BASE_ADDRESS    ((uint32_t)(EEPROM_START_ADDRESS + 0x0000))
  63. #define PAGE0_END_ADDRESS     ((uint32_t)(EEPROM_START_ADDRESS + (PAGE_SIZE - 1)))
  64. #define PAGE0_ID               FLASH_Sector_2

  65. #define PAGE1_BASE_ADDRESS    ((uint32_t)(EEPROM_START_ADDRESS + 0x4000))
  66. #define PAGE1_END_ADDRESS     ((uint32_t)(EEPROM_START_ADDRESS + (2 * PAGE_SIZE - 1)))
  67. #define PAGE1_ID               FLASH_Sector_3

  68. /* Used Flash pages for EEPROM emulation */
  69. #define PAGE0                 ((uint16_t)0x0000)
  70. #define PAGE1                 ((uint16_t)0x0001)

  71. /* No valid page define */
  72. #define NO_VALID_PAGE         ((uint16_t)0x00AB)

  73. /* Page status definitions */
  74. #define ERASED                ((uint16_t)0xFFFF)     /* Page is empty */
  75. #define RECEIVE_DATA          ((uint16_t)0xEEEE)     /* Page is marked to receive data */
  76. #define VALID_PAGE            ((uint16_t)0x0000)     /* Page containing valid data */

  77. /* Valid pages in read and write defines */
  78. #define READ_FROM_VALID_PAGE  ((uint8_t)0x00)
  79. #define WRITE_IN_VALID_PAGE   ((uint8_t)0x01)

  80. /* Page full define */
  81. #define PAGE_FULL             ((uint8_t)0x80)

  82. /* Variables' number */
  83. #define EEPROM_NumbOfVar                128
  84. extern uint16_t EEPROM_VirtAddVarTab[EEPROM_NumbOfVar];

  85. /* Exported types ------------------------------------------------------------*/
  86. /* Exported macro ------------------------------------------------------------*/
  87. /* Exported functions ------------------------------------------------------- */
  88. uint16_t EE_Init(void);
  89. uint16_t EE_ReadVariable(uint16_t VirtAddress, uint16_t* Data);
  90. uint16_t EE_WriteVariable(uint16_t VirtAddress, uint16_t Data);

  91. #endif /* __EEPROM_H */

  92. /******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
复制代码

源文件
  1. /**
  2.   ******************************************************************************
  3.   * @file    EEPROM_Emulation/src/eeprom.c
  4.   * @author  MCD Application Team
  5.   * @version V1.0.0
  6.   * @date    10-October-2011
  7.   * @brief   This file provides all the EEPROM emulation firmware functions.
  8.   ******************************************************************************
  9.   * @attention
  10.   *
  11.   * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
  12.   * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
  13.   * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
  14.   * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
  15.   * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
  16.   * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
  17.   *
  18.   * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
  19.   ******************************************************************************
  20.   */

  21. /** @addtogroup EEPROM_Emulation
  22.   * @{
  23.   */

  24. /* Includes ------------------------------------------------------------------*/
  25. #include "eeprom.h"

  26. /* Private typedef -----------------------------------------------------------*/
  27. /* Private define ------------------------------------------------------------*/
  28. /* Private macro -------------------------------------------------------------*/
  29. /* Private variables ---------------------------------------------------------*/

  30. /* Global variable used to store variable value in read sequence */
  31. uint16_t DataVar = 0;

  32. /* Virtual address defined by the user: 0xFFFF value is prohibited */
  33. uint16_t EEPROM_VirtAddVarTab[EEPROM_NumbOfVar] =
  34. {
  35.         0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
  36.         0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, 0x0010,
  37.         0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018,
  38.         0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, 0x0020,
  39.         0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
  40.         0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, 0x0030,
  41.         0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
  42.         0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, 0x0040,
  43.         0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
  44.         0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050,
  45.         0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
  46.         0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, 0x0060,
  47.         0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068,
  48.         0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070,
  49.         0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078,
  50.         0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, 0x0080,
  51. };

  52. /* Private function prototypes -----------------------------------------------*/
  53. /* Private functions ---------------------------------------------------------*/
  54. static FLASH_Status EE_Format(void);
  55. static uint16_t EE_FindValidPage(uint8_t Operation);
  56. static uint16_t EE_VerifyPageFullWriteVariable(uint16_t VirtAddress, uint16_t Data);
  57. static uint16_t EE_PageTransfer(uint16_t VirtAddress, uint16_t Data);

  58. /**
  59.   * @brief  Restore the pages to a known good state in case of page's status
  60.   *   corruption after a power loss.
  61.   * @param  None.
  62.   * @retval - Flash error code: on write Flash error
  63.   *         - FLASH_COMPLETE: on success
  64.   */
  65. uint16_t EE_Init(void)
  66. {
  67.   uint16_t PageStatus0 = 6, PageStatus1 = 6;
  68.   uint16_t VarIdx = 0;
  69.   uint16_t EepromStatus = 0, ReadStatus = 0;
  70.   int16_t x = -1;
  71.   uint16_t  FlashStatus;

  72.   /* Get Page0 status */
  73.   PageStatus0 = (*(__IO uint16_t*)PAGE0_BASE_ADDRESS);
  74.   /* Get Page1 status */
  75.   PageStatus1 = (*(__IO uint16_t*)PAGE1_BASE_ADDRESS);

  76.   /* Check for invalid header states and repair if necessary */
  77.   switch (PageStatus0)
  78.   {
  79.     case ERASED:
  80.       if (PageStatus1 == VALID_PAGE) /* Page0 erased, Page1 valid */
  81.       {
  82.         /* Erase Page0 */
  83.         FlashStatus = FLASH_EraseSector(PAGE0_ID,VOLTAGE_RANGE);
  84.         /* If erase operation was failed, a Flash error code is returned */
  85.         if (FlashStatus != FLASH_COMPLETE)
  86.         {
  87.           return FlashStatus;
  88.         }
  89.       }
  90.       else if (PageStatus1 == RECEIVE_DATA) /* Page0 erased, Page1 receive */
  91.       {
  92.         /* Erase Page0 */
  93.         FlashStatus = FLASH_EraseSector(PAGE0_ID, VOLTAGE_RANGE);
  94.         /* If erase operation was failed, a Flash error code is returned */
  95.         if (FlashStatus != FLASH_COMPLETE)
  96.         {
  97.           return FlashStatus;
  98.         }
  99.         /* Mark Page1 as valid */
  100.         FlashStatus = FLASH_ProgramHalfWord(PAGE1_BASE_ADDRESS, VALID_PAGE);
  101.         /* If program operation was failed, a Flash error code is returned */
  102.         if (FlashStatus != FLASH_COMPLETE)
  103.         {
  104.           return FlashStatus;
  105.         }
  106.       }
  107.       else /* First EEPROM access (Page0&1 are erased) or invalid state -> format EEPROM */
  108.       {
  109.         /* Erase both Page0 and Page1 and set Page0 as valid page */
  110.         FlashStatus = EE_Format();
  111.         /* If erase/program operation was failed, a Flash error code is returned */
  112.         if (FlashStatus != FLASH_COMPLETE)
  113.         {
  114.           return FlashStatus;
  115.         }
  116.       }
  117.       break;

  118.     case RECEIVE_DATA:
  119.       if (PageStatus1 == VALID_PAGE) /* Page0 receive, Page1 valid */
  120.       {
  121.         /* Transfer data from Page1 to Page0 */
  122.         for (VarIdx = 0; VarIdx < EEPROM_NumbOfVar; VarIdx++)
  123.         {
  124.           if (( *(__IO uint16_t*)(PAGE0_BASE_ADDRESS + 6)) == EEPROM_VirtAddVarTab[VarIdx])
  125.           {
  126.             x = VarIdx;
  127.           }
  128.           if (VarIdx != x)
  129.           {
  130.             /* Read the last variables' updates */
  131.             ReadStatus = EE_ReadVariable(EEPROM_VirtAddVarTab[VarIdx], &DataVar);
  132.             /* In case variable corresponding to the virtual address was found */
  133.             if (ReadStatus != 0x1)
  134.             {
  135.               /* Transfer the variable to the Page0 */
  136.               EepromStatus = EE_VerifyPageFullWriteVariable(EEPROM_VirtAddVarTab[VarIdx], DataVar);
  137.               /* If program operation was failed, a Flash error code is returned */
  138.               if (EepromStatus != FLASH_COMPLETE)
  139.               {
  140.                 return EepromStatus;
  141.               }
  142.             }
  143.           }
  144.         }
  145.         /* Mark Page0 as valid */
  146.         FlashStatus = FLASH_ProgramHalfWord(PAGE0_BASE_ADDRESS, VALID_PAGE);
  147.         /* If program operation was failed, a Flash error code is returned */
  148.         if (FlashStatus != FLASH_COMPLETE)
  149.         {
  150.           return FlashStatus;
  151.         }
  152.         /* Erase Page1 */
  153.         FlashStatus = FLASH_EraseSector(PAGE1_ID, VOLTAGE_RANGE);
  154.         /* If erase operation was failed, a Flash error code is returned */
  155.         if (FlashStatus != FLASH_COMPLETE)
  156.         {
  157.           return FlashStatus;
  158.         }
  159.       }
  160.       else if (PageStatus1 == ERASED) /* Page0 receive, Page1 erased */
  161.       {
  162.         /* Erase Page1 */
  163.         FlashStatus = FLASH_EraseSector(PAGE1_ID, VOLTAGE_RANGE);
  164.         /* If erase operation was failed, a Flash error code is returned */
  165.         if (FlashStatus != FLASH_COMPLETE)
  166.         {
  167.           return FlashStatus;
  168.         }
  169.         /* Mark Page0 as valid */
  170.         FlashStatus = FLASH_ProgramHalfWord(PAGE0_BASE_ADDRESS, VALID_PAGE);
  171.         /* If program operation was failed, a Flash error code is returned */
  172.         if (FlashStatus != FLASH_COMPLETE)
  173.         {
  174.           return FlashStatus;
  175.         }
  176.       }
  177.       else /* Invalid state -> format eeprom */
  178.       {
  179.         /* Erase both Page0 and Page1 and set Page0 as valid page */
  180.         FlashStatus = EE_Format();
  181.         /* If erase/program operation was failed, a Flash error code is returned */
  182.         if (FlashStatus != FLASH_COMPLETE)
  183.         {
  184.           return FlashStatus;
  185.         }
  186.       }
  187.       break;

  188.     case VALID_PAGE:
  189.       if (PageStatus1 == VALID_PAGE) /* Invalid state -> format eeprom */
  190.       {
  191.         /* Erase both Page0 and Page1 and set Page0 as valid page */
  192.         FlashStatus = EE_Format();
  193.         /* If erase/program operation was failed, a Flash error code is returned */
  194.         if (FlashStatus != FLASH_COMPLETE)
  195.         {
  196.           return FlashStatus;
  197.         }
  198.       }
  199.       else if (PageStatus1 == ERASED) /* Page0 valid, Page1 erased */
  200.       {
  201.         /* Erase Page1 */
  202.         FlashStatus = FLASH_EraseSector(PAGE1_ID, VOLTAGE_RANGE);
  203.         /* If erase operation was failed, a Flash error code is returned */
  204.         if (FlashStatus != FLASH_COMPLETE)
  205.         {
  206.           return FlashStatus;
  207.         }
  208.       }
  209.       else /* Page0 valid, Page1 receive */
  210.       {
  211.         /* Transfer data from Page0 to Page1 */
  212.         for (VarIdx = 0; VarIdx < EEPROM_NumbOfVar; VarIdx++)
  213.         {
  214.           if ((*(__IO uint16_t*)(PAGE1_BASE_ADDRESS + 6)) == EEPROM_VirtAddVarTab[VarIdx])
  215.           {
  216.             x = VarIdx;
  217.           }
  218.           if (VarIdx != x)
  219.           {
  220.             /* Read the last variables' updates */
  221.             ReadStatus = EE_ReadVariable(EEPROM_VirtAddVarTab[VarIdx], &DataVar);
  222.             /* In case variable corresponding to the virtual address was found */
  223.             if (ReadStatus != 0x1)
  224.             {
  225.               /* Transfer the variable to the Page1 */
  226.               EepromStatus = EE_VerifyPageFullWriteVariable(EEPROM_VirtAddVarTab[VarIdx], DataVar);
  227.               /* If program operation was failed, a Flash error code is returned */
  228.               if (EepromStatus != FLASH_COMPLETE)
  229.               {
  230.                 return EepromStatus;
  231.               }
  232.             }
  233.           }
  234.         }
  235.         /* Mark Page1 as valid */
  236.         FlashStatus = FLASH_ProgramHalfWord(PAGE1_BASE_ADDRESS, VALID_PAGE);
  237.         /* If program operation was failed, a Flash error code is returned */
  238.         if (FlashStatus != FLASH_COMPLETE)
  239.         {
  240.           return FlashStatus;
  241.         }
  242.         /* Erase Page0 */
  243.         FlashStatus = FLASH_EraseSector(PAGE0_ID, VOLTAGE_RANGE);
  244.         /* If erase operation was failed, a Flash error code is returned */
  245.         if (FlashStatus != FLASH_COMPLETE)
  246.         {
  247.           return FlashStatus;
  248.         }
  249.       }
  250.       break;

  251.     default:  /* Any other state -> format eeprom */
  252.       /* Erase both Page0 and Page1 and set Page0 as valid page */
  253.       FlashStatus = EE_Format();
  254.       /* If erase/program operation was failed, a Flash error code is returned */
  255.       if (FlashStatus != FLASH_COMPLETE)
  256.       {
  257.         return FlashStatus;
  258.       }
  259.       break;
  260.   }

  261.   return FLASH_COMPLETE;
  262. }

  263. /**
  264.   * @brief  Returns the last stored variable data, if found, which correspond to
  265.   *   the passed virtual address
  266.   * @param  VirtAddress: Variable virtual address
  267.   * @param  Data: Global variable contains the read variable value
  268.   * @retval Success or error status:
  269.   *           - 0: if variable was found
  270.   *           - 1: if the variable was not found
  271.   *           - NO_VALID_PAGE: if no valid page was found.
  272.   */
  273. uint16_t EE_ReadVariable(uint16_t VirtAddress, uint16_t* Data)
  274. {
  275.   uint16_t ValidPage = PAGE0;
  276.   uint16_t AddressValue = 0x5555, ReadStatus = 1;
  277.   uint32_t Address = EEPROM_START_ADDRESS, PageStartAddress = EEPROM_START_ADDRESS;

  278.   /* Get active Page for read operation */
  279.   ValidPage = EE_FindValidPage(READ_FROM_VALID_PAGE);

  280.   /* Check if there is no valid page */
  281.   if (ValidPage == NO_VALID_PAGE)
  282.   {
  283.     return  NO_VALID_PAGE;
  284.   }

  285.   /* Get the valid Page start Address */
  286.   PageStartAddress = (uint32_t)(EEPROM_START_ADDRESS + (uint32_t)(ValidPage * PAGE_SIZE));

  287.   /* Get the valid Page end Address */
  288.   Address = (uint32_t)((EEPROM_START_ADDRESS - 2) + (uint32_t)((1 + ValidPage) * PAGE_SIZE));

  289.   /* Check each active page address starting from end */
  290.   while (Address > (PageStartAddress + 2))
  291.   {
  292.     /* Get the current location content to be compared with virtual address */
  293.     AddressValue = (*(__IO uint16_t*)Address);

  294.     /* Compare the read address with the virtual address */
  295.     if (AddressValue == VirtAddress)
  296.     {
  297.       /* Get content of Address-2 which is variable value */
  298.       *Data = (*(__IO uint16_t*)(Address - 2));

  299.       /* In case variable value is read, reset ReadStatus flag */
  300.       ReadStatus = 0;

  301.       break;
  302.     }
  303.     else
  304.     {
  305.       /* Next address location */
  306.       Address = Address - 4;
  307.     }
  308.   }

  309.   /* Return ReadStatus value: (0: variable exist, 1: variable doesn't exist) */
  310.   return ReadStatus;
  311. }

  312. /**
  313.   * @brief  Writes/upadtes variable data in EEPROM.
  314.   * @param  VirtAddress: Variable virtual address
  315.   * @param  Data: 16 bit data to be written
  316.   * @retval Success or error status:
  317.   *           - FLASH_COMPLETE: on success
  318.   *           - PAGE_FULL: if valid page is full
  319.   *           - NO_VALID_PAGE: if no valid page was found
  320.   *           - Flash error code: on write Flash error
  321.   */
  322. uint16_t EE_WriteVariable(uint16_t VirtAddress, uint16_t Data)
  323. {
  324.   uint16_t Status = 0;

  325.   /* Write the variable virtual address and value in the EEPROM */
  326.   Status = EE_VerifyPageFullWriteVariable(VirtAddress, Data);

  327.   /* In case the EEPROM active page is full */
  328.   if (Status == PAGE_FULL)
  329.   {
  330.     /* Perform Page transfer */
  331.     Status = EE_PageTransfer(VirtAddress, Data);
  332.   }

  333.   /* Return last operation status */
  334.   return Status;
  335. }

  336. /**
  337.   * @brief  Erases PAGE and PAGE1 and writes VALID_PAGE header to PAGE
  338.   * @param  None
  339.   * @retval Status of the last operation (Flash write or erase) done during
  340.   *         EEPROM formating
  341.   */
  342. static FLASH_Status EE_Format(void)
  343. {
  344.   FLASH_Status FlashStatus = FLASH_COMPLETE;

  345.   /* Erase Page0 */
  346.   FlashStatus = FLASH_EraseSector(PAGE0_ID, VOLTAGE_RANGE);

  347.   /* If erase operation was failed, a Flash error code is returned */
  348.   if (FlashStatus != FLASH_COMPLETE)
  349.   {
  350.     return FlashStatus;
  351.   }

  352.   /* Set Page0 as valid page: Write VALID_PAGE at Page0 base address */
  353.   FlashStatus = FLASH_ProgramHalfWord(PAGE0_BASE_ADDRESS, VALID_PAGE);

  354.   /* If program operation was failed, a Flash error code is returned */
  355.   if (FlashStatus != FLASH_COMPLETE)
  356.   {
  357.     return FlashStatus;
  358.   }

  359.   /* Erase Page1 */
  360.   FlashStatus = FLASH_EraseSector(PAGE1_ID, VOLTAGE_RANGE);

  361.   /* Return Page1 erase operation status */
  362.   return FlashStatus;
  363. }

  364. /**
  365.   * @brief  Find valid Page for write or read operation
  366.   * @param  Operation: operation to achieve on the valid page.
  367.   *   This parameter can be one of the following values:
  368.   *     @arg READ_FROM_VALID_PAGE: read operation from valid page
  369.   *     @arg WRITE_IN_VALID_PAGE: write operation from valid page
  370.   * @retval Valid page number (PAGE or PAGE1) or NO_VALID_PAGE in case
  371.   *   of no valid page was found
  372.   */
  373. static uint16_t EE_FindValidPage(uint8_t Operation)
  374. {
  375.   uint16_t PageStatus0 = 6, PageStatus1 = 6;

  376.   /* Get Page0 actual status */
  377.   PageStatus0 = (*(__IO uint16_t*)PAGE0_BASE_ADDRESS);

  378.   /* Get Page1 actual status */
  379.   PageStatus1 = (*(__IO uint16_t*)PAGE1_BASE_ADDRESS);

  380.   /* Write or read operation */
  381.   switch (Operation)
  382.   {
  383.     case WRITE_IN_VALID_PAGE:   /* ---- Write operation ---- */
  384.       if (PageStatus1 == VALID_PAGE)
  385.       {
  386.         /* Page0 receiving data */
  387.         if (PageStatus0 == RECEIVE_DATA)
  388.         {
  389.           return PAGE0;         /* Page0 valid */
  390.         }
  391.         else
  392.         {
  393.           return PAGE1;         /* Page1 valid */
  394.         }
  395.       }
  396.       else if (PageStatus0 == VALID_PAGE)
  397.       {
  398.         /* Page1 receiving data */
  399.         if (PageStatus1 == RECEIVE_DATA)
  400.         {
  401.           return PAGE1;         /* Page1 valid */
  402.         }
  403.         else
  404.         {
  405.           return PAGE0;         /* Page0 valid */
  406.         }
  407.       }
  408.       else
  409.       {
  410.         return NO_VALID_PAGE;   /* No valid Page */
  411.       }

  412.     case READ_FROM_VALID_PAGE:  /* ---- Read operation ---- */
  413.       if (PageStatus0 == VALID_PAGE)
  414.       {
  415.         return PAGE0;           /* Page0 valid */
  416.       }
  417.       else if (PageStatus1 == VALID_PAGE)
  418.       {
  419.         return PAGE1;           /* Page1 valid */
  420.       }
  421.       else
  422.       {
  423.         return NO_VALID_PAGE ;  /* No valid Page */
  424.       }

  425.     default:
  426.       return PAGE0;             /* Page0 valid */
  427.   }
  428. }

  429. /**
  430.   * @brief  Verify if active page is full and Writes variable in EEPROM.
  431.   * @param  VirtAddress: 16 bit virtual address of the variable
  432.   * @param  Data: 16 bit data to be written as variable value
  433.   * @retval Success or error status:
  434.   *           - FLASH_COMPLETE: on success
  435.   *           - PAGE_FULL: if valid page is full
  436.   *           - NO_VALID_PAGE: if no valid page was found
  437.   *           - Flash error code: on write Flash error
  438.   */
  439. static uint16_t EE_VerifyPageFullWriteVariable(uint16_t VirtAddress, uint16_t Data)
  440. {
  441.   FLASH_Status FlashStatus = FLASH_COMPLETE;
  442.   uint16_t ValidPage = PAGE0;
  443.   uint32_t Address = EEPROM_START_ADDRESS, PageEndAddress = EEPROM_START_ADDRESS+PAGE_SIZE;

  444.   /* Get valid Page for write operation */
  445.   ValidPage = EE_FindValidPage(WRITE_IN_VALID_PAGE);

  446.   /* Check if there is no valid page */
  447.   if (ValidPage == NO_VALID_PAGE)
  448.   {
  449.     return  NO_VALID_PAGE;
  450.   }

  451.   /* Get the valid Page start Address */
  452.   Address = (uint32_t)(EEPROM_START_ADDRESS + (uint32_t)(ValidPage * PAGE_SIZE));

  453.   /* Get the valid Page end Address */
  454.   PageEndAddress = (uint32_t)((EEPROM_START_ADDRESS - 2) + (uint32_t)((1 + ValidPage) * PAGE_SIZE));

  455.   /* Check each active page address starting from begining */
  456.   while (Address < PageEndAddress)
  457.   {
  458.     /* Verify if Address and Address+2 contents are 0xFFFFFFFF */
  459.     if ((*(__IO uint32_t*)Address) == 0xFFFFFFFF)
  460.     {
  461.       /* Set variable data */
  462.       FlashStatus = FLASH_ProgramHalfWord(Address, Data);
  463.       /* If program operation was failed, a Flash error code is returned */
  464.       if (FlashStatus != FLASH_COMPLETE)
  465.       {
  466.         return FlashStatus;
  467.       }
  468.       /* Set variable virtual address */
  469.       FlashStatus = FLASH_ProgramHalfWord(Address + 2, VirtAddress);
  470.       /* Return program operation status */
  471.       return FlashStatus;
  472.     }
  473.     else
  474.     {
  475.       /* Next address location */
  476.       Address = Address + 4;
  477.     }
  478.   }

  479.   /* Return PAGE_FULL in case the valid page is full */
  480.   return PAGE_FULL;
  481. }

  482. /**
  483.   * @brief  Transfers last updated variables data from the full Page to
  484.   *   an empty one.
  485.   * @param  VirtAddress: 16 bit virtual address of the variable
  486.   * @param  Data: 16 bit data to be written as variable value
  487.   * @retval Success or error status:
  488.   *           - FLASH_COMPLETE: on success
  489.   *           - PAGE_FULL: if valid page is full
  490.   *           - NO_VALID_PAGE: if no valid page was found
  491.   *           - Flash error code: on write Flash error
  492.   */
  493. static uint16_t EE_PageTransfer(uint16_t VirtAddress, uint16_t Data)
  494. {
  495.   FLASH_Status FlashStatus = FLASH_COMPLETE;
  496.   uint32_t NewPageAddress = EEPROM_START_ADDRESS;
  497.   uint16_t OldPageId=0;
  498.   uint16_t ValidPage = PAGE0, VarIdx = 0;
  499.   uint16_t EepromStatus = 0, ReadStatus = 0;

  500.   /* Get active Page for read operation */
  501.   ValidPage = EE_FindValidPage(READ_FROM_VALID_PAGE);

  502.   if (ValidPage == PAGE1)       /* Page1 valid */
  503.   {
  504.     /* New page address where variable will be moved to */
  505.     NewPageAddress = PAGE0_BASE_ADDRESS;

  506.     /* Old page ID where variable will be taken from */
  507.     OldPageId = PAGE1_ID;
  508.   }
  509.   else if (ValidPage == PAGE0)  /* Page0 valid */
  510.   {
  511.     /* New page address  where variable will be moved to */
  512.     NewPageAddress = PAGE1_BASE_ADDRESS;

  513.     /* Old page ID where variable will be taken from */
  514.     OldPageId = PAGE0_ID;
  515.   }
  516.   else
  517.   {
  518.     return NO_VALID_PAGE;       /* No valid Page */
  519.   }

  520.   /* Set the new Page status to RECEIVE_DATA status */
  521.   FlashStatus = FLASH_ProgramHalfWord(NewPageAddress, RECEIVE_DATA);
  522.   /* If program operation was failed, a Flash error code is returned */
  523.   if (FlashStatus != FLASH_COMPLETE)
  524.   {
  525.     return FlashStatus;
  526.   }

  527.   /* Write the variable passed as parameter in the new active page */
  528.   EepromStatus = EE_VerifyPageFullWriteVariable(VirtAddress, Data);
  529.   /* If program operation was failed, a Flash error code is returned */
  530.   if (EepromStatus != FLASH_COMPLETE)
  531.   {
  532.     return EepromStatus;
  533.   }

  534.   /* Transfer process: transfer variables from old to the new active page */
  535.   for (VarIdx = 0; VarIdx < EEPROM_NumbOfVar; VarIdx++)
  536.   {
  537.     if (EEPROM_VirtAddVarTab[VarIdx] != VirtAddress)  /* Check each variable except the one passed as parameter */
  538.     {
  539.       /* Read the other last variable updates */
  540.       ReadStatus = EE_ReadVariable(EEPROM_VirtAddVarTab[VarIdx], &DataVar);
  541.       /* In case variable corresponding to the virtual address was found */
  542.       if (ReadStatus != 0x1)
  543.       {
  544.         /* Transfer the variable to the new active page */
  545.         EepromStatus = EE_VerifyPageFullWriteVariable(EEPROM_VirtAddVarTab[VarIdx], DataVar);
  546.         /* If program operation was failed, a Flash error code is returned */
  547.         if (EepromStatus != FLASH_COMPLETE)
  548.         {
  549.           return EepromStatus;
  550.         }
  551.       }
  552.     }
  553.   }

  554.   /* Erase the old Page: Set old Page status to ERASED status */
  555.   FlashStatus = FLASH_EraseSector(OldPageId, VOLTAGE_RANGE);
  556.   /* If erase operation was failed, a Flash error code is returned */
  557.   if (FlashStatus != FLASH_COMPLETE)
  558.   {
  559.     return FlashStatus;
  560.   }

  561.   /* Set new Page status to VALID_PAGE status */
  562.   FlashStatus = FLASH_ProgramHalfWord(NewPageAddress, VALID_PAGE);
  563.   /* If program operation was failed, a Flash error code is returned */
  564.   if (FlashStatus != FLASH_COMPLETE)
  565.   {
  566.     return FlashStatus;
  567.   }

  568.   /* Return last operation flash status */
  569.   return FlashStatus;
  570. }

  571. /**
  572.   * @}
  573.   */

  574. /******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
复制代码

使用指南
EEPROM 仿真应用所需的扇区大小和扇区数量可根据系统使用寿命内写入的数据量进行选择。需要特别注意的是STM32F103与STM32F407的Flash扇区大小、扇区数量、扇区地址是不一样的,因此为仿真EEPROM分配扇区时,针对不同的单片机应当有不同的分配扇区策略。

以STM32F103VE为例,它的主存储器分为256页,每页大小为2KB,共512KB。由于每页的大小相同的,因此可以直接选取最后两个扇区作为EEPROM仿真应用的扇区。

以STM32F407ZG为例,它的主存储器分为12个扇区,其中包含4个16KB扇区、1个64KB扇区和7个128KB 的扇区,共1MB。由于最后的7个扇区容量过大,因此直接选取最后两个扇区是不合适的。如果选取两个16KB扇区作为EEPROM仿真应用的扇区,将破坏正常程序烧录在Flash中的结构(从第一个扇区的首地址开始烧写)。因此最好设置一个BootLoader程序(占用前两个扇区,共32K空间),然后通过此程序跳转到用户程序。用户程序从第五个扇区开始烧录。这样可以将第三与第四扇区作为EEPROM仿真应用的扇区。

应用层扩展
源码

应用层的StorableData数组以float类型的数据保存变量的值,因此需要两个16位的空间在仿真EEPROM中储存。通过定义一个联合体类型,可以方便的实现float类型的数据与16位字节数组的相互转换。

  1. typedef union
  2. {
  3.         float toFloat;
  4.         uint16_t toUint16Array[2];
  5. } EepDataUnion;
复制代码

要使用一个完善的“可存储类型”的变量,还需要指定在EEPROM中的存储位置、默认值、索引值等其他信息。通过定义一个结构体类型来封装可存储类型的变量:

  1. typedef struct
  2. {
  3.         char name[6];
  4.         EepDataUnion value;
  5.         const EepDataUnion defaultValue;
  6.         const uint16_t EEP_Index;
  7.         const uint16_t GLO_Index;
  8. } EepromData_typedef;
复制代码

EepromData_typedef结构体类型的各成员简介如下:
name为变量的名称,不影响存储与读写的功能,可以根据需要调整字符串存储空间大小
value为变量的值,这是一个联合体变量,可以通过.toFloat获取浮点数表示的值,通过.toUint16Array获取16位数组表示的值
defaultValue为变量的默认值,数据类型与value相同,它记录了这个变量的默认值。
EEP_Index为此变量在EEPROM中存储的位置,在连续存储的情况下,它一般设置为GLO_Index的两倍
GLO_Index为此变量的全局序列号,如果是在一个数组中,它应当设置为在数组中的索引号
为了增加数据存储安全性能,将全局数组变量StorableData[]的第一个成员设置为校验数据,它主要有以下几个作用:

检测是否首次烧录(启用仿真EEPROM)程序,如果是首次烧录程序(EEPROM中没有保存StorableData成员的值)则执行初始化,将StorableData成员的默认值保存在EEPROM中的对应位置。
记录MCU的启动次数。完成StorableData成员在EEPROM中的初始化之后,每次启动MCU都会将此值加1。因此通过读取此值可以判断MCU的开机次数,进而推断电路板的工作时长、使用寿命等信息。

头文件
  1. #ifndef __GLOBALVARIATE_H__
  2. #define __GLOBALVARIATE_H__

  3. #include "stm32f4xx_conf.h"
  4. #include "stm32f4xx.h"

  5. typedef union
  6. {
  7.         float toFloat;
  8.         uint16_t toUint16Array[2];
  9. } EepDataUnion;

  10. typedef struct
  11. {
  12.         char name[6];
  13.         EepDataUnion value;
  14.         EepDataUnion defaultValue;
  15.         uint16_t EEP_Index;
  16.         uint16_t GLO_Index;
  17. } EepromData_typedef;

  18. #define EEPROM_CKECKCODE_COUNT                 100000.0f

  19. extern uint16_t STORABLE_DATA_COUNT;

  20. extern volatile EepromData_typedef StorableData[];

  21. void StorableData_InitAll();

  22. void StorableData_SaveDefaultValue(const EepromData_typedef *EEPROM_Data_Struct);
  23. void StorableData_SaveAllDefaultValue();

  24. void StorableData_SaveValue(const EepromData_typedef *EEPROM_Data_Struct);
  25. void StorableData_SaveAllValue();

  26. void StorableData_LoadValueFromEEPROM(EepromData_typedef *EEPROM_Data_Struct);
  27. void StorableData_LoadAllValueFromEEPROM();

  28. void StorableData_ResetValue(EepromData_typedef *EEPROM_Data_Struct);
  29. void StorableData_ResetAllValue();

  30. void StorableData_SetValue_Float(uint16_t index, float value);
  31. void StorableData_SetValue_16BitArray(uint16_t index, uint16_t *array);

  32. float StorableData_GetValue(uint16_t index);

  33. #endif
复制代码

源文件
  1. #include "globalVariate.h"
  2. #include "eeprom.h"

  3. /**
  4. * STORABLE_DATA_COUNT的值必须等于EepromData_typedef数组数量,
  5. * 因此它将在void StorableData_InitAll()中被计算出来,以确保数值准确
  6. */

  7. uint16_t STORABLE_DATA_COUNT = 0;

  8. volatile EepromData_typedef StorableData[] =
  9. {
  10.         { {""}, .value = { .toFloat = 0 }, .defaultValue = { .toFloat = EEPROM_CKECKCODE_COUNT }, 0, 0 },

  11.         { {""}, .value = { .toFloat = 0 }, .defaultValue = { .toFloat = 0 }, 2, 1 },                //通道1:Iout1-4mA 电压
  12.         { {""}, .value = { .toFloat = 500 }, .defaultValue = { .toFloat = 0 }, 4, 2 },                //通道1:Iout1-20mA对应电压
  13.         { {""}, .value = { .toFloat = 0 }, .defaultValue = { .toFloat = 0 }, 6, 3 },                //通道1:传感器类型
  14.         { {""}, .value = { .toFloat = 0 }, .defaultValue = { .toFloat = 0 }, 8, 4 },                //通道1:输出信号类型

  15.         { {""}, .value = { .toFloat = 0 }, .defaultValue = { .toFloat = 0 }, 10, 5 },                //通道2:Iout2-4mA对应电压
  16.         { {""}, .value = { .toFloat = 500 }, .defaultValue = { .toFloat = 0 }, 12, 6 },                //通道2:Iout2-20mA对应电压
  17.         { {""}, .value = { .toFloat = 0 }, .defaultValue = { .toFloat = 0 }, 14, 7 },                //通道2:传感器类型
  18.         { {""}, .value = { .toFloat = 0 }, .defaultValue = { .toFloat = 0 }, 16, 8 },                //通道2:输出信号类型
  19. };


  20. /**
  21. * @brief 初始化StorableData_Struct数组(应当在程序运行进入主循环之前调用)
  22. *         主要通过第一个StorableData_Struct[0]是否等于默认值(100,000)来判断当前MCU是否为首次烧录。
  23. *         如果当前MCU为首次烧录,则将默认值先保存进EEPROM,再加载到StorableData_Struct数组。
  24. *         每次开机运行调用本函数时,都会将StorableData_Struct[0].value.toFloat的值加一。
  25. *         通过读取StorableData_Struct[0].value.toFloat的值(减去100,000),亦可以判断MCU的累计开机次数。
  26. */
  27. void StorableData_InitAll()
  28. {

  29.         STORABLE_DATA_COUNT = sizeof(StorableData) / sizeof(*StorableData);

  30.         StorableData_LoadAllValueFromEEPROM();

  31.         ///首次烧录
  32.         if(StorableData[0].value.toFloat < EEPROM_CKECKCODE_COUNT)
  33.         {
  34.                 StorableData_SaveAllDefaultValue();
  35.                 StorableData_LoadAllValueFromEEPROM();
  36.         }
  37.         else
  38.         {
  39.                 StorableData[0].value.toFloat += 1.0;
  40.                 StorableData_SaveValue((const EepromData_typedef*) &StorableData[0]);
  41.         }
  42. }


  43. /**
  44. * @brief 将指定的StorableData默认值存储在EEPROM中
  45. */
  46. void StorableData_SaveDefaultValue(const EepromData_typedef *EEPROM_Data_Struct) {
  47.         FLASH_Unlock();
  48.         EE_Init();

  49.         EE_WriteVariable(EEPROM_VirtAddVarTab[EEPROM_Data_Struct->EEP_Index],EEPROM_Data_Struct->defaultValue.toUint16Array[0]);
  50.         EE_WriteVariable(EEPROM_VirtAddVarTab[EEPROM_Data_Struct->EEP_Index+1],EEPROM_Data_Struct->defaultValue.toUint16Array[1]);

  51.         FLASH_Lock();
  52. }

  53. /**
  54. * @brief 将全部的StorableData默认值存储在EEPROM中
  55. */
  56. void StorableData_SaveAllDefaultValue()
  57. {
  58.         FLASH_Unlock();
  59.         EE_Init();

  60.         for (uint16_t i = 0; i < STORABLE_DATA_COUNT; i++)
  61.         {
  62.                 EE_WriteVariable(EEPROM_VirtAddVarTab[StorableData<i>.EEP_Index],StorableData<i>.defaultValue.toUint16Array[0]);
  63.                 EE_WriteVariable(EEPROM_VirtAddVarTab[StorableData<i>.EEP_Index+1],StorableData<i>.defaultValue.toUint16Array[1]);
  64.         }

  65.         FLASH_Lock();
  66. }


  67. /**
  68. * @brief 将指定的StorableData实时值存储在EEPROM中
  69. */
  70. void StorableData_SaveValue(const EepromData_typedef *EEPROM_Data_Struct)
  71. {
  72.         FLASH_Unlock();
  73.         EE_Init();

  74.         EE_WriteVariable(EEPROM_VirtAddVarTab[EEPROM_Data_Struct->EEP_Index],EEPROM_Data_Struct->value.toUint16Array[0]);
  75.         EE_WriteVariable(EEPROM_VirtAddVarTab[EEPROM_Data_Struct->EEP_Index+1],EEPROM_Data_Struct->value.toUint16Array[1]);

  76.         FLASH_Lock();
  77. }

  78. /**
  79. * @brief 将全部的StorableData实时值存储在EEPROM中
  80. */
  81. void StorableData_SaveAllValue()
  82. {
  83.         FLASH_Unlock();
  84.         EE_Init();
  85.         uint16_t count = sizeof(StorableData) / sizeof(*StorableData);
  86.         for (uint16_t i = 0; i < count; i++)
  87.         {
  88.                 EE_WriteVariable(EEPROM_VirtAddVarTab[StorableData<i>.EEP_Index],StorableData<i>.value.toUint16Array[0]);
  89.                 EE_WriteVariable(EEPROM_VirtAddVarTab[StorableData<i>.EEP_Index+1],StorableData<i>.value.toUint16Array[1]);
  90.         }
  91.         FLASH_Lock();
  92. }

  93. /**
  94. * @brief 将EEPROM中对应的值赋予指定的StorableData实时值
  95. */
  96. void StorableData_LoadValueFromEEPROM(EepromData_typedef *EEPROM_Data_Struct)
  97. {
  98.         FLASH_Unlock();
  99.         EE_Init();
  100.         EE_ReadVariable(EEPROM_VirtAddVarTab[EEPROM_Data_Struct->EEP_Index],&EEPROM_Data_Struct->value.toUint16Array[0]);
  101.         EE_ReadVariable(EEPROM_VirtAddVarTab[EEPROM_Data_Struct->EEP_Index+1],&EEPROM_Data_Struct->value.toUint16Array[1]);
  102.         FLASH_Lock();
  103. }

  104. /**
  105. * @brief 将EEPROM中全部的值赋予全部的StorableData实时值
  106. */
  107. void StorableData_LoadAllValueFromEEPROM()
  108. {
  109.         FLASH_Unlock();
  110.         EE_Init();

  111.         uint16_t count = sizeof(StorableData) / sizeof(*StorableData);
  112.         for (uint16_t i = 0; i < count; i++)
  113.         {
  114.                 EE_ReadVariable(EEPROM_VirtAddVarTab[StorableData<i>.EEP_Index],(uint16_t *) &StorableData<i>.value.toUint16Array[0]);
  115.                 EE_ReadVariable(EEPROM_VirtAddVarTab[StorableData<i>.EEP_Index+1],(uint16_t *) &StorableData<i>.value.toUint16Array[1]);
  116.         }

  117.         FLASH_Lock();
  118. }

  119. /**
  120. * @brief 将指定的StorableData实时值重置为默认值
  121. */
  122. void StorableData_ResetValue(EepromData_typedef *EEPROM_Data_Struct)
  123. {
  124.         EEPROM_Data_Struct->value.toUint16Array[0] = EEPROM_Data_Struct->defaultValue.toUint16Array[0];
  125.         EEPROM_Data_Struct->value.toUint16Array[1] = EEPROM_Data_Struct->defaultValue.toUint16Array[1];
  126. }

  127. /**
  128. * @brief 将全部的StorableData实时值重置为默认值
  129. */
  130. void StorableData_ResetAllValue()
  131. {
  132.         uint16_t count = sizeof(StorableData) / sizeof(*StorableData);
  133.         for (uint16_t i = 0; i < count; i++) {
  134.                 StorableData<i>.value.toUint16Array[0] = StorableData<i>.defaultValue.toUint16Array[0];
  135.                 StorableData<i>.value.toUint16Array[1] = StorableData<i>.defaultValue.toUint16Array[1];
  136.         }
  137. }


  138. void StorableData_SetValue_Float(uint16_t index, float value)
  139. {
  140.         StorableData[index].value.toFloat = value;
  141. }


  142. void StorableData_SetValue_16BitArray(uint16_t index, uint16_t *array)
  143. {
  144.         StorableData[index].value.toUint16Array[0] = array[0];
  145.         StorableData[index].value.toUint16Array[1] = array[1];
  146. }


  147. float StorableData_GetValue(uint16_t index)
  148. {
  149.         return StorableData[index].value.toFloat;
  150. }</i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i>
复制代码

使用指南
定义StorableData[]数组,正确设置数组成员的值(注意最大数组成员数量不能超过64,否则需要修改EEPROM库中的虚拟地址分配表)。示例如下:
  1. volatile EepromData_typedef StorableData[] =
  2. {
  3.         { {""}, .value = { .toFloat = 0 }, .defaultValue = { .toFloat = EEPROM_CKECKCODE_COUNT }, 0, 0 },

  4.         { {""}, .value = { .toFloat = 0 }, .defaultValue = { .toFloat = 0 }, 2, 1 },                //通道1:Iout1-4mA 电压
  5.         { {""}, .value = { .toFloat = 500 }, .defaultValue = { .toFloat = 0 }, 4, 2 },                //通道1:Iout1-20mA对应电压
  6.         { {""}, .value = { .toFloat = 0 }, .defaultValue = { .toFloat = 0 }, 6, 3 },                //通道1:传感器类型
  7.         { {""}, .value = { .toFloat = 0 }, .defaultValue = { .toFloat = 0 }, 8, 4 },                //通道1:输出信号类型

  8.         { {""}, .value = { .toFloat = 0 }, .defaultValue = { .toFloat = 0 }, 10, 5 },                //通道2:Iout2-4mA对应电压
  9.         { {""}, .value = { .toFloat = 500 }, .defaultValue = { .toFloat = 0 }, 12, 6 },                //通道2:Iout2-20mA对应电压
  10.         { {""}, .value = { .toFloat = 0 }, .defaultValue = { .toFloat = 0 }, 14, 7 },                //通道2:传感器类型
  11.         { {""}, .value = { .toFloat = 0 }, .defaultValue = { .toFloat = 0 }, 16, 8 },                //通道2:输出信号类型
  12. };
复制代码

在程序启动的时候(一般在外设配置完成后)初始化应用层扩展库。应用层扩展库初始化的时候会自动先初始化EEPROM仿真库,并判断是否需要重置StorableData成员为默认值(一般在首次烧录程序的时候需要重置数据)。同时,用以表示数组长度的变量STORABLE_DATA_COUNT将被自动计算与更新。
  1.         StorableData_InitAll();
复制代码

根据项目的需要对StorableData成员进行读取、写入、保存、重置等操作。
读取:StorableData_GetValue(1)。
写入:StorableData_SetValue_Float(1, 919.0)。
保存:StorableData_SaveValue((const EepromData_typedef *)&StorableData[1])。
重置:StorableData_ResetValue(&StorableData[1])。



收藏 评论0 发布时间:2022-4-13 17:00

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版