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