问题背景
在使用后备RAM时出现如下问题:
1.后备RAM地址段数据不能修改;
2.后备RAM可以修改,但是软件复位之后,数据被清除;
3.数据可以软件复位保存,但是掉电一段时间之后,数据被清除;
问题分析
STM32提供4KB的备份SRAM,在开发程序时可以用于存储掉电不丢失的数据(需要RTC纽扣电池支持),特别是一些实时修改的,掉电不能丢失的数据。
在一些方面与后备寄存器一样,两者最主要的特性就是:当有系统复位/电源复位/待机模式下被唤醒这三种情况时,BKP中的值不会丢失或被复位。
两者的不同体现在如下:
1.在大小上,后备寄存器中包括了42个16位的寄存器,共可保存84字节的内容,而后备RAM中可以保存4KB的内容;
2.在首地址上,后备寄存器的首地址是0x58004050,而后备RAM的首地址是0x38800000;
后备RAM的使用需要执行如下四步操作:
1.使能后备RAM的时钟;
2.后备地址写使能;
3.VBAT使能;
4.备份功能使能;
时钟分析
对于最新使用的H7系列的单片机,一段RAM的使用,是否需要单独使能相关时钟,需要根据如图1所示的框图进行判断,原则就是:非CPU总线上的其它总线都需要单独使能总线时钟,图中后备RAM所在总线是SRD总线。
因此我们需要在单片机系统时钟初始化完成之后,单独使能后备RAM时钟,__HAL_RCC_BKPRAM_CLK_ENABLE,需要注意,该总线上还有其它RAM和外设,在使用时,都需要单独使能,如需要使用SRD SRAM时,就需要调用__HAL_RCC_SRDSRAM_CLK_ENABLE对该RAM的时钟进行使能。
即,需要调用__HAL_RCC_BKPRAM_CLK_ENABLE();对后备RAM的时钟进行使能,这样我们才能对其进行访问。
后备域时钟
这一点与后备寄存器一致,RTC 模块和时钟配置是在后备区域,即在系统复位或从待机模式唤醒后 RTC 的设置和时间维持不变,只要后备区域供电正常,那么 RTC 将可以一直运行。但是在系统复位后,会自动禁止访问后备寄存器和 RTC,以防止对后备区域(BKP)的意外写操作。所以在要设置时间之前,先要取消备份区域(BKP)写保护。
所以,在每次系统初始化完成以及后备RAM时钟使能完成之后,我们还需要手动修改PWR的CR1寄存器的第8位/DBP,如图2所示,是数据手册中对该位的描述,使能代码如下:
PWR->CR1|=1<<8;
实际上在RTC的初始化中,已经执行了该操作,图2中可以看出,该寄存器同时还控制了RTC寄存器的访问,所以如果不关闭写保护,那么我们也将无法操作RTC。
VBAT监测
与RTC不同,后备RAM需要单独使能电压的BAT监测,后备寄存器的掉电保存不需要单独使能BAT,如图3所示,我们需要对该寄存器的位进行使能,代码如下:
PWR->CR2 |= 1<<4;
VBAT optional external power supply for Backup domain when VDD is not present(VBAT mode), must be connected to VDD when this feature is not used,如图4所示是VBAT与备份域的框图,所以我们需要使能电源监测和调节功能,只有监测打开,备份功能才有意义。
备份功能
图4中可以看出,我们还需要使能备份域中的备份功能backup regulator,如图5所示是该寄存器的描述,代码如下:
PWR->CR2 |= 1<<0;
图5可以看出,使能该功能只是为了保证数据能够在Standby和VBAT模式的时候也能保存,如图6所示是数据手册中的解释(我们在仅使用普通模式时,也可以不使能该项)。
问题总结
本次问题是首次使用备份RAM,由于对其不够了解,所以不知从何入手,一旦对其进行了解,那么也就算是成功了,本次问题的处理比较简单,大致可以总结成如下代码:
__HAL_RCC_BKPRAM_CLK_ENABLE(); //使能后备RAM时钟
PWR->CR1|=1<<8; //使能后备域的写(关闭写保护)
PWR->CR2 |= 1<<4; //使能VBAT调压器
PWR->CR2 |= 1<<0; //使能后备域的保存功能
除了以上初始化阶段需要注意的点,在该地址段的使用过程中,需要注意他的首地址是0x38800000,并且大小仅有4KB,不建议在调试时,直接通过Memory中修改该地址段的数据,实测,通过该方式进行修改,复位后会恢复,所以最好是通过定义一个数组,然后将该数组强制指定到该位置,如下所示:
#define ADDRMGT_BK_SRAM_ADDRESS_STARTADDR (unsigned long)0x38800000
#define ADDRMGT_BK_SRAM_ADDRESS_SIZE (unsigned long)0x00000800
#define ADDRMGT_BK_SRAM_ADDRESS_NUM (unsigned long)0x00000400
volatile unsigned short AddrMgtBKRAMMap[ADDRMGT_BK_SRAM_ADDRESS_NUM] attribute((at(ADDRMGT_BK_SRAM_ADDRESS_STARTADDR)));
如果必须要人为地令备份域复位(所有数据都被清零),那么有两种方法:
a)软件复位(操作RCC_BDCR中的BDRST位产生);
b) VDD和VBAT均掉电,那么在VDD或都VBAT上电时将引发备分域复位
还有两个特殊操作也可以清除后备RAM的数据:
1.through the Flash interface when a protection level change from level 1 to level 0 isrequested (refer to the description of read protection (RDP) in the Flash programming manual).
2.after a tamper event(侵入监测事件), by filling the backup RAM with zeros upon the first attempt to write access it.