Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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
Generated on Tue Aug 9 2022 00:37:20 by
