Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

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-2019 ARM Limited
00003  * SPDX-License-Identifier: Apache-2.0
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License");
00006  * you may not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  *     http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 #include "drivers/SPI.h"
00018 #include "platform/mbed_critical.h"
00019 
00020 #if DEVICE_SPI_ASYNCH
00021 #include "platform/mbed_power_mgmt.h"
00022 #endif
00023 
00024 #if DEVICE_SPI
00025 
00026 namespace mbed {
00027 
00028 SPI::spi_peripheral_s SPI::_peripherals[SPI_PERIPHERALS_USED];
00029 int SPI::_peripherals_used;
00030 
00031 SPI::SPI(PinName mosi, PinName miso, PinName sclk, PinName ssel) :
00032 #if DEVICE_SPI_ASYNCH
00033     _irq(this),
00034 #endif
00035     _mosi(mosi),
00036     _miso(miso),
00037     _sclk(sclk),
00038     _hw_ssel(ssel),
00039     _sw_ssel(NC),
00040     _static_pinmap(NULL),
00041     _init_func(_do_init)
00042 {
00043     // Need backwards compatibility with HALs not providing API
00044 #ifdef DEVICE_SPI_COUNT
00045     _peripheral_name = spi_get_peripheral_name(_mosi, _miso, _sclk);
00046 #else
00047     _peripheral_name = GlobalSPI;
00048 #endif
00049 
00050     _do_construct();
00051 }
00052 
00053 SPI::SPI(PinName mosi, PinName miso, PinName sclk, PinName ssel, use_gpio_ssel_t) :
00054 #if DEVICE_SPI_ASYNCH
00055     _irq(this),
00056 #endif
00057     _mosi(mosi),
00058     _miso(miso),
00059     _sclk(sclk),
00060     _hw_ssel(NC),
00061     _sw_ssel(ssel, 1),
00062     _static_pinmap(NULL),
00063     _init_func(_do_init)
00064 {
00065     // Need backwards compatibility with HALs not providing API
00066 #ifdef DEVICE_SPI_COUNT
00067     _peripheral_name = spi_get_peripheral_name(_mosi, _miso, _sclk);
00068 #else
00069     _peripheral_name = GlobalSPI;
00070 #endif
00071     _do_construct();
00072 }
00073 
00074 SPI::SPI(const spi_pinmap_t &pinmap) :
00075 #if DEVICE_SPI_ASYNCH
00076     _irq(this),
00077 #endif
00078     _mosi(pinmap.mosi_pin),
00079     _miso(pinmap.miso_pin),
00080     _sclk(pinmap.sclk_pin),
00081     _hw_ssel(pinmap.ssel_pin),
00082     _sw_ssel(NC),
00083     _static_pinmap(&pinmap),
00084     _peripheral_name((SPIName)pinmap.peripheral),
00085     _init_func(_do_init_direct)
00086 
00087 {
00088     _do_construct();
00089 }
00090 
00091 SPI::SPI(const spi_pinmap_t &pinmap, PinName ssel) :
00092 #if DEVICE_SPI_ASYNCH
00093     _irq(this),
00094 #endif
00095     _mosi(pinmap.mosi_pin),
00096     _miso(pinmap.miso_pin),
00097     _sclk(pinmap.sclk_pin),
00098     _hw_ssel(NC),
00099     _sw_ssel(ssel, 1),
00100     _static_pinmap(&pinmap),
00101     _peripheral_name((SPIName)pinmap.peripheral),
00102     _init_func(_do_init_direct)
00103 {
00104     _do_construct();
00105 }
00106 
00107 void SPI::_do_init(SPI *obj)
00108 {
00109     spi_init(&obj->_peripheral->spi, obj->_mosi, obj->_miso, obj->_sclk, obj->_hw_ssel);
00110 }
00111 
00112 void SPI::_do_init_direct(SPI *obj)
00113 {
00114     spi_init_direct(&obj->_peripheral->spi, obj->_static_pinmap);
00115 }
00116 
00117 void SPI::_do_construct()
00118 {
00119     // No lock needed in the constructor
00120 #if DEVICE_SPI_ASYNCH
00121     _usage = DMA_USAGE_NEVER;
00122     _deep_sleep_locked = false;
00123 #endif
00124     _select_count = 0;
00125     _bits = 8;
00126     _mode = 0;
00127     _hz = 1000000;
00128     _write_fill = SPI_FILL_CHAR;
00129 
00130     core_util_critical_section_enter();
00131     // lookup in a critical section if we already have it else initialize it
00132 
00133     _peripheral = SPI::_lookup(_peripheral_name);
00134     if (!_peripheral) {
00135         _peripheral = SPI::_alloc();
00136         _peripheral->name = _peripheral_name;
00137     }
00138     core_util_critical_section_exit();
00139 
00140 #if DEVICE_SPI_ASYNCH && TRANSACTION_QUEUE_SIZE_SPI
00141     // prime the SingletonPtr, so we don't have a problem trying to
00142     // construct the buffer if asynch operation initiated from IRQ
00143     _peripheral->transaction_buffer.get();
00144 #endif
00145     // we don't need to _acquire at this stage.
00146     // this will be done anyway before any operation.
00147 }
00148 
00149 SPI::~SPI()
00150 {
00151     lock();
00152     /* Make sure a stale pointer isn't left in peripheral's owner field */
00153     if (_peripheral->owner == this) {
00154         _peripheral->owner = NULL;
00155     }
00156     unlock();
00157 }
00158 
00159 SPI::spi_peripheral_s *SPI::_lookup(SPI::SPIName name)
00160 {
00161     SPI::spi_peripheral_s *result = NULL;
00162     core_util_critical_section_enter();
00163     for (int idx = 0; idx < _peripherals_used; idx++) {
00164         if (_peripherals[idx].name == name) {
00165             result = &_peripherals[idx];
00166             break;
00167         }
00168     }
00169     core_util_critical_section_exit();
00170     return result;
00171 }
00172 
00173 SPI::spi_peripheral_s *SPI::_alloc()
00174 {
00175     MBED_ASSERT(_peripherals_used < SPI_PERIPHERALS_USED);
00176     return &_peripherals[_peripherals_used++];
00177 }
00178 
00179 void SPI::format(int bits, int mode)
00180 {
00181     lock();
00182     _bits = bits;
00183     _mode = mode;
00184     // If changing format while you are the owner then just
00185     // update format, but if owner is changed then even frequency should be
00186     // updated which is done by acquire.
00187     if (_peripheral->owner == this) {
00188         spi_format(&_peripheral->spi, _bits, _mode, 0);
00189     } else {
00190         _acquire();
00191     }
00192     unlock();
00193 }
00194 
00195 void SPI::frequency(int hz)
00196 {
00197     lock();
00198     _hz = hz;
00199     // If changing format while you are the owner then just
00200     // update frequency, but if owner is changed then even frequency should be
00201     // updated which is done by acquire.
00202     if (_peripheral->owner == this) {
00203         spi_frequency(&_peripheral->spi, _hz);
00204     } else {
00205         _acquire();
00206     }
00207     unlock();
00208 }
00209 
00210 // Note: Private function with no locking
00211 void SPI::_acquire()
00212 {
00213     if (_peripheral->owner != this) {
00214         _init_func(this);
00215         spi_format(&_peripheral->spi, _bits, _mode, 0);
00216         spi_frequency(&_peripheral->spi, _hz);
00217         _peripheral->owner = this;
00218     }
00219 }
00220 
00221 int SPI::write(int value)
00222 {
00223     select();
00224     int ret = spi_master_write(&_peripheral->spi, value);
00225     deselect();
00226     return ret;
00227 }
00228 
00229 int SPI::write(const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length)
00230 {
00231     select();
00232     int ret = spi_master_block_write(&_peripheral->spi, tx_buffer, tx_length, rx_buffer, rx_length, _write_fill);
00233     deselect();
00234     return ret;
00235 }
00236 
00237 void SPI::_set_ssel(int val)
00238 {
00239     if (_sw_ssel.is_connected()) {
00240         _sw_ssel = val;
00241     }
00242 }
00243 
00244 void SPI::lock()
00245 {
00246     _peripheral->mutex->lock();
00247 }
00248 
00249 void SPI::select()
00250 {
00251     lock();
00252     if (_select_count++ == 0) {
00253         _acquire();
00254         _set_ssel(0);
00255     }
00256 }
00257 
00258 void SPI::unlock()
00259 {
00260     _peripheral->mutex->unlock();
00261 }
00262 
00263 void SPI::deselect()
00264 {
00265     if (--_select_count == 0) {
00266         _set_ssel(1);
00267     }
00268     unlock();
00269 }
00270 
00271 void SPI::set_default_write_value(char data)
00272 {
00273     // this does not actually need to lock the peripheral.
00274     lock();
00275     _write_fill = data;
00276     unlock();
00277 }
00278 
00279 #if DEVICE_SPI_ASYNCH
00280 
00281 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)
00282 {
00283     if (spi_active(&_peripheral->spi)) {
00284         return queue_transfer(tx_buffer, tx_length, rx_buffer, rx_length, bit_width, callback, event);
00285     }
00286     start_transfer(tx_buffer, tx_length, rx_buffer, rx_length, bit_width, callback, event);
00287     return 0;
00288 }
00289 
00290 void SPI::abort_transfer()
00291 {
00292     spi_abort_asynch(&_peripheral->spi);
00293     unlock_deep_sleep();
00294 #if TRANSACTION_QUEUE_SIZE_SPI
00295     dequeue_transaction();
00296 #endif
00297 }
00298 
00299 void SPI::clear_transfer_buffer()
00300 {
00301 #if TRANSACTION_QUEUE_SIZE_SPI
00302     _peripheral->transaction_buffer->reset();
00303 #endif
00304 }
00305 
00306 void SPI::abort_all_transfers()
00307 {
00308     clear_transfer_buffer();
00309     abort_transfer();
00310 }
00311 
00312 int SPI::set_dma_usage(DMAUsage usage)
00313 {
00314     if (spi_active(&_peripheral->spi)) {
00315         return -1;
00316     }
00317     _usage = usage;
00318     return  0;
00319 }
00320 
00321 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)
00322 {
00323 #if TRANSACTION_QUEUE_SIZE_SPI
00324     transaction_t t;
00325 
00326     t.tx_buffer = const_cast<void *>(tx_buffer);
00327     t.tx_length = tx_length;
00328     t.rx_buffer = rx_buffer;
00329     t.rx_length = rx_length;
00330     t.event = event;
00331     t.callback = callback;
00332     t.width = bit_width;
00333     Transaction<SPI>  transaction(this, t);
00334     if (_peripheral->transaction_buffer->full()) {
00335         return -1; // the buffer is full
00336     } else {
00337         core_util_critical_section_enter();
00338         _peripheral->transaction_buffer->push(transaction);
00339         if (!spi_active(&_peripheral->spi)) {
00340             dequeue_transaction();
00341         }
00342         core_util_critical_section_exit();
00343         return 0;
00344     }
00345 #else
00346     return -1;
00347 #endif
00348 }
00349 
00350 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)
00351 {
00352     lock_deep_sleep();
00353     _acquire();
00354     _set_ssel(0);
00355     _callback = callback;
00356     _irq.callback(&SPI::irq_handler_asynch);
00357     spi_master_transfer(&_peripheral->spi, tx_buffer, tx_length, rx_buffer, rx_length, bit_width, _irq.entry(), event, _usage);
00358 }
00359 
00360 void SPI::lock_deep_sleep()
00361 {
00362     if (_deep_sleep_locked == false) {
00363         sleep_manager_lock_deep_sleep();
00364         _deep_sleep_locked = true;
00365     }
00366 }
00367 
00368 void SPI::unlock_deep_sleep()
00369 {
00370     if (_deep_sleep_locked == true) {
00371         sleep_manager_unlock_deep_sleep();
00372         _deep_sleep_locked = false;
00373     }
00374 }
00375 
00376 #if TRANSACTION_QUEUE_SIZE_SPI
00377 
00378 void SPI::start_transaction(transaction_t *data)
00379 {
00380     start_transfer(data->tx_buffer, data->tx_length, data->rx_buffer, data->rx_length, data->width, data->callback, data->event);
00381 }
00382 
00383 void SPI::dequeue_transaction()
00384 {
00385     Transaction<SPI> t;
00386     if (_peripheral->transaction_buffer->pop(t)) {
00387         SPI *obj = t.get_object();
00388         transaction_t *data = t.get_transaction();
00389         obj->start_transaction(data);
00390     }
00391 }
00392 
00393 #endif
00394 
00395 void SPI::irq_handler_asynch(void)
00396 {
00397     int event = spi_irq_handler_asynch(&_peripheral->spi);
00398     if (_callback && (event & SPI_EVENT_ALL)) {
00399         _set_ssel(1);
00400         unlock_deep_sleep();
00401         _callback.call(event & SPI_EVENT_ALL);
00402     }
00403 #if TRANSACTION_QUEUE_SIZE_SPI
00404     if (event & (SPI_EVENT_ALL | SPI_EVENT_INTERNAL_TRANSFER_COMPLETE)) {
00405         // SPI peripheral is free (event happened), dequeue transaction
00406         dequeue_transaction();
00407     }
00408 #endif
00409 }
00410 
00411 #endif
00412 
00413 } // namespace mbed
00414 
00415 #endif