SHIO

Fork of mbed-stm32l0/l1-src by lzbp li

Revision:
525:c320967f86b9
Parent:
212:34d62c0b2af6
Child:
552:a1b9575155a3
--- a/common/SPI.cpp	Mon Apr 27 09:45:08 2015 +0100
+++ b/common/SPI.cpp	Tue Apr 28 11:45:12 2015 +0100
@@ -19,8 +19,16 @@
 
 namespace mbed {
 
+#if DEVICE_SPI_ASYNCH && TRANSACTION_QUEUE_SIZE_SPI
+CircularBuffer<Transaction<SPI>, TRANSACTION_QUEUE_SIZE_SPI> SPI::_transaction_buffer;
+#endif
+
 SPI::SPI(PinName mosi, PinName miso, PinName sclk, PinName _unused) :
         _spi(),
+#if DEVICE_SPI_ASYNCH
+        _irq(this),
+        _usage(DMA_USAGE_NEVER),
+#endif
         _bits(8),
         _mode(0),
         _hz(1000000) {
@@ -58,6 +66,115 @@
     return spi_master_write(&_spi, value);
 }
 
+#if DEVICE_SPI_ASYNCH
+
+int SPI::transfer(void *tx_buffer, int tx_length, void *rx_buffer, int rx_length, unsigned char bit_width, const event_callback_t& callback, int event)
+{
+    if (spi_active(&_spi)) {
+        return queue_transfer(tx_buffer, tx_length, rx_buffer, rx_length, bit_width, callback, event);
+    }
+    start_transfer(tx_buffer, tx_length, rx_buffer, rx_length, bit_width, callback, event);
+    return 0;
+}
+
+void SPI::abort_transfer()
+{
+    spi_abort_asynch(&_spi);
+#if TRANSACTION_QUEUE_SIZE_SPI
+    dequeue_transaction();
+#endif
+}
+
+
+void SPI::clear_transfer_buffer()
+{
+#if TRANSACTION_QUEUE_SIZE_SPI
+    _transaction_buffer.reset();
+#endif
+}
+
+void SPI::abort_all_transfers()
+{
+    clear_transfer_buffer();
+    abort_transfer();
+}
+
+int SPI::set_dma_usage(DMAUsage usage)
+{
+    if (spi_active(&_spi)) {
+        return -1;
+    }
+    _usage = usage;
+    return  0;
+}
+
+int SPI::queue_transfer(void *tx_buffer, int tx_length, void *rx_buffer, int rx_length, unsigned char bit_width, const event_callback_t& callback, int event)
+{
+#if TRANSACTION_QUEUE_SIZE_SPI
+    transaction_t t;
+
+    t.tx_buffer = tx_buffer;
+    t.tx_length = tx_length;
+    t.rx_buffer = rx_buffer;
+    t.rx_length = rx_length;
+    t.event = event;
+    t.callback = callback;
+    t.width = bit_width;
+    Transaction<SPI> transaction(this, t);
+    if (_transaction_buffer.full()) {
+        return -1; // the buffer is full
+    } else {
+        _transaction_buffer.push(transaction);
+        return 0;
+    }
+#else
+    return -1;
+#endif
+}
+
+void SPI::start_transfer(void *tx_buffer, int tx_length, void *rx_buffer, int rx_length, unsigned char bit_width, const event_callback_t& callback, int event)
+{
+    aquire();
+    _callback = callback;
+    _irq.callback(&SPI::irq_handler_asynch);
+    spi_master_transfer(&_spi, tx_buffer, tx_length, rx_buffer, rx_length, bit_width, _irq.entry(), event , _usage);
+}
+
+#if TRANSACTION_QUEUE_SIZE_SPI
+
+void SPI::start_transaction(transaction_t *data)
+{
+    start_transfer(data->tx_buffer, data->tx_length, data->rx_buffer, data->rx_length, data->width, data->callback, data->event);
+}
+
+void SPI::dequeue_transaction()
+{
+    Transaction<SPI> t;
+    if (_transaction_buffer.pop(t)) {
+        SPI* obj = t.get_object();
+        transaction_t* data = t.get_transaction();
+        obj->start_transaction(data);
+    }
+}
+
+#endif
+
+void SPI::irq_handler_asynch(void)
+{
+    int event = spi_irq_handler_asynch(&_spi);
+    if (_callback && (event & SPI_EVENT_ALL)) {
+        _callback.call(event & SPI_EVENT_ALL);
+    }
+#if TRANSACTION_QUEUE_SIZE_SPI
+    if (event & (SPI_EVENT_ALL | SPI_EVENT_INTERNAL_TRANSFER_COMPLETE)) {
+        // SPI peripheral is free (event happend), dequeue transaction
+        dequeue_transaction();
+    }
+#endif
+}
+
+#endif
+
 } // namespace mbed
 
 #endif