takashi kadono / Mbed OS Nucleo_446

Dependencies:   ssd1331

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