cpu/cortexm_common: add persistent RAM invalidation
Contribution description
Added cpu_invalidate_persistent_ram(), which forces a clear of any persistent RAM on next reboot. This is useful e.g. after performing a firmware update.
Testing procedure
It's relatively difficult to provide tests for persistent state. However, I wrote a small application and tested it with different configurations on same54-xpro, which does provide backup RAM, and samd20-xpro, which doesn't.
main.c:
#include "cpu.h"
#include "periph/pm.h"
#include "test_utils/expect.h"
#include <stdio.h>
#ifdef CPU_HAS_BACKUP_RAM
#include "periph/gpio.h"
BACKUP_RAM_NOINIT uint32_t volatile noinit_backup_var;
BACKUP_RAM_DATA uint32_t volatile backup_var = 1;
#endif
__attribute__((__section__(".noinit"))) uint32_t volatile noinit_var;
MAYBE_UNUSED
static void _wakeup_isr(void *arg)
{
(void)arg;
puts("wakeup from backup\n");
}
int main(void)
{
printf("noinit_var=%"PRIu32"\n", noinit_var);
#ifdef CPU_HAS_BACKUP_RAM
printf("noinit_backup_var=%"PRIu32"\n", noinit_backup_var);
printf("backup_var=%"PRIu32"\n", backup_var);
#endif
#ifdef CPU_HAS_BACKUP_RAM
noinit_backup_var = 1;
backup_var = 2;
#endif
noinit_var = 1;
/* comment this to allow RAM contents to persist */
cpu_invalidate_persistent_ram();
#ifdef CPU_HAS_BACKUP_RAM
/* also inits tamper pin interrupt (module periph_gpio_tamper_wake) */
int res = gpio_init_int(GPIO_PIN(PC, 1),
GPIO_IN_PU,
GPIO_FALLING,
_wakeup_isr,
NULL);
expect(res == 0);
/* comment this to reboot instead */
pm_set(0);
#endif
pm_reboot();
return 0;
}
Makefile:
# BOARD ?= samd20-xpro
BOARD ?= same54-xpro
include ../Makefile.cpu_common
FEATURES_REQUIRED += cpu_core_cortexm
ifeq (same54-xpro, $(BOARD))
USEMODULE += periph_gpio_tamper_wake
USEMODULE += periph_gpio
USEMODULE += periph_gpio_irq
endif
include $(RIOTBASE)/Makefile.include
Murdock results
:heavy_check_mark: PASSED
cace91636028f4d644bf34e01f29aa3a0572e53f cpu/cortexm_common: added invalidate variable for persistent RAM
| Success | Failures | Total | Runtime |
|---|---|---|---|
| 10535 | 0 | 10536 | 19m:32s |
Artifacts
I'm not sure if this is the right thing to do since you'll need a way to verify your .noiinit section contains valid data anyway.
e.g. a magic value at the start or end of your .noinit section that gets set once you use it - this could then be cleared when you do a firmware update that changes the data structure of the section.