mirror of https://github.com/ARMmbed/mbed-os.git
commit
e12f116ec1
|
@ -0,0 +1,60 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2017 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "utest/utest.h"
|
||||
#include "unity/unity.h"
|
||||
#include "greentea-client/test_env.h"
|
||||
|
||||
#if !DEVICE_SLEEP
|
||||
#error [NOT_SUPPORTED] test not supported
|
||||
#endif
|
||||
|
||||
using namespace utest::v1;
|
||||
|
||||
void sleep_manager_deepsleep_counter_test()
|
||||
{
|
||||
bool deep_sleep_allowed = sleep_manager_can_deep_sleep();
|
||||
TEST_ASSERT_TRUE(deep_sleep_allowed);
|
||||
|
||||
sleep_manager_lock_deep_sleep();
|
||||
deep_sleep_allowed = sleep_manager_can_deep_sleep();
|
||||
TEST_ASSERT_FALSE(deep_sleep_allowed);
|
||||
|
||||
sleep_manager_unlock_deep_sleep();
|
||||
deep_sleep_allowed = sleep_manager_can_deep_sleep();
|
||||
TEST_ASSERT_TRUE(deep_sleep_allowed);
|
||||
}
|
||||
|
||||
utest::v1::status_t greentea_failure_handler(const Case *const source, const failure_t reason)
|
||||
{
|
||||
greentea_case_failure_abort_handler(source, reason);
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
|
||||
{
|
||||
GREENTEA_SETUP(20, "default_auto");
|
||||
return greentea_test_setup_handler(number_of_cases);
|
||||
}
|
||||
|
||||
Case cases[] = {
|
||||
Case("sleep manager - deep sleep counter", sleep_manager_deepsleep_counter_test, greentea_failure_handler),
|
||||
};
|
||||
|
||||
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
|
||||
|
||||
int main() {
|
||||
Harness::run(specification);
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2017 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "utest/utest.h"
|
||||
#include "unity/unity.h"
|
||||
#include "greentea-client/test_env.h"
|
||||
|
||||
#if !DEVICE_SLEEP
|
||||
#error [NOT_SUPPORTED] test not supported
|
||||
#endif
|
||||
|
||||
using namespace utest::v1;
|
||||
|
||||
void sleep_manager_locking_thread_test()
|
||||
{
|
||||
for (uint32_t i = 0; i < 100; i++) {
|
||||
sleep_manager_lock_deep_sleep();
|
||||
Thread::wait(25);
|
||||
sleep_manager_unlock_deep_sleep();
|
||||
}
|
||||
}
|
||||
|
||||
void sleep_manager_multithread_test()
|
||||
{
|
||||
{
|
||||
Callback<void()> cb(sleep_manager_locking_thread_test);
|
||||
Thread t1;
|
||||
Thread t2;
|
||||
|
||||
t1.start(callback(cb));
|
||||
Thread::wait(25);
|
||||
t2.start(callback(cb));
|
||||
|
||||
// Wait for the threads to finish
|
||||
t1.join();
|
||||
t2.join();
|
||||
}
|
||||
|
||||
bool deep_sleep_allowed = sleep_manager_can_deep_sleep();
|
||||
TEST_ASSERT_TRUE_MESSAGE(deep_sleep_allowed, "Deep sleep should be allowed");
|
||||
}
|
||||
|
||||
void sleep_manager_locking_irq_test()
|
||||
{
|
||||
sleep_manager_lock_deep_sleep();
|
||||
sleep_manager_unlock_deep_sleep();
|
||||
}
|
||||
|
||||
void sleep_manager_irq_test()
|
||||
{
|
||||
{
|
||||
Ticker ticker1;
|
||||
Timer timer;
|
||||
|
||||
ticker1.attach_us(&sleep_manager_locking_irq_test, 500);
|
||||
|
||||
// run this for 5 seconds
|
||||
timer.start();
|
||||
int start = timer.read();
|
||||
int end = start + 5;
|
||||
while (timer.read() < end) {
|
||||
sleep_manager_locking_irq_test();
|
||||
}
|
||||
timer.stop();
|
||||
}
|
||||
|
||||
bool deep_sleep_allowed = sleep_manager_can_deep_sleep();
|
||||
TEST_ASSERT_TRUE_MESSAGE(deep_sleep_allowed, "Deep sleep should be allowed");
|
||||
}
|
||||
|
||||
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
|
||||
{
|
||||
GREENTEA_SETUP(30, "default_auto");
|
||||
return greentea_test_setup_handler(number_of_cases);
|
||||
}
|
||||
|
||||
Case cases[] = {
|
||||
Case("sleep manager HAL - locking multithreaded", sleep_manager_multithread_test),
|
||||
Case("sleep manager HAL - locking IRQ", sleep_manager_irq_test),
|
||||
};
|
||||
|
||||
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
|
||||
|
||||
int main() {
|
||||
Harness::run(specification);
|
||||
}
|
|
@ -18,16 +18,15 @@
|
|||
#if DEVICE_CAN
|
||||
|
||||
#include "cmsis.h"
|
||||
#include "platform/mbed_sleep.h"
|
||||
|
||||
namespace mbed {
|
||||
|
||||
static void donothing() {}
|
||||
|
||||
CAN::CAN(PinName rd, PinName td) : _can(), _irq() {
|
||||
// No lock needed in constructor
|
||||
|
||||
for (size_t i = 0; i < sizeof _irq / sizeof _irq[0]; i++) {
|
||||
_irq[i] = callback(donothing);
|
||||
_irq[i] = NULL;
|
||||
}
|
||||
|
||||
can_init(&_can, rd, td);
|
||||
|
@ -38,7 +37,7 @@ CAN::CAN(PinName rd, PinName td, int hz) : _can(), _irq() {
|
|||
// No lock needed in constructor
|
||||
|
||||
for (size_t i = 0; i < sizeof _irq / sizeof _irq[0]; i++) {
|
||||
_irq[i] = callback(donothing);
|
||||
_irq[i] = NULL;
|
||||
}
|
||||
|
||||
can_init_freq(&_can, rd, td, hz);
|
||||
|
@ -115,10 +114,18 @@ int CAN::filter(unsigned int id, unsigned int mask, CANFormat format, int handle
|
|||
void CAN::attach(Callback<void()> func, IrqType type) {
|
||||
lock();
|
||||
if (func) {
|
||||
// lock deep sleep only the first time
|
||||
if (!_irq[(CanIrqType)type]) {
|
||||
sleep_manager_lock_deep_sleep();
|
||||
}
|
||||
_irq[(CanIrqType)type] = func;
|
||||
can_irq_set(&_can, (CanIrqType)type, 1);
|
||||
} else {
|
||||
_irq[(CanIrqType)type] = callback(donothing);
|
||||
// unlock deep sleep only the first time
|
||||
if (_irq[(CanIrqType)type]) {
|
||||
sleep_manager_unlock_deep_sleep();
|
||||
}
|
||||
_irq[(CanIrqType)type] = NULL;
|
||||
can_irq_set(&_can, (CanIrqType)type, 0);
|
||||
}
|
||||
unlock();
|
||||
|
@ -126,7 +133,9 @@ void CAN::attach(Callback<void()> func, IrqType type) {
|
|||
|
||||
void CAN::_irq_handler(uint32_t id, CanIrqType type) {
|
||||
CAN *handler = (CAN*)id;
|
||||
handler->_irq[type].call();
|
||||
if (handler->_irq[type]) {
|
||||
handler->_irq[type].call();
|
||||
}
|
||||
}
|
||||
|
||||
void CAN::lock() {
|
||||
|
|
|
@ -235,7 +235,9 @@ public:
|
|||
|
||||
/** Attach a function to call whenever a CAN frame received interrupt is
|
||||
* generated.
|
||||
*
|
||||
*
|
||||
* This function locks the deep sleep while a callback is attached
|
||||
*
|
||||
* @param func A pointer to a void function, or 0 to set as none
|
||||
* @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)
|
||||
*/
|
||||
|
|
|
@ -17,6 +17,10 @@
|
|||
|
||||
#if DEVICE_I2C
|
||||
|
||||
#if DEVICE_I2C_ASYNCH
|
||||
#include "platform/mbed_sleep.h"
|
||||
#endif
|
||||
|
||||
namespace mbed {
|
||||
|
||||
I2C *I2C::_owner = NULL;
|
||||
|
@ -129,6 +133,7 @@ int I2C::transfer(int address, const char *tx_buffer, int tx_length, char *rx_bu
|
|||
unlock();
|
||||
return -1; // transaction ongoing
|
||||
}
|
||||
sleep_manager_lock_deep_sleep();
|
||||
aquire();
|
||||
|
||||
_callback = callback;
|
||||
|
@ -143,6 +148,7 @@ void I2C::abort_transfer(void)
|
|||
{
|
||||
lock();
|
||||
i2c_abort_asynch(&_i2c);
|
||||
sleep_manager_unlock_deep_sleep();
|
||||
unlock();
|
||||
}
|
||||
|
||||
|
@ -152,6 +158,9 @@ void I2C::irq_handler_asynch(void)
|
|||
if (_callback && event) {
|
||||
_callback.call(event);
|
||||
}
|
||||
if (event) {
|
||||
sleep_manager_unlock_deep_sleep();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -159,6 +159,8 @@ public:
|
|||
|
||||
/** Start non-blocking I2C transfer.
|
||||
*
|
||||
* This function locks the deep sleep until any event has occured
|
||||
*
|
||||
* @param address 8/10 bit I2c slave address
|
||||
* @param tx_buffer The TX buffer with data to be transfered
|
||||
* @param tx_length The length of TX buffer in bytes
|
||||
|
|
|
@ -16,6 +16,10 @@
|
|||
#include "drivers/SPI.h"
|
||||
#include "platform/mbed_critical.h"
|
||||
|
||||
#if DEVICE_SPI_ASYNCH
|
||||
#include "platform/mbed_sleep.h"
|
||||
#endif
|
||||
|
||||
#if DEVICE_SPI
|
||||
|
||||
namespace mbed {
|
||||
|
@ -136,6 +140,7 @@ int SPI::transfer(const void *tx_buffer, int tx_length, void *rx_buffer, int rx_
|
|||
void SPI::abort_transfer()
|
||||
{
|
||||
spi_abort_asynch(&_spi);
|
||||
sleep_manager_unlock_deep_sleep();
|
||||
#if TRANSACTION_QUEUE_SIZE_SPI
|
||||
dequeue_transaction();
|
||||
#endif
|
||||
|
@ -195,6 +200,7 @@ int SPI::queue_transfer(const void *tx_buffer, int tx_length, void *rx_buffer, i
|
|||
|
||||
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)
|
||||
{
|
||||
sleep_manager_lock_deep_sleep();
|
||||
_acquire();
|
||||
_callback = callback;
|
||||
_irq.callback(&SPI::irq_handler_asynch);
|
||||
|
@ -224,6 +230,7 @@ void SPI::irq_handler_asynch(void)
|
|||
{
|
||||
int event = spi_irq_handler_asynch(&_spi);
|
||||
if (_callback && (event & SPI_EVENT_ALL)) {
|
||||
sleep_manager_unlock_deep_sleep();
|
||||
_callback.call(event & SPI_EVENT_ALL);
|
||||
}
|
||||
#if TRANSACTION_QUEUE_SIZE_SPI
|
||||
|
|
|
@ -156,6 +156,8 @@ public:
|
|||
|
||||
/** Start non-blocking SPI transfer using 8bit buffers.
|
||||
*
|
||||
* This function locks the deep sleep until any event has occured
|
||||
*
|
||||
* @param tx_buffer The TX buffer with data to be transfered. If NULL is passed,
|
||||
* the default SPI value is sent
|
||||
* @param tx_length The length of TX buffer in bytes
|
||||
|
|
|
@ -16,23 +16,23 @@
|
|||
#include "drivers/SerialBase.h"
|
||||
#include "platform/mbed_wait_api.h"
|
||||
#include "platform/mbed_critical.h"
|
||||
#include "platform/mbed_sleep.h"
|
||||
|
||||
#if DEVICE_SERIAL
|
||||
|
||||
namespace mbed {
|
||||
|
||||
static void donothing() {};
|
||||
|
||||
SerialBase::SerialBase(PinName tx, PinName rx, int baud) :
|
||||
#if DEVICE_SERIAL_ASYNCH
|
||||
_thunk_irq(this), _tx_usage(DMA_USAGE_NEVER),
|
||||
_rx_usage(DMA_USAGE_NEVER),
|
||||
_rx_usage(DMA_USAGE_NEVER), _tx_callback(NULL),
|
||||
_rx_callback(NULL),
|
||||
#endif
|
||||
_serial(), _baud(baud) {
|
||||
// No lock needed in the constructor
|
||||
|
||||
for (size_t i = 0; i < sizeof _irq / sizeof _irq[0]; i++) {
|
||||
_irq[i] = donothing;
|
||||
_irq[i] = NULL;
|
||||
}
|
||||
|
||||
serial_init(&_serial, tx, rx);
|
||||
|
@ -73,10 +73,18 @@ void SerialBase::attach(Callback<void()> func, IrqType type) {
|
|||
// Disable interrupts when attaching interrupt handler
|
||||
core_util_critical_section_enter();
|
||||
if (func) {
|
||||
// lock deep sleep only the first time
|
||||
if (!_irq[type]) {
|
||||
sleep_manager_lock_deep_sleep();
|
||||
}
|
||||
_irq[type] = func;
|
||||
serial_irq_set(&_serial, (SerialIrq)type, 1);
|
||||
} else {
|
||||
_irq[type] = donothing;
|
||||
// unlock deep sleep only the first time
|
||||
if (_irq[type]) {
|
||||
sleep_manager_unlock_deep_sleep();
|
||||
}
|
||||
_irq[type] = NULL;
|
||||
serial_irq_set(&_serial, (SerialIrq)type, 0);
|
||||
}
|
||||
core_util_critical_section_exit();
|
||||
|
@ -85,7 +93,9 @@ void SerialBase::attach(Callback<void()> func, IrqType type) {
|
|||
|
||||
void SerialBase::_irq_handler(uint32_t id, SerialIrq irq_type) {
|
||||
SerialBase *handler = (SerialBase*)id;
|
||||
handler->_irq[irq_type]();
|
||||
if (handler->_irq[irq_type]) {
|
||||
handler->_irq[irq_type]();
|
||||
}
|
||||
}
|
||||
|
||||
int SerialBase::_base_getc() {
|
||||
|
@ -173,16 +183,27 @@ void SerialBase::start_write(const void *buffer, int buffer_size, char buffer_wi
|
|||
_tx_callback = callback;
|
||||
|
||||
_thunk_irq.callback(&SerialBase::interrupt_handler_asynch);
|
||||
sleep_manager_lock_deep_sleep();
|
||||
serial_tx_asynch(&_serial, buffer, buffer_size, buffer_width, _thunk_irq.entry(), event, _tx_usage);
|
||||
}
|
||||
|
||||
void SerialBase::abort_write(void)
|
||||
{
|
||||
// rx might still be active
|
||||
if (_rx_callback) {
|
||||
sleep_manager_unlock_deep_sleep();
|
||||
}
|
||||
_tx_callback = NULL;
|
||||
serial_tx_abort_asynch(&_serial);
|
||||
}
|
||||
|
||||
void SerialBase::abort_read(void)
|
||||
{
|
||||
// tx might still be active
|
||||
if (_tx_callback) {
|
||||
sleep_manager_unlock_deep_sleep();
|
||||
}
|
||||
_rx_callback = NULL;
|
||||
serial_rx_abort_asynch(&_serial);
|
||||
}
|
||||
|
||||
|
@ -228,6 +249,7 @@ void SerialBase::start_read(void *buffer, int buffer_size, char buffer_width, co
|
|||
{
|
||||
_rx_callback = callback;
|
||||
_thunk_irq.callback(&SerialBase::interrupt_handler_asynch);
|
||||
sleep_manager_lock_deep_sleep();
|
||||
serial_rx_asynch(&_serial, buffer, buffer_size, buffer_width, _thunk_irq.entry(), event, char_match, _rx_usage);
|
||||
}
|
||||
|
||||
|
@ -235,14 +257,22 @@ void SerialBase::interrupt_handler_asynch(void)
|
|||
{
|
||||
int event = serial_irq_handler_asynch(&_serial);
|
||||
int rx_event = event & SERIAL_EVENT_RX_MASK;
|
||||
bool unlock_deepsleep = false;
|
||||
|
||||
if (_rx_callback && rx_event) {
|
||||
unlock_deepsleep = true;
|
||||
_rx_callback.call(rx_event);
|
||||
}
|
||||
|
||||
int tx_event = event & SERIAL_EVENT_TX_MASK;
|
||||
if (_tx_callback && tx_event) {
|
||||
unlock_deepsleep = true;
|
||||
_tx_callback.call(tx_event);
|
||||
}
|
||||
// unlock if tx or rx events are generated
|
||||
if (unlock_deepsleep) {
|
||||
sleep_manager_unlock_deep_sleep();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -167,6 +167,8 @@ public:
|
|||
|
||||
/** Begin asynchronous write using 8bit buffer. The completition invokes registered TX event callback
|
||||
*
|
||||
* This function locks the deep sleep until any event has occured
|
||||
*
|
||||
* @param buffer The buffer where received data will be stored
|
||||
* @param length The buffer length in bytes
|
||||
* @param callback The event callback function
|
||||
|
@ -176,6 +178,8 @@ public:
|
|||
|
||||
/** Begin asynchronous write using 16bit buffer. The completition invokes registered TX event callback
|
||||
*
|
||||
* This function locks the deep sleep until any event has occured
|
||||
*
|
||||
* @param buffer The buffer where received data will be stored
|
||||
* @param length The buffer length in bytes
|
||||
* @param callback The event callback function
|
||||
|
@ -189,6 +193,8 @@ public:
|
|||
|
||||
/** Begin asynchronous reading using 8bit buffer. The completition invokes registred RX event callback.
|
||||
*
|
||||
* This function locks the deep sleep until any event has occured
|
||||
*
|
||||
* @param buffer The buffer where received data will be stored
|
||||
* @param length The buffer length in bytes
|
||||
* @param callback The event callback function
|
||||
|
@ -199,6 +205,8 @@ public:
|
|||
|
||||
/** Begin asynchronous reading using 16bit buffer. The completition invokes registred RX event callback.
|
||||
*
|
||||
* This function locks the deep sleep until any event has occured
|
||||
*
|
||||
* @param buffer The buffer where received data will be stored
|
||||
* @param length The buffer length in bytes
|
||||
* @param callback The event callback function
|
||||
|
@ -241,10 +249,10 @@ protected:
|
|||
|
||||
#if DEVICE_SERIAL_ASYNCH
|
||||
CThunk<SerialBase> _thunk_irq;
|
||||
event_callback_t _tx_callback;
|
||||
event_callback_t _rx_callback;
|
||||
DMAUsage _tx_usage;
|
||||
DMAUsage _rx_usage;
|
||||
event_callback_t _tx_callback;
|
||||
event_callback_t _rx_callback;
|
||||
#endif
|
||||
|
||||
serial_t _serial;
|
||||
|
|
|
@ -25,6 +25,10 @@ namespace mbed {
|
|||
void Ticker::detach() {
|
||||
core_util_critical_section_enter();
|
||||
remove();
|
||||
// unlocked only if we were attached (we locked it)
|
||||
if (_function) {
|
||||
sleep_manager_unlock_deep_sleep();
|
||||
}
|
||||
_function = 0;
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "platform/Callback.h"
|
||||
#include "platform/mbed_toolchain.h"
|
||||
#include "platform/NonCopyable.h"
|
||||
#include "platform/mbed_sleep.h"
|
||||
|
||||
namespace mbed {
|
||||
/** \addtogroup drivers */
|
||||
|
@ -63,10 +64,10 @@ namespace mbed {
|
|||
class Ticker : public TimerEvent, private NonCopyable<Ticker> {
|
||||
|
||||
public:
|
||||
Ticker() : TimerEvent() {
|
||||
Ticker() : TimerEvent(), _function(0) {
|
||||
}
|
||||
|
||||
Ticker(const ticker_data_t *data) : TimerEvent(data) {
|
||||
Ticker(const ticker_data_t *data) : TimerEvent(data), _function(0) {
|
||||
data->interface->init();
|
||||
}
|
||||
|
||||
|
@ -102,6 +103,10 @@ public:
|
|||
* @param t the time between calls in micro-seconds
|
||||
*/
|
||||
void attach_us(Callback<void()> func, us_timestamp_t t) {
|
||||
// lock only for the initial callback setup
|
||||
if (!_function) {
|
||||
sleep_manager_lock_deep_sleep();
|
||||
}
|
||||
_function = func;
|
||||
setup(t);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include "drivers/Ticker.h"
|
||||
#include "platform/NonCopyable.h"
|
||||
#include "platform/mbed_sleep.h"
|
||||
|
||||
namespace mbed {
|
||||
/** \addtogroup drivers */
|
||||
|
|
|
@ -31,6 +31,7 @@ Timer::Timer(const ticker_data_t *data) : _running(), _start(), _time(), _ticker
|
|||
void Timer::start() {
|
||||
core_util_critical_section_enter();
|
||||
if (!_running) {
|
||||
sleep_manager_lock_deep_sleep();
|
||||
_start = ticker_read_us(_ticker_data);
|
||||
_running = 1;
|
||||
}
|
||||
|
@ -40,6 +41,9 @@ void Timer::start() {
|
|||
void Timer::stop() {
|
||||
core_util_critical_section_enter();
|
||||
_time += slicetime();
|
||||
if (_running) {
|
||||
sleep_manager_unlock_deep_sleep();
|
||||
}
|
||||
_running = 0;
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "platform/platform.h"
|
||||
#include "hal/ticker_api.h"
|
||||
#include "platform/NonCopyable.h"
|
||||
#include "platform/mbed_sleep.h"
|
||||
|
||||
namespace mbed {
|
||||
/** \addtogroup drivers */
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2017 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "mbed_sleep.h"
|
||||
#include "mbed_critical.h"
|
||||
#include "sleep_api.h"
|
||||
#include "mbed_error.h"
|
||||
#include <limits.h>
|
||||
|
||||
#if DEVICE_SLEEP
|
||||
|
||||
// deep sleep locking counter. A target is allowed to deep sleep if counter == 0
|
||||
static uint16_t deep_sleep_lock = 0U;
|
||||
|
||||
void sleep_manager_lock_deep_sleep(void)
|
||||
{
|
||||
core_util_critical_section_enter();
|
||||
if (deep_sleep_lock == USHRT_MAX) {
|
||||
core_util_critical_section_exit();
|
||||
error("Deep sleep lock would overflow (> USHRT_MAX)");
|
||||
}
|
||||
core_util_atomic_incr_u16(&deep_sleep_lock, 1);
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
void sleep_manager_unlock_deep_sleep(void)
|
||||
{
|
||||
core_util_critical_section_enter();
|
||||
if (deep_sleep_lock == 0) {
|
||||
core_util_critical_section_exit();
|
||||
error("Deep sleep lock would underflow (< 0)");
|
||||
}
|
||||
core_util_atomic_decr_u16(&deep_sleep_lock, 1);
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
bool sleep_manager_can_deep_sleep(void)
|
||||
{
|
||||
return deep_sleep_lock == 0 ? true : false;
|
||||
}
|
||||
|
||||
void sleep_manager_sleep_auto(void)
|
||||
{
|
||||
core_util_critical_section_enter();
|
||||
// debug profile should keep debuggers attached, no deep sleep allowed
|
||||
#ifdef MBED_DEBUG
|
||||
hal_sleep();
|
||||
#else
|
||||
if (sleep_manager_can_deep_sleep()) {
|
||||
hal_deepsleep();
|
||||
} else {
|
||||
hal_sleep();
|
||||
}
|
||||
#endif
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// locking is valid only if DEVICE_SLEEP is defined
|
||||
// we provide empty implementation
|
||||
|
||||
void sleep_manager_lock_deep_sleep(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void sleep_manager_unlock_deep_sleep(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool sleep_manager_can_deep_sleep(void)
|
||||
{
|
||||
// no sleep implemented
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
1
mbed.h
1
mbed.h
|
@ -90,6 +90,7 @@
|
|||
#include "platform/FileHandle.h"
|
||||
#include "platform/DirHandle.h"
|
||||
#include "platform/CriticalSectionLock.h"
|
||||
#include "platform/DeepSleepLock.h"
|
||||
|
||||
// mbed Non-hardware components
|
||||
#include "platform/Callback.h"
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2017 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef MBED_DEEPSLEEPLOCK_H
|
||||
#define MBED_DEEPSLEEPLOCK_H
|
||||
|
||||
#include "platform/mbed_sleep.h"
|
||||
|
||||
namespace mbed {
|
||||
|
||||
|
||||
/** RAII object for disabling, then restoring the deep sleep mode
|
||||
* Usage:
|
||||
* @code
|
||||
*
|
||||
* void f() {
|
||||
* // some code here
|
||||
* {
|
||||
* DeepSleepLock lock;
|
||||
* // Code in this block will run with the deep sleep mode locked
|
||||
* }
|
||||
* // deep sleep mode will be restored to their previous state
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
class DeepSleepLock {
|
||||
public:
|
||||
DeepSleepLock()
|
||||
{
|
||||
sleep_manager_lock_deep_sleep();
|
||||
}
|
||||
|
||||
~DeepSleepLock()
|
||||
{
|
||||
sleep_manager_unlock_deep_sleep();
|
||||
}
|
||||
|
||||
/** Mark the start of a locked deep sleep section
|
||||
*/
|
||||
void lock()
|
||||
{
|
||||
sleep_manager_lock_deep_sleep();
|
||||
}
|
||||
|
||||
/** Mark the end of a locked deep sleep section
|
||||
*/
|
||||
void unlock()
|
||||
{
|
||||
sleep_manager_unlock_deep_sleep();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -20,11 +20,87 @@
|
|||
#define MBED_SLEEP_H
|
||||
|
||||
#include "sleep_api.h"
|
||||
#include "mbed_toolchain.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Sleep manager API
|
||||
* The sleep manager provides API to automatically select sleep mode.
|
||||
*
|
||||
* There are two sleep modes:
|
||||
* - sleep
|
||||
* - deepsleep
|
||||
*
|
||||
* Use locking/unlocking deepsleep for drivers that depend on features that
|
||||
* are not allowed (=disabled) during the deepsleep. For instance, high frequency
|
||||
* clocks.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
*
|
||||
* void driver::handler()
|
||||
* {
|
||||
* if (_sensor.get_event()) {
|
||||
* // any event - we are finished, unlock the deepsleep
|
||||
* sleep_manager_unlock_deep_sleep();
|
||||
* _callback();
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* int driver::measure(event_t event, callback_t& callback)
|
||||
* {
|
||||
* _callback = callback;
|
||||
* sleep_manager_lock_deep_sleep();
|
||||
* // start async transaction, we are waiting for an event
|
||||
* return _sensor.start(event, callback);
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
|
||||
/** Lock the deep sleep mode
|
||||
*
|
||||
* This locks the automatic deep mode selection.
|
||||
* sleep_manager_sleep_auto() will ignore deepsleep mode if
|
||||
* this function is invoked at least once (the internal counter is non-zero)
|
||||
*
|
||||
* Use this locking mechanism for interrupt driven API that are
|
||||
* running in the background and deepsleep could affect their functionality
|
||||
*
|
||||
* The lock is a counter, can be locked up to USHRT_MAX
|
||||
* This function is IRQ and thread safe
|
||||
*/
|
||||
void sleep_manager_lock_deep_sleep(void);
|
||||
|
||||
/** Unlock the deep sleep mode
|
||||
*
|
||||
* Use unlocking in pair with sleep_manager_lock_deep_sleep().
|
||||
*
|
||||
* The lock is a counter, should be equally unlocked as locked
|
||||
* This function is IRQ and thread safe
|
||||
*/
|
||||
void sleep_manager_unlock_deep_sleep(void);
|
||||
|
||||
/** Get the status of deep sleep allowance for a target
|
||||
*
|
||||
* @return true if a target can go to deepsleep, false otherwise
|
||||
*/
|
||||
bool sleep_manager_can_deep_sleep(void);
|
||||
|
||||
/** Enter auto selected sleep mode. It chooses the sleep or deeepsleep modes based
|
||||
* on the deepsleep locking counter
|
||||
*
|
||||
* This function is IRQ and thread safe
|
||||
*
|
||||
* @note
|
||||
* If MBED_DEBUG is defined, only hal_sleep is allowed. This ensures the debugger
|
||||
* to be active for debug modes.
|
||||
*
|
||||
*/
|
||||
void sleep_manager_sleep_auto(void);
|
||||
|
||||
/** Send the microcontroller to sleep
|
||||
*
|
||||
* @note This function can be a noop if not implemented by the platform.
|
||||
|
@ -46,11 +122,9 @@ extern "C" {
|
|||
__INLINE static void sleep(void)
|
||||
{
|
||||
#if !(defined(FEATURE_UVISOR) && defined(TARGET_UVISOR_SUPPORTED))
|
||||
#ifndef MBED_DEBUG
|
||||
#if DEVICE_SLEEP
|
||||
hal_sleep();
|
||||
sleep_manager_sleep_auto();
|
||||
#endif /* DEVICE_SLEEP */
|
||||
#endif /* MBED_DEBUG */
|
||||
#endif /* !(defined(FEATURE_UVISOR) && defined(TARGET_UVISOR_SUPPORTED)) */
|
||||
}
|
||||
|
||||
|
@ -60,7 +134,7 @@ __INLINE static void sleep(void)
|
|||
* @note This function will be a noop in debug mode (debug build profile when MBED_DEBUG is defined)
|
||||
* @note This function will be a noop while uVisor is in use.
|
||||
*
|
||||
* This processor is setup ready for deep sleep, and sent to sleep using __WFI(). This mode
|
||||
* This processor is setup ready for deep sleep, and sent to sleep. This mode
|
||||
* has the same sleep features as sleep plus it powers down peripherals and clocks. All state
|
||||
* is still maintained.
|
||||
*
|
||||
|
@ -71,14 +145,14 @@ __INLINE static void sleep(void)
|
|||
* Flash re-programming and the USB serial port will remain active, but the mbed program will no longer be
|
||||
* able to access the LocalFileSystem
|
||||
*/
|
||||
|
||||
MBED_DEPRECATED_SINCE("mbed-os-5.6", "One entry point for an application, use sleep()")
|
||||
__INLINE static void deepsleep(void)
|
||||
{
|
||||
#if !(defined(FEATURE_UVISOR) && defined(TARGET_UVISOR_SUPPORTED))
|
||||
#ifndef MBED_DEBUG
|
||||
#if DEVICE_SLEEP
|
||||
hal_deepsleep();
|
||||
sleep_manager_sleep_auto();
|
||||
#endif /* DEVICE_SLEEP */
|
||||
#endif /* MBED_DEBUG */
|
||||
#endif /* !(defined(FEATURE_UVISOR) && defined(TARGET_UVISOR_SUPPORTED)) */
|
||||
}
|
||||
|
||||
|
|
|
@ -22,14 +22,16 @@
|
|||
|
||||
#include "rtos/rtos_idle.h"
|
||||
#include "platform/mbed_sleep.h"
|
||||
#include "mbed_critical.h"
|
||||
|
||||
static void default_idle_hook(void)
|
||||
{
|
||||
/* Sleep: ideally, we should put the chip to sleep.
|
||||
Unfortunately, this usually requires disconnecting the interface chip (debugger).
|
||||
This can be done, but it would break the local file system.
|
||||
*/
|
||||
// critical section to complete sleep with locked deepsleep
|
||||
core_util_critical_section_enter();
|
||||
sleep_manager_lock_deep_sleep();
|
||||
sleep();
|
||||
sleep_manager_unlock_deep_sleep();
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
static void (*idle_hook_fptr)(void) = &default_idle_hook;
|
||||
|
||||
|
|
Loading…
Reference in New Issue