forked

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