From e6d8a9a8a4729c5abf6312f5404d8769e55c0736 Mon Sep 17 00:00:00 2001 From: Martin Kojtal <0xc0170@gmail.com> Date: Mon, 14 Aug 2017 16:25:31 +0100 Subject: [PATCH] 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 --- drivers/CAN.cpp | 3 +++ drivers/CAN.h | 4 +++- drivers/I2C.cpp | 9 +++++++++ drivers/I2C.h | 2 ++ drivers/SPI.cpp | 7 +++++++ drivers/SPI.h | 2 ++ drivers/SerialBase.cpp | 27 ++++++++++++++++++++++++++- drivers/SerialBase.h | 12 ++++++++++-- drivers/Ticker.cpp | 1 + drivers/Ticker.h | 2 ++ drivers/Timeout.h | 1 + drivers/Timer.cpp | 2 ++ drivers/Timer.h | 1 + 13 files changed, 69 insertions(+), 4 deletions(-) diff --git a/drivers/CAN.cpp b/drivers/CAN.cpp index 37fdf2ec22..2169021a4e 100644 --- a/drivers/CAN.cpp +++ b/drivers/CAN.cpp @@ -18,6 +18,7 @@ #if DEVICE_CAN #include "cmsis.h" +#include "platform/mbed_sleep.h" namespace mbed { @@ -115,9 +116,11 @@ int CAN::filter(unsigned int id, unsigned int mask, CANFormat format, int handle void CAN::attach(Callback func, IrqType type) { lock(); if (func) { + sleep_manager_lock_deep_sleep(); _irq[(CanIrqType)type] = func; can_irq_set(&_can, (CanIrqType)type, 1); } else { + sleep_manager_unlock_deep_sleep(); _irq[(CanIrqType)type] = callback(donothing); can_irq_set(&_can, (CanIrqType)type, 0); } diff --git a/drivers/CAN.h b/drivers/CAN.h index 65a7be8c02..668e32c256 100644 --- a/drivers/CAN.h +++ b/drivers/CAN.h @@ -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) */ diff --git a/drivers/I2C.cpp b/drivers/I2C.cpp index c1db1d351f..6f9bd0b027 100644 --- a/drivers/I2C.cpp +++ b/drivers/I2C.cpp @@ -17,6 +17,10 @@ #if DEVICE_I2C +#if DEVICE_I2C_ASYNCH +#include "platform/mbed_sleep.h" +#endif + namespace mbed { 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) { lock(); + sleep_manager_lock_deep_sleep(); if (i2c_active(&_i2c)) { unlock(); return -1; // transaction ongoing @@ -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(); + } } diff --git a/drivers/I2C.h b/drivers/I2C.h index b2e4eac60d..b4fbc2f093 100644 --- a/drivers/I2C.h +++ b/drivers/I2C.h @@ -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 diff --git a/drivers/SPI.cpp b/drivers/SPI.cpp index fc3764e241..9b2209b0fe 100644 --- a/drivers/SPI.cpp +++ b/drivers/SPI.cpp @@ -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 diff --git a/drivers/SPI.h b/drivers/SPI.h index 645243070d..e312dcc7b3 100644 --- a/drivers/SPI.h +++ b/drivers/SPI.h @@ -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 diff --git a/drivers/SerialBase.cpp b/drivers/SerialBase.cpp index 2c4cb7ae04..17c8bd61e4 100644 --- a/drivers/SerialBase.cpp +++ b/drivers/SerialBase.cpp @@ -16,17 +16,21 @@ #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() {}; +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 @@ -73,9 +77,11 @@ void SerialBase::attach(Callback func, IrqType type) { // Disable interrupts when attaching interrupt handler core_util_critical_section_enter(); if (func) { + sleep_manager_lock_deep_sleep(); _irq[type] = func; serial_irq_set(&_serial, (SerialIrq)type, 1); } else { + sleep_manager_unlock_deep_sleep(); _irq[type] = donothing; 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; _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); } @@ -235,14 +252,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 diff --git a/drivers/SerialBase.h b/drivers/SerialBase.h index 6723f6a2ee..835e1a33b1 100644 --- a/drivers/SerialBase.h +++ b/drivers/SerialBase.h @@ -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 _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; diff --git a/drivers/Ticker.cpp b/drivers/Ticker.cpp index 0b4048a37b..e49e5d2526 100644 --- a/drivers/Ticker.cpp +++ b/drivers/Ticker.cpp @@ -26,6 +26,7 @@ void Ticker::detach() { core_util_critical_section_enter(); remove(); _function = 0; + sleep_manager_unlock_deep_sleep(); core_util_critical_section_exit(); } diff --git a/drivers/Ticker.h b/drivers/Ticker.h index 917eb7c84b..2c60e043cd 100644 --- a/drivers/Ticker.h +++ b/drivers/Ticker.h @@ -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 */ @@ -103,6 +104,7 @@ public: */ void attach_us(Callback func, us_timestamp_t t) { _function = func; + sleep_manager_lock_deep_sleep(); setup(t); } diff --git a/drivers/Timeout.h b/drivers/Timeout.h index b0508d7b88..8d9a19327e 100644 --- a/drivers/Timeout.h +++ b/drivers/Timeout.h @@ -18,6 +18,7 @@ #include "drivers/Ticker.h" #include "platform/NonCopyable.h" +#include "platform/mbed_sleep.h" namespace mbed { /** \addtogroup drivers */ diff --git a/drivers/Timer.cpp b/drivers/Timer.cpp index 3951c3d501..392744e565 100644 --- a/drivers/Timer.cpp +++ b/drivers/Timer.cpp @@ -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; } @@ -41,6 +42,7 @@ void Timer::stop() { core_util_critical_section_enter(); _time += slicetime(); _running = 0; + sleep_manager_unlock_deep_sleep(); core_util_critical_section_exit(); } diff --git a/drivers/Timer.h b/drivers/Timer.h index 50c47d387b..e353720b96 100644 --- a/drivers/Timer.h +++ b/drivers/Timer.h @@ -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 */