http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/a280628a/hw/mcu/atmel/samd21xx/src/sam0/drivers/sercom/spi_master_vec/spi_master_vec.c ---------------------------------------------------------------------- diff --git a/hw/mcu/atmel/samd21xx/src/sam0/drivers/sercom/spi_master_vec/spi_master_vec.c b/hw/mcu/atmel/samd21xx/src/sam0/drivers/sercom/spi_master_vec/spi_master_vec.c deleted file mode 100755 index 39a7327..0000000 --- a/hw/mcu/atmel/samd21xx/src/sam0/drivers/sercom/spi_master_vec/spi_master_vec.c +++ /dev/null @@ -1,586 +0,0 @@ -/** - * \file - * - * \brief SERCOM SPI master with vectored I/O driver implementation - * - * Copyright (C) 2013-2015 Atmel Corporation. All rights reserved. - * - * \asf_license_start - * - * \page License - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. The name of Atmel may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * 4. This software may only be redistributed and used in connection with an - * Atmel microcontroller product. - * - * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * \asf_license_stop - * - */ -/* - * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> - */ - -#include "spi_master_vec.h" -#include <sercom_interrupt.h> -#include <system.h> -#include <system_interrupt.h> - -/** - * \ingroup asfdoc_sam0_sercom_spi_master_vec_group - * - * @{ - */ - -/** - * \name Internal functions - * @{ - */ - -/** \cond INTERNAL */ - -static void _spi_master_vec_int_handler(uint8_t sercom_index); - -/** - * \brief Wait for SERCOM SPI to synchronize - * - * \param[in] sercom_spi SERCOM SPI to check for synchronization. - * - * \note The implementation of this function depends on the SERCOM revision. - */ -static inline void _spi_master_vec_wait_for_sync(SercomSpi *const sercom_spi) -{ -#if defined(FEATURE_SERCOM_SYNCBUSY_SCHEME_VERSION_1) - while (sercom_spi->STATUS.reg & SERCOM_SPI_STATUS_SYNCBUSY) { - /* Intentionally left empty */ - } -#elif defined(FEATURE_SERCOM_SYNCBUSY_SCHEME_VERSION_2) - while (sercom_spi->SYNCBUSY.reg) { - /* Intentionally left empty */ - } -#else -# error Unknown SERCOM SYNCBUSY scheme! -#endif -} - -/** - * \brief Pin MUX configuration helper - * - * \param[in] pinmux Pin MUX setting to apply. Special values: - * \arg \c PINMUX_UNUSED to do nothing. - * \arg \c PINMUX_DEFAULT to use default pin MUX for the SERCOM pad. - * \param[in] sercom,padnum SERCOM pad specification, for \ref PINMUX_DEFAULT. - */ -static inline void _spi_master_vec_pinmux_helper(uint32_t pinmux, - Sercom *const sercom, uint8_t padnum) -{ - struct system_pinmux_config pin_conf; - - if (pinmux == PINMUX_DEFAULT) { - pinmux = _sercom_get_default_pad(sercom, padnum); - } - - if (pinmux == PINMUX_UNUSED) { - return; - } - - system_pinmux_get_config_defaults(&pin_conf); - pin_conf.mux_position = pinmux & 0xFFFF; - system_pinmux_pin_set_config(pinmux >> 16, &pin_conf); -}; - -/** \endcond */ - -/** @} */ - -/** - * \brief Initialize hardware and driver instance - * - * This function configures the clock system for the specified SERCOM module, - * sets up the related pins and their MUX, initializes the SERCOM in SPI master - * mode, and prepares the driver instance for operation. - * - * \pre \ref system_init() must have been called prior to this function. - * - * The SERCOM SPI module is left disabled after initialization, and must be - * enabled with \ref spi_master_vec_enable() before a transfer can be done. - * - * \param[out] module Driver instance to initialize. - * \param[in,out] sercom SERCOM module to initialize and associate driver - * instance with. - * \param[in] config Driver configuration to use. - * - * \return Status of initialization. - * \retval STATUS_OK if initialization succeeded. - * \retval STATUS_ERR_INVALID_ARG if driver has been misconfigured. - */ -enum status_code spi_master_vec_init(struct spi_master_vec_module *const module, - Sercom *const sercom, const struct spi_master_vec_config *const config) -{ - Assert(module); - Assert(sercom); - Assert(config); - - enum status_code status; - SercomSpi *const spi_hw = &(sercom->SPI); - struct system_gclk_chan_config gclk_chan_conf; - uint16_t tmp_baud; - uint32_t sercom_index = _sercom_get_sercom_inst_index((Sercom *)spi_hw); -#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) - uint32_t pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos; -#else - uint32_t pm_index = sercom_index + PM_APBCMASK_SERCOM0_Pos; -#endif - uint32_t gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; - uint32_t gclk_hz; - - module->sercom = sercom; - - /* Enable clock for the module interface */ - system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index); - - /* Set up the GCLK for the module */ - system_gclk_chan_get_config_defaults(&gclk_chan_conf); - gclk_chan_conf.source_generator = config->gclk_generator; - system_gclk_chan_set_config(gclk_index, &gclk_chan_conf); - system_gclk_chan_enable(gclk_index); - sercom_set_gclk_generator(config->gclk_generator, false); - - _spi_master_vec_wait_for_sync(spi_hw); - - /* Set up the SERCOM SPI module as master */ - spi_hw->CTRLA.reg = SERCOM_SPI_CTRLA_MODE(0x3); - spi_hw->CTRLA.reg |= (uint32_t)config->mux_setting - | config->transfer_mode - | config->data_order - | ((config->run_in_standby || system_is_debugger_present()) ? - SERCOM_SPI_CTRLA_RUNSTDBY : 0); - - /* Get baud value from configured baudrate and internal clock rate */ - gclk_hz = system_gclk_chan_get_hz(gclk_index); - status = _sercom_get_sync_baud_val(config->baudrate, gclk_hz, &tmp_baud); - - if (status != STATUS_OK) { - /* Baud rate calculation error! */ - return STATUS_ERR_INVALID_ARG; - } - - spi_hw->BAUD.reg = (uint8_t)tmp_baud; - - /* Configure the pin multiplexers */ - _spi_master_vec_pinmux_helper(config->pinmux_pad0, sercom, 0); - _spi_master_vec_pinmux_helper(config->pinmux_pad3, sercom, 3); - - /* SERCOM PAD1 and PAD2 are used for slave SS. - * This is a SPI master driver, so control of slave SS must be left to - * the PORT module, i.e., peripheral MUX should not be set for that pin. - * DOPO controls which PAD is used for slave SS: - * If DOPO is odd, SERCOM_PAD1 is SS: SERCOM_PAD2 can be MUXed. - * If DOPO is even, SERCOM_PAD2 is SS: SERCOM_PAD1 can be MUXed. - */ - if (config->mux_setting & (1 << SERCOM_SPI_CTRLA_DOPO_Pos)) { - _spi_master_vec_pinmux_helper(config->pinmux_pad2, sercom, 2); - } else { - _spi_master_vec_pinmux_helper(config->pinmux_pad1, sercom, 1); - } - - /* Initialize our instance and register interrupt handler + data */ - module->rx_bufdesc_ptr = NULL; - module->tx_bufdesc_ptr = NULL; - module->direction = SPI_MASTER_VEC_DIRECTION_IDLE; - module->status = STATUS_OK; -#ifdef CONF_SPI_MASTER_VEC_OS_SUPPORT - CONF_SPI_MASTER_VEC_CREATE_SEMAPHORE(module->busy_semaphore); -#endif - - _sercom_set_handler(sercom_index, _spi_master_vec_int_handler); - _sercom_instances[sercom_index] = module; - - return STATUS_OK; -} - -/** - * \brief Enable the SERCOM SPI module - * - * This function must be called after \ref spi_master_vec_init() before a - * transfer can be started. - * - * \param[in,out] module Driver instance to operate on. - */ -void spi_master_vec_enable(const struct spi_master_vec_module *const module) -{ - Assert(module); - Assert(module->sercom); - - SercomSpi *const spi_hw = &(module->sercom->SPI); - - spi_hw->INTENCLR.reg = SERCOM_SPI_INTFLAG_DRE | SERCOM_SPI_INTFLAG_RXC - | SERCOM_SPI_INTFLAG_TXC; - - _spi_master_vec_wait_for_sync(spi_hw); - - spi_hw->CTRLA.reg |= SERCOM_SPI_CTRLA_ENABLE; - - system_interrupt_enable(_sercom_get_interrupt_vector(module->sercom)); -} - -/** - * \brief Disable the SERCOM SPI module - * - * \param[in,out] module Driver instance to operate on. - */ -void spi_master_vec_disable(struct spi_master_vec_module *const module) -{ - Assert(module); - Assert(module->sercom); - - SercomSpi *const spi_hw = &(module->sercom->SPI); - - system_interrupt_disable(_sercom_get_interrupt_vector(module->sercom)); - - _spi_master_vec_wait_for_sync(spi_hw); - - spi_hw->CTRLB.reg = 0; - spi_hw->CTRLA.reg &= ~SERCOM_SPI_CTRLA_ENABLE; - module->rx_bufdesc_ptr = NULL; - module->tx_bufdesc_ptr = NULL; - module->direction = SPI_MASTER_VEC_DIRECTION_IDLE; - module->status = STATUS_OK; -} - -/** - * \brief Reset the SERCOM SPI module - * - * This function will disable and reset the SPI module to its power on default - * values. - * - * \param[in,out] module Pointer to a driver instance. - */ -void spi_master_vec_reset(struct spi_master_vec_module *const module) -{ - /* Sanity check arguments */ - Assert(module); - Assert(module->sercom); - - SercomSpi *const spi_hw = &(module->sercom->SPI); - - /* Disable the module */ - spi_master_vec_disable(module); - - _spi_master_vec_wait_for_sync(spi_hw); - - /* Software reset the module */ - spi_hw->CTRLA.reg |= SERCOM_SPI_CTRLA_SWRST; - -#ifdef CONF_SPI_MASTER_VEC_OS_SUPPORT - CONF_SPI_MASTER_VEC_DELETE_SEMAPHORE(module->busy_semaphore); -#endif -} - -/** - * \brief Start vectored I/O transfer - * - * This function initiates a uni- or bidirectional SPI transfer from/to any - * number of data buffers. The transfer is interrupt-driven and will run in the - * background, after this function has returned. - * - * The buffers to transmit from or receive into must be described in arrays of - * buffer descriptors. These arrays \e must end with descriptors that specify - * zero buffer length. The first descriptor in an array can \e not specify zero - * length. The number of bytes to transmit and to receive do not have to be - * equal. - * - * If the address for a receive buffer is set to \c NULL, the received bytes - * corresponding to that buffer descriptor will be discarded. This is useful if - * slave is already set up to transfer a number of bytes, but the master has no - * available buffer to receive them into. As an example, to receive the two - * first bytes and discard the 128 following, the buffer descriptors could be: -\code - struct spi_master_vec_bufdesc rx_buffers[3] = { - // Read two status bytes - {.data = status_buffer, .length = 2}, - // Discard 128 data bytes - {.data = NULL, .length = 128}, - // End of reception - {.length = 0}, - }; -\endcode - * - * To initiate a unidirectional transfer, pass \c NULL as the address of either - * buffer descriptor array, like this: -\code - // Transmit some buffers - spi_master_vec_transceive_buffer_job(&module, tx_buffers, NULL); - - // Receive some buffers - spi_master_vec_transceive_buffer_job(&module, NULL, rx_buffers); -\endcode - * - * \pre \ref spi_master_vec_init() and \ref spi_master_vec_enable() must have - * been called before this function. - * - * \param[in,out] module Driver instance to operate on. - * \param[in] tx_bufdescs address of buffer descriptor array for bytes to - * transmit. - * \arg \c NULL if the transfer is a simplex read. - * \param[in,out] rx_bufdescs address of buffer descriptor array for storing - * received bytes. - * \arg \c NULL if the transfer is a simplex write. - * - * \return Status of transfer start. - * \retval STATUS_OK if transfer was started. - * \retval STATUS_BUSY if a transfer is already on-going. - */ -enum status_code spi_master_vec_transceive_buffer_job( - struct spi_master_vec_module *const module, - struct spi_master_vec_bufdesc tx_bufdescs[], - struct spi_master_vec_bufdesc rx_bufdescs[]) -{ - Assert(module); - Assert(module->sercom); - Assert(tx_bufdescs || rx_bufdescs); - - SercomSpi *const spi_hw = &(module->sercom->SPI); - uint32_t tmp_ctrlb; - uint8_t tmp_intenset; - - system_interrupt_enter_critical_section(); - if (module->status == STATUS_BUSY) { - system_interrupt_leave_critical_section(); - return STATUS_BUSY; - } else { - module->status = STATUS_BUSY; - system_interrupt_leave_critical_section(); - } - -#ifdef CONF_SPI_MASTER_VEC_OS_SUPPORT - CONF_SPI_MASTER_VEC_TAKE_SEMAPHORE(module->busy_semaphore); -#endif - - module->tx_bufdesc_ptr = tx_bufdescs; - module->rx_bufdesc_ptr = rx_bufdescs; - - if (tx_bufdescs && rx_bufdescs) { - Assert(tx_bufdescs[0].length); - Assert(rx_bufdescs[0].length); - - module->direction = SPI_MASTER_VEC_DIRECTION_BOTH; - module->tx_length = tx_bufdescs[0].length; - module->tx_head_ptr = tx_bufdescs[0].data; - module->rx_length = rx_bufdescs[0].length; - module->rx_head_ptr = rx_bufdescs[0].data; - module->tx_lead_on_rx = 0; - tmp_ctrlb = SERCOM_SPI_CTRLB_RXEN; - tmp_intenset = SERCOM_SPI_INTFLAG_DRE | SERCOM_SPI_INTFLAG_RXC; - } else { - if (tx_bufdescs) { - Assert(tx_bufdescs[0].length); - - module->direction = SPI_MASTER_VEC_DIRECTION_WRITE; - module->tx_length = tx_bufdescs[0].length; - module->tx_head_ptr = tx_bufdescs[0].data; - tmp_ctrlb = 0; - tmp_intenset = SERCOM_SPI_INTFLAG_DRE; - } else { - Assert(rx_bufdescs[0].length); - - module->direction = SPI_MASTER_VEC_DIRECTION_READ; - module->rx_length = rx_bufdescs[0].length; - module->rx_head_ptr = rx_bufdescs[0].data; - module->tx_lead_on_rx = 0; - tmp_ctrlb = SERCOM_SPI_CTRLB_RXEN; - tmp_intenset = SERCOM_SPI_INTFLAG_DRE | SERCOM_SPI_INTFLAG_RXC; - } - } - - /* Ensure the SERCOM is sync'ed before writing these registers */ - _spi_master_vec_wait_for_sync(spi_hw); - - spi_hw->CTRLB.reg = tmp_ctrlb; - spi_hw->INTENSET.reg = tmp_intenset; - - return STATUS_OK; -} - -/** - * \brief Interrupt handler - * - * \param[in] sercom_index SERCOM instance number passed from the master SERCOM - * driver. - */ -static void _spi_master_vec_int_handler(uint8_t sercom_index) -{ - struct spi_master_vec_module *const module = - _sercom_instances[sercom_index]; - enum _spi_master_vec_direction dir = module->direction; - SercomSpi *const spi_hw = &(module->sercom->SPI); - uint8_t int_status; - - int_status = spi_hw->INTFLAG.reg ; - int_status &= spi_hw->INTENSET.reg; - - if (int_status & SERCOM_SPI_INTFLAG_DRE) { - uint_fast8_t tx_lead_on_rx = module->tx_lead_on_rx; - - /* If TX is ahead of RX by 2+ bytes, allow RX to catch up. - * Note: will only happen _once_ per READ or BOTH. - */ - if ((tx_lead_on_rx >= 2) && (dir != SPI_MASTER_VEC_DIRECTION_WRITE)) { - Assert((dir == SPI_MASTER_VEC_DIRECTION_READ) - || (dir == SPI_MASTER_VEC_DIRECTION_BOTH)); - Assert(int_status & SERCOM_SPI_INTFLAG_RXC); - /* Otherwise, we can send more bytes */ - } else { - module->tx_lead_on_rx = ++tx_lead_on_rx; - - /* If doing a READ, just send 0 to trigger the transfer */ - if (dir == SPI_MASTER_VEC_DIRECTION_READ) { - uint32_t tx_lead_limit; - - spi_hw->DATA.reg = 0; - -check_for_read_end: - /* With current TX'ed bytes, will we get the last RX byte? - * If so, we can disable the DRE interrupt to stop transmitting. - * - * Since a buffer can have minimum 1 byte length, this check is - * simplified by first checking if the RX end is so close that - * the max. 2 byte lead of TX may actually fill the buffers. - */ - tx_lead_limit = (module->rx_bufdesc_ptr + 1)->length; - - if (!tx_lead_limit || !(module->rx_bufdesc_ptr + 2)->length) { - tx_lead_limit += module->rx_length; - - if (tx_lead_on_rx >= tx_lead_limit) { - spi_hw->INTENCLR.reg = SERCOM_SPI_INTFLAG_DRE; - } - } - /* For WRITE and BOTH, output current byte */ - } else { - spi_master_vec_buflen_t tx_length; - uint8_t *tx_head_ptr; - - tx_head_ptr = module->tx_head_ptr; - spi_hw->DATA.reg = *(tx_head_ptr++); - - /* Check if this was the last byte to send */ - tx_length = module->tx_length - 1; - - if (tx_length) { - module->tx_head_ptr = tx_head_ptr; - module->tx_length = tx_length; - } else { - /* Any more buffers left to send, perhaps? */ - tx_length = (++module->tx_bufdesc_ptr)->length; - - if (tx_length) { - module->tx_head_ptr = module->tx_bufdesc_ptr->data; - module->tx_length = tx_length; - } else { - if (dir == SPI_MASTER_VEC_DIRECTION_WRITE) { - /* Disable DRE and enable TXC to end WRITE */ - spi_hw->INTENCLR.reg = SERCOM_SPI_INTFLAG_DRE; - spi_hw->INTENSET.reg = SERCOM_SPI_INTFLAG_TXC; - } else { - /* For BOTH, check if we still have bytes to read */ - dir = SPI_MASTER_VEC_DIRECTION_READ; - module->direction = dir; - goto check_for_read_end; - } - } - } - } - } - } - - /* For READ and BOTH, store the received byte */ - if (int_status & SERCOM_SPI_INTFLAG_RXC) { - spi_master_vec_buflen_t rx_length; - uint8_t *rx_head_ptr; - - rx_head_ptr = module->rx_head_ptr; - if (rx_head_ptr != NULL) { - *(rx_head_ptr++) = spi_hw->DATA.reg; - } else { - uint8_t dummy; - dummy = spi_hw->DATA.reg; - UNUSED(dummy); - } - module->tx_lead_on_rx--; - - /* Check if this was the last byte to receive */ - rx_length = module->rx_length - 1; - - if (rx_length) { - module->rx_head_ptr = rx_head_ptr; - module->rx_length = rx_length; - } else { - /* Any more buffers left to receive into? */ - rx_length = (++module->rx_bufdesc_ptr)->length; - - if (rx_length) { - module->rx_head_ptr = module->rx_bufdesc_ptr->data; - module->rx_length = rx_length; - } else { - /* Disable the SPI receiver (instant effect) and RX interrupt */ - spi_hw->CTRLB.reg = 0; - spi_hw->INTENCLR.reg = SERCOM_SPI_INTFLAG_RXC; - - if (dir == SPI_MASTER_VEC_DIRECTION_READ) { - /* If doing READ, end the transaction here */ - dir = SPI_MASTER_VEC_DIRECTION_IDLE; - module->direction = dir; - module->status = STATUS_OK; -#ifdef CONF_SPI_MASTER_VEC_OS_SUPPORT - CONF_SPI_MASTER_VEC_GIVE_SEMAPHORE_FROM_ISR(module->busy_semaphore); -#endif - } else { - /* If doing BOTH, change direction to WRITE */ - dir = SPI_MASTER_VEC_DIRECTION_WRITE; - module->direction = dir; - } - } - } - } - - /* For WRITE */ - if (int_status & SERCOM_SPI_INTFLAG_TXC) { - /* End transaction here, since last byte has been sent */ - spi_hw->INTENCLR.reg = SERCOM_SPI_INTFLAG_TXC; - - dir = SPI_MASTER_VEC_DIRECTION_IDLE; - module->direction = dir; - module->status = STATUS_OK; -#ifdef CONF_SPI_MASTER_VEC_OS_SUPPORT - CONF_SPI_MASTER_VEC_GIVE_SEMAPHORE_FROM_ISR(module->busy_semaphore); -#endif - } -} - -/** - * @} - */ \ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/a280628a/hw/mcu/atmel/samd21xx/src/sam0/drivers/sercom/spi_master_vec/spi_master_vec.h ---------------------------------------------------------------------- diff --git a/hw/mcu/atmel/samd21xx/src/sam0/drivers/sercom/spi_master_vec/spi_master_vec.h b/hw/mcu/atmel/samd21xx/src/sam0/drivers/sercom/spi_master_vec/spi_master_vec.h deleted file mode 100755 index a10ae22..0000000 --- a/hw/mcu/atmel/samd21xx/src/sam0/drivers/sercom/spi_master_vec/spi_master_vec.h +++ /dev/null @@ -1,692 +0,0 @@ -/** - * \file - * - * \brief SERCOM SPI master with vectored I/O driver include - * - * Copyright (C) 2013-2015 Atmel Corporation. All rights reserved. - * - * \asf_license_start - * - * \page License - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. The name of Atmel may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * 4. This software may only be redistributed and used in connection with an - * Atmel microcontroller product. - * - * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * \asf_license_stop - * - */ -/* - * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> - */ - -#ifndef SPI_MASTER_VEC_H -#define SPI_MASTER_VEC_H - -#include <compiler.h> -#include <gclk.h> -#include <port.h> -#include <spi.h> -#include <status_codes.h> -#include <conf_spi_master_vec.h> - -/** - * \defgroup asfdoc_sam0_sercom_spi_master_vec_group SAM Serial Peripheral Interface Master Driver w/ Vectored I/O (SERCOM SPI) - * - * This driver for Atmel® | SMART SAM devices provides an interface for the configuration - * and operation of the SERCOM module in SPI master mode and uses vectored I/O - * for data transfers. - * - * The following peripherals are used by this driver: - * - SERCOM (Serial Communication Interface) - * - * The following devices can use this driver: - * - Atmel | SMART SAM D20/D21 - * - Atmel | SMART SAM R21 - * - Atmel | SMART SAM D09/D10/D11 - * - Atmel | SMART SAM L21/L22 - * - Atmel | SMART SAM DA1 - * - Atmel | SMART SAM C20/C21 - * - * The reader is assumed to be familiar with the regular SERCOM SPI driver, and - * how it is configured and operated. Configuration of this driver is done a - * similar way and actually re-uses several enumerations (configuration values) - * from the regular SERCOM SPI driver. - * - * The outline of this documentation is as follows: - * - \ref asfdoc_sam0_sercom_spi_master_vec_prerequisites - * - \ref asfdoc_sam0_sercom_spi_master_vec_module_overview - * - \ref asfdoc_sam0_sercom_spi_master_vec_special_considerations - * - \ref asfdoc_sam0_sercom_spi_master_vec_extra_info - * - \ref asfdoc_sam0_sercom_spi_master_vec_examples - * - \ref asfdoc_sam0_sercom_spi_master_vec_api_overview - * - * - * \section asfdoc_sam0_sercom_spi_master_vec_prerequisites Prerequisites - * - * This driver uses the \ref asfdoc_sam0_system_clock_group "SYSTEM clock driver" - * to select the SERCOM's clock source and to configure the SERCOM for the - * desired baud rate. Ensure that the selected clock source is configured and - * that the clock system is initialized. This is typically done indirectly with - * \ref system_init(), or directly with \ref system_clock_init(). - * - * According to the datasheet, the minimum and maximum limits for the baud rate - * is given by: \f$ \frac{1}{2^{17}} \times f_{clk} \le f_{baud} - * \le \frac{1}{2} \times f_{clk} \f$. - * - * - * \section asfdoc_sam0_sercom_spi_master_vec_module_overview Module Overview - * - * This SERCOM SPI master driver supports uni- and bidirectional transfers of - * 8-bit data with vectored I/O, also know as scatter/gather. - * It does not implement control of SS or slave addressing since the intended - * usage is in stacks which usually have their own protocols and handshaking - * schemes. - * - * - * \subsection asfdoc_sam0_sercom_spi_master_vectored_io Vectored I/O - * - * Vectored I/O enables the transfer of data from/to any number of buffers with - * arbitrary memory locations without having to do several transfers, i.e., one - * buffer at a time. This feature is useful in stacks because it allows each - * layer of the stack to have a dedicated data buffer, thus avoiding the need - * for a centralized data buffer that the different layers must use in - * cooperation. - * - * The vectored I/O relies on arrays of buffer descriptors which must be passed - * to the driver to start a transfer. These buffer descriptors specify where in - * memory each buffer is, and how large they are. - * \ref asfdoc_sam0_vectored_io_example "The figure below" illustrates this - * for an example with three buffers of varying sizes that are transmitted. - * - * \anchor asfdoc_sam0_vectored_io_example - * \dot -digraph bufptr_to_spiord { - rankdir=LR; - subgraph cluster_bufptr { - style=invis; - bufptr_label [shape=none, label="Buffer descriptors"]; - bufptrs [shape=record, label="<bf1> [0]|<bf2> [1]|<bf3> [2]|<bf4> [3]"]; - } - subgraph cluster_buf { - style=invis; - buf_label [shape=none, label="Memory layout"]; - bufs [shape=record, label="...|<b1>"yy"|...|<b3>"z"|<b2>"xxx"|..."]; - } - subgraph cluster_spiord { - style=invis; - spiord_label [shape=none, label="SPI transmission"]; - spiord [shape=record, label="<s1>"yy"|<s2>"xxx"|<s3>"z""]; - } - bufptrs:bf1 -> bufs:b1 -> spiord:s1; - bufptrs:bf2 -> bufs:b2 -> spiord:s2; - bufptrs:bf3 -> bufs:b3 -> spiord:s3; - bufptrs:bf4 -> "none"; -} - * \enddot - * - * Note that the last descriptor \e must indicate no next buffer in order for - * the driver to detect that the end of the buffer list has been reached. This - * means that for \c N buffers, \c N+1 buffer descriptors are needed. - * - * Bidirectional transfers are supported without any restrictions on the buffer - * descriptors, so the number of bytes and buffers to receive and transmit do - * \e not have to be the same. - * - * \sa spi_master_vec_transceive_buffer_job() for details on starting transfers. - * - * - * \subsection asfdoc_sam0_sercom_spi_master_os_support OS support - * - * Since this driver is interrupt-driven, it is possible for the MCU to run - * other code while a transfer is on-going. - * - * In a single-threaded application, this can be achieved by starting a transfer - * and then avoid any waiting for completion until absolutely required, e.g., - * when a new transfer is needed. - * - * But in a multi-threaded application, for example based on FreeRTOS, one can - * utilize \e semaphores to let the OS know when a function is waiting and thus - * blocking the thread, and that other threads can be run instead. Put another - * way, the waiting can be made efficient. - * - * This driver has an internal semaphore which is used to signal to the OS - * whenever a function is waiting for a transfer to complete. And since the - * semaphore datatypes and functions are OS-specific, the support has been made - * configurable by the use of macros. Note that support for FreeRTOS is already - * implemented, but must be enabled. - * - * \sa CONF_SPI_MASTER_VEC_OS_SUPPORT for more on the configurable OS support. - * - * - * \section asfdoc_sam0_sercom_spi_master_vec_special_considerations Special Considerations - * - * \subsection asfdoc_sam0_sercom_spi_master_vec_special_isr Interrupt safety - * - * This driver should not be used within interrupt contexts. The reason for this - * is that the driver itself is interrupt driven. Further, the configurable OS - * support is implemented with the assumption that transfers are only started - * in threads, not in interrupt service routines, because it gives the simplest - * API. - * - * - * \subsection asfdoc_sam0_sercom_spi_master_vec_special_mux Signal MUX - * - * The SERCOM module has two layers of signal multiplexing in SPI mode: - * -# SERCOM pad MUX: This routes the SPI signals to internal lines. - * -# PORT pin MUX: This routes the internal line to a device pin. - * - * Both of these layers are configured in the \ref spi_master_vec_config - * "configuration structure", using the members named \c mux_setting and - * \c pinmux_padN. These must be set in combination. - * - * The driver supplies values for the - * \ref spi_master_vec_config::mux_setting "SERCOM pad MUX" from the standard - * ASF SERCOM SPI driver. For the PORT pin MUX configuration, refer to the - * peripheral include file for the device (\c pio_samd20XNN.h ) and use the - * macros that are prefixed with \c PINMUX_, such as - * \c PINMUX_PA04D_SERCOM0_PAD0. It is also possible to use the default pin MUX - * setting for a SERCOM pad by using the \ref PINMUX_DEFAULT macro. The defaults - * are defined in the file \ref sercom_pinout.h. - * - * Note that for \ref spi_master_vec_init() to function properly with the macro - * \ref PINMUX_DEFAULT, the order of the values in \c pinmux_padN \e must be - * correct, i.e., \c pinmux_pad0 must contain the pin MUX setting for - * multiplexing SERCOM pad 0, and so on. - * - * - * \section asfdoc_sam0_sercom_spi_master_vec_extra_info Extra Information - * - * For extra information, see - * \subpage asfdoc_sam0_sercom_spi_master_vec_extra. This includes: - * - \ref asfdoc_sam0_sercom_spi_master_vec_extra_acronyms - * - \ref asfdoc_sam0_sercom_spi_master_vec_extra_dependencies - * - \ref asfdoc_sam0_sercom_spi_master_vec_extra_errata - * - \ref asfdoc_sam0_sercom_spi_master_vec_extra_history - * - * - * \section asfdoc_sam0_sercom_spi_master_vec_examples Examples - * - * For a list of examples related to this driver, see - * \ref asfdoc_sam0_sercom_spi_master_vec_exqsg. - * - * - * \section asfdoc_sam0_sercom_spi_master_vec_api_overview API Overview - * - * @{ - */ - -/** - * Driver configuration structure - * - * \sa asfdoc_sam0_sercom_spi_master_vec_special_considerations for more - * information regarding SERCOM pad and pin MUX. - */ -struct spi_master_vec_config { - /** Baud rate in Hertz. */ - uint32_t baudrate; - /** GCLK generator to use for the SERCOM. */ - enum gclk_generator gclk_generator; - /** Enabled in sleep modes. */ - bool run_in_standby; - /** SERCOM pad MUX setting. */ - enum spi_signal_mux_setting mux_setting; - /** Transfer mode. */ - enum spi_transfer_mode transfer_mode; - /** Data order. */ - enum spi_data_order data_order; - /** Pin MUX setting for SERCOM pad 0. */ - uint32_t pinmux_pad0; - /** Pin MUX setting for SERCOM pad 1. */ - uint32_t pinmux_pad1; - /** Pin MUX setting for SERCOM pad 2. */ - uint32_t pinmux_pad2; - /** Pin MUX setting for SERCOM pad 4. */ - uint32_t pinmux_pad3; -}; - -/** Buffer length container. */ -typedef uint16_t spi_master_vec_buflen_t; - -/** Buffer descriptor structure. */ -struct spi_master_vec_bufdesc { - /** Pointer to buffer start. */ - void *data; - /** Length of buffer. */ - spi_master_vec_buflen_t length; -}; - -/** Transfer direction */ -enum _spi_master_vec_direction { - SPI_MASTER_VEC_DIRECTION_READ, - SPI_MASTER_VEC_DIRECTION_WRITE, - SPI_MASTER_VEC_DIRECTION_BOTH, - SPI_MASTER_VEC_DIRECTION_IDLE, -}; - -/** Driver instance. */ -struct spi_master_vec_module { -#if !defined(__DOXYGEN__) - Sercom *volatile sercom; - volatile bool locked; - volatile enum _spi_master_vec_direction direction; - volatile enum status_code status; - volatile spi_master_vec_buflen_t rx_length; - volatile spi_master_vec_buflen_t tx_length; - uint8_t *volatile rx_head_ptr; - uint8_t *volatile tx_head_ptr; - volatile uint_fast8_t tx_lead_on_rx; - struct spi_master_vec_bufdesc *volatile rx_bufdesc_ptr; - struct spi_master_vec_bufdesc *volatile tx_bufdesc_ptr; -# ifdef CONF_SPI_MASTER_VEC_OS_SUPPORT - CONF_SPI_MASTER_VEC_SEMAPHORE_TYPE busy_semaphore; -# endif -#endif -}; - -/** - * \name Configuration and Initialization - * @{ - */ - -/** - * \brief Initialize configuration with default values. - * - * \param[out] config Configuration struct to initialize. - */ -static inline void spi_master_vec_get_config_defaults( - struct spi_master_vec_config *const config) -{ - config->baudrate = 100000; - config->gclk_generator = GCLK_GENERATOR_0; - config->run_in_standby = false; - config->mux_setting = SPI_SIGNAL_MUX_SETTING_D; - config->transfer_mode = SPI_TRANSFER_MODE_0; - config->data_order = SPI_DATA_ORDER_MSB; - config->pinmux_pad0 = PINMUX_DEFAULT; - config->pinmux_pad1 = PINMUX_DEFAULT; - config->pinmux_pad2 = PINMUX_DEFAULT; - config->pinmux_pad3 = PINMUX_DEFAULT; -} - -#ifdef __cplusplus -extern "C" { -#endif - -enum status_code spi_master_vec_init(struct spi_master_vec_module *const module, - Sercom *const sercom, const struct spi_master_vec_config *const config); - -/** @} */ - -/** - * \name Enable/Disable and Reset - * @{ - */ - -void spi_master_vec_enable(const struct spi_master_vec_module *const module); -void spi_master_vec_disable(struct spi_master_vec_module *const module); -void spi_master_vec_reset(struct spi_master_vec_module *const module); - -/** @} */ - -/** - * \name Lock/Unlock - * @{ - */ - -/** - * \brief Attempt to get lock on driver instance - * - * This function checks the instance's lock, which indicates whether or not it - * is currently in use, and sets the lock if it was not already set. - * - * The purpose of this is to enable exclusive access to driver instances, so - * that, e.g., transactions by different services will not interfere with each - * other. - * - * \param[in,out] module Pointer to the driver instance to lock. - * - * \retval STATUS_OK if the module was locked. - * \retval STATUS_BUSY if the module was already locked. - */ -static inline enum status_code spi_master_vec_lock( - struct spi_master_vec_module *const module) -{ - enum status_code status; - - system_interrupt_enter_critical_section(); - - if (module->locked) { - status = STATUS_BUSY; - } else { - module->locked = true; - status = STATUS_OK; - } - - system_interrupt_leave_critical_section(); - - return status; -} - -/** - * \brief Unlock driver instance - * - * This function clears the instance lock, indicating that it is available for - * use. - * - * \param[in,out] module Pointer to the driver instance to lock. - */ -static inline void spi_master_vec_unlock( - struct spi_master_vec_module *const module) -{ - module->locked = false; -} - -/** @} */ - -/** - * \name Read/Write and Status - * @{ - */ - -enum status_code spi_master_vec_transceive_buffer_job( - struct spi_master_vec_module *const module, - struct spi_master_vec_bufdesc tx_bufdescs[], - struct spi_master_vec_bufdesc rx_bufdescs[]); - -/** - * \brief Get current status of transfer. - * - * \param[in] module Driver instance to operate on. - * - * \return Current status of driver instance. - * \retval STATUS_OK if idle and previous transfer succeeded. - * \retval STATUS_BUSY if a transfer is ongoing. - * \retval <other> if previous transfer failed. - */ -static inline enum status_code spi_master_vec_get_job_status( - const struct spi_master_vec_module *const module) -{ - return module->status; -} - -/** - * \brief Get status of transfer upon job end. - * - * \param[in] module Driver instance to operate on. - * - * \return Current status of driver instance. - * \retval STATUS_OK if idle and previous transfer succeeded. - * \retval <other> if previous transfer failed. - */ -static inline enum status_code spi_master_vec_get_job_status_wait( - const struct spi_master_vec_module *const module) -{ - enum status_code status; - -#ifdef CONF_SPI_MASTER_VEC_OS_SUPPORT - CONF_SPI_MASTER_VEC_TAKE_SEMAPHORE(module->busy_semaphore); - status = spi_master_vec_get_job_status(module); - CONF_SPI_MASTER_VEC_GIVE_SEMAPHORE(module->busy_semaphore); -#else - do { - status = spi_master_vec_get_job_status(module); - } while (status == STATUS_BUSY); -#endif - - return status; -} - - -/** - * \brief Start vectored I/O transfer, wait for it to end. - * - * \param[in,out] module Driver instance to operate on. - * \param[in] tx_bufdescs address of buffer descriptor array for bytes to - * transmit. - * \arg \c NULL if the transfer is a simplex read. - * \param[in,out] rx_bufdescs address of buffer descriptor array for storing - * received bytes. - * \arg \c NULL if the transfer is a simplex write. - * - * \return Status of transfer start. - * \retval STATUS_OK if transfer succeeded. - * \retval STATUS_BUSY if a transfer was already on-going. - * \retval <other> if transfer failed. - */ -static inline enum status_code spi_master_vec_transceive_buffer_wait( - struct spi_master_vec_module *const module, - struct spi_master_vec_bufdesc tx_bufdescs[], - struct spi_master_vec_bufdesc rx_bufdescs[]) -{ - enum status_code status; - - status = spi_master_vec_transceive_buffer_job(module, tx_bufdescs, - rx_bufdescs); - - if (status == STATUS_BUSY) { - return status; - } - - return spi_master_vec_get_job_status_wait(module); -} - -/** @} */ - -#ifdef __cplusplus -} -#endif - -/** - * \name OS Support Configuration - * @{ - */ - -/** - * \def CONF_SPI_MASTER_VEC_OS_SUPPORT - * \brief Enable support for OS - * - * Defining this symbol will enable support for an OS, e.g., FreeRTOS, by using - * the macros in this group: - * - \ref CONF_SPI_MASTER_VEC_SEMAPHORE_TYPE - * - \ref CONF_SPI_MASTER_VEC_CREATE_SEMAPHORE - * - \ref CONF_SPI_MASTER_VEC_DELETE_SEMAPHORE - * - \ref CONF_SPI_MASTER_VEC_TAKE_SEMAPHORE - * - \ref CONF_SPI_MASTER_VEC_GIVE_SEMAPHORE - * - \ref CONF_SPI_MASTER_VEC_GIVE_SEMAPHORE_FROM_ISR - * - * The user must ensure that these macros map to the implementation for the OS - * that is used. Further, required includes must be added alongside these macros - * in \ref conf_spi_master_vec.h. - * - * The purpose of this configuration is to enable usage of the OS' semaphore - * system to wait for transfers to end rather than continuously polling the - * transfer status, which is an inefficient approach. - */ - -/** - * \def CONF_SPI_MASTER_VEC_SEMAPHORE_TYPE - * \brief Semaphore datatype - */ - -/** - * \def CONF_SPI_MASTER_VEC_CREATE_SEMAPHORE - * \brief Create/initialize semaphore - * - * \param semaphore Semaphore member in driver instance. - */ - -/** - * \def CONF_SPI_MASTER_VEC_DELETE_SEMAPHORE - * \brief Delete semaphore - * - * \param semaphore Semaphore member in driver instance. - */ - -/** - * \def CONF_SPI_MASTER_VEC_TAKE_SEMAPHORE - * \brief Wait for and take semaphore - * - * \param semaphore Semaphore member in driver instance. - */ - -/** - * \def CONF_SPI_MASTER_VEC_GIVE_SEMAPHORE - * \brief Give semaphore back - * - * \param semaphore Semaphore member in driver instance. - */ - -/** - * \def CONF_SPI_MASTER_VEC_GIVE_SEMAPHORE_FROM_ISR - * \brief Give semaphore back from an ISR - * - * \param semaphore Semaphore member in driver instance. - */ - -/** @} */ - -/** - * @} - */ - -/** - * \page asfdoc_sam0_sercom_spi_master_vec_extra Extra Information for SERCOM SPI Master Driver w/ Vectored I/O - * - * - * \section asfdoc_sam0_sercom_spi_master_vec_extra_acronyms Acronyms - * - * The table below presents the acronyms used in this module. - * - * <table> - * <tr> - * <th>Acronym</td> - * <th>Description</td> - * </tr> - * <tr> - * <td>GCLK</td> - * <td>Generic Clock</td> - * </tr> - * <tr> - * <td>MISO</td> - * <td>Master Input, Slave Output</td> - * </tr> - * <tr> - * <td>MOSI</td> - * <td>Master Output, Slave Input</td> - * </tr> - * <tr> - * <td>SCK</td> - * <td>Serial Clock</td> - * </tr> - * <tr> - * <td>SPI</td> - * <td>Serial Peripheral Interface</td> - * </tr> - * <tr> - * <td>SS</td> - * <td>Slave Select</td> - * </tr> - * </table> - * - * - * \section asfdoc_sam0_sercom_spi_master_vec_extra_dependencies Dependencies - * - * This driver has the following dependencies: - * - \ref asfdoc_sam0_system_group "System driver" - * - \ref group_sam0_utils "Compiler driver" - * - \ref asfdoc_sam0_port_group "Port driver" - * - \ref Common SERCOM driver base - * - * - * \section asfdoc_sam0_sercom_spi_master_vec_extra_errata Errata - * - * There are no errata related to this driver. - * - * - * \section asfdoc_sam0_sercom_spi_master_vec_extra_history Module History - * - * An overview of the module history is presented in the table below, with - * details on the enhancements and fixes made to the module since its first - * release. The current version of this corresponds to the newest version in the - * table. - * - * <table> - * <tr> - * <th>Changelog</th> - * </tr> - * <tr> - * <td>Initial Release</td> - * </tr> - * </table> - */ - -/** - * \page asfdoc_sam0_sercom_spi_master_vec_exqsg Examples for SERCOM SPI Master Driver w/ Vectored I/O - * - * This is a list of the available Quick Start guides (QSGs) and example - * applications for \ref asfdoc_sam0_sercom_spi_master_vec_group. QSGs are - * simple examples with step-by-step instructions to configure and use this - * driver in a selection of use cases. Note that QSGs can be compiled as a - * standalone application or be added to the user application. - * - * - \subpage asfdoc_sam0_sercom_spi_master_vec_basic - */ - - /** - * \page asfdoc_sam0_sercom_spi_master_vec_document_revision_history Document Revision History - * - * <table> - * <tr> - * <th>Doc. Rev.</td> - * <th>Date</td> - * <th>Comments</td> - * </tr> - * <tr> - * <td>D</td> - * <td>12/2014</td> - * <td>Add SAM L21/C21 support.</td> - * </tr> - * <tr> - * <td>C</td> - * <td>04/2014</td> - * <td>Add SAM D10/D11 support.</td> - * </tr> - * <tr> - * <td>B</td> - * <td>03/2014</td> - * <td>Add SAMR21 support.</td> - * </tr> - * <tr> - * <td>A</td> - * <td>01/2014</td> - * <td>Initial release</td> - * </tr> - * </table> - */ - -#endif /* SPI_MASTER_VEC_H */ http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/a280628a/hw/mcu/atmel/samd21xx/src/sam0/drivers/sercom/usart/usart.c ---------------------------------------------------------------------- diff --git a/hw/mcu/atmel/samd21xx/src/sam0/drivers/sercom/usart/usart.c b/hw/mcu/atmel/samd21xx/src/sam0/drivers/sercom/usart/usart.c deleted file mode 100755 index 5772ae0..0000000 --- a/hw/mcu/atmel/samd21xx/src/sam0/drivers/sercom/usart/usart.c +++ /dev/null @@ -1,811 +0,0 @@ -/** - * \file - * - * \brief SAM SERCOM USART Driver - * - * Copyright (C) 2012-2015 Atmel Corporation. All rights reserved. - * - * \asf_license_start - * - * \page License - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. The name of Atmel may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * 4. This software may only be redistributed and used in connection with an - * Atmel microcontroller product. - * - * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * \asf_license_stop - * - */ -/* - * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> - */ -#include "usart.h" -#include <pinmux.h> -#if USART_CALLBACK_MODE == true -# include "usart_interrupt.h" -#endif - -/** - * \internal - * Set Configuration of the USART module - */ -static enum status_code _usart_set_config( - struct usart_module *const module, - const struct usart_config *const config) -{ - /* Sanity check arguments */ - Assert(module); - Assert(module->hw); - - /* Get a pointer to the hardware module instance */ - SercomUsart *const usart_hw = &(module->hw->USART); - - /* Index for generic clock */ - uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw); - uint32_t gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; - - /* Cache new register values to minimize the number of register writes */ - uint32_t ctrla = 0; - uint32_t ctrlb = 0; -#ifdef FEATURE_USART_ISO7816 - uint32_t ctrlc = 0; -#endif - uint16_t baud = 0; - uint32_t transfer_mode; - - enum sercom_asynchronous_operation_mode mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC; - enum sercom_asynchronous_sample_num sample_num = SERCOM_ASYNC_SAMPLE_NUM_16; - -#ifdef FEATURE_USART_OVER_SAMPLE - switch (config->sample_rate) { - case USART_SAMPLE_RATE_16X_ARITHMETIC: - mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC; - sample_num = SERCOM_ASYNC_SAMPLE_NUM_16; - break; - case USART_SAMPLE_RATE_8X_ARITHMETIC: - mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC; - sample_num = SERCOM_ASYNC_SAMPLE_NUM_8; - break; - case USART_SAMPLE_RATE_3X_ARITHMETIC: - mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC; - sample_num = SERCOM_ASYNC_SAMPLE_NUM_3; - break; - case USART_SAMPLE_RATE_16X_FRACTIONAL: - mode = SERCOM_ASYNC_OPERATION_MODE_FRACTIONAL; - sample_num = SERCOM_ASYNC_SAMPLE_NUM_16; - break; - case USART_SAMPLE_RATE_8X_FRACTIONAL: - mode = SERCOM_ASYNC_OPERATION_MODE_FRACTIONAL; - sample_num = SERCOM_ASYNC_SAMPLE_NUM_8; - break; - } -#endif - - /* Set data order, internal muxing, and clock polarity */ - ctrla = (uint32_t)config->data_order | - (uint32_t)config->mux_setting | - #ifdef FEATURE_USART_OVER_SAMPLE - config->sample_adjustment | - config->sample_rate | - #endif - #ifdef FEATURE_USART_IMMEDIATE_BUFFER_OVERFLOW_NOTIFICATION - (config->immediate_buffer_overflow_notification << SERCOM_USART_CTRLA_IBON_Pos) | - #endif - (config->clock_polarity_inverted << SERCOM_USART_CTRLA_CPOL_Pos); - - enum status_code status_code = STATUS_OK; - - transfer_mode = (uint32_t)config->transfer_mode; -#ifdef FEATURE_USART_ISO7816 - if(config->iso7816_config.enabled) { - transfer_mode = config->iso7816_config.protocol_t; - } -#endif - /* Get baud value from mode and clock */ -#ifdef FEATURE_USART_ISO7816 - if(config->iso7816_config.enabled) { - baud = config->baudrate; - } else { -#endif - switch (transfer_mode) - { - case USART_TRANSFER_SYNCHRONOUSLY: - if (!config->use_external_clock) { - status_code = _sercom_get_sync_baud_val(config->baudrate, - system_gclk_chan_get_hz(gclk_index), &baud); - } - - break; - - case USART_TRANSFER_ASYNCHRONOUSLY: - if (config->use_external_clock) { - status_code = - _sercom_get_async_baud_val(config->baudrate, - config->ext_clock_freq, &baud, mode, sample_num); - } else { - status_code = - _sercom_get_async_baud_val(config->baudrate, - system_gclk_chan_get_hz(gclk_index), &baud, mode, sample_num); - } - - break; - } - - /* Check if calculating the baudrate failed */ - if (status_code != STATUS_OK) { - /* Abort */ - return status_code; - } -#ifdef FEATURE_USART_ISO7816 - } -#endif - -#ifdef FEATURE_USART_IRDA - if(config->encoding_format_enable) { - usart_hw->RXPL.reg = config->receive_pulse_length; - } -#endif - - /* Wait until synchronization is complete */ - _usart_wait_for_sync(module); - - /*Set baud val */ - usart_hw->BAUD.reg = baud; - - /* Set sample mode */ - ctrla |= transfer_mode; - - if (config->use_external_clock == false) { - ctrla |= SERCOM_USART_CTRLA_MODE(0x1); - } - else { - ctrla |= SERCOM_USART_CTRLA_MODE(0x0); - } - - /* Set stopbits and enable transceivers */ - ctrlb = - #ifdef FEATURE_USART_IRDA - (config->encoding_format_enable << SERCOM_USART_CTRLB_ENC_Pos) | - #endif - #ifdef FEATURE_USART_START_FRAME_DECTION - (config->start_frame_detection_enable << SERCOM_USART_CTRLB_SFDE_Pos) | - #endif - #ifdef FEATURE_USART_COLLISION_DECTION - (config->collision_detection_enable << SERCOM_USART_CTRLB_COLDEN_Pos) | - #endif - (config->receiver_enable << SERCOM_USART_CTRLB_RXEN_Pos) | - (config->transmitter_enable << SERCOM_USART_CTRLB_TXEN_Pos); - -#ifdef FEATURE_USART_ISO7816 - if(config->iso7816_config.enabled) { - ctrla |= SERCOM_USART_CTRLA_FORM(0x07); - if (config->iso7816_config.enable_inverse) { - ctrla |= SERCOM_USART_CTRLA_TXINV | SERCOM_USART_CTRLA_RXINV; - } - ctrlb |= USART_CHARACTER_SIZE_8BIT; - - switch(config->iso7816_config.protocol_t) { - case ISO7816_PROTOCOL_T_0: - ctrlb |= (uint32_t)config->stopbits; - ctrlc |= SERCOM_USART_CTRLC_GTIME(config->iso7816_config.guard_time) | \ - (config->iso7816_config.inhibit_nack) | \ - (config->iso7816_config.successive_recv_nack) | \ - SERCOM_USART_CTRLC_MAXITER(config->iso7816_config.max_iterations); - break; - case ISO7816_PROTOCOL_T_1: - ctrlb |= USART_STOPBITS_1; - break; - } - } else { -#endif - ctrlb |= (uint32_t)config->character_size; - /* Check parity mode bits */ - if (config->parity != USART_PARITY_NONE) { - ctrla |= SERCOM_USART_CTRLA_FORM(1); - ctrlb |= config->parity; - } else { -#ifdef FEATURE_USART_LIN_SLAVE - if(config->lin_slave_enable) { - ctrla |= SERCOM_USART_CTRLA_FORM(0x4); - } else { - ctrla |= SERCOM_USART_CTRLA_FORM(0); - } -#else - ctrla |= SERCOM_USART_CTRLA_FORM(0); -#endif - } -#ifdef FEATURE_USART_ISO7816 - } -#endif - -#ifdef FEATURE_USART_LIN_MASTER - usart_hw->CTRLC.reg = ((usart_hw->CTRLC.reg) & SERCOM_USART_CTRLC_GTIME_Msk) - | config->lin_header_delay - | config->lin_break_length; - - if (config->lin_node != LIN_INVALID_MODE) { - ctrla &= ~(SERCOM_USART_CTRLA_FORM(0xf)); - ctrla |= config->lin_node; - } -#endif - - /* Set whether module should run in standby. */ - if (config->run_in_standby || system_is_debugger_present()) { - ctrla |= SERCOM_USART_CTRLA_RUNSTDBY; - } - - /* Wait until synchronization is complete */ - _usart_wait_for_sync(module); - - /* Write configuration to CTRLB */ - usart_hw->CTRLB.reg = ctrlb; - - /* Wait until synchronization is complete */ - _usart_wait_for_sync(module); - - /* Write configuration to CTRLA */ - usart_hw->CTRLA.reg = ctrla; - -#ifdef FEATURE_USART_RS485 - if ((usart_hw->CTRLA.reg & SERCOM_USART_CTRLA_FORM_Msk) != \ - SERCOM_USART_CTRLA_FORM(0x07)) { - usart_hw->CTRLC.reg &= ~(SERCOM_USART_CTRLC_GTIME(0x7)); - usart_hw->CTRLC.reg |= SERCOM_USART_CTRLC_GTIME(config->rs485_guard_time); - } -#endif - -#ifdef FEATURE_USART_ISO7816 - if(config->iso7816_config.enabled) { - _usart_wait_for_sync(module); - usart_hw->CTRLC.reg = ctrlc; - } -#endif - - return STATUS_OK; -} - -/** - * \brief Initializes the device - * - * Initializes the USART device based on the setting specified in the - * configuration struct. - * - * \param[out] module Pointer to USART device - * \param[in] hw Pointer to USART hardware instance - * \param[in] config Pointer to configuration struct - * - * \return Status of the initialization. - * - * \retval STATUS_OK The initialization was successful - * \retval STATUS_BUSY The USART module is busy - * resetting - * \retval STATUS_ERR_DENIED The USART has not been disabled in - * advance of initialization - * \retval STATUS_ERR_INVALID_ARG The configuration struct contains - * invalid configuration - * \retval STATUS_ERR_ALREADY_INITIALIZED The SERCOM instance has already been - * initialized with different clock - * configuration - * \retval STATUS_ERR_BAUD_UNAVAILABLE The BAUD rate given by the - * configuration - * struct cannot be reached with - * the current clock configuration - */ -enum status_code usart_init( - struct usart_module *const module, - Sercom *const hw, - const struct usart_config *const config) -{ - /* Sanity check arguments */ - Assert(module); - Assert(hw); - Assert(config); - - enum status_code status_code = STATUS_OK; - - /* Assign module pointer to software instance struct */ - module->hw = hw; - - /* Get a pointer to the hardware module instance */ - SercomUsart *const usart_hw = &(module->hw->USART); - - uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw); - uint32_t pm_index, gclk_index; -#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) -#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 + MCLK_APBCMASK_SERCOM0_Pos; - gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; -#endif -#else - pm_index = sercom_index + PM_APBCMASK_SERCOM0_Pos; - gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; -#endif - - if (usart_hw->CTRLA.reg & SERCOM_USART_CTRLA_SWRST) { - /* The module is busy resetting itself */ - return STATUS_BUSY; - } - - if (usart_hw->CTRLA.reg & SERCOM_USART_CTRLA_ENABLE) { - /* Check the module is enabled */ - return STATUS_ERR_DENIED; - } - - /* 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 = config->generator_source; - system_gclk_chan_set_config(gclk_index, &gclk_chan_conf); - system_gclk_chan_enable(gclk_index); - sercom_set_gclk_generator(config->generator_source, false); - - /* Set character size */ - module->character_size = config->character_size; - - /* Set transmitter and receiver status */ - module->receiver_enabled = config->receiver_enable; - module->transmitter_enabled = config->transmitter_enable; - -#ifdef FEATURE_USART_LIN_SLAVE - module->lin_slave_enabled = config->lin_slave_enable; -#endif -#ifdef FEATURE_USART_START_FRAME_DECTION - module->start_frame_detection_enabled = config->start_frame_detection_enable; -#endif -#ifdef FEATURE_USART_ISO7816 - module->iso7816_mode_enabled = config->iso7816_config.enabled; -#endif - /* Set configuration according to the config struct */ - status_code = _usart_set_config(module, config); - if(status_code != STATUS_OK) { - return status_code; - } - - struct system_pinmux_config pin_conf; - system_pinmux_get_config_defaults(&pin_conf); - pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT; - pin_conf.input_pull = SYSTEM_PINMUX_PIN_PULL_NONE; - - uint32_t pad_pinmuxes[] = { - config->pinmux_pad0, config->pinmux_pad1, - config->pinmux_pad2, config->pinmux_pad3 - }; - - /* Configure the SERCOM pins according to the user configuration */ - for (uint8_t pad = 0; pad < 4; pad++) { - uint32_t current_pinmux = pad_pinmuxes[pad]; - - if (current_pinmux == PINMUX_DEFAULT) { - current_pinmux = _sercom_get_default_pad(hw, pad); - } - - if (current_pinmux != PINMUX_UNUSED) { - pin_conf.mux_position = current_pinmux & 0xFFFF; - system_pinmux_pin_set_config(current_pinmux >> 16, &pin_conf); - } - } - -#if USART_CALLBACK_MODE == true - /* Initialize parameters */ - for (uint32_t i = 0; i < USART_CALLBACK_N; i++) { - module->callback[i] = NULL; - } - - module->tx_buffer_ptr = NULL; - module->rx_buffer_ptr = NULL; - module->remaining_tx_buffer_length = 0x0000; - module->remaining_rx_buffer_length = 0x0000; - module->callback_reg_mask = 0x00; - module->callback_enable_mask = 0x00; - module->rx_status = STATUS_OK; - module->tx_status = STATUS_OK; - - /* Set interrupt handler and register USART software module struct in - * look-up table */ - uint8_t instance_index = _sercom_get_sercom_inst_index(module->hw); - _sercom_set_handler(instance_index, _usart_interrupt_handler); - _sercom_instances[instance_index] = module; -#endif - - return status_code; -} - -/** - * \brief Transmit a character via the USART - * - * This blocking function will transmit a single character via the - * USART. - * - * \param[in] module Pointer to the software instance struct - * \param[in] tx_data Data to transfer - * - * \return Status of the operation. - * \retval STATUS_OK If the operation was completed - * \retval STATUS_BUSY If the operation was not completed, due to the USART - * module being busy - * \retval STATUS_ERR_DENIED If the transmitter is not enabled - */ -enum status_code usart_write_wait( - struct usart_module *const module, - const uint16_t tx_data) -{ - /* Sanity check arguments */ - Assert(module); - Assert(module->hw); - - /* Get a pointer to the hardware module instance */ - SercomUsart *const usart_hw = &(module->hw->USART); - - /* Check that the transmitter is enabled */ - if (!(module->transmitter_enabled)) { - return STATUS_ERR_DENIED; - } - -#if USART_CALLBACK_MODE == true - /* Check if the USART is busy doing asynchronous operation. */ - if (module->remaining_tx_buffer_length > 0) { - return STATUS_BUSY; - } - -#else - /* Check if USART is ready for new data */ - if (!(usart_hw->INTFLAG.reg & SERCOM_USART_INTFLAG_DRE)) { - /* Return error code */ - return STATUS_BUSY; - } -#endif - - /* Wait until synchronization is complete */ - _usart_wait_for_sync(module); - - /* Write data to USART module */ - usart_hw->DATA.reg = tx_data; - - while (!(usart_hw->INTFLAG.reg & SERCOM_USART_INTFLAG_TXC)) { - /* Wait until data is sent */ - } - - return STATUS_OK; -} - -/** - * \brief Receive a character via the USART - * - * This blocking function will receive a character via the USART. - * - * \param[in] module Pointer to the software instance struct - * \param[out] rx_data Pointer to received data - * - * \return Status of the operation. - * \retval STATUS_OK If the operation was completed - * \retval STATUS_BUSY If the operation was not completed, - * due to the USART module being busy - * \retval STATUS_ERR_BAD_FORMAT If the operation was not completed, - * due to configuration mismatch between USART - * and the sender - * \retval STATUS_ERR_BAD_OVERFLOW If the operation was not completed, - * due to the baudrate being too low or the - * system frequency being too high - * \retval STATUS_ERR_BAD_DATA If the operation was not completed, due to - * data being corrupted - * \retval STATUS_ERR_DENIED If the receiver is not enabled - */ -enum status_code usart_read_wait( - struct usart_module *const module, - uint16_t *const rx_data) -{ - /* Sanity check arguments */ - Assert(module); - Assert(module->hw); - - /* Error variable */ - uint8_t error_code; - - /* Get a pointer to the hardware module instance */ - SercomUsart *const usart_hw = &(module->hw->USART); - - /* Check that the receiver is enabled */ - if (!(module->receiver_enabled)) { - return STATUS_ERR_DENIED; - } - -#if USART_CALLBACK_MODE == true - /* Check if the USART is busy doing asynchronous operation. */ - if (module->remaining_rx_buffer_length > 0) { - return STATUS_BUSY; - } -#endif - - /* Check if USART has new data */ - if (!(usart_hw->INTFLAG.reg & SERCOM_USART_INTFLAG_RXC)) { - /* Return error code */ - return STATUS_BUSY; - } - - /* Wait until synchronization is complete */ - _usart_wait_for_sync(module); - - /* Read out the status code and mask away all but the 3 LSBs*/ - error_code = (uint8_t)(usart_hw->STATUS.reg & SERCOM_USART_STATUS_MASK); - - /* Check if an error has occurred during the receiving */ - if (error_code) { - /* Check which error occurred */ - if (error_code & SERCOM_USART_STATUS_FERR) { - /* Clear flag by writing a 1 to it and - * return with an error code */ - usart_hw->STATUS.reg = SERCOM_USART_STATUS_FERR; - - return STATUS_ERR_BAD_FORMAT; - } else if (error_code & SERCOM_USART_STATUS_BUFOVF) { - /* Clear flag by writing a 1 to it and - * return with an error code */ - usart_hw->STATUS.reg = SERCOM_USART_STATUS_BUFOVF; - - return STATUS_ERR_OVERFLOW; - } else if (error_code & SERCOM_USART_STATUS_PERR) { - /* Clear flag by writing a 1 to it and - * return with an error code */ - usart_hw->STATUS.reg = SERCOM_USART_STATUS_PERR; - - return STATUS_ERR_BAD_DATA; - } -#ifdef FEATURE_USART_LIN_SLAVE - else if (error_code & SERCOM_USART_STATUS_ISF) { - /* Clear flag by writing 1 to it and - * return with an error code */ - usart_hw->STATUS.reg |= SERCOM_USART_STATUS_ISF; - - return STATUS_ERR_PROTOCOL; - } -#endif -#ifdef FEATURE_USART_COLLISION_DECTION - else if (error_code & SERCOM_USART_STATUS_COLL) { - /* Clear flag by writing 1 to it - * return with an error code */ - usart_hw->STATUS.reg |= SERCOM_USART_STATUS_COLL; - - return STATUS_ERR_PACKET_COLLISION; - } -#endif - } - - /* Read data from USART module */ - *rx_data = usart_hw->DATA.reg; - - return STATUS_OK; -} - -/** - * \brief Transmit a buffer of characters via the USART - * - * This blocking function will transmit a block of \c length characters - * via the USART. - * - * \note Using this function in combination with the interrupt (\c _job) functions is - * not recommended as it has no functionality to check if there is an - * ongoing interrupt driven operation running or not. - * - * \param[in] module Pointer to USART software instance struct - * \param[in] tx_data Pointer to data to transmit - * \param[in] length Number of characters to transmit - * - * \note If using 9-bit data, the array that *tx_data point to should be defined - * as uint16_t array and should be casted to uint8_t* pointer. Because it - * is an address pointer, the highest byte is not discarded. For example: - * \code - #define TX_LEN 3 - uint16_t tx_buf[TX_LEN] = {0x0111, 0x0022, 0x0133}; - usart_write_buffer_wait(&module, (uint8_t*)tx_buf, TX_LEN); - \endcode - * - * \return Status of the operation. - * \retval STATUS_OK If operation was completed - * \retval STATUS_ERR_INVALID_ARG If operation was not completed, due to invalid - * arguments - * \retval STATUS_ERR_TIMEOUT If operation was not completed, due to USART - * module timing out - * \retval STATUS_ERR_DENIED If the transmitter is not enabled - */ -enum status_code usart_write_buffer_wait( - struct usart_module *const module, - const uint8_t *tx_data, - uint16_t length) -{ - /* Sanity check arguments */ - Assert(module); - Assert(module->hw); - - /* Check if the buffer length is valid */ - if (length == 0) { - return STATUS_ERR_INVALID_ARG; - } - - /* Check that the transmitter is enabled */ - if (!(module->transmitter_enabled)) { - return STATUS_ERR_DENIED; - } - - /* Get a pointer to the hardware module instance */ - SercomUsart *const usart_hw = &(module->hw->USART); - - /* Wait until synchronization is complete */ - _usart_wait_for_sync(module); - - uint16_t tx_pos = 0; - - /* Blocks while buffer is being transferred */ - while (length--) { - /* Wait for the USART to be ready for new data and abort - * operation if it doesn't get ready within the timeout*/ - for (uint32_t i = 0; i <= USART_TIMEOUT; i++) { - if (usart_hw->INTFLAG.reg & SERCOM_USART_INTFLAG_DRE) { - break; - } else if (i == USART_TIMEOUT) { - return STATUS_ERR_TIMEOUT; - } - } - - /* Data to send is at least 8 bits long */ - uint16_t data_to_send = tx_data[tx_pos++]; - - /* Check if the character size exceeds 8 bit */ - if (module->character_size == USART_CHARACTER_SIZE_9BIT) { - data_to_send |= (tx_data[tx_pos++] << 8); - } - - /* Send the data through the USART module */ - usart_write_wait(module, data_to_send); - } - - /* Wait until Transmit is complete or timeout */ - for (uint32_t i = 0; i <= USART_TIMEOUT; i++) { - if (usart_hw->INTFLAG.reg & SERCOM_USART_INTFLAG_TXC) { - break; - } else if (i == USART_TIMEOUT) { - return STATUS_ERR_TIMEOUT; - } - } - - return STATUS_OK; -} - -/** - * \brief Receive a buffer of \c length characters via the USART - * - * This blocking function will receive a block of \c length characters - * via the USART. - * - * \note Using this function in combination with the interrupt (\c *_job) - * functions is not recommended as it has no functionality to check if - * there is an ongoing interrupt driven operation running or not. - * - * \param[in] module Pointer to USART software instance struct - * \param[out] rx_data Pointer to receive buffer - * \param[in] length Number of characters to receive - * - * \note If using 9-bit data, the array that *rx_data point to should be defined - * as uint16_t array and should be casted to uint8_t* pointer. Because it - * is an address pointer, the highest byte is not discarded. For example: - * \code - #define RX_LEN 3 - uint16_t rx_buf[RX_LEN] = {0x0,}; - usart_read_buffer_wait(&module, (uint8_t*)rx_buf, RX_LEN); - \endcode - * - * \return Status of the operation. - * \retval STATUS_OK If operation was completed - * \retval STATUS_ERR_INVALID_ARG If operation was not completed, due to an - * invalid argument being supplied - * \retval STATUS_ERR_TIMEOUT If operation was not completed, due - * to USART module timing out - * \retval STATUS_ERR_BAD_FORMAT If the operation was not completed, - * due to a configuration mismatch - * between USART and the sender - * \retval STATUS_ERR_BAD_OVERFLOW If the operation was not completed, - * due to the baudrate being too low or the - * system frequency being too high - * \retval STATUS_ERR_BAD_DATA If the operation was not completed, due - * to data being corrupted - * \retval STATUS_ERR_DENIED If the receiver is not enabled - */ -enum status_code usart_read_buffer_wait( - struct usart_module *const module, - uint8_t *rx_data, - uint16_t length) -{ - /* Sanity check arguments */ - Assert(module); - Assert(module->hw); - - /* Check if the buffer length is valid */ - if (length == 0) { - return STATUS_ERR_INVALID_ARG; - } - - /* Check that the receiver is enabled */ - if (!(module->receiver_enabled)) { - return STATUS_ERR_DENIED; - } - - /* Get a pointer to the hardware module instance */ - SercomUsart *const usart_hw = &(module->hw->USART); - - uint16_t rx_pos = 0; - - /* Blocks while buffer is being received */ - while (length--) { - /* Wait for the USART to have new data and abort operation if it - * doesn't get ready within the timeout*/ - for (uint32_t i = 0; i <= USART_TIMEOUT; i++) { - if (usart_hw->INTFLAG.reg & SERCOM_USART_INTFLAG_RXC) { - break; - } else if (i == USART_TIMEOUT) { - return STATUS_ERR_TIMEOUT; - } - } - - enum status_code retval; - uint16_t received_data = 0; - - retval = usart_read_wait(module, &received_data); - - if (retval != STATUS_OK) { - /* Overflow, abort */ - return retval; - } - - /* Read value will be at least 8-bits long */ - rx_data[rx_pos++] = received_data; - - /* If 9-bit data, write next received byte to the buffer */ - if (module->character_size == USART_CHARACTER_SIZE_9BIT) { - rx_data[rx_pos++] = (received_data >> 8); - } - } - - return STATUS_OK; -}