SilentSensors / mbed-dev

Fork of mbed-dev by mbed official

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