打印
[应用相关]

STM32学习笔记(16)-数据的保存与毁灭-BKP功能

[复制链接]
619|10
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
alternate|  楼主 | 2020-2-7 16:20 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
通过研究,大体明白了BKP的功能,简述如下:
1.  BKP可以用来保存数据
       BKP中包括了42个16位的寄存器,共可保存84字节的内容,它们由VBAT的供电来维挂。
2.  BKP内保存的数据可以被毁灭(如果有人希望恶意得到这些数据的话,令其丢失比保护数据更重要)。STM32提供了一种称之为TAMPER的机制来完成。中文译为“侵入检测”,这需要占用一个外部引脚(PC13)。
3.  如果不用侵入检测功能,那么这个外部引脚可以用作RTC校准功能,这个稍后再研究。
4.  当有系统复位/电源复位/待机模式下被唤醒这三种情况时,BKP中的值不会丢失或被复位。

使用特权

评论回复
沙发
alternate|  楼主 | 2020-2-7 16:21 | 只看该作者
       先回来研究一下STM32的复位机制。以下是数据手册的相关部分。

       6.1  复位

       STM32F10xxx支持三种复位形式,分别为系统复位、上电复位和备份区域复位。

       6.1.1  系统复位

       系统复位将复位除时钟控制寄存器CSR中的复位标志和备份区域中的寄存器以外的所有寄存器

       当以下事件中的一件发生时,产生一个系统复位:

       1.NRST管脚上的低电平(外部复位)

例如:按下板子上的RESET按钮就产生一个外部复位(属于系统复位)

       2.窗口看门狗计数终止(WWDG复位)

       3.独立看门狗计数终止(IWDG复位)

       4.软件复位(SW复位)

       5.低功耗管理复位

       可通过查看RCC_CSR控制状态寄存器中的复位状态标志位识别复位事件来源

使用特权

评论回复
板凳
alternate|  楼主 | 2020-2-7 16:21 | 只看该作者
以下是RCC_CSR的内容:





调试时不太容易区分,以下是某次调试中截到的RCC_CSR数据。




       6.1.2  电源复位

       当以下事件中之一发生时,产生电源复位:

       1. 上电/掉电复位(POR/PDR复位)

       2. 从待机模式中返回

       电源复位将复位除了备份区域外的所有寄存器。(见图3)

       图中复位源将最终作用于RESET管脚,并在复位过程中保持低电平。复位入口矢量被固定在地址0x0000_0004。更多细节,参阅表36。

检测可以是否上电/掉电复位可以用以下的函数:

RCC_GetFlagStatus(RCC_FLAG_PORRST)

其中RCC_FLAG_PORRST也可以被替代成以下的一些符号,以检测不同的内容:

使用特权

评论回复
地板
alternate|  楼主 | 2020-2-7 16:21 | 只看该作者
5.  如果必须要人为地令备份域复位(所有数据都被清零),那么有两种方法:

a)         软件复位(操作RCC_BDCR中的BDRST位产生。);以下是RCC_BDCR中相关的内容:

6.3.9 备份域控制寄存器  (RCC_BDCR)







b)        VDD和VBAT均掉电,那么在VDD或都VBAT上电时将引发备分域复位(这是为了保护数据的完整性?)

使用特权

评论回复
5
alternate|  楼主 | 2020-2-7 16:22 | 只看该作者
6.  数据寄存器究竟是哪些呢?



       那么在STM32提供的库里又是如何来用这些寄存器的呢?我们找一找,在stm32f10x_bkp.c中,代码如下:

/**

  * @brief  Writes user data to the specified Data Backup Register.

  * @param  BKP_DR: specifies the Data Backup Register.

  *   This parameter can be BKP_DRx where x:[1, 42]

  * @param  Data: data to write

  * @retval None

  */

void BKP_WriteBackupRegister(uint16_t BKP_DR, uint16_t Data)

{

  __IO uint32_t tmp = 0;

  /* Check the parameters */

  assert_param(IS_BKP_DR(BKP_DR));

  tmp = (uint32_t)BKP_BASE;

  tmp += BKP_DR;

  *(__IO uint32_t *) tmp = Data;

}

使用特权

评论回复
6
alternate|  楼主 | 2020-2-7 16:22 | 只看该作者
       即只需要提供两个参数,第一个是BKP地址,第二个是数据,两个都是16位的数据。第二个参数没有问题,第一个参数如何提供呢?看例子中的代码:

/**

  * @brief  Writes data Backup DRx registers.

  * @param  FirstBackupData: data to be written to Backup data registers.

  * @retval None

  */

void WriteToBackupReg(uint16_t FirstBackupData)

{

  uint32_t index = 0;

  for (index = 0; index < BKP_DR_NUMBER; index++)

  {

    BKP_WriteBackupRegister(BKPDataReg[index], FirstBackupData + (index * 0x5A));

  }

}

使用特权

评论回复
7
alternate|  楼主 | 2020-2-7 16:22 | 只看该作者
从上面的代码可以看到,第一个参数是用

BKPDataReg[index]

来提供的,这个又是什么东西呢?再找:

uint16_t BKPDataReg[BKP_DR_NUMBER] =

  {

    BKP_DR1, BKP_DR2, BKP_DR3, BKP_DR4, BKP_DR5, BKP_DR6, BKP_DR7, BKP_DR8,

    BKP_DR9, BKP_DR10, BKP_DR11, BKP_DR12, BKP_DR13, BKP_DR14, BKP_DR15, BKP_DR16,

    BKP_DR17, BKP_DR18, BKP_DR19, BKP_DR20, BKP_DR21, BKP_DR22, BKP_DR23, BKP_DR24,

    BKP_DR25, BKP_DR26, BKP_DR27, BKP_DR28, BKP_DR29, BKP_DR30, BKP_DR31, BKP_DR32,

    BKP_DR33, BKP_DR34, BKP_DR35, BKP_DR36, BKP_DR37, BKP_DR38, BKP_DR39, BKP_DR40,

    BKP_DR41, BKP_DR42

  };

原来最终还是用BKP_DR**这样的格式来用的,其中的**代表的序号。即5.4.1中的x。

使用特权

评论回复
8
alternate|  楼主 | 2020-2-7 16:23 | 只看该作者
7.复位后,对备份寄存器和RTC的访问被禁止,并且备份域被保护以防止可能存在的意外的写操作。执行以下操作可以使能对备份寄存器和RTC的访问。

       ●  通过设置寄存器RCC_APB1ENR的PWREN和BKPEN位来打开电源和后备接口的时钟

以下是相关代码:

RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);

这个没有什么可说的,关于打开时钟,前面已多次涉及到。

使用特权

评论回复
9
alternate|  楼主 | 2020-2-7 16:23 | 只看该作者
      ●  电源控制寄存器(PWR_CR)的DBP位来使能对后备寄存器和RTC的访问。

以下是相关代码:

  PWR_BackupAccessCmd(ENABLE);

代码本身相当简洁,不过我们还是再深入一点点。

这个PWR_BackupAccessCmd代码如下:(在stm32f10x_pwr.c文件中)

/**

  * @brief  Enables or disables access to the RTC and backup registers.

  * @param  NewState: new state of the access to the RTC and backup registers.

  *   This parameter can be: ENABLE or DISABLE.

  * @retval None

  */

void PWR_BackupAccessCmd(FunctionalState NewState)

{

  /* Check the parameters */

  assert_param(IS_FUNCTIONAL_STATE(NewState));

  *(__IO uint32_t *) CR_DBP_BB = (uint32_t)NewState;

}

使用特权

评论回复
10
alternate|  楼主 | 2020-2-7 16:23 | 只看该作者
而CR_DBP_BB在这里(stm32f10x_pwr.c文件中):

/* Alias word address of DBP bit */

#define CR_OFFSET                (PWR_OFFSET + 0x00)

#define DBP_BitNumber            0x08

#define CR_DBP_BB                (PERIPH_BB_BASE + (CR_OFFSET * 32) + (DBP_BitNumber * 4))

使用特权

评论回复
11
alternate|  楼主 | 2020-2-7 16:23 | 只看该作者
8.一番探索,暂告一段落。由于我的板子与EVAL板略有不同,4个发光管分别接GPIOD的8,9,10和11引脚,所以在程序中做了如下改动(stm3210e_eval.h文件中):

#define LEDn                        4

#define LED1_GPIO_PORT              GPIOD

#define LED1_GPIO_CLK               RCC_APB2Periph_GPIOD

#define LED1_GPIO_PIN               GPIO_Pin_8

#define LED2_GPIO_PORT              GPIOD

#define LED2_GPIO_CLK               RCC_APB2Periph_GPIOD

#define LED2_GPIO_PIN               GPIO_Pin_9

#define LED3_GPIO_PORT              GPIOD

#define LED3_GPIO_CLK               RCC_APB2Periph_GPIOD

#define LED3_GPIO_PIN               GPIO_Pin_10

#define LED4_GPIO_PORT              GPIOD

#define LED4_GPIO_CLK               RCC_APB2Periph_GPIOD

#define LED4_GPIO_PIN               GPIO_Pin_11

       然后在板子上将JP6插到VBAT端,并且为板子上现成的电池座中装入一块电池。

       执行程序,结果是LED4亮(程序运行)LED1和LED3灯点亮,其含义如下:

(1. LD3 on / LD1 on: a Power On Reset occurred and the values in the BKP data  registers are correct)。

       按下复位按钮后,LD1,LD2,LED3均灭,其含义如下:

(3. LD3 off / LD1 off / LD2 off: no Power On Reset occurred)

使用特权

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

本版积分规则

40

主题

457

帖子

0

粉丝