Rtos API example

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