Fix bug allowing SPI::abort_transfer to incorrectly unlock deep sleep mode

- Add flag to SPI class to track if the SPI instance has locked deep sleep mode.
- Wrap call to sleep_manager_lock_deep_sleep to only be called if SPI instance
  hasn't already locked deep sleep.
- Wrap call to sleep_manager_unlock_deep_sleep to only be called if SPI has
  currently locked deep sleep mode.
pull/5722/head
Steven Cartmell 2017-12-18 11:36:30 +00:00
parent c832515274
commit c2670870dc
2 changed files with 29 additions and 3 deletions

View File

@ -33,6 +33,7 @@ SPI::SPI(PinName mosi, PinName miso, PinName sclk, PinName ssel) :
#if DEVICE_SPI_ASYNCH #if DEVICE_SPI_ASYNCH
_irq(this), _irq(this),
_usage(DMA_USAGE_NEVER), _usage(DMA_USAGE_NEVER),
_deep_sleep_locked(false),
#endif #endif
_bits(8), _bits(8),
_mode(0), _mode(0),
@ -140,7 +141,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(); unlock_deep_sleep();
#if TRANSACTION_QUEUE_SIZE_SPI #if TRANSACTION_QUEUE_SIZE_SPI
dequeue_transaction(); dequeue_transaction();
#endif #endif
@ -200,13 +201,29 @@ 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(); lock_deep_sleep();
_acquire(); _acquire();
_callback = callback; _callback = callback;
_irq.callback(&SPI::irq_handler_asynch); _irq.callback(&SPI::irq_handler_asynch);
spi_master_transfer(&_spi, tx_buffer, tx_length, rx_buffer, rx_length, bit_width, _irq.entry(), event , _usage); spi_master_transfer(&_spi, tx_buffer, tx_length, rx_buffer, rx_length, bit_width, _irq.entry(), event , _usage);
} }
void SPI::lock_deep_sleep()
{
if (_deep_sleep_locked == false) {
sleep_manager_lock_deep_sleep();
_deep_sleep_locked = true;
}
}
void SPI::unlock_deep_sleep()
{
if (_deep_sleep_locked == true) {
sleep_manager_unlock_deep_sleep();
_deep_sleep_locked = false;
}
}
#if TRANSACTION_QUEUE_SIZE_SPI #if TRANSACTION_QUEUE_SIZE_SPI
void SPI::start_transaction(transaction_t *data) void SPI::start_transaction(transaction_t *data)
@ -230,7 +247,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(); 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

@ -246,6 +246,14 @@ protected:
*/ */
void 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 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);
private:
/** Lock deep sleep only if it is not yet locked */
void lock_deep_sleep();
/** Unlock deep sleep in case it is locked */
void unlock_deep_sleep();
#if TRANSACTION_QUEUE_SIZE_SPI #if TRANSACTION_QUEUE_SIZE_SPI
/** Start a new transaction /** Start a new transaction
@ -274,6 +282,7 @@ protected:
CThunk<SPI> _irq; CThunk<SPI> _irq;
event_callback_t _callback; event_callback_t _callback;
DMAUsage _usage; DMAUsage _usage;
bool _deep_sleep_locked;
#endif #endif
void aquire(void); void aquire(void);