8000 nubcore rtc fix test; Improved time keeping #2728 · nubcore/micropython@ecbf75e · GitHub
[go: up one dir, main page]

Skip to content

Commit ecbf75e

Browse files
committed
nubcore rtc fix test; Improved time keeping micropython#2728
1 parent e45035d commit ecbf75e

File tree

4 files changed

+86
-51
lines changed

4 files changed

+86
-51
lines changed

esp8266/fatfs_port.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ DWORD get_fattime(void) {
3333

3434
// TODO: Optimize division (there's no HW division support on ESP8266,
3535
// so it's expensive).
36-
uint32_t secs = (uint32_t)(pyb_rtc_get_us_since_2000() / 1000000);
36+
uint32_t secs = (uint32_t)(esp_clk_get_us_since_2000() / 1000000);
3737

3838
timeutils_struct_time_t tm;
3939
timeutils_seconds_since_2000_to_struct_time(secs, &tm);

esp8266/machine_rtc.c

Lines changed: 80 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,20 @@
3333
#include "timeutils.h"
3434
#include "user_interface.h"
3535
#include "modmachine.h"
36+
#include "ets_alt_task.h"
3637

3738
typedef struct _pyb_rtc_obj_t {
3839
mp_obj_base_t base;
3940
} pyb_rtc_obj_t;
4041

4142
#define MEM_MAGIC 0x75507921
42-
#define MEM_DELTA_ADDR 64
43-
#define MEM_CAL_ADDR (MEM_DELTA_ADDR + 2)
44-
#define MEM_USER_MAGIC_ADDR (MEM_CAL_ADDR + 1)
43+
#define MEM_RTC_BASE 64
44+
#define MEM_RTCOFS_ADDR (MEM_RTC_BASE + 0)
45+
#define MEM_RTCREF_ADDR (MEM_RTCOFS_ADDR + 2)
46+
#define MEM_USER_MAGIC_ADDR (MEM_RTCREF_ADDR + 1)
4547
#define MEM_USER_LEN_ADDR (MEM_USER_MAGIC_ADDR + 1)
4648
#define MEM_USER_DATA_ADDR (MEM_USER_LEN_ADDR + 1)
47-
#define MEM_USER_MAXLEN (512 - (MEM_USER_DATA_ADDR - MEM_DELTA_ADDR) * 4)
49+
#define MEM_USER_MAXLEN (512 - (MEM_USER_DATA_ADDR - MEM_RTC_BASE) * 4)
4850

4951
// singleton RTC object
5052
STATIC const pyb_rtc_obj_t pyb_rtc_obj = {{&pyb_rtc_type}};
@@ -55,75 +57,103 @@ uint64_t pyb_rtc_alarm0_expiry; // in microseconds
5557

5658
// RTC overflow checking
5759
STATIC uint32_t rtc_last_ticks;
60+
STATIC uint32_t rtc_last_cal;
61+
// Clock overflow checking
62+
STATIC uint64_t clk_offset;
63+
64+
uint64_t esp_clk_get_us_since_boot() {
65+
return ((uint64_t)system_time_high_word << 32) | (uint64_t)system_get_time();
66+
}
67+
68+
void esp_clk_set_us_since_2000(uint64_t nowus) {
69+
// Set current time as base for future calculations
70+
clk_offset = nowus - esp_clk_get_us_since_boot();
71+
};
72+
73+
uint64_t esp_clk_get_us_since_2000() {
74+
return clk_offset + esp_clk_get_us_since_boot();
75+
};
76+
77+
void pyb_rtc_set_us_since_2000(uint64_t nowus) {
78+
// Get the current clock tick
79+
rtc_last_ticks = system_get_rtc_time();
80+
// Set current time as base for future calculations
81+
system_rtc_mem_write(MEM_RTCOFS_ADDR, &nowus, sizeof(nowus));
82+
system_rtc_mem_write(MEM_RTCREF_ADDR, &rtc_last_ticks, sizeof(rtc_last_ticks));
83+
};
84+
85+
uint64_t pyb_rtc_get_us_since_2000() {
86+
uint64_t offset;
87+
uint32_t rtc_ticks;
88+
89+
system_rtc_mem_read(MEM_RTCOFS_ADDR, &offset, sizeof(offset));
90+
rtc_ticks = system_get_rtc_time();
91+
rtc_last_cal = system_rtc_clock_cali_proc();
92+
93+
int64_t delta = rtc_ticks;
94+
if (rtc_ticks >= rtc_last_ticks) {
95+
delta-= rtc_last_ticks;
96+
} else {
97+
// If overflow happened, assume 1 wrap-around and persist info for the new cycle
98+
delta+= ~rtc_last_ticks+1;
99+
}
100+
offset+= (delta * rtc_last_cal) >> 12;
101+
// Since RTC cal is volatile, we have to rebase every time
102+
rtc_last_ticks = rtc_ticks;
103+
// Since RTC enjoys persistence across (some) reboots, we persist the rebase to enjoy the benefit
104+
system_rtc_mem_write(MEM_RTCREF_ADDR, &rtc_last_ticks, sizeof(rtc_last_ticks));
105+
system_rtc_mem_write(MEM_RTCOFS_ADDR, &offset, sizeof(offset));
106+
return offset;
107+
};
58108

59109
void mp_hal_rtc_init(void) {
60110
uint32_t magic;
61111

62112
system_rtc_mem_read(MEM_USER_MAGIC_ADDR, &magic, sizeof(magic));
63113
if (magic != MEM_MAGIC) {
114+
// Reset clock to 2000-01-01 00:00:00 AM
115+
esp_clk_set_us_since_2000(0);
116+
pyb_rtc_set_us_since_2000(0);
64117
magic = MEM_MAGIC;
65118
system_rtc_mem_write(MEM_USER_MAGIC_ADDR, &magic, sizeof(magic));
66-
uint32_t cal = system_rtc_clock_cali_proc();
67-
int64_t delta = 0;
68-
system_rtc_mem_write(MEM_CAL_ADDR, &cal, sizeof(cal));
69-
system_rtc_mem_write(MEM_DELTA_ADDR, &delta, sizeof(delta));
70119
uint32_t len = 0;
71120
system_rtc_mem_write(MEM_USER_LEN_ADDR, &len, sizeof(len));
121+
} else {
122+
// Check reset cause to determine what to do with stored RTC ticks
123+
struct rst_info *rtc_info = system_get_rst_info();
124+
if (rtc_info->reason == REASON_EXT_SYS_RST) {
125+
// External reset, RTC ticks reset to zero
126+
// Note: PowerOn and ChipEn also cause ticks to reset but since they also randomize entire RTC memory,
127+
// it is assumed the control flow never reach here for those two cases
128+
rtc_last_ticks = 0;
129+
system_rtc_mem_write(MEM_RTCREF_ADDR, &rtc_last_ticks, sizeof(rtc_last_ticks));
130+
} else {
131+
// Load back the RTC cycle base
132+
system_rtc_mem_read(MEM_RTCREF_ADDR, &rtc_last_ticks, sizeof(rtc_last_ticks));
133+
}
134+
// Use rtc clock's data to reinitialize system clock
135+
esp_clk_set_us_since_2000(pyb_rtc_get_us_since_2000());
72136
}
73-
// system_get_rtc_time() is always 0 after reset/deepsleep
74-
rtc_last_ticks = system_get_rtc_time();
75137

76138
// reset ALARM0 state
77139
pyb_rtc_alarm0_wake = 0;
78140
pyb_rtc_alarm0_expiry = 0;
79141
}
80142

81-
STATIC mp_obj_t pyb_rtc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
143+
STATIC mp_obj_t pyb_rtc_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
82144
// check arguments
83145
mp_arg_check_num(n_args, n_kw, 0, 0, false);
84146

85147
// return constant object
86148
return (mp_obj_t)&pyb_rtc_obj;
87149
}
88150

89-
void pyb_rtc_set_us_since_2000(uint64_t nowus) {
90-
uint32_t cal = system_rtc_clock_cali_proc();
91-
// Save RTC ticks for overflow detection.
92-
rtc_last_ticks = system_get_rtc_time();
93-
int64_t delta = nowus - (((uint64_t)rtc_last_ticks * cal) >> 12);
94-
95-
// As the calibration value jitters quite a bit, to make the
96-
// clock at least somewhat practially usable, we need to store it
97-
system_rtc_mem_write(MEM_CAL_ADDR, &cal, sizeof(cal));
98-
system_rtc_mem_write(MEM_DELTA_ADDR, &delta, sizeof(delta));
99-
};
100-
101-
uint64_t pyb_rtc_get_us_since_2000() {
102-
uint32_t cal;
103-
int64_t delta;
104-
uint32_t rtc_ticks;
105-
106-
system_rtc_mem_read(MEM_CAL_ADDR, &cal, sizeof(cal));
107-
system_rtc_mem_read(MEM_DELTA_ADDR, &delta, sizeof(delta));
108-
109-
// ESP-SDK system_get_rtc_time() only returns uint32 and therefore
110-
// overflow about every 7:45h. Thus, we have to check for
111-
// overflow and handle it.
112-
rtc_ticks = system_get_rtc_time();
113-
if (rtc_ticks < rtc_last_ticks) {
114-
// Adjust delta because of RTC overflow.
115-
delta += (uint64_t)cal << 20;
116-
system_rtc_mem_write(MEM_DELTA_ADDR, &delta, sizeof(delta));
117-
}
118-
rtc_last_ticks = rtc_ticks;
119-
120-
return (((uint64_t)rtc_ticks * cal) >> 12) + delta;
121-
};
122-
123151
void rtc_prepare_deepsleep(uint64_t sleep_us) {
124152
// RTC time will reset at wake up. Let's be preared for this.
125-
int64_t delta = pyb_rtc_get_us_since_2000() + sleep_us;
126-
system_rtc_mem_write(MEM_DELTA_ADDR, &delta, sizeof(delta));
153+
int64_t newoffset = pyb_rtc_get_us_since_2000() + sleep_us;
154+
rtc_last_ticks+= (sleep_us << 12) / rtc_last_cal;
155+
system_rtc_mem_write(MEM_RTCOFS_ADDR, &newoffset, sizeof(newoffset));
156+
system_rtc_mem_write(MEM_RTCREF_ADDR, &rtc_last_ticks, sizeof(rtc_last_ticks));
127157
}
128158

129159
STATIC mp_obj_t pyb_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) {
@@ -151,14 +181,16 @@ STATIC mp_obj_t pyb_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) {
151181
mp_obj_t *items;
152182
mp_obj_get_array_fixed_n(args[1], 8, &items);
153183

154-
pyb_rtc_set_us_since_2000(
184+
uint64_t arg_us = (
155185
((uint64_t)timeutils_seconds_since_2000(
156186
mp_obj_get_int(items[0]),
157187
mp_obj_get_int(items[1]),
158188
mp_obj_get_int(items[2]),
159189
mp_obj_get_int(items[4]),
160190
mp_obj_get_int(items[5]),
161191
mp_obj_get_int(items[6])) * 1000 + mp_obj_get_int(items[7])) * 1000);
192+
pyb_rtc_set_us_since_2000(arg_us);
193+
esp_clk_set_us_since_2000(arg_us);
162194

163195
return mp_const_none;
164196
}

esp8266/modmachine.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ void pin_set(uint pin, int value);
3434
extern uint32_t pyb_rtc_alarm0_wake;
3535
extern uint64_t pyb_rtc_alarm0_expiry;
3636

37+
void esp_clk_set_us_since_2000(uint64_t nowus);
38+
uint64_t esp_clk_get_us_since_2000();
39+
3740
void pyb_rtc_set_us_since_2000(uint64_t nowus);
3841
uint64_t pyb_rtc_get_us_since_2000();
3942
void rtc_prepare_deepsleep(uint64_t sleep_us);

esp8266/modutime.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ STATIC mp_obj_t time_localtime(mp_uint_t n_args, const mp_obj_t *args) {
6060
timeutils_struct_time_t tm;
6161
mp_int_t seconds;
6262
if (n_args == 0 || args[0] == mp_const_none) {
63-
seconds = pyb_rtc_get_us_since_2000() / 1000 / 1000;
63+
seconds = esp_clk_get_us_since_2000() / 1000 / 1000;
6464
} else {
6565
seconds = mp_obj_get_int(args[0]);
6666
}
@@ -103,7 +103,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(time_mktime_obj, time_mktime);
103103
/// Returns the number of seconds, as an integer, since 1/1/2000.
104104
STATIC mp_obj_t time_time(void) {
105105
// get date and time
106-
return mp_obj_new_int(pyb_rtc_get_us_since_2000() / 1000 / 1000);
106+
return mp_obj_new_int(esp_clk_get_us_since_2000() / 1000 / 1000);
107107
}
108108
MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time);
109109

0 commit comments

Comments
 (0)
0