Skip to content

Commit e12f116

Browse files
Merge pull request #4912 from 0xc0170/dev_sleep_drivers
Add sleep manager API
2 parents 814eaa9 + f6c34a2 commit e12f116

File tree

20 files changed

+507
-28
lines changed

20 files changed

+507
-28
lines changed

TESTS/mbed_hal/sleep_manager/main.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
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+
#include "utest/utest.h"
17+
#include "unity/unity.h"
18+
#include "greentea-client/test_env.h"
19+
20+
#if !DEVICE_SLEEP
21+
#error [NOT_SUPPORTED] test not supported
22+
#endif
23+
24+
using namespace utest::v1;
25+
26+
void sleep_manager_deepsleep_counter_test()
27+
{
28+
bool deep_sleep_allowed = sleep_manager_can_deep_sleep();
29+
TEST_ASSERT_TRUE(deep_sleep_allowed);
30+
31+
sleep_manager_lock_deep_sleep();
32+
deep_sleep_allowed = sleep_manager_can_deep_sleep();
33+
TEST_ASSERT_FALSE(deep_sleep_allowed);
34+
35+
sleep_manager_unlock_deep_sleep();
36+
deep_sleep_allowed = sleep_manager_can_deep_sleep();
37+
TEST_ASSERT_TRUE(deep_sleep_allowed);
38+
}
39+
40+
utest::v1::status_t greentea_failure_handler(const Case *const source, const failure_t reason)
41+
{
42+
greentea_case_failure_abort_handler(source, reason);
43+
return STATUS_CONTINUE;
44+
}
45+
46+
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
47+
{
48+
GREENTEA_SETUP(20, "default_auto");
49+
return greentea_test_setup_handler(number_of_cases);
50+
}
51+
52+
Case cases[] = {
53+
Case("sleep manager - deep sleep counter", sleep_manager_deepsleep_counter_test, greentea_failure_handler),
54+
};
55+
56+
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
57+
58+
int main() {
59+
Harness::run(specification);
60+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
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 "utest/utest.h"
18+
#include "unity/unity.h"
19+
#include "greentea-client/test_env.h"
20+
21+
#if !DEVICE_SLEEP
22+
#error [NOT_SUPPORTED] test not supported
23+
#endif
24+
25+
using namespace utest::v1;
26+
27+
void sleep_manager_locking_thread_test()
28+
{
29+
for (uint32_t i = 0; i < 100; i++) {
30+
sleep_manager_lock_deep_sleep();
31+
Thread::wait(25);
32+
sleep_manager_unlock_deep_sleep();
33+
}
34+
}
35+
36+
void sleep_manager_multithread_test()
37+
{
38+
{
39+
Callback<void()> cb(sleep_manager_locking_thread_test);
40+
Thread t1;
41+
Thread t2;
42+
43+
t1.start(callback(cb));
44+
Thread::wait(25);
45+
t2.start(callback(cb));
46+
47+
// Wait for the threads to finish
48+
t1.join();
49+
t2.join();
50+
}
51+
52+
bool deep_sleep_allowed = sleep_manager_can_deep_sleep();
53+
TEST_ASSERT_TRUE_MESSAGE(deep_sleep_allowed, "Deep sleep should be allowed");
54+
}
55+
56+
void sleep_manager_locking_irq_test()
57+
{
58+
sleep_manager_lock_deep_sleep();
59+
sleep_manager_unlock_deep_sleep();
60+
}
61+
62+
void sleep_manager_irq_test()
63+
{
64+
{
65+
Ticker ticker1;
66+
Timer timer;
67+
68+
ticker1.attach_us(&sleep_manager_locking_irq_test, 500);
69+
70+
// run this for 5 seconds
71+
timer.start();
72+
int start = timer.read();
73+
int end = start + 5;
74+
while (timer.read() < end) {
75+
sleep_manager_locking_irq_test();
76+
}
77+
timer.stop();
78+
}
79+
80+
bool deep_sleep_allowed = sleep_manager_can_deep_sleep();
81+
TEST_ASSERT_TRUE_MESSAGE(deep_sleep_allowed, "Deep sleep should be allowed");
82+
}
83+
84+
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
85+
{
86+
GREENTEA_SETUP(30, "default_auto");
87+
return greentea_test_setup_handler(number_of_cases);
88+
}
89+
90+
Case cases[] = {
91+
Case("sleep manager HAL - locking multithreaded", sleep_manager_multithread_test),
92+
Case("sleep manager HAL - locking IRQ", sleep_manager_irq_test),
93+
};
94+
95+
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
96+
97+
int main() {
98+
Harness::run(specification);
99+
}

drivers/CAN.cpp

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,15 @@
1818
#if DEVICE_CAN
1919

2020
#include "cmsis.h"
21+
#include "platform/mbed_sleep.h"
2122

2223
namespace mbed {
2324

24-
static void donothing() {}
25-
2625
CAN::CAN(PinName rd, PinName td) : _can(), _irq() {
2726
// No lock needed in constructor
2827

2928
for (size_t i = 0; i < sizeof _irq / sizeof _irq[0]; i++) {
30-
_irq[i] = callback(donothing);
29+
_irq[i] = NULL;
3130
}
3231

3332
can_init(&_can, rd, td);
@@ -38,7 +37,7 @@ CAN::CAN(PinName rd, PinName td, int hz) : _can(), _irq() {
3837
// No lock needed in constructor
3938

4039
for (size_t i = 0; i < sizeof _irq / sizeof _irq[0]; i++) {
41-
_irq[i] = callback(donothing);
40+
_irq[i] = NULL;
4241
}
4342

4443
can_init_freq(&_can, rd, td, hz);
@@ -115,18 +114,28 @@ int CAN::filter(unsigned int id, unsigned int mask, CANFormat format, int handle
115114
void CAN::attach(Callback<void()> func, IrqType type) {
116115
lock();
117116
if (func) {
117+
// lock deep sleep only the first time
118+
if (!_irq[(CanIrqType)type]) {
119+
sleep_manager_lock_deep_sleep();
120+
}
118121
_irq[(CanIrqType)type] = func;
119122
can_irq_set(&_can, (CanIrqType)type, 1);
120123
} else {
121-
_irq[(CanIrqType)type] = callback(donothing);
124+
// unlock deep sleep only the first time
125+
if (_irq[(CanIrqType)type]) {
126+
sleep_manager_unlock_deep_sleep();
127+
}
128+
_irq[(CanIrqType)type] = NULL;
122129
can_irq_set(&_can, (CanIrqType)type, 0);
123130
}
124131
unlock();
125132
}
126133

127134
void CAN::_irq_handler(uint32_t id, CanIrqType type) {
128135
CAN *handler = (CAN*)id;
129-
handler->_irq[type].call();
136+
if (handler->_irq[type]) {
137+
handler->_irq[type].call();
138+
}
130139
}
131140

132141
void CAN::lock() {

drivers/CAN.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,9 @@ class CAN : private NonCopyable<CAN> {
235235

236236
/** Attach a function to call whenever a CAN frame received interrupt is
237237
* generated.
238-
*
238+
*
239+
* This function locks the deep sleep while a callback is attached
240+
*
239241
* @param func A pointer to a void function, or 0 to set as none
240242
* @param type Which CAN interrupt to attach the member function to (CAN::RxIrq for message received, CAN::TxIrq for transmitted or aborted, CAN::EwIrq for error warning, CAN::DoIrq for data overrun, CAN::WuIrq for wake-up, CAN::EpIrq for error passive, CAN::AlIrq for arbitration lost, CAN::BeIrq for bus error)
241243
*/

drivers/I2C.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717

1818
#if DEVICE_I2C
1919

20+
#if DEVICE_I2C_ASYNCH
21+
#include "platform/mbed_sleep.h"
22+
#endif
23+
2024
namespace mbed {
2125

2226
I2C *I2C::_owner = NULL;
@@ -129,6 +133,7 @@ int I2C::transfer(int address, const char *tx_buffer, int tx_length, char *rx_bu
129133
unlock();
130134
return -1; // transaction ongoing
131135
}
136+
sleep_manager_lock_deep_sleep();
132137
aquire();
133138

134139
_callback = callback;
@@ -143,6 +148,7 @@ void I2C::abort_transfer(void)
143148
{
144149
lock();
145150
i2c_abort_asynch(&_i2c);
151+
sleep_manager_unlock_deep_sleep();
146152
unlock();
147153
}
148154

@@ -152,6 +158,9 @@ void I2C::irq_handler_asynch(void)
152158
if (_callback && event) {
153159
_callback.call(event);
154160
}
161+
if (event) {
162+
sleep_manager_unlock_deep_sleep();
163+
}
155164

156165
}
157166

drivers/I2C.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ class I2C : private NonCopyable<I2C> {
159159

160160
/** Start non-blocking I2C transfer.
161161
*
162+
* This function locks the deep sleep until any event has occured
163+
*
162164
* @param address 8/10 bit I2c slave address
163165
* @param tx_buffer The TX buffer with data to be transfered
164166
* @param tx_length The length of TX buffer in bytes

drivers/SPI.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616
#include "drivers/SPI.h"
1717
#include "platform/mbed_critical.h"
1818

19+
#if DEVICE_SPI_ASYNCH
20+
#include "platform/mbed_sleep.h"
21+
#endif
22+
1923
#if DEVICE_SPI
2024

2125
namespace mbed {
@@ -136,6 +140,7 @@ int SPI::transfer(const void *tx_buffer, int tx_length, void *rx_buffer, int rx_
136140
void SPI::abort_transfer()
137141
{
138142
spi_abort_asynch(&_spi);
143+
sleep_manager_unlock_deep_sleep();
139144
#if TRANSACTION_QUEUE_SIZE_SPI
140145
dequeue_transaction();
141146
#endif
@@ -195,6 +200,7 @@ int SPI::queue_transfer(const void *tx_buffer, int tx_length, void *rx_buffer, i
195200

196201
void SPI::start_transfer(const void *tx_buffer, int tx_length, void *rx_buffer, int rx_length, unsigned char bit_width, const event_callback_t& callback, int event)
197202
{
203+
sleep_manager_lock_deep_sleep();
198204
_acquire();
199205
_callback = callback;
200206
_irq.callback(&SPI::irq_handler_asynch);
@@ -224,6 +230,7 @@ void SPI::irq_handler_asynch(void)
224230
{
225231
int event = spi_irq_handler_asynch(&_spi);
226232
if (_callback && (event & SPI_EVENT_ALL)) {
233+
sleep_manager_unlock_deep_sleep();
227234
_callback.call(event & SPI_EVENT_ALL);
228235
}
229236
#if TRANSACTION_QUEUE_SIZE_SPI

drivers/SPI.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,8 @@ class SPI : private NonCopyable<SPI> {
156156

157157
/** Start non-blocking SPI transfer using 8bit buffers.
158158
*
159+
* This function locks the deep sleep until any event has occured
160+
*
159161
* @param tx_buffer The TX buffer with data to be transfered. If NULL is passed,
160162
* the default SPI value is sent
161163
* @param tx_length The length of TX buffer in bytes

0 commit comments

Comments
 (0)