mbed-os5 only for TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Revision:
1:9db0e321a9f4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/source/SPI.cpp	Tue Dec 31 06:02:27 2019 +0000
@@ -0,0 +1,415 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2019 ARM Limited
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "drivers/SPI.h"
+#include "platform/mbed_critical.h"
+
+#if DEVICE_SPI_ASYNCH
+#include "platform/mbed_power_mgmt.h"
+#endif
+
+#if DEVICE_SPI
+
+namespace mbed {
+
+SPI::spi_peripheral_s SPI::_peripherals[SPI_PERIPHERALS_USED];
+int SPI::_peripherals_used;
+
+SPI::SPI(PinName mosi, PinName miso, PinName sclk, PinName ssel) :
+#if DEVICE_SPI_ASYNCH
+    _irq(this),
+#endif
+    _mosi(mosi),
+    _miso(miso),
+    _sclk(sclk),
+    _hw_ssel(ssel),
+    _sw_ssel(NC),
+    _static_pinmap(NULL),
+    _init_func(_do_init)
+{
+    // Need backwards compatibility with HALs not providing API
+#ifdef DEVICE_SPI_COUNT
+    _peripheral_name = spi_get_peripheral_name(_mosi, _miso, _sclk);
+#else
+    _peripheral_name = GlobalSPI;
+#endif
+
+    _do_construct();
+}
+
+SPI::SPI(PinName mosi, PinName miso, PinName sclk, PinName ssel, use_gpio_ssel_t) :
+#if DEVICE_SPI_ASYNCH
+    _irq(this),
+#endif
+    _mosi(mosi),
+    _miso(miso),
+    _sclk(sclk),
+    _hw_ssel(NC),
+    _sw_ssel(ssel, 1),
+    _static_pinmap(NULL),
+    _init_func(_do_init)
+{
+    // Need backwards compatibility with HALs not providing API
+#ifdef DEVICE_SPI_COUNT
+    _peripheral_name = spi_get_peripheral_name(_mosi, _miso, _sclk);
+#else
+    _peripheral_name = GlobalSPI;
+#endif
+    _do_construct();
+}
+
+SPI::SPI(const spi_pinmap_t &pinmap) :
+#if DEVICE_SPI_ASYNCH
+    _irq(this),
+#endif
+    _mosi(pinmap.mosi_pin),
+    _miso(pinmap.miso_pin),
+    _sclk(pinmap.sclk_pin),
+    _hw_ssel(pinmap.ssel_pin),
+    _sw_ssel(NC),
+    _static_pinmap(&pinmap),
+    _peripheral_name((SPIName)pinmap.peripheral),
+    _init_func(_do_init_direct)
+
+{
+    _do_construct();
+}
+
+SPI::SPI(const spi_pinmap_t &pinmap, PinName ssel) :
+#if DEVICE_SPI_ASYNCH
+    _irq(this),
+#endif
+    _mosi(pinmap.mosi_pin),
+    _miso(pinmap.miso_pin),
+    _sclk(pinmap.sclk_pin),
+    _hw_ssel(NC),
+    _sw_ssel(ssel, 1),
+    _static_pinmap(&pinmap),
+    _peripheral_name((SPIName)pinmap.peripheral),
+    _init_func(_do_init_direct)
+{
+    _do_construct();
+}
+
+void SPI::_do_init(SPI *obj)
+{
+    spi_init(&obj->_peripheral->spi, obj->_mosi, obj->_miso, obj->_sclk, obj->_hw_ssel);
+}
+
+void SPI::_do_init_direct(SPI *obj)
+{
+    spi_init_direct(&obj->_peripheral->spi, obj->_static_pinmap);
+}
+
+void SPI::_do_construct()
+{
+    // No lock needed in the constructor
+#if DEVICE_SPI_ASYNCH
+    _usage = DMA_USAGE_NEVER;
+    _deep_sleep_locked = false;
+#endif
+    _select_count = 0;
+    _bits = 8;
+    _mode = 0;
+    _hz = 1000000;
+    _write_fill = SPI_FILL_CHAR;
+
+    core_util_critical_section_enter();
+    // lookup in a critical section if we already have it else initialize it
+
+    _peripheral = SPI::_lookup(_peripheral_name);
+    if (!_peripheral) {
+        _peripheral = SPI::_alloc();
+        _peripheral->name = _peripheral_name;
+    }
+    core_util_critical_section_exit();
+
+#if DEVICE_SPI_ASYNCH && TRANSACTION_QUEUE_SIZE_SPI
+    // prime the SingletonPtr, so we don't have a problem trying to
+    // construct the buffer if asynch operation initiated from IRQ
+    _peripheral->transaction_buffer.get();
+#endif
+    // we don't need to _acquire at this stage.
+    // this will be done anyway before any operation.
+}
+
+SPI::~SPI()
+{
+    lock();
+    /* Make sure a stale pointer isn't left in peripheral's owner field */
+    if (_peripheral->owner == this) {
+        _peripheral->owner = NULL;
+    }
+    unlock();
+}
+
+SPI::spi_peripheral_s *SPI::_lookup(SPI::SPIName name)
+{
+    SPI::spi_peripheral_s *result = NULL;
+    core_util_critical_section_enter();
+    for (int idx = 0; idx < _peripherals_used; idx++) {
+        if (_peripherals[idx].name == name) {
+            result = &_peripherals[idx];
+            break;
+        }
+    }
+    core_util_critical_section_exit();
+    return result;
+}
+
+SPI::spi_peripheral_s *SPI::_alloc()
+{
+    MBED_ASSERT(_peripherals_used < SPI_PERIPHERALS_USED);
+    return &_peripherals[_peripherals_used++];
+}
+
+void SPI::format(int bits, int mode)
+{
+    lock();
+    _bits = bits;
+    _mode = mode;
+    // If changing format while you are the owner then just
+    // update format, but if owner is changed then even frequency should be
+    // updated which is done by acquire.
+    if (_peripheral->owner == this) {
+        spi_format(&_peripheral->spi, _bits, _mode, 0);
+    } else {
+        _acquire();
+    }
+    unlock();
+}
+
+void SPI::frequency(int hz)
+{
+    lock();
+    _hz = hz;
+    // If changing format while you are the owner then just
+    // update frequency, but if owner is changed then even frequency should be
+    // updated which is done by acquire.
+    if (_peripheral->owner == this) {
+        spi_frequency(&_peripheral->spi, _hz);
+    } else {
+        _acquire();
+    }
+    unlock();
+}
+
+// Note: Private function with no locking
+void SPI::_acquire()
+{
+    if (_peripheral->owner != this) {
+        _init_func(this);
+        spi_format(&_peripheral->spi, _bits, _mode, 0);
+        spi_frequency(&_peripheral->spi, _hz);
+        _peripheral->owner = this;
+    }
+}
+
+int SPI::write(int value)
+{
+    select();
+    int ret = spi_master_write(&_peripheral->spi, value);
+    deselect();
+    return ret;
+}
+
+int SPI::write(const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length)
+{
+    select();
+    int ret = spi_master_block_write(&_peripheral->spi, tx_buffer, tx_length, rx_buffer, rx_length, _write_fill);
+    deselect();
+    return ret;
+}
+
+void SPI::_set_ssel(int val)
+{
+    if (_sw_ssel.is_connected()) {
+        _sw_ssel = val;
+    }
+}
+
+void SPI::lock()
+{
+    _peripheral->mutex->lock();
+}
+
+void SPI::select()
+{
+    lock();
+    if (_select_count++ == 0) {
+        _acquire();
+        _set_ssel(0);
+    }
+}
+
+void SPI::unlock()
+{
+    _peripheral->mutex->unlock();
+}
+
+void SPI::deselect()
+{
+    if (--_select_count == 0) {
+        _set_ssel(1);
+    }
+    unlock();
+}
+
+void SPI::set_default_write_value(char data)
+{
+    // this does not actually need to lock the peripheral.
+    lock();
+    _write_fill = data;
+    unlock();
+}
+
+#if DEVICE_SPI_ASYNCH
+
+int SPI::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)
+{
+    if (spi_active(&_peripheral->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(&_peripheral->spi);
+    unlock_deep_sleep();
+#if TRANSACTION_QUEUE_SIZE_SPI
+    dequeue_transaction();
+#endif
+}
+
+void SPI::clear_transfer_buffer()
+{
+#if TRANSACTION_QUEUE_SIZE_SPI
+    _peripheral->transaction_buffer->reset();
+#endif
+}
+
+void SPI::abort_all_transfers()
+{
+    clear_transfer_buffer();
+    abort_transfer();
+}
+
+int SPI::set_dma_usage(DMAUsage usage)
+{
+    if (spi_active(&_peripheral->spi)) {
+        return -1;
+    }
+    _usage = usage;
+    return  0;
+}
+
+int SPI::queue_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)
+{
+#if TRANSACTION_QUEUE_SIZE_SPI
+    transaction_t t;
+
+    t.tx_buffer = const_cast<void *>(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 (_peripheral->transaction_buffer->full()) {
+        return -1; // the buffer is full
+    } else {
+        core_util_critical_section_enter();
+        _peripheral->transaction_buffer->push(transaction);
+        if (!spi_active(&_peripheral->spi)) {
+            dequeue_transaction();
+        }
+        core_util_critical_section_exit();
+        return 0;
+    }
+#else
+    return -1;
+#endif
+}
+
+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)
+{
+    lock_deep_sleep();
+    _acquire();
+    _set_ssel(0);
+    _callback = callback;
+    _irq.callback(&SPI::irq_handler_asynch);
+    spi_master_transfer(&_peripheral->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
+
+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 (_peripheral->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(&_peripheral->spi);
+    if (_callback && (event & SPI_EVENT_ALL)) {
+        _set_ssel(1);
+        unlock_deep_sleep();
+        _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 happened), dequeue transaction
+        dequeue_transaction();
+    }
+#endif
+}
+
+#endif
+
+} // namespace mbed
+
+#endif