diff options
| author | Scott Shawcroft <scott@adafruit.com> | 2020-05-18 15:06:42 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-05-18 15:06:42 -0700 |
| commit | af68ddebefa3d7a21de1c33768f0fc7bdb238f26 (patch) | |
| tree | bc63e8e5e2699f6ed2fba76160c94ae4b43ebcfc | |
| parent | 9811c1fe4b76d41c95d0d96df84e478b76dec261 (diff) | |
| parent | 9f7c26c60ddcd8ef371290e505f21148e3c98726 (diff) | |
Merge pull request #2924 from simmel-project/nrf-rtc-persist
NRF: Persist RTC offset across reboots
| -rw-r--r-- | ports/nrf/boards/common.template.ld | 15 | ||||
| -rw-r--r-- | ports/nrf/common-hal/rtc/RTC.c | 29 | ||||
| -rw-r--r-- | ports/nrf/common-hal/rtc/RTC.h | 1 | ||||
| -rw-r--r-- | ports/nrf/supervisor/port.c | 21 |
4 files changed, 56 insertions, 10 deletions
diff --git a/ports/nrf/boards/common.template.ld b/ports/nrf/boards/common.template.ld index a2bbf0ec8..9a7df69a4 100644 --- a/ports/nrf/boards/common.template.ld +++ b/ports/nrf/boards/common.template.ld @@ -103,7 +103,7 @@ SECTIONS _edata = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */ } >RAM - /* Uninitialized data section */ + /* Zero-initialized data section */ .bss : { . = ALIGN(4); @@ -116,6 +116,19 @@ SECTIONS _ebss = .; /* define a global symbol at bss end; used by startup code and GC */ } >RAM + /* Uninitialized data section + Data placed into this section will remain unchanged across reboots. */ + .uninitialized (NOLOAD) : + { + . = ALIGN(4); + _suninitialized = .; /* define a global symbol at uninitialized start; currently unused */ + *(.uninitialized) + *(.uninitialized*) + + . = ALIGN(4); + _euninitialized = .; /* define a global symbol at uninitialized end; currently unused */ + } >RAM + /* this is to define the start of the heap, and make sure we have a minimum size */ .heap : { diff --git a/ports/nrf/common-hal/rtc/RTC.c b/ports/nrf/common-hal/rtc/RTC.c index 9f56f2f0d..06345f589 100644 --- a/ports/nrf/common-hal/rtc/RTC.c +++ b/ports/nrf/common-hal/rtc/RTC.c @@ -34,11 +34,28 @@ #include "supervisor/shared/translate.h" // This is the time in seconds since 2000 that the RTC was started. -static uint32_t rtc_offset = 0; +__attribute__((section(".uninitialized"))) static uint32_t rtc_offset[3]; + +// These values are placed before and after the current RTC count. They are +// used to determine if the RTC count is valid. These randomly-generated values +// will be set when the RTC value is set in order to mark the RTC as valid. If +// the system crashes or reboots, these values will remain undisturbed and the +// RTC offset will remain valid. +// +// If Circuit Python is updated or these symbols shift around, the prefix and +// suffix will no longer match, and the time will no longer be valid. +#define RTC_OFFSET_CHECK_PREFIX 0x25ea7e2a +#define RTC_OFFSET_CHECK_SUFFIX 0x2b80b69e + +void common_hal_rtc_init(void) { + // If the prefix and suffix are not valid, zero-initialize the RTC offset. + if ((rtc_offset[0] != RTC_OFFSET_CHECK_PREFIX) || (rtc_offset[2] != RTC_OFFSET_CHECK_SUFFIX)) + rtc_offset[1] = 0; +} void common_hal_rtc_get_time(timeutils_struct_time_t *tm) { uint64_t ticks_s = port_get_raw_ticks(NULL) / 1024; - timeutils_seconds_since_2000_to_struct_time(rtc_offset + ticks_s, tm); + timeutils_seconds_since_2000_to_struct_time(rtc_offset[1] + ticks_s, tm); } void common_hal_rtc_set_time(timeutils_struct_time_t *tm) { @@ -46,7 +63,13 @@ void common_hal_rtc_set_time(timeutils_struct_time_t *tm) { uint32_t epoch_s = timeutils_seconds_since_2000( tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec ); - rtc_offset = epoch_s - ticks_s; + rtc_offset[1] = epoch_s - ticks_s; + + // Set the prefix and suffix in order to indicate the time is valid. This + // must be done after the offset is updated, in case there is a crash or + // power failure. + rtc_offset[0] = RTC_OFFSET_CHECK_PREFIX; + rtc_offset[2] = RTC_OFFSET_CHECK_SUFFIX; } int common_hal_rtc_get_calibration(void) { diff --git a/ports/nrf/common-hal/rtc/RTC.h b/ports/nrf/common-hal/rtc/RTC.h index 0207c8338..e51f1f784 100644 --- a/ports/nrf/common-hal/rtc/RTC.h +++ b/ports/nrf/common-hal/rtc/RTC.h @@ -29,5 +29,6 @@ extern void rtc_init(void); extern void rtc_reset(void); +extern void common_hal_rtc_init(void); #endif // MICROPY_INCLUDED_NRF_COMMON_HAL_RTC_RTC_H diff --git a/ports/nrf/supervisor/port.c b/ports/nrf/supervisor/port.c index 539a9cf90..4edb78f7c 100644 --- a/ports/nrf/supervisor/port.c +++ b/ports/nrf/supervisor/port.c @@ -120,6 +120,10 @@ safe_mode_t port_init(void) { // Configure millisecond timer initialization. tick_init(); +#if CIRCUITPY_RTC + common_hal_rtc_init(); +#endif + #if CIRCUITPY_ANALOGIO analogin_init(); #endif @@ -177,8 +181,13 @@ void reset_cpu(void) { NVIC_SystemReset(); } +// The uninitialized data section is placed directly after BSS, under the theory +// that Circuit Python has a lot more .data and .bss than the bootloader. As a +// result, this section is less likely to be tampered with by the bootloader. +extern uint32_t _euninitialized; + uint32_t *port_heap_get_bottom(void) { - return port_stack_get_limit(); + return &_euninitialized; } uint32_t *port_heap_get_top(void) { @@ -186,21 +195,21 @@ uint32_t *port_heap_get_top(void) { } uint32_t *port_stack_get_limit(void) { - return &_ebss; + return &_euninitialized; } uint32_t *port_stack_get_top(void) { return &_estack; } -extern uint32_t _ebss; -// Place the word to save just after our BSS section that gets blanked. +// Place the word in the uninitialized section so it won't get overwritten. +__attribute__((section(".uninitialized"))) uint32_t _saved_word; void port_set_saved_word(uint32_t value) { - _ebss = value; + _saved_word = value; } uint32_t port_get_saved_word(void) { - return _ebss; + return _saved_word; } uint64_t port_get_raw_ticks(uint8_t* subticks) { |
