zoukankan      html  css  js  c++  java
  • STM32学习笔记(16)数据的保存与毁灭BKP功能(1)

    转自:http://blog.ednchina.com/czlyzhj/1821516/message.aspx

    通过研究,大体明白了BKP的功能,简述如下:

    1.  BKP可以用来保存数据

           BKP中包括了42个16位的寄存器,共可保存84字节的内容,它们由VBAT的供电来维挂。

    2.  BKP内保存的数据可以被毁灭(如果有人希望恶意得到这些数据的话,令其丢失比保护数据更重要)。STM32提供了一种称之为TAMPER的机制来完成。中文译为“侵入检测”,这需要占用一个外部引脚(PC13)。

    3.  如果不用侵入检测功能,那么这个外部引脚可以用作RTC校准功能,这个稍后再研究。

    4.  当有系统复位/电源复位/待机模式下被唤醒这三种情况时,BKP中的值不会丢失或被复位。

           先回来研究一下STM32的复位机制。以下是数据手册的相关部分。

           6.1  复位 

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

           6.1.1  系统复位 

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

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

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

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

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

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

           4.软件复位(SW复位)

           5.低功耗管理复位

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

    以下是RCC_CSR的内容:

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

           6.1.2  电源复位 

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

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

           2. 从待机模式中返回

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

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

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

    RCC_GetFlagStatus(RCC_FLAG_PORRST)

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

    **************************************************************************

    5.  如果必须要人为地令备份域复位(所有数据都被清零),那么有两种方法:

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

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

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

    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;

    }

           即只需要提供两个参数,第一个是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));

      } 

    }

    从上面的代码可以看到,第一个参数是用

    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。

    7.复位后,对备份寄存器和RTC的访问被禁止,并且备份域被保护以防止可能存在的意外的写操作。执行以下操作可以使能对备份寄存器和RTC的访问。

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

    以下是相关代码:

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);

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

           ●  电源控制寄存器(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;

    }

    而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))

    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)

  • 相关阅读:
    迭代器概念与traits编程技法
    C++模板的特化与偏特化
    c++ operator关键字
    cookie-小总结吧
    ping
    git
    setTimeout()基础/setInterval()基础
    SASS
    命令行编译sass
    sublime添加sass编译
  • 原文地址:https://www.cnblogs.com/hnrainll/p/1934177.html
Copyright © 2011-2022 走看看