inport from local

Dependents:   Hobbyking_Cheetah_0511

Committer:
NYX
Date:
Mon Mar 16 06:35:48 2020 +0000
Revision:
0:85b3fd62ea1a
reinport to mbed;

Who changed what in which revision?

UserRevisionLine numberNew contents of line
NYX 0:85b3fd62ea1a 1 /* mbed Microcontroller Library
NYX 0:85b3fd62ea1a 2 * Copyright (c) 2006-2013 ARM Limited
NYX 0:85b3fd62ea1a 3 *
NYX 0:85b3fd62ea1a 4 * Licensed under the Apache License, Version 2.0 (the "License");
NYX 0:85b3fd62ea1a 5 * you may not use this file except in compliance with the License.
NYX 0:85b3fd62ea1a 6 * You may obtain a copy of the License at
NYX 0:85b3fd62ea1a 7 *
NYX 0:85b3fd62ea1a 8 * http://www.apache.org/licenses/LICENSE-2.0
NYX 0:85b3fd62ea1a 9 *
NYX 0:85b3fd62ea1a 10 * Unless required by applicable law or agreed to in writing, software
NYX 0:85b3fd62ea1a 11 * distributed under the License is distributed on an "AS IS" BASIS,
NYX 0:85b3fd62ea1a 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
NYX 0:85b3fd62ea1a 13 * See the License for the specific language governing permissions and
NYX 0:85b3fd62ea1a 14 * limitations under the License.
NYX 0:85b3fd62ea1a 15 */
NYX 0:85b3fd62ea1a 16 #include "drivers/SPI.h"
NYX 0:85b3fd62ea1a 17 #include "platform/mbed_critical.h"
NYX 0:85b3fd62ea1a 18
NYX 0:85b3fd62ea1a 19 #if DEVICE_SPI_ASYNCH
NYX 0:85b3fd62ea1a 20 #include "platform/mbed_sleep.h"
NYX 0:85b3fd62ea1a 21 #endif
NYX 0:85b3fd62ea1a 22
NYX 0:85b3fd62ea1a 23 #if DEVICE_SPI
NYX 0:85b3fd62ea1a 24
NYX 0:85b3fd62ea1a 25 namespace mbed {
NYX 0:85b3fd62ea1a 26
NYX 0:85b3fd62ea1a 27 #if DEVICE_SPI_ASYNCH && TRANSACTION_QUEUE_SIZE_SPI
NYX 0:85b3fd62ea1a 28 CircularBuffer<Transaction<SPI>, TRANSACTION_QUEUE_SIZE_SPI> SPI::_transaction_buffer;
NYX 0:85b3fd62ea1a 29 #endif
NYX 0:85b3fd62ea1a 30
NYX 0:85b3fd62ea1a 31 SPI::SPI(PinName mosi, PinName miso, PinName sclk, PinName ssel) :
NYX 0:85b3fd62ea1a 32 _spi(),
NYX 0:85b3fd62ea1a 33 #if DEVICE_SPI_ASYNCH
NYX 0:85b3fd62ea1a 34 _irq(this),
NYX 0:85b3fd62ea1a 35 _usage(DMA_USAGE_NEVER),
NYX 0:85b3fd62ea1a 36 #endif
NYX 0:85b3fd62ea1a 37 _bits(8),
NYX 0:85b3fd62ea1a 38 _mode(0),
NYX 0:85b3fd62ea1a 39 _hz(1000000),
NYX 0:85b3fd62ea1a 40 _write_fill(SPI_FILL_CHAR) {
NYX 0:85b3fd62ea1a 41 // No lock needed in the constructor
NYX 0:85b3fd62ea1a 42
NYX 0:85b3fd62ea1a 43 spi_init(&_spi, mosi, miso, sclk, ssel);
NYX 0:85b3fd62ea1a 44 _acquire();
NYX 0:85b3fd62ea1a 45 }
NYX 0:85b3fd62ea1a 46
NYX 0:85b3fd62ea1a 47 void SPI::format(int bits, int mode) {
NYX 0:85b3fd62ea1a 48 lock();
NYX 0:85b3fd62ea1a 49 _bits = bits;
NYX 0:85b3fd62ea1a 50 _mode = mode;
NYX 0:85b3fd62ea1a 51 // If changing format while you are the owner than just
NYX 0:85b3fd62ea1a 52 // update format, but if owner is changed than even frequency should be
NYX 0:85b3fd62ea1a 53 // updated which is done by acquire.
NYX 0:85b3fd62ea1a 54 if (_owner == this) {
NYX 0:85b3fd62ea1a 55 spi_format(&_spi, _bits, _mode, 0);
NYX 0:85b3fd62ea1a 56 } else {
NYX 0:85b3fd62ea1a 57 _acquire();
NYX 0:85b3fd62ea1a 58 }
NYX 0:85b3fd62ea1a 59 unlock();
NYX 0:85b3fd62ea1a 60 }
NYX 0:85b3fd62ea1a 61
NYX 0:85b3fd62ea1a 62 void SPI::frequency(int hz) {
NYX 0:85b3fd62ea1a 63 lock();
NYX 0:85b3fd62ea1a 64 _hz = hz;
NYX 0:85b3fd62ea1a 65 // If changing format while you are the owner than just
NYX 0:85b3fd62ea1a 66 // update frequency, but if owner is changed than even frequency should be
NYX 0:85b3fd62ea1a 67 // updated which is done by acquire.
NYX 0:85b3fd62ea1a 68 if (_owner == this) {
NYX 0:85b3fd62ea1a 69 spi_frequency(&_spi, _hz);
NYX 0:85b3fd62ea1a 70 } else {
NYX 0:85b3fd62ea1a 71 _acquire();
NYX 0:85b3fd62ea1a 72 }
NYX 0:85b3fd62ea1a 73 unlock();
NYX 0:85b3fd62ea1a 74 }
NYX 0:85b3fd62ea1a 75
NYX 0:85b3fd62ea1a 76 SPI* SPI::_owner = NULL;
NYX 0:85b3fd62ea1a 77 SingletonPtr<PlatformMutex> SPI::_mutex;
NYX 0:85b3fd62ea1a 78
NYX 0:85b3fd62ea1a 79 // ignore the fact there are multiple physical spis, and always update if it wasnt us last
NYX 0:85b3fd62ea1a 80 void SPI::aquire() {
NYX 0:85b3fd62ea1a 81 lock();
NYX 0:85b3fd62ea1a 82 if (_owner != this) {
NYX 0:85b3fd62ea1a 83 spi_format(&_spi, _bits, _mode, 0);
NYX 0:85b3fd62ea1a 84 spi_frequency(&_spi, _hz);
NYX 0:85b3fd62ea1a 85 _owner = this;
NYX 0:85b3fd62ea1a 86 }
NYX 0:85b3fd62ea1a 87 unlock();
NYX 0:85b3fd62ea1a 88 }
NYX 0:85b3fd62ea1a 89
NYX 0:85b3fd62ea1a 90 // Note: Private function with no locking
NYX 0:85b3fd62ea1a 91 void SPI::_acquire() {
NYX 0:85b3fd62ea1a 92 if (_owner != this) {
NYX 0:85b3fd62ea1a 93 spi_format(&_spi, _bits, _mode, 0);
NYX 0:85b3fd62ea1a 94 spi_frequency(&_spi, _hz);
NYX 0:85b3fd62ea1a 95 _owner = this;
NYX 0:85b3fd62ea1a 96 }
NYX 0:85b3fd62ea1a 97 }
NYX 0:85b3fd62ea1a 98
NYX 0:85b3fd62ea1a 99 int SPI::write(int value) {
NYX 0:85b3fd62ea1a 100 lock();
NYX 0:85b3fd62ea1a 101 _acquire();
NYX 0:85b3fd62ea1a 102 int ret = spi_master_write(&_spi, value);
NYX 0:85b3fd62ea1a 103 unlock();
NYX 0:85b3fd62ea1a 104 return ret;
NYX 0:85b3fd62ea1a 105 }
NYX 0:85b3fd62ea1a 106
NYX 0:85b3fd62ea1a 107 int SPI::write(const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length) {
NYX 0:85b3fd62ea1a 108 lock();
NYX 0:85b3fd62ea1a 109 _acquire();
NYX 0:85b3fd62ea1a 110 int ret = spi_master_block_write(&_spi, tx_buffer, tx_length, rx_buffer, rx_length, _write_fill);
NYX 0:85b3fd62ea1a 111 unlock();
NYX 0:85b3fd62ea1a 112 return ret;
NYX 0:85b3fd62ea1a 113 }
NYX 0:85b3fd62ea1a 114
NYX 0:85b3fd62ea1a 115 void SPI::lock() {
NYX 0:85b3fd62ea1a 116 _mutex->lock();
NYX 0:85b3fd62ea1a 117 }
NYX 0:85b3fd62ea1a 118
NYX 0:85b3fd62ea1a 119 void SPI::unlock() {
NYX 0:85b3fd62ea1a 120 _mutex->unlock();
NYX 0:85b3fd62ea1a 121 }
NYX 0:85b3fd62ea1a 122
NYX 0:85b3fd62ea1a 123 void SPI::set_default_write_value(char data) {
NYX 0:85b3fd62ea1a 124 lock();
NYX 0:85b3fd62ea1a 125 _write_fill = data;
NYX 0:85b3fd62ea1a 126 unlock();
NYX 0:85b3fd62ea1a 127 }
NYX 0:85b3fd62ea1a 128
NYX 0:85b3fd62ea1a 129 #if DEVICE_SPI_ASYNCH
NYX 0:85b3fd62ea1a 130
NYX 0:85b3fd62ea1a 131 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)
NYX 0:85b3fd62ea1a 132 {
NYX 0:85b3fd62ea1a 133 if (spi_active(&_spi)) {
NYX 0:85b3fd62ea1a 134 return queue_transfer(tx_buffer, tx_length, rx_buffer, rx_length, bit_width, callback, event);
NYX 0:85b3fd62ea1a 135 }
NYX 0:85b3fd62ea1a 136 start_transfer(tx_buffer, tx_length, rx_buffer, rx_length, bit_width, callback, event);
NYX 0:85b3fd62ea1a 137 return 0;
NYX 0:85b3fd62ea1a 138 }
NYX 0:85b3fd62ea1a 139
NYX 0:85b3fd62ea1a 140 void SPI::abort_transfer()
NYX 0:85b3fd62ea1a 141 {
NYX 0:85b3fd62ea1a 142 spi_abort_asynch(&_spi);
NYX 0:85b3fd62ea1a 143 sleep_manager_unlock_deep_sleep();
NYX 0:85b3fd62ea1a 144 #if TRANSACTION_QUEUE_SIZE_SPI
NYX 0:85b3fd62ea1a 145 dequeue_transaction();
NYX 0:85b3fd62ea1a 146 #endif
NYX 0:85b3fd62ea1a 147 }
NYX 0:85b3fd62ea1a 148
NYX 0:85b3fd62ea1a 149
NYX 0:85b3fd62ea1a 150 void SPI::clear_transfer_buffer()
NYX 0:85b3fd62ea1a 151 {
NYX 0:85b3fd62ea1a 152 #if TRANSACTION_QUEUE_SIZE_SPI
NYX 0:85b3fd62ea1a 153 _transaction_buffer.reset();
NYX 0:85b3fd62ea1a 154 #endif
NYX 0:85b3fd62ea1a 155 }
NYX 0:85b3fd62ea1a 156
NYX 0:85b3fd62ea1a 157 void SPI::abort_all_transfers()
NYX 0:85b3fd62ea1a 158 {
NYX 0:85b3fd62ea1a 159 clear_transfer_buffer();
NYX 0:85b3fd62ea1a 160 abort_transfer();
NYX 0:85b3fd62ea1a 161 }
NYX 0:85b3fd62ea1a 162
NYX 0:85b3fd62ea1a 163 int SPI::set_dma_usage(DMAUsage usage)
NYX 0:85b3fd62ea1a 164 {
NYX 0:85b3fd62ea1a 165 if (spi_active(&_spi)) {
NYX 0:85b3fd62ea1a 166 return -1;
NYX 0:85b3fd62ea1a 167 }
NYX 0:85b3fd62ea1a 168 _usage = usage;
NYX 0:85b3fd62ea1a 169 return 0;
NYX 0:85b3fd62ea1a 170 }
NYX 0:85b3fd62ea1a 171
NYX 0:85b3fd62ea1a 172 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)
NYX 0:85b3fd62ea1a 173 {
NYX 0:85b3fd62ea1a 174 #if TRANSACTION_QUEUE_SIZE_SPI
NYX 0:85b3fd62ea1a 175 transaction_t t;
NYX 0:85b3fd62ea1a 176
NYX 0:85b3fd62ea1a 177 t.tx_buffer = const_cast<void *>(tx_buffer);
NYX 0:85b3fd62ea1a 178 t.tx_length = tx_length;
NYX 0:85b3fd62ea1a 179 t.rx_buffer = rx_buffer;
NYX 0:85b3fd62ea1a 180 t.rx_length = rx_length;
NYX 0:85b3fd62ea1a 181 t.event = event;
NYX 0:85b3fd62ea1a 182 t.callback = callback;
NYX 0:85b3fd62ea1a 183 t.width = bit_width;
NYX 0:85b3fd62ea1a 184 Transaction<SPI> transaction(this, t);
NYX 0:85b3fd62ea1a 185 if (_transaction_buffer.full()) {
NYX 0:85b3fd62ea1a 186 return -1; // the buffer is full
NYX 0:85b3fd62ea1a 187 } else {
NYX 0:85b3fd62ea1a 188 core_util_critical_section_enter();
NYX 0:85b3fd62ea1a 189 _transaction_buffer.push(transaction);
NYX 0:85b3fd62ea1a 190 if (!spi_active(&_spi)) {
NYX 0:85b3fd62ea1a 191 dequeue_transaction();
NYX 0:85b3fd62ea1a 192 }
NYX 0:85b3fd62ea1a 193 core_util_critical_section_exit();
NYX 0:85b3fd62ea1a 194 return 0;
NYX 0:85b3fd62ea1a 195 }
NYX 0:85b3fd62ea1a 196 #else
NYX 0:85b3fd62ea1a 197 return -1;
NYX 0:85b3fd62ea1a 198 #endif
NYX 0:85b3fd62ea1a 199 }
NYX 0:85b3fd62ea1a 200
NYX 0:85b3fd62ea1a 201 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)
NYX 0:85b3fd62ea1a 202 {
NYX 0:85b3fd62ea1a 203 sleep_manager_lock_deep_sleep();
NYX 0:85b3fd62ea1a 204 _acquire();
NYX 0:85b3fd62ea1a 205 _callback = callback;
NYX 0:85b3fd62ea1a 206 _irq.callback(&SPI::irq_handler_asynch);
NYX 0:85b3fd62ea1a 207 spi_master_transfer(&_spi, tx_buffer, tx_length, rx_buffer, rx_length, bit_width, _irq.entry(), event , _usage);
NYX 0:85b3fd62ea1a 208 }
NYX 0:85b3fd62ea1a 209
NYX 0:85b3fd62ea1a 210 #if TRANSACTION_QUEUE_SIZE_SPI
NYX 0:85b3fd62ea1a 211
NYX 0:85b3fd62ea1a 212 void SPI::start_transaction(transaction_t *data)
NYX 0:85b3fd62ea1a 213 {
NYX 0:85b3fd62ea1a 214 start_transfer(data->tx_buffer, data->tx_length, data->rx_buffer, data->rx_length, data->width, data->callback, data->event);
NYX 0:85b3fd62ea1a 215 }
NYX 0:85b3fd62ea1a 216
NYX 0:85b3fd62ea1a 217 void SPI::dequeue_transaction()
NYX 0:85b3fd62ea1a 218 {
NYX 0:85b3fd62ea1a 219 Transaction<SPI> t;
NYX 0:85b3fd62ea1a 220 if (_transaction_buffer.pop(t)) {
NYX 0:85b3fd62ea1a 221 SPI* obj = t.get_object();
NYX 0:85b3fd62ea1a 222 transaction_t* data = t.get_transaction();
NYX 0:85b3fd62ea1a 223 obj->start_transaction(data);
NYX 0:85b3fd62ea1a 224 }
NYX 0:85b3fd62ea1a 225 }
NYX 0:85b3fd62ea1a 226
NYX 0:85b3fd62ea1a 227 #endif
NYX 0:85b3fd62ea1a 228
NYX 0:85b3fd62ea1a 229 void SPI::irq_handler_asynch(void)
NYX 0:85b3fd62ea1a 230 {
NYX 0:85b3fd62ea1a 231 int event = spi_irq_handler_asynch(&_spi);
NYX 0:85b3fd62ea1a 232 if (_callback && (event & SPI_EVENT_ALL)) {
NYX 0:85b3fd62ea1a 233 sleep_manager_unlock_deep_sleep();
NYX 0:85b3fd62ea1a 234 _callback.call(event & SPI_EVENT_ALL);
NYX 0:85b3fd62ea1a 235 }
NYX 0:85b3fd62ea1a 236 #if TRANSACTION_QUEUE_SIZE_SPI
NYX 0:85b3fd62ea1a 237 if (event & (SPI_EVENT_ALL | SPI_EVENT_INTERNAL_TRANSFER_COMPLETE)) {
NYX 0:85b3fd62ea1a 238 // SPI peripheral is free (event happend), dequeue transaction
NYX 0:85b3fd62ea1a 239 dequeue_transaction();
NYX 0:85b3fd62ea1a 240 }
NYX 0:85b3fd62ea1a 241 #endif
NYX 0:85b3fd62ea1a 242 }
NYX 0:85b3fd62ea1a 243
NYX 0:85b3fd62ea1a 244 #endif
NYX 0:85b3fd62ea1a 245
NYX 0:85b3fd62ea1a 246 } // namespace mbed
NYX 0:85b3fd62ea1a 247
NYX 0:85b3fd62ea1a 248 #endif