cancel
Showing results for 
Search instead for 
Did you mean: 

SOLVED: Backup SRAM for STM32 is wiped between resets

turbofish
Associate II

Solved: The problem was an improper reading, the BKSRAM-clock was not initialized when reading back the report. Updating with "correct" code for posterity.

I'm writing a (better) hard-fault handler for my STM32f207zg and want to do the following:

  1. Have a horrible crash
  2. Jump into my (C) fault handler
  3. Save various registers (CFSR, HFSR, LR, PC, ...) in the backup SRAM
  4. Reset
  5. When back in main(), check if the watchdog reset the system
  6. Fetch the "crash report" saved in the SRAM
  7. Dump it on CAN

1,2,4,5,7 is easy, but I'm having problems with saving/restoring from the SRAM.

The hardfault-handler calls the function fault_bksram_init() after filling up the fault_crash_t structure with data. It then calls fault_write_crash() in order to write the "report" to the SRAM. I can see using my debugger that the data is actually written to the address defined in BKPSRAM_BASE; however, after doing a reset using the debugger the memory at BKPSRAM_BASE is wiped with 0xff . In order words, the data is lost between resets.

I have the correct voltage connected to VBat (the RTC works nicely) but I have never used the backup SRAM before.

Am I missing something in the initialization of the SRAM? Is it something with doing this in a hard-fault handler that I'm missing? Or is the debugger reset that messes up the SRAM?

void fault_bksram_init(void) {
    /* Enable PWR clock */
    RCC->APB1ENR |= RCC_APB1ENR_PWREN;
 
    /* Enable backup SRAM Clock */
    RCC->AHB1ENR |= RCC_AHB1ENR_BKPSRAMEN;
 
    /* Disable write protection */
    PWR->CR |= PWR_CR_DBP;
 
    /* Enable backup regulator */
    PWR->CSR |= PWR_CSR_BRE;
 
    /* Wait for backup regulator to be ready  */
    while (!(PWR->CSR & (PWR_FLAG_BRR)));
}
void fault_write_crash(fault_crash_t* crash) {
    /* Copy crash to BKSRAM */
    fault_bksram_init();
     memcpy((void*)BKPSRAM_BASE, (void*)crash, sizeof(fault_crash_t));
}
void fault_read_crash(fault_crash_t* crash) {
    /* Copy crash from BKSRAM*/
    fault_bksram_init();
    memcpy((void*)crash, (void*)BKPSRAM_BASE, sizeof(fault_crash_t));
 
    if (crash->magic != FAULT_MAGIC) {
        memset((void*)crash, 0, sizeof(fault_crash_t));
    }
}

1 ACCEPTED SOLUTION

Accepted Solutions

The regular SRAM is kinda used (not completely, but close) and I have this 4KB of BKSRAM just "laying around", and I already have a battery on my PCB (the system needs to have a good RTC in order to function).

View solution in original post

4 REPLIES 4

Can you make sure DBP is "really" enabled after enabling it (by waiting until the bit reports as set)?

Also, from the RM:

Access to the backup SRAM

  1. Enable the power interface clock by setting the PWREN bits in the RCC APB1peripheral clock enable register (RCC_APB1ENR)
  2. Set the DBP bit in the PWR power control register (PWR_CR) to enable access to thebackup domain
  3. Enable the backup SRAM clock by setting BKPSRAMEN bit in the RCC AHB1peripheral clock register (RCC_AHB1ENR)

Just in case, you have 2 and 3 mixed.

S.Ma
Principal

Actually, if you don't power off the mcu, why not exclude a small area of the regular SRAM by editing the linker memory map config file? You can override and write this area which won't be initialized by any startup function. There are some system flags to tell if the reset is caused by power on or else to discriminate. Maybe no need to plan for the backup SRAM which maybe dedicated to power failures.

The regular SRAM is kinda used (not completely, but close) and I have this 4KB of BKSRAM just "laying around", and I already have a battery on my PCB (the system needs to have a good RTC in order to function).

The order doesn't seem to affect this particular issue. But in general its a good idea to follow...