Drivers with interrupts: adding sleep deep locking

Any driver with attach or async API should be considered for deep sleep.

Add locking to those that require in most cases
high-frequency clocks:

- CAN
- I2C
- SPI
- Serial
- Ticker/Timeout/Timer
pull/4912/head
Martin Kojtal 2017-08-14 16:25:31 +01:00
parent fcdb04351f
commit e6d8a9a8a4
13 changed files with 69 additions and 4 deletions

View File

@ -18,6 +18,7 @@
#if DEVICE_CAN #if DEVICE_CAN
#include "cmsis.h" #include "cmsis.h"
#include "platform/mbed_sleep.h"
namespace mbed { namespace mbed {
@ -115,9 +116,11 @@ int CAN::filter(unsigned int id, unsigned int mask, CANFormat format, int handle
void CAN::attach(Callback<void()> func, IrqType type) { void CAN::attach(Callback<void()> func, IrqType type) {
lock(); lock();
if (func) { if (func) {
sleep_manager_lock_deep_sleep();
_irq[(CanIrqType)type] = func; _irq[(CanIrqType)type] = func;
can_irq_set(&_can, (CanIrqType)type, 1); can_irq_set(&_can, (CanIrqType)type, 1);
} else { } else {
sleep_manager_unlock_deep_sleep();
_irq[(CanIrqType)type] = callback(donothing); _irq[(CanIrqType)type] = callback(donothing);
can_irq_set(&_can, (CanIrqType)type, 0); can_irq_set(&_can, (CanIrqType)type, 0);
} }

View File

@ -235,7 +235,9 @@ public:
/** Attach a function to call whenever a CAN frame received interrupt is /** Attach a function to call whenever a CAN frame received interrupt is
* generated. * 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 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) * @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)
*/ */

View File

@ -17,6 +17,10 @@
#if DEVICE_I2C #if DEVICE_I2C
#if DEVICE_I2C_ASYNCH
#include "platform/mbed_sleep.h"
#endif
namespace mbed { namespace mbed {
I2C *I2C::_owner = NULL; I2C *I2C::_owner = NULL;
@ -125,6 +129,7 @@ void I2C::unlock() {
int I2C::transfer(int address, const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length, const event_callback_t& callback, int event, bool repeated) int I2C::transfer(int address, const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length, const event_callback_t& callback, int event, bool repeated)
{ {
lock(); lock();
sleep_manager_lock_deep_sleep();
if (i2c_active(&_i2c)) { if (i2c_active(&_i2c)) {
unlock(); unlock();
return -1; // transaction ongoing return -1; // transaction ongoing
@ -143,6 +148,7 @@ void I2C::abort_transfer(void)
{ {
lock(); lock();
i2c_abort_asynch(&_i2c); i2c_abort_asynch(&_i2c);
sleep_manager_unlock_deep_sleep();
unlock(); unlock();
} }
@ -152,6 +158,9 @@ void I2C::irq_handler_asynch(void)
if (_callback && event) { if (_callback && event) {
_callback.call(event); _callback.call(event);
} }
if (event) {
sleep_manager_unlock_deep_sleep();
}
} }

View File

@ -159,6 +159,8 @@ public:
/** Start non-blocking I2C transfer. /** 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 address 8/10 bit I2c slave address
* @param tx_buffer The TX buffer with data to be transfered * @param tx_buffer The TX buffer with data to be transfered
* @param tx_length The length of TX buffer in bytes * @param tx_length The length of TX buffer in bytes

View File

@ -16,6 +16,10 @@
#include "drivers/SPI.h" #include "drivers/SPI.h"
#include "platform/mbed_critical.h" #include "platform/mbed_critical.h"
#if DEVICE_SPI_ASYNCH
#include "platform/mbed_sleep.h"
#endif
#if DEVICE_SPI #if DEVICE_SPI
namespace mbed { 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() void SPI::abort_transfer()
{ {
spi_abort_asynch(&_spi); spi_abort_asynch(&_spi);
sleep_manager_unlock_deep_sleep();
#if TRANSACTION_QUEUE_SIZE_SPI #if TRANSACTION_QUEUE_SIZE_SPI
dequeue_transaction(); dequeue_transaction();
#endif #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) 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(); _acquire();
_callback = callback; _callback = callback;
_irq.callback(&SPI::irq_handler_asynch); _irq.callback(&SPI::irq_handler_asynch);
@ -224,6 +230,7 @@ void SPI::irq_handler_asynch(void)
{ {
int event = spi_irq_handler_asynch(&_spi); int event = spi_irq_handler_asynch(&_spi);
if (_callback && (event & SPI_EVENT_ALL)) { if (_callback && (event & SPI_EVENT_ALL)) {
sleep_manager_unlock_deep_sleep();
_callback.call(event & SPI_EVENT_ALL); _callback.call(event & SPI_EVENT_ALL);
} }
#if TRANSACTION_QUEUE_SIZE_SPI #if TRANSACTION_QUEUE_SIZE_SPI

View File

@ -156,6 +156,8 @@ public:
/** Start non-blocking SPI transfer using 8bit buffers. /** 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, * @param tx_buffer The TX buffer with data to be transfered. If NULL is passed,
* the default SPI value is sent * the default SPI value is sent
* @param tx_length The length of TX buffer in bytes * @param tx_length The length of TX buffer in bytes

View File

@ -16,17 +16,21 @@
#include "drivers/SerialBase.h" #include "drivers/SerialBase.h"
#include "platform/mbed_wait_api.h" #include "platform/mbed_wait_api.h"
#include "platform/mbed_critical.h" #include "platform/mbed_critical.h"
#include "platform/mbed_sleep.h"
#if DEVICE_SERIAL #if DEVICE_SERIAL
namespace mbed { namespace mbed {
static void donothing() {}; static void donothing() {};
static void donothing2(int arg) {};
SerialBase::SerialBase(PinName tx, PinName rx, int baud) : SerialBase::SerialBase(PinName tx, PinName rx, int baud) :
#if DEVICE_SERIAL_ASYNCH #if DEVICE_SERIAL_ASYNCH
_thunk_irq(this), _tx_usage(DMA_USAGE_NEVER), _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 #endif
_serial(), _baud(baud) { _serial(), _baud(baud) {
// No lock needed in the constructor // No lock needed in the constructor
@ -73,9 +77,11 @@ void SerialBase::attach(Callback<void()> func, IrqType type) {
// Disable interrupts when attaching interrupt handler // Disable interrupts when attaching interrupt handler
core_util_critical_section_enter(); core_util_critical_section_enter();
if (func) { if (func) {
sleep_manager_lock_deep_sleep();
_irq[type] = func; _irq[type] = func;
serial_irq_set(&_serial, (SerialIrq)type, 1); serial_irq_set(&_serial, (SerialIrq)type, 1);
} else { } else {
sleep_manager_unlock_deep_sleep();
_irq[type] = donothing; _irq[type] = donothing;
serial_irq_set(&_serial, (SerialIrq)type, 0); serial_irq_set(&_serial, (SerialIrq)type, 0);
} }
@ -173,16 +179,27 @@ void SerialBase::start_write(const void *buffer, int buffer_size, char buffer_wi
_tx_callback = callback; _tx_callback = callback;
_thunk_irq.callback(&SerialBase::interrupt_handler_asynch); _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); serial_tx_asynch(&_serial, buffer, buffer_size, buffer_width, _thunk_irq.entry(), event, _tx_usage);
} }
void SerialBase::abort_write(void) 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); serial_tx_abort_asynch(&_serial);
} }
void SerialBase::abort_read(void) 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); serial_rx_abort_asynch(&_serial);
} }
@ -235,14 +252,22 @@ void SerialBase::interrupt_handler_asynch(void)
{ {
int event = serial_irq_handler_asynch(&_serial); int event = serial_irq_handler_asynch(&_serial);
int rx_event = event & SERIAL_EVENT_RX_MASK; int rx_event = event & SERIAL_EVENT_RX_MASK;
bool unlock_deepsleep = false;
if (_rx_callback && rx_event) { if (_rx_callback && rx_event) {
unlock_deepsleep = true;
_rx_callback.call(rx_event); _rx_callback.call(rx_event);
} }
int tx_event = event & SERIAL_EVENT_TX_MASK; int tx_event = event & SERIAL_EVENT_TX_MASK;
if (_tx_callback && tx_event) { if (_tx_callback && tx_event) {
unlock_deepsleep = true;
_tx_callback.call(tx_event); _tx_callback.call(tx_event);
} }
// unlock if tx or rx events are generated
if (unlock_deepsleep) {
sleep_manager_unlock_deep_sleep();
}
} }
#endif #endif

View File

@ -167,6 +167,8 @@ public:
/** Begin asynchronous write using 8bit buffer. The completition invokes registered TX event callback /** 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 buffer The buffer where received data will be stored
* @param length The buffer length in bytes * @param length The buffer length in bytes
* @param callback The event callback function * @param callback The event callback function
@ -176,6 +178,8 @@ public:
/** Begin asynchronous write using 16bit buffer. The completition invokes registered TX event callback /** 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 buffer The buffer where received data will be stored
* @param length The buffer length in bytes * @param length The buffer length in bytes
* @param callback The event callback function * @param callback The event callback function
@ -189,6 +193,8 @@ public:
/** Begin asynchronous reading using 8bit buffer. The completition invokes registred RX event callback. /** 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 buffer The buffer where received data will be stored
* @param length The buffer length in bytes * @param length The buffer length in bytes
* @param callback The event callback function * @param callback The event callback function
@ -199,6 +205,8 @@ public:
/** Begin asynchronous reading using 16bit buffer. The completition invokes registred RX event callback. /** 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 buffer The buffer where received data will be stored
* @param length The buffer length in bytes * @param length The buffer length in bytes
* @param callback The event callback function * @param callback The event callback function
@ -241,10 +249,10 @@ protected:
#if DEVICE_SERIAL_ASYNCH #if DEVICE_SERIAL_ASYNCH
CThunk<SerialBase> _thunk_irq; CThunk<SerialBase> _thunk_irq;
event_callback_t _tx_callback;
event_callback_t _rx_callback;
DMAUsage _tx_usage; DMAUsage _tx_usage;
DMAUsage _rx_usage; DMAUsage _rx_usage;
event_callback_t _tx_callback;
event_callback_t _rx_callback;
#endif #endif
serial_t _serial; serial_t _serial;

View File

@ -26,6 +26,7 @@ void Ticker::detach() {
core_util_critical_section_enter(); core_util_critical_section_enter();
remove(); remove();
_function = 0; _function = 0;
sleep_manager_unlock_deep_sleep();
core_util_critical_section_exit(); core_util_critical_section_exit();
} }

View File

@ -20,6 +20,7 @@
#include "platform/Callback.h" #include "platform/Callback.h"
#include "platform/mbed_toolchain.h" #include "platform/mbed_toolchain.h"
#include "platform/NonCopyable.h" #include "platform/NonCopyable.h"
#include "platform/mbed_sleep.h"
namespace mbed { namespace mbed {
/** \addtogroup drivers */ /** \addtogroup drivers */
@ -103,6 +104,7 @@ public:
*/ */
void attach_us(Callback<void()> func, us_timestamp_t t) { void attach_us(Callback<void()> func, us_timestamp_t t) {
_function = func; _function = func;
sleep_manager_lock_deep_sleep();
setup(t); setup(t);
} }

View File

@ -18,6 +18,7 @@
#include "drivers/Ticker.h" #include "drivers/Ticker.h"
#include "platform/NonCopyable.h" #include "platform/NonCopyable.h"
#include "platform/mbed_sleep.h"
namespace mbed { namespace mbed {
/** \addtogroup drivers */ /** \addtogroup drivers */

View File

@ -31,6 +31,7 @@ Timer::Timer(const ticker_data_t *data) : _running(), _start(), _time(), _ticker
void Timer::start() { void Timer::start() {
core_util_critical_section_enter(); core_util_critical_section_enter();
if (!_running) { if (!_running) {
sleep_manager_lock_deep_sleep();
_start = ticker_read_us(_ticker_data); _start = ticker_read_us(_ticker_data);
_running = 1; _running = 1;
} }
@ -41,6 +42,7 @@ void Timer::stop() {
core_util_critical_section_enter(); core_util_critical_section_enter();
_time += slicetime(); _time += slicetime();
_running = 0; _running = 0;
sleep_manager_unlock_deep_sleep();
core_util_critical_section_exit(); core_util_critical_section_exit();
} }

View File

@ -19,6 +19,7 @@
#include "platform/platform.h" #include "platform/platform.h"
#include "hal/ticker_api.h" #include "hal/ticker_api.h"
#include "platform/NonCopyable.h" #include "platform/NonCopyable.h"
#include "platform/mbed_sleep.h"
namespace mbed { namespace mbed {
/** \addtogroup drivers */ /** \addtogroup drivers */