SOLVED: Backup SRAM for STM32 is wiped between resets
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:
- Have a horrible crash
- Jump into my (C) fault handler
- Save various registers (CFSR, HFSR, LR, PC, ...) in the backup SRAM
- Reset
- When back in main(), check if the watchdog reset the system
- Fetch the "crash report" saved in the SRAM
- 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));
}
}