Skip to content

Add tickless feature #4943

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions TESTS/mbedmicro-rtos-mbed/idle_loop/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright (c) 2017, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* 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.h"
#include "rtos.h"
#include "greentea-client/test_env.h"
#include "unity/unity.h"
#include "utest/utest.h"

using namespace utest::v1;


void idle_loop_test_only_sleep()
{
LowPowerTimer timer;
timestamp_t start = timer.read_us();
sleep_manager_lock_deep_sleep();
TEST_ASSERT_FALSE(sleep_manager_can_deep_sleep());
// idle loop for 5 seconds to test if we wake up
wait(5);
timestamp_t end = timer.read_us();
TEST_ASSERT_UINT32_WITHIN(100, 5000000, end - start);
sleep_manager_unlock_deep_sleep();
}

void idle_loop_test_deep_sleep()
{
LowPowerTimer timer;
timestamp_t start = timer.read_us();
TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep());
// idle loop for 5 seconds to test if we wake up
wait(5);
timestamp_t end = timer.read_us();
TEST_ASSERT_UINT32_WITHIN(10000, 5000000, end - start);
}

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;
}

Case cases[] = {
Case("Idle loop - sleep only", idle_loop_test_only_sleep, greentea_failure_handler),
Case("Idle loop - deep sleep", idle_loop_test_deep_sleep, greentea_failure_handler)
};

utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(25, "default_auto");
return greentea_test_setup_handler(number_of_cases);
}

Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);

int main() {
Harness::run(specification);
}

8 changes: 8 additions & 0 deletions drivers/CAN.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,17 @@ 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] == callback(donothing)) {
sleep_manager_lock_deep_sleep();
}
_irq[(CanIrqType)type] = func;
can_irq_set(&_can, (CanIrqType)type, 1);
} else {
// unlock deep sleep only the first time
if (_irq[(CanIrqType)type] != callback(donothing)) {
sleep_manager_unlock_deep_sleep();
}
_irq[(CanIrqType)type] = callback(donothing);
can_irq_set(&_can, (CanIrqType)type, 0);
}
Expand Down
5 changes: 4 additions & 1 deletion drivers/CAN.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "platform/Callback.h"
#include "platform/PlatformMutex.h"
#include "platform/NonCopyable.h"
#include "platform/mbed_sleep.h"

namespace mbed {
/** \addtogroup drivers */
Expand Down Expand Up @@ -235,7 +236,9 @@ class CAN : private NonCopyable<CAN> {

/** 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)
*/
Expand Down
5 changes: 5 additions & 0 deletions drivers/I2C.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,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;
Expand All @@ -143,6 +144,7 @@ void I2C::abort_transfer(void)
{
lock();
i2c_abort_asynch(&_i2c);
sleep_manager_unlock_deep_sleep();
unlock();
}

Expand All @@ -152,6 +154,9 @@ void I2C::irq_handler_asynch(void)
if (_callback && event) {
_callback.call(event);
}
if (event) {
sleep_manager_unlock_deep_sleep();
}

}

Expand Down
3 changes: 3 additions & 0 deletions drivers/I2C.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "platform/CThunk.h"
#include "hal/dma_api.h"
#include "platform/FunctionPointer.h"
#include "platform/mbed_sleep.h"
#endif

namespace mbed {
Expand Down Expand Up @@ -159,6 +160,8 @@ class I2C : private NonCopyable<I2C> {

/** 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
Expand Down
3 changes: 3 additions & 0 deletions drivers/SPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,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
Expand Down Expand Up @@ -195,6 +196,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);
Expand Down Expand Up @@ -224,6 +226,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
Expand Down
3 changes: 3 additions & 0 deletions drivers/SPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "platform/CircularBuffer.h"
#include "platform/FunctionPointer.h"
#include "platform/Transaction.h"
#include "platform/mbed_sleep.h"
#endif

namespace mbed {
Expand Down Expand Up @@ -156,6 +157,8 @@ class SPI : private NonCopyable<SPI> {

/** 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
Expand Down
33 changes: 32 additions & 1 deletion drivers/SerialBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,14 @@
namespace mbed {

static void donothing() {};
static void donothing2(int arg) {};


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(donothing2),
_rx_callback(donothing2),
#endif
_serial(), _baud(baud) {
// No lock needed in the constructor
Expand Down Expand Up @@ -73,9 +76,17 @@ 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] == donothing) {
sleep_manager_lock_deep_sleep();
}
_irq[type] = func;
serial_irq_set(&_serial, (SerialIrq)type, 1);
} else {
// unlock deep sleep only the first time
if (_irq[type] != donothing) {
sleep_manager_unlock_deep_sleep();
}
_irq[type] = donothing;
serial_irq_set(&_serial, (SerialIrq)type, 0);
}
Expand Down Expand Up @@ -173,16 +184,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 == &donothing2) {
sleep_manager_unlock_deep_sleep();
}
_tx_callback = donothing2;
serial_tx_abort_asynch(&_serial);
}

void SerialBase::abort_read(void)
{
// tx might still be active
if (_tx_callback == &donothing2) {
sleep_manager_unlock_deep_sleep();
}
_rx_callback = donothing2;
serial_rx_abort_asynch(&_serial);
}

Expand Down Expand Up @@ -228,21 +250,30 @@ 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);
}

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
Expand Down
13 changes: 11 additions & 2 deletions drivers/SerialBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "serial_api.h"
#include "mbed_toolchain.h"
#include "platform/NonCopyable.h"
#include "platform/mbed_sleep.h"

#if DEVICE_SERIAL_ASYNCH
#include "CThunk.h"
Expand Down Expand Up @@ -167,6 +168,8 @@ class SerialBase : private NonCopyable<SerialBase> {

/** 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
Expand All @@ -176,6 +179,8 @@ class SerialBase : private NonCopyable<SerialBase> {

/** 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
Expand All @@ -189,6 +194,8 @@ class SerialBase : private NonCopyable<SerialBase> {

/** 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
Expand All @@ -199,6 +206,8 @@ class SerialBase : private NonCopyable<SerialBase> {

/** 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
Expand Down Expand Up @@ -241,10 +250,10 @@ class SerialBase : private NonCopyable<SerialBase> {

#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;
Expand Down
4 changes: 4 additions & 0 deletions drivers/Ticker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down
9 changes: 7 additions & 2 deletions drivers/Ticker.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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();
}

Expand Down Expand Up @@ -102,6 +103,10 @@ class Ticker : public TimerEvent, private NonCopyable<Ticker> {
* @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);
}
Expand Down
1 change: 1 addition & 0 deletions drivers/Timeout.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#include "drivers/Ticker.h"
#include "platform/NonCopyable.h"
#include "platform/mbed_sleep.h"

namespace mbed {
/** \addtogroup drivers */
Expand Down
Loading