david lukofsky / Mbed 2 deprecated STM32_read_analog

Dependencies:   mbed

mySPI/mySPI.cpp

Committer:
lukofsky
Date:
2018-11-13
Revision:
1:df1ae6d3fd03

File content as of revision 1:df1ae6d3fd03:

////////////////////////////////////////////////////////////////////////
// NOTE: two changes
//  (1) include "mySPI.h" instead of "SPI.h"
//  (2) commented out lock, _acquire, and unlock from the write method
////////////////////////////////////////////////////////////////////////

/* 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 custom SPI header file instead of default SPI header file
//#include "drivers/SPI.h"
#include "mySPI.h"

#include "platform/mbed_critical.h"



#if DEVICE_SPI_ASYNCH

#include "platform/mbed_power_mgmt.h"

#endif



#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),

    _deep_sleep_locked(false),

#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 then just

    // update format, but if owner is changed then 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 then just

    // update frequency, but if owner is changed then 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 wasn't 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);

    unlock_deep_sleep();

#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)

{

    lock_deep_sleep();

    _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);

}



void SPI::lock_deep_sleep()

{

    if (_deep_sleep_locked == false) {

        sleep_manager_lock_deep_sleep();

        _deep_sleep_locked = true;

    }

}



void SPI::unlock_deep_sleep()

{

    if (_deep_sleep_locked == true) {

        sleep_manager_unlock_deep_sleep();

        _deep_sleep_locked = false;

    }

}



#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)) {

        unlock_deep_sleep();

        _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 happened), dequeue transaction

        dequeue_transaction();

    }

#endif

}



#endif



} // namespace mbed



#endif