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