2828
2929#define SLEEP_DURATION_US 20000ULL
3030#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
3234
3335using utest::v1::Case;
3436using utest::v1::Specification;
3537using utest::v1::Harness;
3638
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+
3759void test_lock_unlock ()
3860{
3961 TEST_ASSERT_TRUE (sleep_manager_can_deep_sleep ());
@@ -62,8 +84,6 @@ void test_lock_eq_ushrt_max()
6284 TEST_ASSERT_TRUE (sleep_manager_can_deep_sleep ());
6385}
6486
65- #if DEVICE_LPTICKER
66- #if DEVICE_USTICKER
6787utest::v1::status_t testcase_setup (const Case *const source, const size_t index_of_case)
6888{
6989 // 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
98118 return utest::v1::greentea_case_teardown_handler (source, passed, failed, failure);
99119}
100120
121+ #if DEVICE_LPTICKER
122+ #if DEVICE_USTICKER
101123/* This test is based on the fact that the high-speed clocks are turned off
102124 * in deep sleep mode but remain on in the ordinary sleep mode. Low-speed
103125 * clocks stay on for both sleep and deep sleep modes.
@@ -115,10 +137,18 @@ void test_sleep_auto()
115137 const ticker_irq_handler_type lp_ticker_irq_handler_org = set_lp_ticker_irq_handler (lp_ticker_isr);
116138 us_timestamp_t us_ts1, us_ts2, lp_ts1, lp_ts2, us_diff1, us_diff2, lp_diff1, lp_diff2;
117139
118- sleep_manager_lock_deep_sleep ();
140+ /* Let's avoid the Lp ticker wrap-around case */
141+ wraparound_lp_protect ();
119142 uint32_t lp_wakeup_ts_raw = lp_ticker_read () + us_to_ticks (SLEEP_DURATION_US, lp_ticker_info->frequency );
120143 timestamp_t lp_wakeup_ts = overflow_protect (lp_wakeup_ts_raw, lp_ticker_info->bits );
121144 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+
122152 us_ts1 = ticks_to_us (us_ticker_read (), us_ticker_info->frequency );
123153 lp_ts1 = ticks_to_us (lp_ticker_read (), lp_ticker_info->frequency );
124154
@@ -144,13 +174,21 @@ void test_sleep_auto()
144174 // Wait for hardware serial buffers to flush.
145175 busy_wait_ms (SERIAL_FLUSH_TIME_MS);
146176
177+ /* Let's avoid the Lp ticker wrap-around case */
178+ wraparound_lp_protect ();
147179 lp_wakeup_ts_raw = lp_ticker_read () + us_to_ticks (SLEEP_DURATION_US, lp_ticker_info->frequency );
148180 lp_wakeup_ts = overflow_protect (lp_wakeup_ts_raw, lp_ticker_info->bits );
149181 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+
150187 us_ts1 = ticks_to_us (us_ticker_read (), us_ticker_info->frequency );
151188 lp_ts1 = ticks_to_us (lp_ticker_read (), lp_ticker_info->frequency );
152189
153190 sleep_manager_sleep_auto ();
191+
154192 us_ts2 = ticks_to_us (us_ticker_read (), us_ticker_info->frequency );
155193 us_diff2 = (us_ts1 <= us_ts2) ? (us_ts2 - us_ts1) : (us_ticker_mask - us_ts1 + us_ts2 + 1 );
156194 lp_ts2 = ticks_to_us (lp_ticker_read (), lp_ticker_info->frequency );
@@ -175,73 +213,117 @@ void test_sleep_auto()
175213}
176214#endif
177215
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+
178240void test_lock_unlock_test_check ()
179241{
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);
183243
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++) {
188245
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 ();
197247
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);
225298}
226299#endif
227300
228301utest::v1::status_t testsuite_setup (const size_t number_of_cases)
229302{
230- GREENTEA_SETUP (10 , " default_auto" );
303+ GREENTEA_SETUP (15 , " default_auto" );
231304 return utest::v1::greentea_test_setup_handler (number_of_cases);
232305}
233306
234307Case 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),
237316#if DEVICE_LPTICKER
238317#if DEVICE_USTICKER
239318 Case (" sleep_auto calls sleep/deep sleep based on lock" ,
240319 (utest::v1::case_setup_handler_t ) testcase_setup,
241320 test_sleep_auto,
242321 (utest::v1::case_teardown_handler_t ) testcase_teardown),
243322#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)
245327#endif
246328};
247329
0 commit comments