Merge pull request #2924 from simmel-project/nrf-rtc-persist
NRF: Persist RTC offset across reboots
This commit is contained in:
commit
af68ddebef
@ -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 */
|
_edata = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */
|
||||||
} >RAM
|
} >RAM
|
||||||
|
|
||||||
/* Uninitialized data section */
|
/* Zero-initialized data section */
|
||||||
.bss :
|
.bss :
|
||||||
{
|
{
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
@ -116,6 +116,19 @@ SECTIONS
|
|||||||
_ebss = .; /* define a global symbol at bss end; used by startup code and GC */
|
_ebss = .; /* define a global symbol at bss end; used by startup code and GC */
|
||||||
} >RAM
|
} >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 */
|
/* this is to define the start of the heap, and make sure we have a minimum size */
|
||||||
.heap :
|
.heap :
|
||||||
{
|
{
|
||||||
|
@ -34,11 +34,28 @@
|
|||||||
#include "supervisor/shared/translate.h"
|
#include "supervisor/shared/translate.h"
|
||||||
|
|
||||||
// This is the time in seconds since 2000 that the RTC was started.
|
// 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) {
|
void common_hal_rtc_get_time(timeutils_struct_time_t *tm) {
|
||||||
uint64_t ticks_s = port_get_raw_ticks(NULL) / 1024;
|
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) {
|
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(
|
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
|
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) {
|
int common_hal_rtc_get_calibration(void) {
|
||||||
|
@ -29,5 +29,6 @@
|
|||||||
|
|
||||||
extern void rtc_init(void);
|
extern void rtc_init(void);
|
||||||
extern void rtc_reset(void);
|
extern void rtc_reset(void);
|
||||||
|
extern void common_hal_rtc_init(void);
|
||||||
|
|
||||||
#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_RTC_RTC_H
|
#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_RTC_RTC_H
|
||||||
|
@ -120,6 +120,10 @@ safe_mode_t port_init(void) {
|
|||||||
// Configure millisecond timer initialization.
|
// Configure millisecond timer initialization.
|
||||||
tick_init();
|
tick_init();
|
||||||
|
|
||||||
|
#if CIRCUITPY_RTC
|
||||||
|
common_hal_rtc_init();
|
||||||
|
#endif
|
||||||
|
|
||||||
#if CIRCUITPY_ANALOGIO
|
#if CIRCUITPY_ANALOGIO
|
||||||
analogin_init();
|
analogin_init();
|
||||||
#endif
|
#endif
|
||||||
@ -177,8 +181,13 @@ void reset_cpu(void) {
|
|||||||
NVIC_SystemReset();
|
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) {
|
uint32_t *port_heap_get_bottom(void) {
|
||||||
return port_stack_get_limit();
|
return &_euninitialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t *port_heap_get_top(void) {
|
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) {
|
uint32_t *port_stack_get_limit(void) {
|
||||||
return &_ebss;
|
return &_euninitialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t *port_stack_get_top(void) {
|
uint32_t *port_stack_get_top(void) {
|
||||||
return &_estack;
|
return &_estack;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern uint32_t _ebss;
|
// Place the word in the uninitialized section so it won't get overwritten.
|
||||||
// Place the word to save just after our BSS section that gets blanked.
|
__attribute__((section(".uninitialized"))) uint32_t _saved_word;
|
||||||
void port_set_saved_word(uint32_t value) {
|
void port_set_saved_word(uint32_t value) {
|
||||||
_ebss = value;
|
_saved_word = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t port_get_saved_word(void) {
|
uint32_t port_get_saved_word(void) {
|
||||||
return _ebss;
|
return _saved_word;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t port_get_raw_ticks(uint8_t* subticks) {
|
uint64_t port_get_raw_ticks(uint8_t* subticks) {
|
||||||
|
Loading…
Reference in New Issue
Block a user