001

Committer:
ganlikun
Date:
Sun Jun 12 14:02:44 2022 +0000
Revision:
0:13413ea9a877
00

Who changed what in which revision?

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