João Victor / stm32f4-discovery-CAN-Activation

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