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