Forked.
Fork of mbed-dev by
drivers/SPI.cpp
- Committer:
- Kojto
- Date:
- 2017-08-03
- Revision:
- 170:19eb464bc2be
- Parent:
- 169:e3b6fe271b81
File content as of revision 170:19eb464bc2be:
/* mbed Microcontroller Library * Copyright (c) 2006-2013 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "drivers/SPI.h" #include "platform/mbed_critical.h" #if DEVICE_SPI namespace mbed { #if DEVICE_SPI_ASYNCH && TRANSACTION_QUEUE_SIZE_SPI CircularBuffer<Transaction<SPI>, TRANSACTION_QUEUE_SIZE_SPI> SPI::_transaction_buffer; #endif SPI::SPI(PinName mosi, PinName miso, PinName sclk, PinName ssel) : _spi(), #if DEVICE_SPI_ASYNCH _irq(this), _usage(DMA_USAGE_NEVER), #endif _bits(8), _mode(0), _hz(1000000), _write_fill(SPI_FILL_CHAR) { // No lock needed in the constructor spi_init(&_spi, mosi, miso, sclk, ssel); _acquire(); } void SPI::format(int bits, int mode) { lock(); _bits = bits; _mode = mode; // If changing format while you are the owner than just // update format, but if owner is changed than even frequency should be // updated which is done by acquire. if (_owner == this) { spi_format(&_spi, _bits, _mode, 0); } else { _acquire(); } unlock(); } void SPI::frequency(int hz) { lock(); _hz = hz; // If changing format while you are the owner than just // update frequency, but if owner is changed than even frequency should be // updated which is done by acquire. if (_owner == this) { spi_frequency(&_spi, _hz); } else { _acquire(); } unlock(); } SPI* SPI::_owner = NULL; SingletonPtr<PlatformMutex> SPI::_mutex; // ignore the fact there are multiple physical spis, and always update if it wasnt us last void SPI::aquire() { lock(); if (_owner != this) { spi_format(&_spi, _bits, _mode, 0); spi_frequency(&_spi, _hz); _owner = this; } unlock(); } // Note: Private function with no locking void SPI::_acquire() { if (_owner != this) { spi_format(&_spi, _bits, _mode, 0); spi_frequency(&_spi, _hz); _owner = this; } } int SPI::write(int value) { lock(); _acquire(); int ret = spi_master_write(&_spi, value); unlock(); return ret; } int SPI::write(const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length) { lock(); _acquire(); int ret = spi_master_block_write(&_spi, tx_buffer, tx_length, rx_buffer, rx_length, _write_fill); unlock(); return ret; } void SPI::lock() { _mutex->lock(); } void SPI::unlock() { _mutex->unlock(); } void SPI::set_default_write_value(char data) { lock(); _write_fill = data; unlock(); } #if DEVICE_SPI_ASYNCH 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) { if (spi_active(&_spi)) { return queue_transfer(tx_buffer, tx_length, rx_buffer, rx_length, bit_width, callback, event); } start_transfer(tx_buffer, tx_length, rx_buffer, rx_length, bit_width, callback, event); return 0; } void SPI::abort_transfer() { spi_abort_asynch(&_spi); #if TRANSACTION_QUEUE_SIZE_SPI dequeue_transaction(); #endif } void SPI::clear_transfer_buffer() { #if TRANSACTION_QUEUE_SIZE_SPI _transaction_buffer.reset(); #endif } void SPI::abort_all_transfers() { clear_transfer_buffer(); abort_transfer(); } int SPI::set_dma_usage(DMAUsage usage) { if (spi_active(&_spi)) { return -1; } _usage = usage; return 0; } 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) { #if TRANSACTION_QUEUE_SIZE_SPI transaction_t t; t.tx_buffer = const_cast<void *>(tx_buffer); t.tx_length = tx_length; t.rx_buffer = rx_buffer; t.rx_length = rx_length; t.event = event; t.callback = callback; t.width = bit_width; Transaction<SPI> transaction(this, t); if (_transaction_buffer.full()) { return -1; // the buffer is full } else { core_util_critical_section_enter(); _transaction_buffer.push(transaction); if (!spi_active(&_spi)) { dequeue_transaction(); } core_util_critical_section_exit(); return 0; } #else return -1; #endif } 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) { _acquire(); _callback = callback; _irq.callback(&SPI::irq_handler_asynch); spi_master_transfer(&_spi, tx_buffer, tx_length, rx_buffer, rx_length, bit_width, _irq.entry(), event , _usage); } #if TRANSACTION_QUEUE_SIZE_SPI void SPI::start_transaction(transaction_t *data) { start_transfer(data->tx_buffer, data->tx_length, data->rx_buffer, data->rx_length, data->width, data->callback, data->event); } void SPI::dequeue_transaction() { Transaction<SPI> t; if (_transaction_buffer.pop(t)) { SPI* obj = t.get_object(); transaction_t* data = t.get_transaction(); obj->start_transaction(data); } } #endif void SPI::irq_handler_asynch(void) { int event = spi_irq_handler_asynch(&_spi); if (_callback && (event & SPI_EVENT_ALL)) { _callback.call(event & SPI_EVENT_ALL); } #if TRANSACTION_QUEUE_SIZE_SPI if (event & (SPI_EVENT_ALL | SPI_EVENT_INTERNAL_TRANSFER_COMPLETE)) { // SPI peripheral is free (event happend), dequeue transaction dequeue_transaction(); } #endif } #endif } // namespace mbed #endif