如何在STM32F4中将备份SRAM用作EEPROM

时间:2013-12-18 20:28:34

标签: stm32 eeprom stm32f4discovery

在STM32F4上有两种模拟EEPROM的方法:

  1. 片上4 KB备份SRAM
  2. 片上Flash,具有特定的软件算法
  3. 此处描述了第二个选项:AN3969。

    但遗憾的是,谷歌未能提供有关如何使用第一个选项的信息 - 使用4Kb备份SRAM作为EEPROM?..

    有人可以帮忙讨论这个话题吗?

7 个答案:

答案 0 :(得分:11)

必须这样做:

  1. 启用PWR时钟

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
    
  2. 启用对备份域的访问

    PWR_BackupAccessCmd(ENABLE);
    
  3. 启用备份SRAM时钟

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_BKPSRAM, ENABLE);
    
  4. 启用备份SRAM低功耗稳压器以使其内容保持在VBAT模式

    PWR_BackupRegulatorCmd(ENABLE);
    
  5. 你可以写入/读取数据到sram(这些代码来自STM32F4xx_DSP_StdPeriph_Lib中的BKP_Domain代码)(在我的mcu stm32f417 BKPSRAM_BASE = 0x40024000中)

       // Write to Backup SRAM with 32-Bit Data 
       for (i = 0x0; i < 0x100; i += 4) {
           *(__IO uint32_t *) (BKPSRAM_BASE + i) = i;
       }
    
       // Check the written Data 
       for (i = 0x0; i < 0x100; i += 4) {
              if ((*(__IO uint32_t *) (BKPSRAM_BASE + i)) != i){
                  errorindex++;
              }
       }
    

    然后如果你想:

        // Wait until the Backup SRAM low power Regulator is ready
        while(PWR_GetFlagStatus(PWR_FLAG_BRR) == RESET)
        {}
    

    您可以在STM32F4xx_DSP_StdPeriph_Lib中找到这些功能。

答案 1 :(得分:10)

阅读stm32f4参考手册和stm32f405xx / stm32f407xx数据表后,我同意不清楚如何实际使用备份sram(或它所在的位置)。这是我发现的。只要您有电池电量,RTC寄存器和备份SRAM都包含一定量的存储空间。 RTC包含20个寄存器(80字节),备用sram(AHB1上的自身外设,位于寄存器地址区域内)包含0x1000(4096字节)。默认情况下都不启用。

在DM00037051中(stm32f405xx / stm32f407xx数据表,第29页):

The 4-Kbyte backup SRAM is an EEPROM-like memory area. It can be used to store
data which need to be retained in VBAT and standby mode. This memory area is 
disabled by default to minimize power consumption (see Section 2.2.19: 
Low-power modes). It can be enabled by software.

The backup registers are 32-bit registers used to store 80 bytes of user 
application data when VDD power is not present. Backup registers are not reset
by a system, a power reset, or when the device wakes up from the Standby mode 
(see Section 2.2.19: Low-power modes).

在数据表的第71页和参考手册的第65页

AHB1   |   0x4002 4000 - 0x4002 4FFF   |   BKPSRAM

和数据表的第73页和参考手册的第67页

APB1   |   0x4000 2800 - 0x4000 2BFF   |   RTC & BKP Registers

参考手册的第118-119页包含有关启用备份SRAM和RTC寄存器的信息。

注意:如果您已经在备份域中使用RTC并且只需要存储&lt; = 80字节,那么最好使用RTC备份寄存器,因为启用备份SRAM基本上会使电流消耗翻倍(参见stm32f405 / 7数据表中的表25)。

这里是备份SRAM和备份RTC寄存器的写入和读取功能

int8_t write_to_backup_sram( uint8_t *data, uint16_t bytes, uint16_t offset ) {
  const uint16_t backup_size = 0x1000;
  uint8_t* base_addr = (uint8_t *) BKPSRAM_BASE;
  uint16_t i;
  if( bytes + offset >= backup_size ) {
    /* ERROR : the last byte is outside the backup SRAM region */
    return -1;
  }
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_BKPSRAM, ENABLE);
  /* disable backup domain write protection */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);   // set RCC->APB1ENR.pwren
  PWR_BackupAccessCmd(ENABLE);                          // set PWR->CR.dbp = 1;
  /** enable the backup regulator (used to maintain the backup SRAM content in
    * standby and Vbat modes).  NOTE : this bit is not reset when the device
    * wakes up from standby, system reset or power reset. You can check that
    * the backup regulator is ready on PWR->CSR.brr, see rm p144 */
  PWR_BackupRegulatorCmd(ENABLE);     // set PWR->CSR.bre = 1;
  for( i = 0; i < bytes; i++ ) {
    *(base_addr + offset + i) = *(data + i);
  }
  PWR_BackupAccessCmd(DISABLE);                     // reset PWR->CR.dbp = 0;
  return 0;
}

int8_t read_from_backup_sram( uint8_t *data, uint16_t bytes, uint16_t offset ) {
  const uint16_t backup_size = 0x1000;
  uint8_t* base_addr = (uint8_t *) BKPSRAM_BASE;
  uint16_t i;
  if( bytes + offset >= backup_size ) {
    /* ERROR : the last byte is outside the backup SRAM region */
    return -1;
  }
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_BKPSRAM, ENABLE);
  for( i = 0; i < bytes; i++ ) {
    *(data + i) = *(base_addr + offset + i);
  }
  return 0;
}

int8_t write_to_backup_rtc( uint32_t *data, uint16_t bytes, uint16_t offset ) {
  const uint16_t backup_size = 80;
  volatile uint32_t* base_addr = &(RTC->BKP0R);
  uint16_t i;
  if( bytes + offset >= backup_size ) {
    /* ERROR : the last byte is outside the backup SRAM region */
    return -1;
  } else if( offset % 4 || bytes % 4 ) {
    /* ERROR: data start or num bytes are not word aligned */
    return -2;
  } else {
    bytes >>= 2;      /* divide by 4 because writing words */
  }
  /* disable backup domain write protection */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);   // set RCC->APB1ENR.pwren
  PWR_BackupAccessCmd(ENABLE);                          // set PWR->CR.dbp = 1;
  for( i = 0; i < bytes; i++ ) {
    *(base_addr + offset + i) = *(data + i);
  }
  PWR_BackupAccessCmd(DISABLE);                     // reset PWR->CR.dbp = 0;
  // consider also disabling the power peripherial?
  return 0;
}

int8_t read_from_backup_rtc( uint32_t *data, uint16_t bytes, uint16_t offset ) {
  const uint16_t backup_size = 80;
  volatile uint32_t* base_addr = &(RTC->BKP0R);
  uint16_t i;
  if( bytes + offset >= backup_size ) {
    /* ERROR : the last byte is outside the backup SRAM region */
    return -1;
  } else if( offset % 4 || bytes % 4 ) {
    /* ERROR: data start or num bytes are not word aligned */
    return -2;
  } else {
    bytes >>= 2;      /* divide by 4 because writing words */
  }
  /* read should be 32 bit aligned */
  for( i = 0; i < bytes; i++ ) {
    *(data + i) = *(base_addr + offset + i);
  }
  return 0;
}

答案 2 :(得分:3)

我必须根据用户请求从主程序跳转到bootloader。 所以我在主程序中将一些“幻数”放入BKPSRAM中,进行CPU软复位。 Bootloader始终首先启动。 如果它存在,它会检查“幻数”,它会执行,否则启动主程序

使用HAL时,这是跳转到bootloader的方法:

__HAL_RCC_PWR_CLK_ENABLE();

HAL_PWR_EnableBkUpAccess();

__BKPSRAM_CLK_ENABLE();

*(__IO uint8_t *)0x40024000 = 42;//magic number

HAL_NVIC_SystemReset();

在bootloader内部读取幻数,它足以启用备份sram时钟(bootloader使用StdPeriphDriver)。

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_BKPSRAM, ENABLE);

extRequest = *(__IO uint8_t *)0x40024000;

if(extRequest == 42)
    //run bootloader

cpu是stm32f407

答案 3 :(得分:1)

我目前正在使用STM32F2xx微控制器。根据数据表:

  

4 KB备份SRAM是类似EEPROM的区域。

     

保留RTC备份寄存器的内容......当VDD关闭时,VBAT引脚可以连接到由电池或其他电源提供的可选备用电压。

例如,在微控制器断电时,需要一个超级电容来维护备份寄存器的内容。

另外,根据文件:

  

重置后,备份域(...备份SRAM)受到保护,以防止可能的不必要的写访问。要启用对备份域的访问,请执行以下操作...

它通过直接写入某个外设寄存器为您提供有关如何访问备份域的说明。如果您可以访问STM32F4xx库,可以调用类似的东西(注意:我正在使用STM32F2xx库):

PWR_BackupAccessCmd(ENABLE);

注意:除了简单地调用上述功能之外,还有其他功能,例如启用备份SRAM接口时钟。请参阅STM32F4系列文档。

库源中嵌入了大量文档是非常宝贵的,如果它可用,应该阅读。

在STM32F2系列微控制器上,SRAM位于以下存储器地址范围:

  

0x40024000 - 0x40024FFF

可以写到位置的某个地方,例如,如下:

#define VAR_LOC ((volatile uint8_t *)(0x40024000))
volatile uint8_t *pVar = VAR_LOC;
*pVar = 5;

答案 4 :(得分:1)

以下是使用备份SRAM的HAL库示例。

#define  WRITE_READ_ADDR  0x01 //offset value.you can change according to your application
uint32_t write_arr = 0xA5A5A5A6;
uint32_t read_arr;

int main()
{
   enable_backup_sram();
   writeBkpSram(write_arr);
   while(1)
   {
      read_arr = readBkpSram();
   }
}
void enable_backup_sram(void)
{
    /*DBP : Enable access to Backup domain */
    HAL_PWR_EnableBkUpAccess();
    /*PWREN : Enable backup domain access  */
    __HAL_RCC_PWR_CLK_ENABLE();
    /*BRE : Enable backup regulator
      BRR : Wait for backup regulator to stabilize */
    HAL_PWREx_EnableBkUpReg();
   /*DBP : Disable access to Backup domain */
    HAL_PWR_DisableBkUpAccess();
}

void writeBkpSram(uint32_t l_data)
{
   /* Enable clock to BKPSRAM */
  __HAL_RCC_BKPSRAM_CLK_ENABLE();
  /* Pointer write on specific location of backup SRAM */
  (uint32_t *) (BKPSRAM_BASE + WRITE_READ_ADDR) = l_data;
 /* Disable clock to BKPSRAM */
 __HAL_RCC_BKPSRAM_CLK_DISABLE();
}

uint32_t readBkpSram(void)
{
   uint32_t i_retval;

  /* Enable clock to BKPSRAM */
  __HAL_RCC_BKPSRAM_CLK_ENABLE();
  /* Pointer write from specific location of backup SRAM */
  i_retval =  *(uint32_t*) (BKPSRAM_BASE + WRITE_READ_ADDR);
  /* Disable clock to BKPSRAM */
  __HAL_RCC_BKPSRAM_CLK_DISABLE();
  return i_retval;
}

答案 5 :(得分:0)

可用的例子 在标题中:

//------------------------------------
typedef struct
{
    uint32_t    isDefault;          //must by 0x12345678
    uint32_t    LastTestNumber;     
    uint32_t    LastUserNumber;     
    uint32_t    LastModeTest;       
    uint32_t    calibv;
    uint32_t    calibc;
    uint32_t    WorkTime;           
    int32_t     RTCCalib;
    uint32_t    LCDContrast;

} sBKPSRAM;
extern sBKPSRAM *BKPSRAM;//  = (sSDRAM *)SDRAM_BANK_ADDR;
//------------------------------------

在代码头中 定义为数据:

sBKPSRAM    *BKPSRAM    = (sBKPSRAM *)BKPSRAM_BASE;

在Init:

void main(void)
{
(....)
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_BKPSRAM, ENABLE);
  PWR_BackupAccessCmd(ENABLE);
  PWR_BackupRegulatorCmd(ENABLE);
  ifDefault();
(....)
}

在程序中:

//-------------------------------------------------
void ifDefault(void)
{
    if (BKPSRAM->LastModeTest!=0x12345678)
        {
            printf("BKPSRAM to default\r\n");
            memset(BKPSRAM,0,sizeof(sBKPSRAM));
            BKPSRAM->calibv         =66920;
            BKPSRAM->calibc         =79230;
            BKPSRAM->RTCCalib       =1;
            BKPSRAM->LCDContrast    =2;         
            BKPSRAM->LastModeTest   =0x12345678;
        }
}
//-------------------------------------------------

答案 6 :(得分:0)

用于STM32H7的HAL配置以访问备用SRAM:

#define BKP_RAM (*(__IO uint32_t *) (D3_BKPSRAM_BASE)) //Start address: 0x38800000

Main() {

__HAL_RCC_BKPRAM_CLK_ENABLE();

HAL_PWREx_EnableBkUpReg();

BKP_RAM = 0xA5AA5A55;

}

除此之外,您需要在systemInit()中添加以下一行以启用对备份SRAM的直写访问。

SCB->CACR |= 1<<2;