Skip to content

Commit a2c9152

Browse files
authored
Merge pull request #10700 from LMESTM/hal_sleep_manager_test_update
Update HAL Sleep manager test to cope with STM32 LPTIM HW
2 parents 201a264 + 8d8383b commit a2c9152

File tree

2 files changed

+138
-54
lines changed

2 files changed

+138
-54
lines changed

TESTS/mbed_hal/sleep_manager/main.cpp

Lines changed: 132 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,34 @@
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

3335
using utest::v1::Case;
3436
using utest::v1::Specification;
3537
using 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+
3759
void 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
6787
utest::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+
178240
void 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

228301
utest::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

234307
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),
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

platform/mbed_sleep_manager.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -192,13 +192,15 @@ bool sleep_manager_can_deep_sleep(void)
192192

193193
bool sleep_manager_can_deep_sleep_test_check()
194194
{
195-
const uint32_t check_time_us = 2000;
196-
const ticker_data_t *const ticker = get_us_ticker_data();
197-
uint32_t start = ticker_read(ticker);
198-
while ((ticker_read(ticker) - start) < check_time_us) {
195+
uint32_t check_time_ns = 2000000;
196+
197+
while (check_time_ns) {
199198
if (sleep_manager_can_deep_sleep()) {
200199
return true;
201200
}
201+
202+
wait_ns(100000); // 100 us
203+
check_time_ns -= 100000;
202204
}
203205
return false;
204206
}

0 commit comments

Comments
 (0)