mirror of https://github.com/ARMmbed/mbed-os.git
				
				
				
			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/Timerpull/4912/head
							parent
							
								
									fcdb04351f
								
							
						
					
					
						commit
						e6d8a9a8a4
					
				| 
						 | 
				
			
			@ -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);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			@ -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();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -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();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue