本文共 6689 字,大约阅读时间需要 22 分钟。
STM32F4提供4KB的备份SRAM,在开发程序时可以用于存储掉电不丢失的数据(需要RTC纽扣电池支持),特别是一些实时修改的,掉电不能丢失的数据,比如我用于存储雨量累计流量等实时变化的数据,定时存储到flash,实时存储到备份区(不能频繁的写flash),当备份区数据丢失了再从flash加载,否则每次都从备份区加载。
然而在使用过程中发现备份区域数据丢失!下面从STM32系列芯片提供的整个备份域来看看啥情况。
某些STM32芯片提供了备份SRAM,例如STM32F系列芯片有4K的备份SRAM。然而在使用过程中发现备份区域数据丢失!下面从STM32系列芯片提供的整个备份域来看看啥情况。
首先,这部分在参考手册的电源(PWR)章节有详细的介绍。器件的工作电压 (VDD) 要求介于 1.8 V 到 3.6 V 之间。嵌入式线性调压器用于提供内部 1.2 V数字电源。当主电源 VDD 断电时,可通过 VBAT 电压为实时时钟 (RTC)
、RTC备份寄存器
和 备份 SRAM(BKP SRAM)
供电。具体如下图:
复位后,备份域(RTC 寄存器、RTC 备份寄存器和备份 SRAM)将受到保护,以防止意外的写访问。要使能对备份域的访问,请按以下步骤进行操作:
想要访问备份域还是非常简单的,下面以访问备份SRAM为例,从代码角度说明一下(具体见注释即可):
/** * @brief (使用标准外设库)备份SRAM初始化 * @param[in] void * @retval NULL */static void vBkpSramInit(void){ /* 电源接口时钟使能 (Power interface clock enable) */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); /* DBP 位置 1,使能对备份域的访问 */ PWR_BackupAccessCmd(ENABLE); /* 通过将 RCC AHB1 外设时钟使能寄存器 (RCC_AHB1ENR) 中的 BKPSRAMEN 位置 1, 使能备份 SRAM 时钟 */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_BKPSRAM, ENABLE); /* 应用程序必须等待备份调压器就绪标志 (BRR) 置 1,指示在待机模式和 VBAT 模式下会保持写入 RAM 中的数据。 */ while(PWR_GetFlagStatus(PWR_FLAG_BRR) != SET);}/** (使用HAL库)备份SRAM初始化 * * @param[in] NULL * @retval Null**/void BKP_SRAM_Init(void){ /* 电源接口时钟使能 (Power interface clock enable) */ __HAL_RCC_PWR_CLK_ENABLE(); /* DBP 位置 1,使能对备份域的访问 */ HAL_PWR_EnableBkUpAccess(); /* 通过将 RCC AHB1 外设时钟使能寄存器 (RCC_AHB1ENR) 中的 BKPSRAMEN 位置 1, 使能备份 SRAM 时钟 */ __HAL_RCC_BKPSRAM_CLK_ENABLE(); /* 应用程序必须等待备份调压器就绪标志 (BRR) 置 1,指示在待机模式和 VBAT 模式下会保持写入 RAM 中的数据。 */ HAL_PWREx_EnableBkUpReg();}
经过以上初始化之后,就可以使用备份域中的各部分功能了(RTC和备份SRAM的初始化有些区别)。
初始化后对于备份域中各功能(RTC、RTC备份寄存器、备份SRAM)的使用就比较灵活了。
/*----------------------------标准外设库----------------------------*//** * @brief Writes a data in a specified RTC Backup data register. * @param RTC_BKP_DR: RTC Backup data Register number. * This parameter can be: RTC_BKP_DRx where x can be from 0 to 19 to * specify the register. * @param Data: Data to be written in the specified RTC Backup data register. * @retval None */void RTC_WriteBackupRegister(uint32_t RTC_BKP_DR, uint32_t Data){ __IO uint32_t tmp = 0; /* Check the parameters */ assert_param(IS_RTC_BKP(RTC_BKP_DR)); tmp = RTC_BASE + 0x50; tmp += (RTC_BKP_DR * 4); /* Write the specified register */ *(__IO uint32_t *)tmp = (uint32_t)Data;}/** * @brief Reads data from the specified RTC Backup data Register. * @param RTC_BKP_DR: RTC Backup data Register number. * This parameter can be: RTC_BKP_DRx where x can be from 0 to 19 to * specify the register. * @retval None */uint32_t RTC_ReadBackupRegister(uint32_t RTC_BKP_DR){ __IO uint32_t tmp = 0; /* Check the parameters */ assert_param(IS_RTC_BKP(RTC_BKP_DR)); tmp = RTC_BASE + 0x50; tmp += (RTC_BKP_DR * 4); /* Read the specified register */ return (*(__IO uint32_t *)tmp);}/*----------------------------HAL库----------------------------*//** * @brief Writes a data in a specified RTC Backup data register. * @param hrtc: pointer to a RTC_HandleTypeDef structure that contains * the configuration information for RTC. * @param BackupRegister: RTC Backup data Register number. * This parameter can be: RTC_BKP_DRx where x can be from 0 to 19 to * specify the register. * @param Data: Data to be written in the specified RTC Backup data register. * @retval None */void HAL_RTCEx_BKUPWrite(RTC_HandleTypeDef *hrtc, uint32_t BackupRegister, uint32_t Data){ uint32_t tmp = 0U; /* Check the parameters */ assert_param(IS_RTC_BKP(BackupRegister)); tmp = (uint32_t)&(hrtc->Instance->BKP0R); tmp += (BackupRegister * 4U); /* Write the specified register */ *(__IO uint32_t *)tmp = (uint32_t)Data;}/** * @brief Reads data from the specified RTC Backup data Register. * @param hrtc: pointer to a RTC_HandleTypeDef structure that contains * the configuration information for RTC. * @param BackupRegister: RTC Backup data Register number. * This parameter can be: RTC_BKP_DRx where x can be from 0 to 19 to * specify the register. * @retval Read value */uint32_t HAL_RTCEx_BKUPRead(RTC_HandleTypeDef *hrtc, uint32_t BackupRegister){ uint32_t tmp = 0U; /* Check the parameters */ assert_param(IS_RTC_BKP(BackupRegister)); tmp = (uint32_t)&(hrtc->Instance->BKP0R); tmp += (BackupRegister * 4U); /* Read the specified register */ return (*(__IO uint32_t *)tmp);}
分散加载文件
进行访问的方式。具体为定义自己的结构体,使用结构体定义变量BKP_SRAM myContent __attribute__((section("BKP_SRAM_SECTION")));
,最后使用分散加载文件,将以上定义的变量直接映射到备份SRAM即可。; *************************************************************; *** Scatter-Loading Description File generated by uVision ***; *************************************************************LR_IROM1 0x08000000 0x0000C000 { ; load region size_region ER_IROM1 0x08000000 0x0000C000 { ; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) } RW_IRAM1 0x20000000 0x00020000 { ; RW data .ANY (+RW +ZI) } RW_BkSRAM 0x40024000 0x1000 { *.o (BKP_SRAM_SECTION, +First) ; 备份SRAM }}
在实际产品中使用时,发现备份SRAM中的数据丢失!检查在硬件上并没有出现任何问题,于是从软件一步步分析如下:
在IAP跳转到APP前,将备份域的各时钟失能,这样APP中配置的备份SRAM才会有效。
后续可以测试一下其他外设是否有此问题。最好测试一下同样是挂在同一总线下的外设(GPIO、DMA、备份域时钟全部是在AHB总线下的)。
转自链接: