added prescaler for 16 bit pwm in LPC1347 target

Fork of mbed-dev by mbed official

Revision:
15:a81a8d6c1dfe
Child:
18:da299f395b9e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/targets/hal/TARGET_Atmel/TARGET_SAM_CortexM0P/spi_api.c	Wed Nov 04 16:30:11 2015 +0000
@@ -0,0 +1,944 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2015 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 "mbed_assert.h"
+#include "spi_api.h"
+
+#include "cmsis.h"
+#include "pinmap.h"
+#include "sercom.h"
+
+#include "pinmap_function.h"
+
+#define SPI_MOSI_INDEX	0
+#define SPI_MISO_INDEX	1
+#define SPI_SCLK_INDEX	2
+#define SPI_SSEL_INDEX	3
+
+/**
+ * \brief SPI modes enum
+ *
+ * SPI mode selection.
+ */
+enum spi_mode {
+    /** Master mode. */
+    SPI_MODE_MASTER         = 1,
+    /** Slave mode. */
+    SPI_MODE_SLAVE          = 0,
+};
+
+#if DEVICE_SPI_ASYNCH
+#define pSPI_S(obj)			(&obj->spi)
+#define pSPI_SERCOM(obj)	obj->spi.spi
+#else
+#define pSPI_S(obj)			(obj)
+#define pSPI_SERCOM(obj)	(obj->spi)
+#endif
+#define _SPI(obj)			pSPI_SERCOM(obj)->SPI
+
+/** SPI default baud rate. */
+#define SPI_DEFAULT_BAUD	100000
+
+
+/** SPI timeout value. */
+#  define SPI_TIMEOUT 10000
+
+extern uint8_t g_sys_init;
+uint16_t dummy_fill_word = 0xFFFF;
+
+
+static inline bool spi_is_syncing(spi_t *obj)
+{
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+
+    /* Return synchronization status */
+    return (_SPI(obj).SYNCBUSY.reg);
+}
+
+static inline void spi_enable(spi_t *obj)
+{
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+
+    /* Wait until the synchronization is complete */
+    while (spi_is_syncing(obj));
+
+    /* Enable SPI */
+    _SPI(obj).CTRLA.reg |= SERCOM_SPI_CTRLA_ENABLE;
+}
+
+static inline void spi_disable(spi_t *obj)
+{
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+
+    /* Wait until the synchronization is complete */
+    while (spi_is_syncing(obj));
+
+    /* Disable SPI */
+    _SPI(obj).CTRLA.reg &= ~SERCOM_SPI_CTRLA_ENABLE;
+}
+
+static inline bool spi_is_write_complete(spi_t *obj)
+{
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+
+    /* Check interrupt flag */
+    return (_SPI(obj).INTFLAG.reg & SERCOM_SPI_INTFLAG_TXC);
+}
+
+static inline bool spi_is_ready_to_write(spi_t *obj)
+{
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+
+    /* Check interrupt flag */
+    return (_SPI(obj).INTFLAG.reg & SERCOM_SPI_INTFLAG_DRE);
+}
+
+static inline bool spi_is_ready_to_read(spi_t *obj)
+{
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+
+    /* Check interrupt flag */
+    return (_SPI(obj).INTFLAG.reg & SERCOM_SPI_INTFLAG_RXC);
+}
+
+static inline bool spi_write(spi_t *obj, uint16_t tx_data)
+{
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+
+    /* Check if the data register has been copied to the shift register */
+    if (!spi_is_ready_to_write(obj)) {
+        /* Data register has not been copied to the shift register, return */
+        return false;
+    }
+
+    /* Write the character to the DATA register */
+    _SPI(obj).DATA.reg = tx_data & SERCOM_SPI_DATA_MASK;
+
+    return true;
+}
+
+static inline bool spi_read(spi_t *obj, uint16_t *rx_data)
+{
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+
+    /* Check if data is ready to be read */
+    if (!spi_is_ready_to_read(obj)) {
+        /* No data has been received, return */
+        return false;
+    }
+
+    /* Check if data is overflown */
+    if (_SPI(obj).STATUS.reg & SERCOM_SPI_STATUS_BUFOVF) {
+        /* Clear overflow flag */
+        _SPI(obj).STATUS.reg |= SERCOM_SPI_STATUS_BUFOVF;
+    }
+
+    /* Read the character from the DATA register */
+    if (_SPI(obj).CTRLB.bit.CHSIZE == 1) {
+        *rx_data = (_SPI(obj).DATA.reg & SERCOM_SPI_DATA_MASK);
+    } else {
+        *rx_data = (uint8_t)_SPI(obj).DATA.reg;
+    }
+
+    return true;
+}
+
+static uint32_t spi_find_mux_settings(spi_t *obj)
+{
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+    uint8_t i_dipo;
+    uint8_t i_dopo;
+    uint32_t dipo = 0;
+    uint32_t dopo = 0;
+    uint32_t mux_pad;
+
+    uint32_t mux_settings = 0;
+
+    uint32_t sercom_index = _sercom_get_sercom_inst_index(pSPI_SERCOM(obj));
+
+    if (pSPI_S(obj)->mode == SPI_MODE_MASTER) {
+        i_dipo = SPI_MISO_INDEX;
+        i_dopo = SPI_MOSI_INDEX;
+    } else {
+        i_dipo = SPI_MOSI_INDEX;
+        i_dopo = SPI_MISO_INDEX;
+    }
+
+    /* Find MUX setting */
+    if (pSPI_S(obj)->pins[i_dipo] != NC) {
+        /* Set Data input MUX padding for master */
+        mux_pad = pinmap_pad_sercom(pSPI_S(obj)->pins[i_dipo], sercom_index);
+        if (mux_pad != NC) {
+            /* MUX pad value is same as DIPO value */
+            dipo = mux_pad;
+            mux_settings |= ((dipo << SERCOM_SPI_CTRLA_DIPO_Pos) & SERCOM_SPI_CTRLA_DIPO_Msk);
+        }
+    }
+
+    if (pSPI_S(obj)->pins[i_dopo] != NC) {
+        /* Set Data output MUX padding for master */
+        mux_pad = pinmap_pad_sercom(pSPI_S(obj)->pins[i_dopo], sercom_index);
+        if (mux_pad != NC) {
+            if (mux_pad != 0) {
+                dopo = mux_pad - 1;
+            } else {
+                if (3 == pinmap_pad_sercom(pSPI_S(obj)->pins[SPI_SCLK_INDEX], sercom_index)) {
+                    dopo = 3;
+                } else {
+                    dopo = 0;
+                }
+            }
+            mux_settings |= ((dopo << SERCOM_SPI_CTRLA_DOPO_Pos) & SERCOM_SPI_CTRLA_DOPO_Msk);
+        }
+    }
+
+    return mux_settings;
+}
+
+/**
+ * \defgroup GeneralSPI SPI Configuration Functions
+ * @{
+ */
+
+/** Initialize the SPI peripheral
+ *
+ * Configures the pins used by SPI, sets a default format and frequency, and enables the peripheral
+ * @param[out] obj  The SPI object to initialize
+ * @param[in]  mosi The pin to use for MOSI
+ * @param[in]  miso The pin to use for MISO
+ * @param[in]  sclk The pin to use for SCLK
+ * @param[in]  ssel The pin to use for SSEL
+ */
+void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel)
+{
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+    MBED_ASSERT(sclk != NC);
+
+    uint16_t baud = 0;
+    uint32_t ctrla = 0;
+    uint32_t ctrlb = 0;
+    enum status_code error_code;
+
+    if (g_sys_init == 0) {
+        system_init();
+        g_sys_init = 1;
+    }
+
+    /* Calculate SERCOM instance from pins */
+    uint32_t sercom_index = pinmap_find_sercom(mosi, miso, sclk, ssel);
+    pSPI_SERCOM(obj) = (Sercom*)pinmap_peripheral_sercom(NC, sercom_index);
+
+    /* Disable SPI */
+    spi_disable(obj);
+
+    /* Check if reset is in progress. */
+    if (_SPI(obj).CTRLA.reg & SERCOM_SPI_CTRLA_SWRST) {
+        return;
+    }
+
+    uint32_t pm_index, gclk_index;
+#if (SAML21)
+    if (sercom_index == 5) {
+        pm_index     = MCLK_APBDMASK_SERCOM5_Pos;
+        gclk_index   =  SERCOM5_GCLK_ID_CORE;
+    } else {
+        pm_index     = sercom_index + MCLK_APBCMASK_SERCOM0_Pos;
+        gclk_index   = sercom_index + SERCOM0_GCLK_ID_CORE;
+    }
+#else
+    pm_index     = sercom_index + PM_APBCMASK_SERCOM0_Pos;
+    gclk_index   = sercom_index + SERCOM0_GCLK_ID_CORE;
+#endif
+
+    /* Turn on module in PM */
+#if (SAML21)
+    if (sercom_index == 5) {
+        system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBD, 1 << pm_index);
+    } else {
+        system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index);
+    }
+#else
+    system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index);
+#endif
+
+    /* Set up the GCLK for the module */
+    struct system_gclk_chan_config gclk_chan_conf;
+    system_gclk_chan_get_config_defaults(&gclk_chan_conf);
+    gclk_chan_conf.source_generator = GCLK_GENERATOR_0;
+    system_gclk_chan_set_config(gclk_index, &gclk_chan_conf);
+    system_gclk_chan_enable(gclk_index);
+    sercom_set_gclk_generator(GCLK_GENERATOR_0, false);
+
+    /* Set the SERCOM in SPI master mode */
+    _SPI(obj).CTRLA.reg |= SERCOM_SPI_CTRLA_MODE(0x3);
+    pSPI_S(obj)->mode = SPI_MODE_MASTER;
+
+    /* TODO: Do pin muxing here */
+    struct system_pinmux_config pin_conf;
+    system_pinmux_get_config_defaults(&pin_conf);
+    pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT;
+
+    pSPI_S(obj)->pins[SPI_MOSI_INDEX] = mosi;
+    pSPI_S(obj)->pins[SPI_MISO_INDEX] = miso;
+    pSPI_S(obj)->pins[SPI_SCLK_INDEX] = sclk;
+    pSPI_S(obj)->pins[SPI_SSEL_INDEX] = ssel;
+    /* Configure the SERCOM pins according to the user configuration */
+    for (uint8_t pad = 0; pad < 4; pad++) {
+        uint32_t current_pin = pSPI_S(obj)->pins[pad];
+        if (current_pin != NC) {
+            pin_conf.mux_position = pinmap_function_sercom(current_pin, sercom_index);
+            if ((uint8_t)NC != pin_conf.mux_position) {
+                system_pinmux_pin_set_config(current_pin, &pin_conf);
+            }
+        }
+    }
+
+    /* Get baud value, based on baudrate and the internal clock frequency */
+    uint32_t internal_clock = system_gclk_chan_get_hz(gclk_index);
+    //internal_clock = 8000000;
+    error_code = _sercom_get_sync_baud_val(SPI_DEFAULT_BAUD, internal_clock, &baud);
+    if (error_code != STATUS_OK) {
+        /* Baud rate calculation error */
+        return;
+    }
+    _SPI(obj).BAUD.reg = (uint8_t)baud;
+
+    /* TODO: Find MUX settings */
+    ctrla |= spi_find_mux_settings(obj);
+
+    /* Set SPI character size */
+    ctrlb |= SERCOM_SPI_CTRLB_CHSIZE(0);
+
+    /* Enable receiver */
+    ctrlb |= SERCOM_SPI_CTRLB_RXEN;
+
+    /* Write CTRLA register */
+    _SPI(obj).CTRLA.reg |= ctrla;
+
+    /* Write CTRLB register */
+    _SPI(obj).CTRLB.reg |= ctrlb;
+
+    /* Enable SPI */
+    spi_enable(obj);
+}
+
+/** Release a SPI object
+ *
+ * TODO: spi_free is currently unimplemented
+ * This will require reference counting at the C++ level to be safe
+ *
+ * Return the pins owned by the SPI object to their reset state
+ * Disable the SPI peripheral
+ * Disable the SPI clock
+ * @param[in] obj The SPI object to deinitialize
+ */
+void spi_free(spi_t *obj)
+{
+    // [TODO]
+}
+
+/** Configure the SPI format
+ *
+ * Set the number of bits per frame, configure clock polarity and phase, shift order and master/slave mode
+ * @param[in,out] obj   The SPI object to configure
+ * @param[in]     bits  The number of bits per frame
+ * @param[in]     mode  The SPI mode (clock polarity, phase, and shift direction)
+ * @param[in]     slave Zero for master mode or non-zero for slave mode
+ */
+void spi_format(spi_t *obj, int bits, int mode, int slave)
+{
+    PinMode pull_mode;
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+
+    /* Disable SPI */
+    spi_disable(obj);
+
+
+    if (slave) {
+        /* Set the SERCOM in SPI mode */
+        _SPI(obj).CTRLA.bit.MODE = 0x2;
+        pSPI_S(obj)->mode = SPI_MODE_SLAVE;
+        pull_mode = PullNone;
+        /* Enable PLOADEN to avoid sending dummy character by slave */
+        _SPI(obj).CTRLB.bit.PLOADEN = 1;
+    } else {
+        /* Set the SERCOM in SPI mode */
+        _SPI(obj).CTRLA.bit.MODE = 0x3;
+        pSPI_S(obj)->mode = SPI_MODE_MASTER;
+        pull_mode = PullUp;
+    }
+
+    /* Change pull mode of pins */
+    for (uint8_t pad = 0; pad < 4; pad++) {
+        if (pSPI_S(obj)->pins[pad] != NC) {
+            pin_mode(pSPI_S(obj)->pins[pad], pull_mode);
+        }
+    }
+
+    /* Change MUX settings */
+    uint32_t ctrla = _SPI(obj).CTRLA.reg;
+    ctrla &= ~(SERCOM_SPI_CTRLA_DIPO_Msk | SERCOM_SPI_CTRLA_DOPO_Msk);
+    ctrla |= spi_find_mux_settings(obj);
+    _SPI(obj).CTRLA.reg = ctrla;
+
+    /* Set SPI Frame size - only 8-bit and 9-bit supported now */
+    _SPI(obj).CTRLB.bit.CHSIZE = (bits > 8)? 1 : 0;
+
+    /* Set SPI Clock Phase */
+    _SPI(obj).CTRLA.bit.CPHA = (mode & 0x01)? 1 : 0;
+
+    /* Set SPI Clock Polarity */
+    _SPI(obj).CTRLA.bit.CPOL = (mode & 0x02)? 1 : 0;
+
+    /* Enable SPI */
+    spi_enable(obj);
+}
+
+/** Set the SPI baud rate
+ *
+ * Actual frequency may differ from the desired frequency due to available dividers and bus clock
+ * Configures the SPI peripheral's baud rate
+ * @param[in,out] obj The SPI object to configure
+ * @param[in]     hz  The baud rate in Hz
+ */
+void spi_frequency(spi_t *obj, int hz)
+{
+    uint16_t baud = 0;
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+
+    /* Disable SPI */
+    spi_disable(obj);
+
+    /* Find frequency of the internal SERCOMi_GCLK_ID_CORE */
+    uint32_t sercom_index = _sercom_get_sercom_inst_index(pSPI_SERCOM(obj));
+    uint32_t gclk_index   = sercom_index + SERCOM0_GCLK_ID_CORE;
+    uint32_t internal_clock = system_gclk_chan_get_hz(gclk_index);
+
+    /* Get baud value, based on baudrate and the internal clock frequency */
+    enum status_code error_code = _sercom_get_sync_baud_val(hz, internal_clock, &baud);
+
+    if (error_code != STATUS_OK) {
+        /* Baud rate calculation error, return status code */
+        /* Enable SPI */
+        spi_enable(obj);
+        return;
+    }
+
+    _SPI(obj).BAUD.reg = (uint8_t)baud;
+
+    /* Enable SPI */
+    spi_enable(obj);
+}
+
+/**@}*/
+/**
+ * \defgroup SynchSPI Synchronous SPI Hardware Abstraction Layer
+ * @{
+ */
+
+/** Write a byte out in master mode and receive a value
+ *
+ * @param[in] obj   The SPI peripheral to use for sending
+ * @param[in] value The value to send
+ * @return Returns the value received during send
+ */
+int spi_master_write(spi_t *obj, int value)
+{
+    uint16_t rx_data = 0;
+
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+
+#if DEVICE_SPI_ASYNCH
+    if (obj->spi.status == STATUS_BUSY) {
+        /* Check if the SPI module is busy with a job */
+        return 0;
+    }
+#endif
+
+    /* Wait until the module is ready to write the character */
+    while (!spi_is_ready_to_write(obj));
+
+    /* Write data */
+    spi_write(obj, value);
+
+    if (!(_SPI(obj).CTRLB.bit.RXEN)) {
+        return 0;
+    }
+
+    /* Wait until the module is ready to read the character */
+    while (!spi_is_ready_to_read(obj));
+
+    /* Read data */
+    spi_read(obj, &rx_data);
+
+    return rx_data;
+}
+
+/** Check if a value is available to read
+ *
+ * @param[in] obj The SPI peripheral to check
+ * @return non-zero if a value is available
+ */
+int spi_slave_receive(spi_t *obj)
+{
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+
+    return spi_is_ready_to_read(obj);
+}
+
+/** Get a received value out of the SPI receive buffer in slave mode
+ *
+ * Blocks until a value is available
+ * @param[in] obj The SPI peripheral to read
+ * @return The value received
+ */
+int spi_slave_read(spi_t *obj)
+{
+    int i;
+    uint16_t rx_data = 0;
+
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+
+    /* Check for timeout period */
+    for (i = 0; i < SPI_TIMEOUT; i++) {
+        if (spi_is_ready_to_read(obj)) {
+            break;
+        }
+    }
+    if (i == SPI_TIMEOUT) {
+        /* Not ready to read data within timeout period */
+        return 0;
+    }
+
+    /* Read data */
+    spi_read(obj, &rx_data);
+
+    return rx_data;
+}
+
+/** Write a value to the SPI peripheral in slave mode
+ *
+ * Blocks until the SPI peripheral can be written to
+ * @param[in] obj   The SPI peripheral to write
+ * @param[in] value The value to write
+ */
+void spi_slave_write(spi_t *obj, int value)
+{
+    int i;
+
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+
+    /* Check for timeout period */
+    for (i = 0; i < SPI_TIMEOUT; i++) {
+        if (spi_is_ready_to_write(obj)) {
+            break;
+        }
+    }
+    if (i == SPI_TIMEOUT) {
+        /* Not ready to write data within timeout period */
+        return;
+    }
+
+    /* Write data */
+    spi_write(obj, value);
+}
+
+/** Checks if the specified SPI peripheral is in use
+ *
+ * @param[in] obj The SPI peripheral to check
+ * @return non-zero if the peripheral is currently transmitting
+ */
+int spi_busy(spi_t *obj)
+{
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+
+    return spi_is_write_complete(obj);
+}
+
+/** Get the module number
+ *
+ * @param[in] obj The SPI peripheral to check
+ * @return The module number
+ */
+uint8_t spi_get_module(spi_t *obj)
+{
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+    return _sercom_get_sercom_inst_index(pSPI_SERCOM(obj));
+}
+
+
+#if DEVICE_SPI_ASYNCH
+/**
+ * \defgroup AsynchSPI Asynchronous SPI Hardware Abstraction Layer
+ * @{
+ */
+
+
+/**
+ * \internal
+ * Writes a character from the TX buffer to the Data register.
+ *
+ * \param[in,out]  module  Pointer to SPI software instance struct
+ */
+static void _spi_write_async(spi_t *obj)
+{
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+
+    uint16_t data_to_send;
+    uint8_t *tx_buffer = obj->tx_buff.buffer;
+
+    /* Do nothing if we are at the end of buffer */
+    if (obj->tx_buff.pos < obj->tx_buff.length) {
+        /* Write value will be at least 8-bits long */
+        if (tx_buffer) {
+            data_to_send = tx_buffer[obj->tx_buff.pos];
+        } else {
+            data_to_send = dummy_fill_word;
+        }
+        /* Increment 8-bit index */
+        obj->tx_buff.pos++;
+
+        if (_SPI(obj).CTRLB.bit.CHSIZE == 1) {
+            if (tx_buffer)
+                data_to_send |= (tx_buffer[obj->tx_buff.pos] << 8);
+            /* Increment 8-bit index */
+            obj->tx_buff.pos++;
+        }
+    } else {
+        /* Write a dummy packet */
+        /* TODO: Current implementation do not enter this condition, remove if not needed */
+        data_to_send = dummy_fill_word;
+    }
+
+    /* Write the data to send*/
+    _SPI(obj).DATA.reg = data_to_send & SERCOM_SPI_DATA_MASK;
+
+    /* Check for error */
+    if ((_SPI(obj).INTFLAG.reg & SERCOM_SPI_INTFLAG_ERROR) && (obj->spi.mask & SPI_EVENT_ERROR)) {
+        obj->spi.event |= SPI_EVENT_ERROR;
+    }
+}
+
+/**
+ * \internal
+ * Reads a character from the Data register to the RX buffer.
+ *
+ * \param[in,out]  module  Pointer to SPI software instance struct
+ */
+static void _spi_read_async(spi_t *obj)
+{
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+
+    uint8_t *rx_buffer = obj->rx_buff.buffer;
+
+    /* Check if data is overflown */
+    if (_SPI(obj).STATUS.reg & SERCOM_SPI_STATUS_BUFOVF) {
+        /* Clear overflow flag */
+        _SPI(obj).STATUS.reg |= SERCOM_SPI_STATUS_BUFOVF;
+        if (obj->spi.mask & SPI_EVENT_RX_OVERFLOW) {
+            /* Set overflow error */
+            obj->spi.event |= SPI_EVENT_RX_OVERFLOW;
+            return;
+        }
+    }
+
+    /* Read data, either valid, or dummy */
+    uint16_t received_data = (_SPI(obj).DATA.reg & SERCOM_SPI_DATA_MASK);
+
+    /* Do nothing if we are at the end of buffer */
+    if ((obj->rx_buff.pos >= obj->rx_buff.length) && rx_buffer) {
+        return;
+    }
+
+    /* Read value will be at least 8-bits long */
+    rx_buffer[obj->rx_buff.pos] = received_data;
+    /* Increment 8-bit index */
+    obj->rx_buff.pos++;
+
+    if (_SPI(obj).CTRLB.bit.CHSIZE == 1) {
+        /* 9-bit data, write next received byte to the buffer */
+        rx_buffer[obj->rx_buff.pos] = (received_data >> 8);
+        /* Increment 8-bit index */
+        obj->rx_buff.pos++;
+    }
+
+    /* Check for error */
+    if ((_SPI(obj).INTFLAG.reg & SERCOM_SPI_INTFLAG_ERROR) && (obj->spi.mask & SPI_EVENT_ERROR)) {
+        obj->spi.event |= SPI_EVENT_ERROR;
+    }
+}
+
+/**
+ * \internal
+ * Clears all interrupt flags of SPI
+ *
+ * \param[in,out]  module  Pointer to SPI software instance struct
+ */
+static void _spi_clear_interrupts(spi_t *obj)
+{
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+
+    uint8_t sercom_index = _sercom_get_sercom_inst_index(obj->spi.spi);
+
+    /* Clear all interrupts */
+    _SPI(obj).INTENCLR.reg =
+        SERCOM_SPI_INTFLAG_DRE |
+        SERCOM_SPI_INTFLAG_TXC |
+        SERCOM_SPI_INTFLAG_RXC |
+        SERCOM_SPI_INTFLAG_ERROR;
+    NVIC_DisableIRQ(SERCOM0_IRQn + sercom_index);
+    NVIC_SetVector((SERCOM0_IRQn + sercom_index), (uint32_t)NULL);
+}
+
+/**
+ * \internal
+ * Starts transceive of buffers with a given length
+ *
+ * \param[in,out]  obj   Pointer to SPI software instance struct
+ *
+ */
+static enum status_code _spi_transceive_buffer(spi_t *obj)
+{
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+
+    uint16_t interrupt_status = _SPI(obj).INTFLAG.reg;
+    interrupt_status &= _SPI(obj).INTENSET.reg;
+
+    if (interrupt_status & SERCOM_SPI_INTFLAG_DRE) {
+        /* Clear DRE interrupt */
+        _SPI(obj).INTENCLR.reg = SERCOM_SPI_INTFLAG_DRE;
+        /* Write data */
+        _spi_write_async(obj);
+        /* Set TXC interrupt */
+        _SPI(obj).INTENSET.reg |= SERCOM_SPI_INTFLAG_TXC;
+    }
+    if (interrupt_status & SERCOM_SPI_INTFLAG_TXC) {
+        /* Clear TXC interrupt */
+        _SPI(obj).INTENCLR.reg = SERCOM_SPI_INTFLAG_TXC;
+        if ((obj->rx_buff.buffer) && (obj->rx_buff.pos < obj->rx_buff.length)) {
+            while (!spi_is_ready_to_read(obj));
+            _spi_read_async(obj);
+            if ((obj->tx_buff.pos >= obj->tx_buff.length) && (obj->tx_buff.length < obj->rx_buff.length)) {
+                obj->tx_buff.length = obj->rx_buff.length;
+                obj->tx_buff.buffer = 0;
+            }
+        }
+        if (obj->tx_buff.pos < obj->tx_buff.length) {
+            /* Set DRE interrupt */
+            _SPI(obj).INTENSET.reg |= SERCOM_SPI_INTFLAG_DRE;
+        }
+    }
+
+    if (obj->spi.event & (SPI_EVENT_ERROR | SPI_EVENT_RX_OVERFLOW) || (interrupt_status & SERCOM_SPI_INTFLAG_ERROR)) {
+        /* Clear all interrupts */
+        _spi_clear_interrupts(obj);
+
+        if (interrupt_status & SERCOM_SPI_INTFLAG_ERROR) {
+            obj->spi.event = STATUS_ERR_BAD_DATA;
+        }
+
+        /* Transfer interrupted, invoke the callback function */
+        if (obj->spi.event & SPI_EVENT_RX_OVERFLOW) {
+            obj->spi.status = STATUS_ERR_OVERFLOW;
+        } else {
+            obj->spi.status = STATUS_ERR_BAD_DATA;
+        }
+        return obj->spi.status;
+    }
+
+    if ((obj->tx_buff.pos >= obj->tx_buff.length) && (obj->rx_buff.pos >= obj->rx_buff.length) && (interrupt_status & SERCOM_SPI_INTFLAG_TXC)) {
+        /* Clear all interrupts */
+        _spi_clear_interrupts(obj);
+
+        /* Transfer complete, invoke the callback function */
+        obj->spi.event = SPI_EVENT_INTERNAL_TRANSFER_COMPLETE;
+        obj->spi.status = STATUS_OK;
+    }
+
+    return obj->spi.status;
+}
+
+/** Begin the SPI transfer. Buffer pointers and lengths are specified in tx_buff and rx_buff
+ *
+ * @param[in] obj       The SPI object which holds the transfer information
+ * @param[in] tx        The buffer to send
+ * @param[in] tx_length The number of words to transmit
+ * @param[out]rx        The buffer to receive
+ * @param[in] rx_length The number of words to receive
+ * @param[in] bit_width The bit width of buffer words
+ * @param[in] event     The logical OR of events to be registered
+ * @param[in] handler   SPI interrupt handler
+ * @param[in] hint      A suggestion for how to use DMA with this transfer **< DMA currently not implemented >**
+ */
+void spi_master_transfer(spi_t *obj, const void *tx, size_t tx_length, void *rx, size_t rx_length, uint8_t bit_width, uint32_t handler, uint32_t event, DMAUsage hint)
+{
+    uint16_t dummy_read;
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+
+    uint8_t sercom_index = _sercom_get_sercom_inst_index(obj->spi.spi);
+
+    obj->spi.tx_buffer = tx;
+    obj->tx_buff.buffer = tx;
+    obj->tx_buff.pos = 0;
+    if (tx) {
+        /* Only two bit rates supported now */
+        obj->tx_buff.length = tx_length * ((bit_width > 8)? 2 : 1);
+    } else {
+        if (rx) {
+            obj->tx_buff.length = rx_length * ((bit_width > 8)? 2 : 1);
+        } else {
+            /* Nothing to transfer */
+            return;
+        }
+    }
+
+    obj->spi.rx_buffer = rx;
+    obj->rx_buff.buffer = rx;
+    obj->rx_buff.pos = 0;
+    if (rx) {
+        /* Only two bit rates supported now */
+        obj->rx_buff.length = rx_length * ((bit_width > 8)? 2 : 1);
+    } else {
+        /* Disable RXEN */
+        spi_disable(obj);
+        _SPI(obj).CTRLB.bit.RXEN = 0;
+        spi_enable(obj);
+        obj->rx_buff.length = 0;
+    }
+
+    /* Clear data buffer if there is anything pending to read */
+    while (spi_is_ready_to_read(obj)) {
+        dummy_read = _SPI(obj).DATA.reg;
+    }
+
+    obj->spi.mask = event;
+
+    obj->spi.dma_usage = hint;
+
+    /*if (hint == DMA_USAGE_NEVER) {** TEMP: Commented as DMA is not implemented now */
+    /* Use irq method */
+    uint16_t irq_mask = 0;
+    obj->spi.status = STATUS_BUSY;
+
+    /* Enable interrupt */
+    NVIC_SetVector((SERCOM0_IRQn + sercom_index), handler);
+    NVIC_EnableIRQ(SERCOM0_IRQn + sercom_index);
+
+    /* Clear all interrupts */
+    _SPI(obj).INTENCLR.reg = SERCOM_SPI_INTFLAG_TXC | SERCOM_SPI_INTFLAG_RXC | SERCOM_SPI_INTFLAG_ERROR;
+    _SPI(obj).INTFLAG.reg =  SERCOM_SPI_INTFLAG_TXC | SERCOM_SPI_INTFLAG_ERROR;
+    _SPI(obj).STATUS.reg |=  SERCOM_SPI_STATUS_BUFOVF;
+
+    /* Set SPI interrupts */
+    /* Set DRE flag to kick start transmission */
+    irq_mask |= SERCOM_SPI_INTFLAG_DRE;
+
+    if (event & SPI_EVENT_ERROR) {
+        irq_mask |= SERCOM_SPI_INTFLAG_ERROR;
+    }
+    _SPI(obj).INTENSET.reg = irq_mask;
+    /*} ** TEMP: Commented as DMA is not implemented now */
+}
+
+/** The asynchronous IRQ handler
+ *
+ * Reads the received values out of the RX FIFO, writes values into the TX FIFO and checks for transfer termination
+ * conditions, such as buffer overflows or transfer complete.
+ * @param[in] obj     The SPI object which holds the transfer information
+ * @return event flags if a transfer termination condition was met or 0 otherwise.
+ */
+uint32_t spi_irq_handler_asynch(spi_t *obj)
+{
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+    enum status_code tmp_status;
+
+    uint32_t transfer_event = 0;
+
+    /*if (obj->spi.dma_usage == DMA_USAGE_NEVER) {** TEMP: Commented as DMA is not implemented now */
+    /* IRQ method */
+    tmp_status = _spi_transceive_buffer(obj);
+    if (STATUS_BUSY != tmp_status) {
+        if ((obj->spi.event & SPI_EVENT_INTERNAL_TRANSFER_COMPLETE) && (tmp_status == STATUS_OK)) {
+            obj->spi.event |= SPI_EVENT_COMPLETE;
+        }
+        transfer_event = obj->spi.event & (obj->spi.mask | SPI_EVENT_INTERNAL_TRANSFER_COMPLETE);
+    }
+    /*}** TEMP: Commented as DMA is not implemented now */
+    return transfer_event;
+}
+
+/** Attempts to determine if the SPI peripheral is already in use.
+ * @param[in] obj The SPI object to check for activity
+ * @return non-zero if the SPI port is active or zero if it is not.
+ */
+uint8_t spi_active(spi_t *obj)
+{
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+
+    /* Check if the SPI module is busy with a job */
+    return (obj->spi.status == STATUS_BUSY);
+}
+
+/** Abort an SPI transfer
+ *
+ * @param obj The SPI peripheral to stop
+ */
+void spi_abort_asynch(spi_t *obj)
+{
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+
+    uint8_t sercom_index = _sercom_get_sercom_inst_index(obj->spi.spi);
+
+    /* Clear all interrupts */
+    _SPI(obj).INTENCLR.reg =
+        SERCOM_SPI_INTFLAG_DRE |
+        SERCOM_SPI_INTFLAG_TXC |
+        SERCOM_SPI_INTFLAG_RXC |
+        SERCOM_SPI_INTFLAG_ERROR;
+
+    // TODO: Disable and remove irq handler
+    NVIC_DisableIRQ(SERCOM0_IRQn + sercom_index);
+    NVIC_SetVector((SERCOM0_IRQn + sercom_index), (uint32_t)NULL);
+
+    obj->spi.status = STATUS_ABORTED;
+}
+
+#endif /* DEVICE_SPI_ASYNCH */