Skip to content

Commit cb4e9b3

Browse files
committed
Sleep HAL: add sleep manager API
Sleep manager provides API to lock/unlock deepsleep. This API allows a user to control deep sleep. This API should be done via atomic operations (to be IRQ/thread safe).
1 parent 5bddd88 commit cb4e9b3

File tree

2 files changed

+152
-7
lines changed

2 files changed

+152
-7
lines changed

hal/mbed_sleep_manager.c

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2017 ARM Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "mbed_sleep.h"
18+
#include "mbed_critical.h"
19+
#include "sleep_api.h"
20+
#include "mbed_error.h"
21+
#include <limits.h>
22+
23+
#if DEVICE_SLEEP
24+
25+
// deep sleep locking counter. A target is allowed to deep sleep if counter == 0
26+
static uint16_t deep_sleep_lock = 0U;
27+
28+
void sleep_manager_lock_deep_sleep(void)
29+
{
30+
core_util_critical_section_enter();
31+
if (deep_sleep_lock == USHRT_MAX) {
32+
core_util_critical_section_exit();
33+
error("Deep sleep lock would overflow (> USHRT_MAX)");
34+
}
35+
core_util_atomic_incr_u16(&deep_sleep_lock, 1);
36+
core_util_critical_section_exit();
37+
}
38+
39+
void sleep_manager_unlock_deep_sleep(void)
40+
{
41+
core_util_critical_section_enter();
42+
if (deep_sleep_lock == 0) {
43+
core_util_critical_section_exit();
44+
error("Deep sleep lock would underflow (< 0)");
45+
}
46+
core_util_atomic_decr_u16(&deep_sleep_lock, 1);
47+
core_util_critical_section_exit();
48+
}
49+
50+
bool sleep_manager_can_deep_sleep(void)
51+
{
52+
return deep_sleep_lock == 0 ? true : false;
53+
}
54+
55+
void sleep_manager_sleep_auto(void)
56+
{
57+
core_util_critical_section_enter();
58+
// debug profile should keep debuggers attached, no deep sleep allowed
59+
#ifdef MBED_DEBUG
60+
hal_sleep();
61+
#else
62+
if (sleep_manager_can_deep_sleep()) {
63+
hal_deepsleep();
64+
} else {
65+
hal_sleep();
66+
}
67+
#endif
68+
core_util_critical_section_exit();
69+
}
70+
71+
#endif

platform/mbed_sleep.h

Lines changed: 81 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,87 @@
2020
#define MBED_SLEEP_H
2121

2222
#include "sleep_api.h"
23+
#include "mbed_toolchain.h"
24+
#include <stdbool.h>
2325

2426
#ifdef __cplusplus
2527
extern "C" {
2628
#endif
2729

30+
/** Sleep manager API
31+
* The sleep manager provides API to automatically select sleep mode.
32+
*
33+
* There are two sleep modes:
34+
* - sleep
35+
* - deepsleep
36+
*
37+
* Use locking/unlocking deepsleep for drivers that depend on features that
38+
* are not allowed (=disabled) during the deepsleep. For instance, high frequency
39+
* clocks.
40+
*
41+
* Example:
42+
* @code
43+
*
44+
* void driver::handler()
45+
* {
46+
* if (_sensor.get_event()) {
47+
* // any event - we are finished, unlock the deepsleep
48+
* sleep_manager_unlock_deep_sleep();
49+
* _callback();
50+
* }
51+
* }
52+
*
53+
* int driver::measure(event_t event, callback_t& callback)
54+
* {
55+
* _callback = callback;
56+
* sleep_manager_lock_deep_sleep();
57+
* // start async transaction, we are waiting for an event
58+
* return _sensor.start(event, callback);
59+
* }
60+
* @endcode
61+
*/
62+
63+
/** Lock the deep sleep mode
64+
*
65+
* This locks the automatic deep mode selection.
66+
* sleep_manager_sleep_auto() will ignore deepsleep mode if
67+
* this function is invoked at least once (the internal counter is non-zero)
68+
*
69+
* Use this locking mechanism for interrupt driven API that are
70+
* running in the background and deepsleep could affect their functionality
71+
*
72+
* The lock is a counter, can be locked up to USHRT_MAX
73+
* This function is IRQ and thread safe
74+
*/
75+
void sleep_manager_lock_deep_sleep(void);
76+
77+
/** Unlock the deep sleep mode
78+
*
79+
* Use unlocking in pair with sleep_manager_lock_deep_sleep().
80+
*
81+
* The lock is a counter, should be equally unlocked as locked
82+
* This function is IRQ and thread safe
83+
*/
84+
void sleep_manager_unlock_deep_sleep(void);
85+
86+
/** Get the status of deep sleep allowance for a target
87+
*
88+
* @return true if a target can go to deepsleep, false otherwise
89+
*/
90+
bool sleep_manager_can_deep_sleep(void);
91+
92+
/** Enter auto selected sleep mode. It chooses the sleep or deeepsleep modes based
93+
* on the deepsleep locking counter
94+
*
95+
* This function is IRQ and thread safe
96+
*
97+
* @note
98+
* If MBED_DEBUG is defined, only hal_sleep is allowed. This ensures the debugger
99+
* to be active for debug modes.
100+
*
101+
*/
102+
void sleep_manager_sleep_auto(void);
103+
28104
/** Send the microcontroller to sleep
29105
*
30106
* @note This function can be a noop if not implemented by the platform.
@@ -46,11 +122,9 @@ extern "C" {
46122
__INLINE static void sleep(void)
47123
{
48124
#if !(defined(FEATURE_UVISOR) && defined(TARGET_UVISOR_SUPPORTED))
49-
#ifndef MBED_DEBUG
50125
#if DEVICE_SLEEP
51-
hal_sleep();
126+
sleep_manager_sleep_auto();
52127
#endif /* DEVICE_SLEEP */
53-
#endif /* MBED_DEBUG */
54128
#endif /* !(defined(FEATURE_UVISOR) && defined(TARGET_UVISOR_SUPPORTED)) */
55129
}
56130

@@ -60,7 +134,7 @@ __INLINE static void sleep(void)
60134
* @note This function will be a noop in debug mode (debug build profile when MBED_DEBUG is defined)
61135
* @note This function will be a noop while uVisor is in use.
62136
*
63-
* This processor is setup ready for deep sleep, and sent to sleep using __WFI(). This mode
137+
* This processor is setup ready for deep sleep, and sent to sleep. This mode
64138
* has the same sleep features as sleep plus it powers down peripherals and clocks. All state
65139
* is still maintained.
66140
*
@@ -71,14 +145,14 @@ __INLINE static void sleep(void)
71145
* Flash re-programming and the USB serial port will remain active, but the mbed program will no longer be
72146
* able to access the LocalFileSystem
73147
*/
148+
149+
MBED_DEPRECATED_SINCE("mbed-os-5.6", "One entry point for an application, use sleep()")
74150
__INLINE static void deepsleep(void)
75151
{
76152
#if !(defined(FEATURE_UVISOR) && defined(TARGET_UVISOR_SUPPORTED))
77-
#ifndef MBED_DEBUG
78153
#if DEVICE_SLEEP
79-
hal_deepsleep();
154+
sleep_manager_sleep_auto();
80155
#endif /* DEVICE_SLEEP */
81-
#endif /* MBED_DEBUG */
82156
#endif /* !(defined(FEATURE_UVISOR) && defined(TARGET_UVISOR_SUPPORTED)) */
83157
}
84158

0 commit comments

Comments
 (0)