mbed library sources. Supersedes mbed-src.

Dependents:   Nucleo_Hello_Encoder BLE_iBeaconScan AM1805_DEMO DISCO-F429ZI_ExportTemplate1 ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SPI.cpp Source File

SPI.cpp

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2006-2013 ARM Limited
00003  * SPDX-License-Identifier: Apache-2.0
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License");
00006  * you may not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  *     http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 #include "drivers/SPI.h"
00018 #include "platform/mbed_critical.h"
00019 
00020 #if DEVICE_SPI_ASYNCH
00021 #include "platform/mbed_power_mgmt.h"
00022 #endif
00023 
00024 #if DEVICE_SPI
00025 
00026 namespace mbed {
00027 
00028 #if DEVICE_SPI_ASYNCH && TRANSACTION_QUEUE_SIZE_SPI
00029 CircularBuffer<Transaction<SPI>, TRANSACTION_QUEUE_SIZE_SPI> SPI::_transaction_buffer;
00030 #endif
00031 
00032 SPI::SPI(PinName mosi, PinName miso, PinName sclk, PinName ssel) :
00033     _spi(),
00034 #if DEVICE_SPI_ASYNCH
00035     _irq(this),
00036     _usage(DMA_USAGE_NEVER),
00037     _deep_sleep_locked(false),
00038 #endif
00039     _bits(8),
00040     _mode(0),
00041     _hz(1000000),
00042     _write_fill(SPI_FILL_CHAR)
00043 {
00044     // No lock needed in the constructor
00045     spi_init(&_spi, mosi, miso, sclk, ssel);
00046 }
00047 
00048 SPI::~SPI()
00049 {
00050     if (_owner == this) {
00051         _owner = NULL;
00052     }
00053 }
00054 
00055 void SPI::format(int bits, int mode)
00056 {
00057     lock();
00058     _bits = bits;
00059     _mode = mode;
00060     // If changing format while you are the owner then just
00061     // update format, but if owner is changed then even frequency should be
00062     // updated which is done by acquire.
00063     if (_owner == this) {
00064         spi_format(&_spi, _bits, _mode, 0);
00065     } else {
00066         _acquire();
00067     }
00068     unlock();
00069 }
00070 
00071 void SPI::frequency(int hz)
00072 {
00073     lock();
00074     _hz = hz;
00075     // If changing format while you are the owner then just
00076     // update frequency, but if owner is changed then even frequency should be
00077     // updated which is done by acquire.
00078     if (_owner == this) {
00079         spi_frequency(&_spi, _hz);
00080     } else {
00081         _acquire();
00082     }
00083     unlock();
00084 }
00085 
00086 SPI *SPI::_owner = NULL;
00087 SingletonPtr<PlatformMutex>  SPI::_mutex;
00088 
00089 // ignore the fact there are multiple physical spis, and always update if it wasn't us last
00090 void SPI::aquire()
00091 {
00092     lock();
00093     if (_owner != this) {
00094         spi_format(&_spi, _bits, _mode, 0);
00095         spi_frequency(&_spi, _hz);
00096         _owner = this;
00097     }
00098     unlock();
00099 }
00100 
00101 // Note: Private function with no locking
00102 void SPI::_acquire()
00103 {
00104     if (_owner != this) {
00105         spi_format(&_spi, _bits, _mode, 0);
00106         spi_frequency(&_spi, _hz);
00107         _owner = this;
00108     }
00109 }
00110 
00111 int SPI::write(int value)
00112 {
00113     lock();
00114     _acquire();
00115     int ret = spi_master_write(&_spi, value);
00116     unlock();
00117     return ret;
00118 }
00119 
00120 int SPI::write(const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length)
00121 {
00122     lock();
00123     _acquire();
00124     int ret = spi_master_block_write(&_spi, tx_buffer, tx_length, rx_buffer, rx_length, _write_fill);
00125     unlock();
00126     return ret;
00127 }
00128 
00129 void SPI::lock()
00130 {
00131     _mutex->lock();
00132 }
00133 
00134 void SPI::unlock()
00135 {
00136     _mutex->unlock();
00137 }
00138 
00139 void SPI::set_default_write_value(char data)
00140 {
00141     lock();
00142     _write_fill = data;
00143     unlock();
00144 }
00145 
00146 #if DEVICE_SPI_ASYNCH
00147 
00148 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)
00149 {
00150     if (spi_active(&_spi)) {
00151         return queue_transfer(tx_buffer, tx_length, rx_buffer, rx_length, bit_width, callback, event);
00152     }
00153     start_transfer(tx_buffer, tx_length, rx_buffer, rx_length, bit_width, callback, event);
00154     return 0;
00155 }
00156 
00157 void SPI::abort_transfer()
00158 {
00159     spi_abort_asynch(&_spi);
00160     unlock_deep_sleep();
00161 #if TRANSACTION_QUEUE_SIZE_SPI
00162     dequeue_transaction();
00163 #endif
00164 }
00165 
00166 
00167 void SPI::clear_transfer_buffer()
00168 {
00169 #if TRANSACTION_QUEUE_SIZE_SPI
00170     _transaction_buffer.reset();
00171 #endif
00172 }
00173 
00174 void SPI::abort_all_transfers()
00175 {
00176     clear_transfer_buffer();
00177     abort_transfer();
00178 }
00179 
00180 int SPI::set_dma_usage(DMAUsage usage)
00181 {
00182     if (spi_active(&_spi)) {
00183         return -1;
00184     }
00185     _usage = usage;
00186     return  0;
00187 }
00188 
00189 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)
00190 {
00191 #if TRANSACTION_QUEUE_SIZE_SPI
00192     transaction_t t;
00193 
00194     t.tx_buffer = const_cast<void *>(tx_buffer);
00195     t.tx_length = tx_length;
00196     t.rx_buffer = rx_buffer;
00197     t.rx_length = rx_length;
00198     t.event = event;
00199     t.callback = callback;
00200     t.width = bit_width;
00201     Transaction<SPI>  transaction(this, t);
00202     if (_transaction_buffer.full()) {
00203         return -1; // the buffer is full
00204     } else {
00205         core_util_critical_section_enter();
00206         _transaction_buffer.push(transaction);
00207         if (!spi_active(&_spi)) {
00208             dequeue_transaction();
00209         }
00210         core_util_critical_section_exit();
00211         return 0;
00212     }
00213 #else
00214     return -1;
00215 #endif
00216 }
00217 
00218 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)
00219 {
00220     lock_deep_sleep();
00221     _acquire();
00222     _callback = callback;
00223     _irq.callback(&SPI::irq_handler_asynch);
00224     spi_master_transfer(&_spi, tx_buffer, tx_length, rx_buffer, rx_length, bit_width, _irq.entry(), event, _usage);
00225 }
00226 
00227 void SPI::lock_deep_sleep()
00228 {
00229     if (_deep_sleep_locked == false) {
00230         sleep_manager_lock_deep_sleep();
00231         _deep_sleep_locked = true;
00232     }
00233 }
00234 
00235 void SPI::unlock_deep_sleep()
00236 {
00237     if (_deep_sleep_locked == true) {
00238         sleep_manager_unlock_deep_sleep();
00239         _deep_sleep_locked = false;
00240     }
00241 }
00242 
00243 #if TRANSACTION_QUEUE_SIZE_SPI
00244 
00245 void SPI::start_transaction(transaction_t *data)
00246 {
00247     start_transfer(data->tx_buffer, data->tx_length, data->rx_buffer, data->rx_length, data->width, data->callback, data->event);
00248 }
00249 
00250 void SPI::dequeue_transaction()
00251 {
00252     Transaction<SPI> t;
00253     if (_transaction_buffer.pop(t)) {
00254         SPI *obj = t.get_object();
00255         transaction_t *data = t.get_transaction();
00256         obj->start_transaction(data);
00257     }
00258 }
00259 
00260 #endif
00261 
00262 void SPI::irq_handler_asynch(void)
00263 {
00264     int event = spi_irq_handler_asynch(&_spi);
00265     if (_callback && (event & SPI_EVENT_ALL)) {
00266         unlock_deep_sleep();
00267         _callback.call(event & SPI_EVENT_ALL);
00268     }
00269 #if TRANSACTION_QUEUE_SIZE_SPI
00270     if (event & (SPI_EVENT_ALL | SPI_EVENT_INTERNAL_TRANSFER_COMPLETE)) {
00271         // SPI peripheral is free (event happened), dequeue transaction
00272         dequeue_transaction();
00273     }
00274 #endif
00275 }
00276 
00277 #endif
00278 
00279 } // namespace mbed
00280 
00281 #endif