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.
Fork of mbed-dev by
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 12:11:34 by
1.7.2
