33
33
#include "timeutils.h"
34
34
#include "user_interface.h"
35
35
#include "modmachine.h"
36
+ #include "ets_alt_task.h"
36
37
37
38
typedef struct _pyb_rtc_obj_t {
38
39
mp_obj_base_t base ;
39
40
} pyb_rtc_obj_t ;
40
41
41
42
#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)
45
47
#define MEM_USER_LEN_ADDR (MEM_USER_MAGIC_ADDR + 1)
46
48
#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)
48
50
49
51
// singleton RTC object
50
52
STATIC const pyb_rtc_obj_t pyb_rtc_obj = {{& pyb_rtc_type }};
@@ -55,75 +57,103 @@ uint64_t pyb_rtc_alarm0_expiry; // in microseconds
55
57
56
58
// RTC overflow checking
57
59
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
+ };
58
108
59
109
void mp_hal_rtc_init (void ) {
60
110
uint32_t magic ;
61
111
62
112
system_rtc_mem_read (MEM_USER_MAGIC_ADDR , & magic , sizeof (magic ));
63
113
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 );
64
117
magic = MEM_MAGIC ;
65
118
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 ));
70
119
uint32_t len = 0 ;
71
120
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 ());
72
136
}
73
- // system_get_rtc_time() is always 0 after reset/deepsleep
74
- rtc_last_ticks = system_get_rtc_time ();
75
137
76
138
// reset ALARM0 state
77
139
pyb_rtc_alarm0_wake = 0 ;
78
140
pyb_rtc_alarm0_expiry = 0 ;
79
141
}
80
142
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 ) {
82
144
// check arguments
83
145
mp_arg_check_num (n_args , n_kw , 0 , 0 , false);
84
146
85
147
// return constant object
86
148
return (mp_obj_t )& pyb_rtc_obj ;
87
149
}
88
150
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
-
123
151
void rtc_prepare_deepsleep (uint64_t sleep_us ) {
124
152
// 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 ));
127
157
}
128
158
129
159
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) {
151
181
mp_obj_t * items ;
152
182
mp_obj_get_array_fixed_n (args [1 ], 8 , & items );
153
183
154
- pyb_rtc_set_us_since_2000 (
184
+ uint64_t arg_us = (
155
185
((uint64_t )timeutils_seconds_since_2000 (
156
186
mp_obj_get_int (items [0 ]),
157
187
mp_obj_get_int (items [1 ]),
158
188
mp_obj_get_int (items [2 ]),
159
189
mp_obj_get_int (items [4 ]),
160
190
mp_obj_get_int (items [5 ]),
161
191
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 );
162
194
163
195
return mp_const_none ;
164
196
}
0 commit comments