Skip to content

Commit af68dde

Browse files
authored
Merge pull request #2924 from simmel-project/nrf-rtc-persist
NRF: Persist RTC offset across reboots
2 parents 9811c1f + 9f7c26c commit af68dde

File tree

4 files changed

+56
-10
lines changed

4 files changed

+56
-10
lines changed

ports/nrf/boards/common.template.ld

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ SECTIONS
103103
_edata = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */
104104
} >RAM
105105

106-
/* Uninitialized data section */
106+
/* Zero-initialized data section */
107107
.bss :
108108
{
109109
. = ALIGN(4);
@@ -116,6 +116,19 @@ SECTIONS
116116
_ebss = .; /* define a global symbol at bss end; used by startup code and GC */
117117
} >RAM
118118

119+
/* Uninitialized data section
120+
Data placed into this section will remain unchanged across reboots. */
121+
.uninitialized (NOLOAD) :
122+
{
123+
. = ALIGN(4);
124+
_suninitialized = .; /* define a global symbol at uninitialized start; currently unused */
125+
*(.uninitialized)
126+
*(.uninitialized*)
127+
128+
. = ALIGN(4);
129+
_euninitialized = .; /* define a global symbol at uninitialized end; currently unused */
130+
} >RAM
131+
119132
/* this is to define the start of the heap, and make sure we have a minimum size */
120133
.heap :
121134
{

ports/nrf/common-hal/rtc/RTC.c

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,19 +34,42 @@
3434
#include "supervisor/shared/translate.h"
3535

3636
// This is the time in seconds since 2000 that the RTC was started.
37-
static uint32_t rtc_offset = 0;
37+
__attribute__((section(".uninitialized"))) static uint32_t rtc_offset[3];
38+
39+
// These values are placed before and after the current RTC count. They are
40+
// used to determine if the RTC count is valid. These randomly-generated values
41+
// will be set when the RTC value is set in order to mark the RTC as valid. If
42+
// the system crashes or reboots, these values will remain undisturbed and the
43+
// RTC offset will remain valid.
44+
//
45+
// If Circuit Python is updated or these symbols shift around, the prefix and
46+
// suffix will no longer match, and the time will no longer be valid.
47+
#define RTC_OFFSET_CHECK_PREFIX 0x25ea7e2a
48+
#define RTC_OFFSET_CHECK_SUFFIX 0x2b80b69e
49+
50+
void common_hal_rtc_init(void) {
51+
// If the prefix and suffix are not valid, zero-initialize the RTC offset.
52+
if ((rtc_offset[0] != RTC_OFFSET_CHECK_PREFIX) || (rtc_offset[2] != RTC_OFFSET_CHECK_SUFFIX))
53+
rtc_offset[1] = 0;
54+
}
3855

3956
void common_hal_rtc_get_time(timeutils_struct_time_t *tm) {
4057
uint64_t ticks_s = port_get_raw_ticks(NULL) / 1024;
41-
timeutils_seconds_since_2000_to_struct_time(rtc_offset + ticks_s, tm);
58+
timeutils_seconds_since_2000_to_struct_time(rtc_offset[1] + ticks_s, tm);
4259
}
4360

4461
void common_hal_rtc_set_time(timeutils_struct_time_t *tm) {
4562
uint64_t ticks_s = port_get_raw_ticks(NULL) / 1024;
4663
uint32_t epoch_s = timeutils_seconds_since_2000(
4764
tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec
4865
);
49-
rtc_offset = epoch_s - ticks_s;
66+
rtc_offset[1] = epoch_s - ticks_s;
67+
68+
// Set the prefix and suffix in order to indicate the time is valid. This
69+
// must be done after the offset is updated, in case there is a crash or
70+
// power failure.
71+
rtc_offset[0] = RTC_OFFSET_CHECK_PREFIX;
72+
rtc_offset[2] = RTC_OFFSET_CHECK_SUFFIX;
5073
}
5174

5275
int common_hal_rtc_get_calibration(void) {

ports/nrf/common-hal/rtc/RTC.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,6 @@
2929

3030
extern void rtc_init(void);
3131
extern void rtc_reset(void);
32+
extern void common_hal_rtc_init(void);
3233

3334
#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_RTC_RTC_H

ports/nrf/supervisor/port.c

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,10 @@ safe_mode_t port_init(void) {
120120
// Configure millisecond timer initialization.
121121
tick_init();
122122

123+
#if CIRCUITPY_RTC
124+
common_hal_rtc_init();
125+
#endif
126+
123127
#if CIRCUITPY_ANALOGIO
124128
analogin_init();
125129
#endif
@@ -177,30 +181,35 @@ void reset_cpu(void) {
177181
NVIC_SystemReset();
178182
}
179183

184+
// The uninitialized data section is placed directly after BSS, under the theory
185+
// that Circuit Python has a lot more .data and .bss than the bootloader. As a
186+
// result, this section is less likely to be tampered with by the bootloader.
187+
extern uint32_t _euninitialized;
188+
180189
uint32_t *port_heap_get_bottom(void) {
181-
return port_stack_get_limit();
190+
return &_euninitialized;
182191
}
183192

184193
uint32_t *port_heap_get_top(void) {
185194
return port_stack_get_top();
186195
}
187196

188197
uint32_t *port_stack_get_limit(void) {
189-
return &_ebss;
198+
return &_euninitialized;
190199
}
191200

192201
uint32_t *port_stack_get_top(void) {
193202
return &_estack;
194203
}
195204

196-
extern uint32_t _ebss;
197-
// Place the word to save just after our BSS section that gets blanked.
205+
// Place the word in the uninitialized section so it won't get overwritten.
206+
__attribute__((section(".uninitialized"))) uint32_t _saved_word;
198207
void port_set_saved_word(uint32_t value) {
199-
_ebss = value;
208+
_saved_word = value;
200209
}
201210

202211
uint32_t port_get_saved_word(void) {
203-
return _ebss;
212+
return _saved_word;
204213
}
205214

206215
uint64_t port_get_raw_ticks(uint8_t* subticks) {

0 commit comments

Comments
 (0)