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
#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<void()> 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);
}

View File

@ -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)
*/

View File

@ -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();
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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<void()> 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

View File

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

View File

@ -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();
}

View File

@ -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<void()> func, us_timestamp_t t) {
_function = func;
sleep_manager_lock_deep_sleep();
setup(t);
}

View File

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

View File

@ -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();
}

View File

@ -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 */