28
28
29
29
#define SLEEP_DURATION_US 20000ULL
30
30
#define DEEP_SLEEP_TEST_CHECK_WAIT_US 2000
31
- #define DEEP_SLEEP_TEST_CHECK_WAIT_DELTA_US 500
31
+ // As sleep_manager_can_deep_sleep_test_check() is based on wait_ns
32
+ // and wait_ns can be up to 40% slower, use a 50% delta here.
33
+ #define DEEP_SLEEP_TEST_CHECK_WAIT_DELTA_US 1000
32
34
33
35
using utest::v1::Case;
34
36
using utest::v1::Specification;
35
37
using utest::v1::Harness;
36
38
39
+ #if DEVICE_LPTICKER
40
+ /* Make sure there are enough ticks to cope with more than SLEEP_DURATION_US sleep
41
+ * without hitting the wrap-around.
42
+ */
43
+ void wraparound_lp_protect (void )
44
+ {
45
+ const uint32_t ticks_now = get_lp_ticker_data ()->interface ->read ();
46
+ const ticker_info_t *p_ticker_info = get_lp_ticker_data ()->interface ->get_info ();
47
+
48
+ const uint32_t max_count = ((1 << p_ticker_info->bits ) - 1 );
49
+ const uint32_t delta_ticks = us_to_ticks (SLEEP_DURATION_US * 1.5 , p_ticker_info->frequency );
50
+
51
+ if (ticks_now < (max_count - delta_ticks)) {
52
+ return ;
53
+ }
54
+
55
+ while (get_lp_ticker_data ()->interface ->read () > (max_count - delta_ticks));
56
+ }
57
+ #endif
58
+
37
59
void test_lock_unlock ()
38
60
{
39
61
TEST_ASSERT_TRUE (sleep_manager_can_deep_sleep ());
@@ -62,8 +84,6 @@ void test_lock_eq_ushrt_max()
62
84
TEST_ASSERT_TRUE (sleep_manager_can_deep_sleep ());
63
85
}
64
86
65
- #if DEVICE_LPTICKER
66
- #if DEVICE_USTICKER
67
87
utest::v1::status_t testcase_setup (const Case *const source, const size_t index_of_case)
68
88
{
69
89
// Suspend the RTOS kernel scheduler to prevent interference with duration of sleep.
@@ -98,6 +118,8 @@ utest::v1::status_t testcase_teardown(const Case *const source, const size_t pas
98
118
return utest::v1::greentea_case_teardown_handler (source, passed, failed, failure);
99
119
}
100
120
121
+ #if DEVICE_LPTICKER
122
+ #if DEVICE_USTICKER
101
123
/* This test is based on the fact that the high-speed clocks are turned off
102
124
* in deep sleep mode but remain on in the ordinary sleep mode. Low-speed
103
125
* clocks stay on for both sleep and deep sleep modes.
@@ -115,10 +137,18 @@ void test_sleep_auto()
115
137
const ticker_irq_handler_type lp_ticker_irq_handler_org = set_lp_ticker_irq_handler (lp_ticker_isr);
116
138
us_timestamp_t us_ts1, us_ts2, lp_ts1, lp_ts2, us_diff1, us_diff2, lp_diff1, lp_diff2;
117
139
118
- sleep_manager_lock_deep_sleep ();
140
+ /* Let's avoid the Lp ticker wrap-around case */
141
+ wraparound_lp_protect ();
119
142
uint32_t lp_wakeup_ts_raw = lp_ticker_read () + us_to_ticks (SLEEP_DURATION_US, lp_ticker_info->frequency );
120
143
timestamp_t lp_wakeup_ts = overflow_protect (lp_wakeup_ts_raw, lp_ticker_info->bits );
121
144
lp_ticker_set_interrupt (lp_wakeup_ts);
145
+
146
+ /* Some targets may need an interrupt short time after LPTIM interrupt is
147
+ * set and forbid deep_sleep during that period. Let this period pass */
148
+ TEST_ASSERT_TRUE (sleep_manager_can_deep_sleep_test_check ());
149
+
150
+ sleep_manager_lock_deep_sleep ();
151
+
122
152
us_ts1 = ticks_to_us (us_ticker_read (), us_ticker_info->frequency );
123
153
lp_ts1 = ticks_to_us (lp_ticker_read (), lp_ticker_info->frequency );
124
154
@@ -144,13 +174,21 @@ void test_sleep_auto()
144
174
// Wait for hardware serial buffers to flush.
145
175
busy_wait_ms (SERIAL_FLUSH_TIME_MS);
146
176
177
+ /* Let's avoid the Lp ticker wrap-around case */
178
+ wraparound_lp_protect ();
147
179
lp_wakeup_ts_raw = lp_ticker_read () + us_to_ticks (SLEEP_DURATION_US, lp_ticker_info->frequency );
148
180
lp_wakeup_ts = overflow_protect (lp_wakeup_ts_raw, lp_ticker_info->bits );
149
181
lp_ticker_set_interrupt (lp_wakeup_ts);
182
+
183
+ /* Some targets may need an interrupt short time after LPTIM interrupt is
184
+ * set and forbid deep_sleep during that period. Let this period pass */
185
+ TEST_ASSERT_TRUE (sleep_manager_can_deep_sleep_test_check ());
186
+
150
187
us_ts1 = ticks_to_us (us_ticker_read (), us_ticker_info->frequency );
151
188
lp_ts1 = ticks_to_us (lp_ticker_read (), lp_ticker_info->frequency );
152
189
153
190
sleep_manager_sleep_auto ();
191
+
154
192
us_ts2 = ticks_to_us (us_ticker_read (), us_ticker_info->frequency );
155
193
us_diff2 = (us_ts1 <= us_ts2) ? (us_ts2 - us_ts1) : (us_ticker_mask - us_ts1 + us_ts2 + 1 );
156
194
lp_ts2 = ticks_to_us (lp_ticker_read (), lp_ticker_info->frequency );
@@ -175,73 +213,117 @@ void test_sleep_auto()
175
213
}
176
214
#endif
177
215
216
+ #define US_PER_S 1000000
217
+
218
+ uint32_t diff_us (uint32_t start_ticks, uint32_t stop_ticks, const ticker_info_t *info)
219
+ {
220
+ uint32_t counter_mask = ((1 << info->bits ) - 1 );
221
+
222
+ uint32_t diff_ticks = ((stop_ticks - start_ticks) & counter_mask);
223
+
224
+ return (uint32_t )((uint64_t ) diff_ticks * US_PER_S / info->frequency );
225
+ }
226
+
227
+ volatile bool unlock_deep_sleep = false ;
228
+
229
+ void ticker_event_handler_stub (const ticker_data_t *const ticker)
230
+ {
231
+ lp_ticker_clear_interrupt ();
232
+ if (unlock_deep_sleep) {
233
+ sleep_manager_unlock_deep_sleep_internal ();
234
+ unlock_deep_sleep = false ;
235
+ }
236
+ }
237
+
238
+ ticker_irq_handler_type prev_irq_handler;
239
+
178
240
void test_lock_unlock_test_check ()
179
241
{
180
- // Make sure HAL tickers are initialized.
181
- ticker_read (get_us_ticker_data ());
182
- ticker_read (get_lp_ticker_data ());
242
+ prev_irq_handler = set_lp_ticker_irq_handler (ticker_event_handler_stub);
183
243
184
- // Use LowPowerTimer instead of Timer to prevent deep sleep lock.
185
- LowPowerTimer lp_timer;
186
- us_timestamp_t exec_time_unlocked, exec_time_locked;
187
- LowPowerTimeout lp_timeout;
244
+ for (int i = 0 ; i < 1000 ; i++) {
188
245
189
- // Deep sleep unlocked:
190
- // * sleep_manager_can_deep_sleep() returns true,
191
- // * sleep_manager_can_deep_sleep_test_check() returns true instantly.
192
- TEST_ASSERT_TRUE (sleep_manager_can_deep_sleep ());
193
- lp_timer.start ();
194
- TEST_ASSERT_TRUE (sleep_manager_can_deep_sleep_test_check ());
195
- lp_timer.stop ();
196
- exec_time_unlocked = lp_timer.read_high_resolution_us ();
246
+ wraparound_lp_protect ();
197
247
198
- // Deep sleep locked:
199
- // * sleep_manager_can_deep_sleep() returns false,
200
- // * sleep_manager_can_deep_sleep_test_check() returns false with 2 ms delay.
201
- sleep_manager_lock_deep_sleep ();
202
- TEST_ASSERT_FALSE (sleep_manager_can_deep_sleep ());
203
- lp_timer.reset ();
204
- lp_timer.start ();
205
- TEST_ASSERT_FALSE (sleep_manager_can_deep_sleep_test_check ());
206
- lp_timer.stop ();
207
- exec_time_locked = lp_timer.read_high_resolution_us ();
208
- TEST_ASSERT_UINT64_WITHIN (DEEP_SLEEP_TEST_CHECK_WAIT_DELTA_US, DEEP_SLEEP_TEST_CHECK_WAIT_US,
209
- exec_time_locked - exec_time_unlocked);
210
-
211
- // Deep sleep unlocked with a 1 ms delay:
212
- // * sleep_manager_can_deep_sleep() returns false,
213
- // * sleep_manager_can_deep_sleep_test_check() returns true with a 1 ms delay,
214
- // * sleep_manager_can_deep_sleep() returns true when checked again.
215
- lp_timer.reset ();
216
- lp_timeout.attach_us (mbed::callback (sleep_manager_unlock_deep_sleep_internal),
217
- DEEP_SLEEP_TEST_CHECK_WAIT_US / 2 );
218
- lp_timer.start ();
219
- TEST_ASSERT_FALSE (sleep_manager_can_deep_sleep ());
220
- TEST_ASSERT_TRUE (sleep_manager_can_deep_sleep_test_check ());
221
- lp_timer.stop ();
222
- TEST_ASSERT_UINT64_WITHIN (DEEP_SLEEP_TEST_CHECK_WAIT_DELTA_US, DEEP_SLEEP_TEST_CHECK_WAIT_US / 2 ,
223
- lp_timer.read_high_resolution_us ());
224
- TEST_ASSERT_TRUE (sleep_manager_can_deep_sleep ());
248
+ const ticker_info_t *p_ticker_info = get_lp_ticker_data ()->interface ->get_info ();
249
+
250
+ // Use LowPowerTimer instead of Timer to prevent deep sleep lock.
251
+ us_timestamp_t exec_time_unlocked, exec_time_locked;
252
+ uint32_t start, stop;
253
+
254
+ // Deep sleep unlocked:
255
+ // * sleep_manager_can_deep_sleep() returns true,
256
+ // * sleep_manager_can_deep_sleep_test_check() returns true instantly.
257
+ TEST_ASSERT_TRUE (sleep_manager_can_deep_sleep ());
258
+ start = lp_ticker_read ();
259
+ TEST_ASSERT_TRUE (sleep_manager_can_deep_sleep_test_check ());
260
+ stop = lp_ticker_read ();
261
+ exec_time_unlocked = diff_us (start, stop, p_ticker_info);
262
+
263
+ // Deep sleep locked:
264
+ // * sleep_manager_can_deep_sleep() returns false,
265
+ // * sleep_manager_can_deep_sleep_test_check() returns false with 2 ms delay.
266
+ sleep_manager_lock_deep_sleep ();
267
+ TEST_ASSERT_FALSE (sleep_manager_can_deep_sleep ());
268
+ start = lp_ticker_read ();
269
+ TEST_ASSERT_FALSE (sleep_manager_can_deep_sleep_test_check ());
270
+ stop = lp_ticker_read ();
271
+ exec_time_locked = diff_us (start, stop, p_ticker_info);
272
+ TEST_ASSERT_UINT64_WITHIN (DEEP_SLEEP_TEST_CHECK_WAIT_DELTA_US, DEEP_SLEEP_TEST_CHECK_WAIT_US,
273
+ exec_time_locked - exec_time_unlocked);
274
+
275
+ // Deep sleep unlocked with a 1 ms delay:
276
+ // * sleep_manager_can_deep_sleep() returns false,
277
+ // * sleep_manager_can_deep_sleep_test_check() returns true with a 1 ms delay,
278
+ // * sleep_manager_can_deep_sleep() returns true when checked again.
279
+ unlock_deep_sleep = true ;
280
+ /* Let's avoid the Lp ticker wrap-around case */
281
+ wraparound_lp_protect ();
282
+ start = lp_ticker_read ();
283
+ uint32_t lp_wakeup_ts_raw = start + us_to_ticks (DEEP_SLEEP_TEST_CHECK_WAIT_US / 2 , p_ticker_info->frequency );
284
+ timestamp_t lp_wakeup_ts = overflow_protect (lp_wakeup_ts_raw, p_ticker_info->bits );
285
+ lp_ticker_set_interrupt (lp_wakeup_ts);
286
+
287
+ // Extra wait after setting interrupt to handle CMPOK
288
+ wait_ns (100000 );
289
+ TEST_ASSERT_FALSE (sleep_manager_can_deep_sleep ());
290
+ TEST_ASSERT_TRUE (sleep_manager_can_deep_sleep_test_check ());
291
+ stop = lp_ticker_read ();
292
+ TEST_ASSERT (diff_us (start, stop, p_ticker_info) > 0UL );
293
+ TEST_ASSERT (diff_us (start, stop, p_ticker_info) < DEEP_SLEEP_TEST_CHECK_WAIT_US);
294
+ TEST_ASSERT_TRUE (sleep_manager_can_deep_sleep ());
295
+ }
296
+
297
+ set_lp_ticker_irq_handler (prev_irq_handler);
225
298
}
226
299
#endif
227
300
228
301
utest::v1::status_t testsuite_setup (const size_t number_of_cases)
229
302
{
230
- GREENTEA_SETUP (10 , " default_auto" );
303
+ GREENTEA_SETUP (15 , " default_auto" );
231
304
return utest::v1::greentea_test_setup_handler (number_of_cases);
232
305
}
233
306
234
307
Case cases[] = {
235
- Case (" deep sleep lock/unlock" , test_lock_unlock),
236
- Case (" deep sleep locked USHRT_MAX times" , test_lock_eq_ushrt_max),
308
+ Case (" deep sleep lock/unlock" ,
309
+ (utest::v1::case_setup_handler_t ) testcase_setup,
310
+ test_lock_unlock,
311
+ (utest::v1::case_teardown_handler_t ) testcase_teardown),
312
+ Case (" deep sleep locked USHRT_MAX times" ,
313
+ (utest::v1::case_setup_handler_t ) testcase_setup,
314
+ test_lock_eq_ushrt_max,
315
+ (utest::v1::case_teardown_handler_t ) testcase_teardown),
237
316
#if DEVICE_LPTICKER
238
317
#if DEVICE_USTICKER
239
318
Case (" sleep_auto calls sleep/deep sleep based on lock" ,
240
319
(utest::v1::case_setup_handler_t ) testcase_setup,
241
320
test_sleep_auto,
242
321
(utest::v1::case_teardown_handler_t ) testcase_teardown),
243
322
#endif
244
- Case (" deep sleep lock/unlock test_check" , test_lock_unlock_test_check),
323
+ Case (" deep sleep lock/unlock test_check" ,
324
+ (utest::v1::case_setup_handler_t ) testcase_setup,
325
+ test_lock_unlock_test_check,
326
+ (utest::v1::case_teardown_handler_t ) testcase_teardown)
245
327
#endif
246
328
};
247
329
0 commit comments