/** * SAM D20/D21/R21 Serial Peripheral Interface Driver * * Copyright (C) 2012-2014 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 * */ #ifndef SPI_H_INCLUDED #define SPI_H_INCLUDED /** * SAM D20/D21/R21 Serial Peripheral Interface Driver (SERCOM SPI) * * This driver for SAM D20/D21/R21 devices provides an interface for * the configuration and management of the SERCOM module in its SPI * mode to transfer SPI data frames. * * The following peripherals are used by this module: * * - SERCOM (Serial Communication Interface) * * Module Overview * * The Serial Peripheral Interface (SPI) is a high-speed synchronous * data transfer interface using three or four pins. It allows fast * communication between a master device and one or more peripheral * devices. * * A device connected to the bus must act as a master or a slave. The * master initiates and controls all data transactions. * * The SPI master initiates a communication cycle by pulling low the * Slave Select (SS) pin of the desired slave. The Slave Select pin is * active low. Master and slave prepare data to be sent in their * respective shift registers, and the master generates the required * clock pulses on the SCK line to interchange data. Data is always * shifted from master to slave on the Master Out - Slave In (MOSI) * line, and from slave to master on the Master In - Slave Out (MISO) * line. After each data transfer, the master can synchronize to the * slave by pulling the SS line high. * * \subsection asfdoc_sam0_sercom_spi_bus SPI Bus Connection * In \ref asfdoc_sam0_spi_connection_example "the figure below", the * connection between one master and one slave is shown. * * \anchor asfdoc_sam0_spi_connection_example * \dot * digraph spi_slaves_par { * subgraph cluster_spi_master { * shift_reg [label="Shift register", shape=box]; * mosi_m [label="MOSI", shape=none]; * miso_m [label="MISO", shape=none]; * sck_m [label="SCK", shape=none]; * ss_m [label="GPIO pin", shape=none]; * {rank=same; mosi_m miso_m sck_m ss_m} * label="SPI Master"; * } * subgraph cluster_spi_slave { * mosi_s [label="MOSI", shape=none]; * miso_s [label="MISO", shape=none]; * sck_s [label="SCK", shape=none]; * ss_s [label="SS", shape=none]; * shift_reg_s [label="Shift register", shape=box]; * {rank=same; mosi_s miso_s sck_s ss_s} * label="SPI Slave"; * rankdir=LR; * } * shift_reg:e -> mosi_m:w [label=""]; * mosi_m:e -> mosi_s:w [label=""]; * mosi_s:e -> shift_reg_s:w [label=""]; * miso_s:w -> miso_m:e [label=""]; * sck_m -> sck_s; * ss_m -> ss_s; * shift_reg_s:se -> miso_s:e [label=""]; * miso_m:w -> shift_reg:sw [label=""]; * rankdir=LR; * } * \enddot * * The different lines are as follows: * * MOSI Master Input Slave Output. The line where the data is shifted * out from the master and in to the slave. * * MISO Master Output Slave Input. The line where the data is shifted * out from the slave and in to the master. * * SCK Serial Clock. Generated by the master device. * * SS Slave Select. To initiate a transaction, the master must pull * this line low. * * If the bus consists of several SPI slaves, they can be connected in * parallel and the SPI master can use general I/O pins to control * separate SS lines to each slave on the bus. * * It is also possible to connect all slaves in series. In this * configuration, a common SS is provided to \c N slaves, enabling * them simultaneously. The MISO from the \c N-1 slaves is connected * to the MOSI on the next slave. The \c Nth slave connects its MISO * back to the master. For a complete transaction, the master must * shift \c N+1 characters. * * SPI Character Size * * The SPI character size is configurable to 8 or 9 bits. * * Master Mode * * When configured as a master, the SS pin will be configured as an output. * * Data Transfer * * Writing a character will start the SPI clock generator, and the * character is transferred to the shift register when the shift * register is empty. Once this is done, a new character can be * written. As each character is shifted out from the master, a * character is shifted in from the slave. If the receiver is enabled, * the data is moved to the receive buffer at the completion of the * frame and can be read. * * Slave Mode * * When configured as a slave, the SPI interface will remain inactive * with MISO tri-stated as long as the SS pin is driven high. * * Data Transfer * * The data register can be updated at any time. As the SPI slave * shift register is clocked by SCK, a minimum of three SCK cycles are * needed from the time new data is written, until the character is * ready to be shifted out. If the shift register has not been loaded * with data, the current contents will be transmitted. * * If constant transmission of data is needed in SPI slave mode, the * system clock should be faster than SCK. If the receiver is * enabled, the received character can be read from the. When SS line * is driven high, the slave will not receive any additional data. * * Address Recognition * * When the SPI slave is configured with address recognition, the * first character in a transaction is checked for an address * match. If there is a match, the MISO output is enabled and the * transaction is processed. If the address does not match, the * complete transaction is ignored. * * If the device is asleep, it can be woken up by an address match in * order to process the transaction. * * \note In master mode, an address packet is written by the * \ref spi_select_slave function if the address_enabled configuration is * set in the \ref spi_slave_inst_config struct. * * Data Modes * * There are four combinations of SCK phase and polarity with respect * to serial data. \ref asfdoc_sam0_spi_mode_table "The table below" * shows the clock polarity (CPOL) and clock phase (CPHA) in the * different modes. Leading edge is the first clock edge in a * clock cycle and trailing edge is the last clock edge in a * clock cycle. * * \anchor asfdoc_sam0_spi_mode_table * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
SPI Data Modes
ModeCPOLCPHALeading EdgeTrailing Edge
0 0 0 Rising, Sample Falling, Setup
1 0 1 Rising, Setup Falling, Sample
2 1 0 Falling, Sample Rising, Setup
3 1 1 Falling, Setup Rising, Sample
* * * SERCOM Pads * * The SERCOM pads are automatically configured as seen in * \ref asfdoc_sam0_spi_sercom_pad_table "the table below". If the receiver * is disabled, the data input (MISO for master, MOSI for slave) can be used * for other purposes. * * In master mode, the SS pin(s) must be configured using the \ref spi_slave_inst * struct. * * \anchor asfdoc_sam0_spi_sercom_pad_table * * * * * * * * * * * * * * * * * * * * * * * * * * * *
SERCOM SPI Pad Usages
Pin Master SPI Slave SPI
MOSI Output Input
MISO Input Output
SCK Output Input
SS User defined output enable Input
* * Operation in Sleep Modes * * The SPI module can operate in all sleep modes by setting the * run_in_standby option. The operation in slave and master mode is * shown in the table below. * * * * * * * * * * * * * * * * * *
run_in_standby Slave Master
false Disabled, all reception is dropped GCLK disabled when master is idle, wake on transmit complete
true Wake on reception GCLK is enabled while in sleep modes, wake on all interrupts
* * Clock Generation * * In SPI master mode, the clock (SCK) is generated internally using the * SERCOM baud rate generator. In SPI slave mode, the clock is provided by * an external master on the SCK pin. This clock is used to directly clock * the SPI shift register. * * Pin MUX Settings * * The pin MUX settings must be configured properly, as not all settings * can be used in different modes of operation. * */ #include "sercom/sercom.h" #include "system/pinmux.h" #include "system/port.h" #include #define CONF_SPI_MASTER_ENABLE true #define CONF_SPI_SLAVE_ENABLE true #define CONF_SPI_TIMEOUT 10000 /** * Define SERCOM SPI features set according to different device family. */ # if (SAMD21) || (SAMR21) /** SPI slave select low detection */ # define FEATURE_SPI_SLAVE_SELECT_LOW_DETECT /** Slave select can be controlled by hardware */ # define FEATURE_SPI_HARDWARE_SLAVE_SELECT /** SPI with error detect feature */ # define FEATURE_SPI_ERROR_INTERRUPT /** SPI sync scheme version 2 */ # define FEATURE_SPI_SYNC_SCHEME_VERSION_2 # endif # ifndef PINMUX_DEFAULT /** Default pin mux */ # define PINMUX_DEFAULT 0 # endif # ifndef PINMUX_UNUSED /** Unused PIN mux */ # define PINMUX_UNUSED 0xFFFFFFFF # endif # ifndef SPI_TIMEOUT /** SPI timeout value */ # define SPI_TIMEOUT 10000 # endif /** * Interrupt flags for the SPI module. */ enum spi_interrupt_flag { /** * This flag is set when the contents of the data register has been moved * to the shift register and the data register is ready for new data */ SPI_INTERRUPT_FLAG_DATA_REGISTER_EMPTY = SERCOM_SPI_INTFLAG_DRE, /** * This flag is set when the contents of the shift register has been * shifted out */ SPI_INTERRUPT_FLAG_TX_COMPLETE = SERCOM_SPI_INTFLAG_TXC, /** This flag is set when data has been shifted into the data register */ SPI_INTERRUPT_FLAG_RX_COMPLETE = SERCOM_SPI_INTFLAG_RXC, # ifdef FEATURE_SPI_SLAVE_SELECT_LOW_DETECT /** This flag is set when slave select low */ SPI_INTERRUPT_FLAG_SLAVE_SELECT_LOW = SERCOM_SPI_INTFLAG_SSL, # endif # ifdef FEATURE_SPI_ERROR_INTERRUPT /** This flag is set when combined error happen */ SPI_INTERRUPT_FLAG_COMBINED_ERROR = SERCOM_SPI_INTFLAG_ERROR, # endif }; /** * SPI transfer mode. */ enum spi_transfer_mode { /** Mode 0. Leading edge: rising, sample. Trailing edge: falling, setup */ SPI_TRANSFER_MODE_0 = 0, /** Mode 1. Leading edge: rising, setup. Trailing edge: falling, sample */ SPI_TRANSFER_MODE_1 = SERCOM_SPI_CTRLA_CPHA, /** Mode 2. Leading edge: falling, sample. Trailing edge: rising, setup */ SPI_TRANSFER_MODE_2 = SERCOM_SPI_CTRLA_CPOL, /** Mode 3. Leading edge: falling, setup. Trailing edge: rising, sample */ SPI_TRANSFER_MODE_3 = SERCOM_SPI_CTRLA_CPHA | SERCOM_SPI_CTRLA_CPOL, }; /** * Frame format for slave mode. */ enum spi_frame_format { /** SPI frame */ SPI_FRAME_FORMAT_SPI_FRAME = SERCOM_SPI_CTRLA_FORM(0), /** SPI frame with address */ SPI_FRAME_FORMAT_SPI_FRAME_ADDR = SERCOM_SPI_CTRLA_FORM(2), }; /** * SPI signal mux settings * * Set the functionality of the SERCOM pins. * As not all settings can be used in different modes of operation, proper * settings must be chosen according to the rest of the configuration. * * See \ref asfdoc_sam0_sercom_spi_mux_settings for a description of the * various MUX setting options. */ enum spi_signal_mux_setting { /** SPI MUX setting A */ SPI_SIGNAL_MUX_SETTING_A = (0x0 << SERCOM_SPI_CTRLA_DOPO_Pos) | (0x0 << SERCOM_SPI_CTRLA_DIPO_Pos), /** SPI MUX setting B */ SPI_SIGNAL_MUX_SETTING_B = (0x0 << SERCOM_SPI_CTRLA_DOPO_Pos) | (0x1 << SERCOM_SPI_CTRLA_DIPO_Pos), /** SPI MUX setting C */ SPI_SIGNAL_MUX_SETTING_C = (0x0 << SERCOM_SPI_CTRLA_DOPO_Pos) | (0x2 << SERCOM_SPI_CTRLA_DIPO_Pos), /** SPI MUX setting D */ SPI_SIGNAL_MUX_SETTING_D = (0x0 << SERCOM_SPI_CTRLA_DOPO_Pos) | (0x3 << SERCOM_SPI_CTRLA_DIPO_Pos), /** SPI MUX setting E */ SPI_SIGNAL_MUX_SETTING_E = (0x1 << SERCOM_SPI_CTRLA_DOPO_Pos) | (0x0 << SERCOM_SPI_CTRLA_DIPO_Pos), /** SPI MUX setting F */ SPI_SIGNAL_MUX_SETTING_F = (0x1 << SERCOM_SPI_CTRLA_DOPO_Pos) | (0x1 << SERCOM_SPI_CTRLA_DIPO_Pos), /** SPI MUX setting G */ SPI_SIGNAL_MUX_SETTING_G = (0x1 << SERCOM_SPI_CTRLA_DOPO_Pos) | (0x2 << SERCOM_SPI_CTRLA_DIPO_Pos), /** SPI MUX setting H */ SPI_SIGNAL_MUX_SETTING_H = (0x1 << SERCOM_SPI_CTRLA_DOPO_Pos) | (0x3 << SERCOM_SPI_CTRLA_DIPO_Pos), /** SPI MUX setting I */ SPI_SIGNAL_MUX_SETTING_I = (0x2 << SERCOM_SPI_CTRLA_DOPO_Pos) | (0x0 << SERCOM_SPI_CTRLA_DIPO_Pos), /** SPI MUX setting J */ SPI_SIGNAL_MUX_SETTING_J = (0x2 << SERCOM_SPI_CTRLA_DOPO_Pos) | (0x1 << SERCOM_SPI_CTRLA_DIPO_Pos), /** SPI MUX setting K */ SPI_SIGNAL_MUX_SETTING_K = (0x2 << SERCOM_SPI_CTRLA_DOPO_Pos) | (0x2 << SERCOM_SPI_CTRLA_DIPO_Pos), /** SPI MUX setting L */ SPI_SIGNAL_MUX_SETTING_L = (0x2 << SERCOM_SPI_CTRLA_DOPO_Pos) | (0x3 << SERCOM_SPI_CTRLA_DIPO_Pos), /** SPI MUX setting M */ SPI_SIGNAL_MUX_SETTING_M = (0x3 << SERCOM_SPI_CTRLA_DOPO_Pos) | (0x0 << SERCOM_SPI_CTRLA_DIPO_Pos), /** SPI MUX setting N */ SPI_SIGNAL_MUX_SETTING_N = (0x3 << SERCOM_SPI_CTRLA_DOPO_Pos) | (0x1 << SERCOM_SPI_CTRLA_DIPO_Pos), /** SPI MUX setting O */ SPI_SIGNAL_MUX_SETTING_O = (0x3 << SERCOM_SPI_CTRLA_DOPO_Pos) | (0x2 << SERCOM_SPI_CTRLA_DIPO_Pos), /** SPI MUX setting P */ SPI_SIGNAL_MUX_SETTING_P = (0x3 << SERCOM_SPI_CTRLA_DOPO_Pos) | (0x3 << SERCOM_SPI_CTRLA_DIPO_Pos), }; /** * For slave mode when using the SPI frame with address format. * */ enum spi_addr_mode { /** * \c address_mask in the \ref spi_config struct is used as a mask to the register. */ SPI_ADDR_MODE_MASK = SERCOM_SPI_CTRLB_AMODE(0), /** * The slave responds to the two unique addresses in \c address and * \c address_mask in the \ref spi_config struct. */ SPI_ADDR_MODE_UNIQUE = SERCOM_SPI_CTRLB_AMODE(1), /** * The slave responds to the range of addresses between and including \c address * and \c address_mask in in the \ref spi_config struct. */ SPI_ADDR_MODE_RANGE = SERCOM_SPI_CTRLB_AMODE(2), }; /** * \brief SPI modes enum * * SPI mode selection. */ enum spi_mode { /** Master mode */ SPI_MODE_MASTER = 1, /** Slave mode */ SPI_MODE_SLAVE = 0, }; /** * \brief SPI data order enum * * SPI data order. * */ enum spi_data_order { /** The LSB of the data is transmitted first */ SPI_DATA_ORDER_LSB = SERCOM_SPI_CTRLA_DORD, /** The MSB of the data is transmitted first */ SPI_DATA_ORDER_MSB = 0, }; /** * \brief SPI character size enum * * SPI character size. * */ enum spi_character_size { /** 8 bit character */ SPI_CHARACTER_SIZE_8BIT = SERCOM_SPI_CTRLB_CHSIZE(0), /** 9 bit character */ SPI_CHARACTER_SIZE_9BIT = SERCOM_SPI_CTRLB_CHSIZE(1), }; /** * \brief SPI peripheral slave instance structure * * SPI peripheral slave software instance structure, used to configure the * correct SPI transfer mode settings for an attached slave. See * \ref spi_select_slave. */ struct spi_slave_inst { /** Pin to use as Slave Select */ uint8_t ss_pin; /** Address recognition enabled in slave device */ bool address_enabled; /** Address of slave device */ uint8_t address; }; /** * \brief SPI peripheral slave configuration structure * * SPI Peripheral slave configuration structure */ struct spi_slave_inst_config { /** Pin to use as Slave Select */ uint8_t ss_pin; /** Enable address */ bool address_enabled; /** Address of slave */ uint8_t address; }; /** * \brief Initializes an SPI peripheral slave device configuration structure to default values * * This function will initialize a given SPI slave device configuration * structure to a set of known default values. This function should be called * on any new instance of the configuration structures before being modified by * the user application. * * The default configuration is as follows: * \li Slave Select on GPIO pin 10 * \li Addressing not enabled * * \param[out] config Configuration structure to initialize to default values */ static inline void spi_slave_inst_get_config_defaults( struct spi_slave_inst_config *const config) { assert(config); config->ss_pin = 10; config->address_enabled = false; config->address = 0; } /** * This function will initialize the software SPI peripheral slave, based on * the values of the config struct. The slave can then be selected and * optionally addressed by the \ref spi_select_slave function. * * \param[out] slave Pointer to the software slave instance struct * \param[in] config Pointer to the config struct * */ static inline void spi_attach_slave(struct spi_slave_inst *const slave) // struct spi_slave_inst_config *const config) { assert(slave); // Assert(config); // slave->ss_pin = config->ss_pin; // slave->address_enabled = config->address_enabled; // slave->address = config->address; /* Set config on Slave Select pin */ port_pin_set_config(slave->ss_pin, PORT_PIN_DIR_OUTPUT, PORT_PIN_PULL_UP, false); /* Set high */ port_pin_set_output_level(slave->ss_pin, true); } enum sercom_status_t spi_init(SercomSpi *const hw, enum spi_mode mode, enum spi_data_order data_order, enum spi_transfer_mode transfer_mode, enum spi_signal_mux_setting mux_setting, enum spi_character_size character_size, bool run_in_standby, bool receiver_enable, uint32_t master_baudrate, enum spi_frame_format slave_frame_format, enum spi_addr_mode slave_address_mode, uint8_t slave_address, uint8_t salve_address_mask, bool savle_preload_enable, # ifdef FEATURE_SPI_SLAVE_SELECT_LOW_DETECT bool select_slave_low_detect_enable, # endif # ifdef FEATURE_SPI_HARDWARE_SLAVE_SELECT bool master_slave_select_enable, # endif enum gclk_generator generator_source, uint32_t pinmux_pad0, uint32_t pinmux_pad1, uint32_t pinmux_pad2, uint32_t pinmux_pad3); enum sercom_status_t spi_init_default(SercomSpi *const hw); /** * This function will enable the SERCOM SPI module. * * \param[in,out] module Pointer to the software instance struct */ static inline void spi_enable(SercomSpi* const hw) { /* Sanity check arguments */ assert(hw); // system_interrupt_enable(_sercom_get_interrupt_vector(module->hw)); SPI_WAIT_FOR_SYNC(hw); /* Enable SPI */ hw->CTRLA.reg |= SERCOM_SPI_CTRLA_ENABLE; } /** * This function will disable the SERCOM SPI module. * * \param[in,out] module Pointer to the software instance struct */ static inline void spi_disable(SercomSpi* const hw) { /* Sanity check arguments */ assert(hw); // system_interrupt_disable(_sercom_get_interrupt_vector(module->hw)); SPI_WAIT_FOR_SYNC(hw); /* Disable SPI */ hw->CTRLA.reg &= ~SERCOM_SPI_CTRLA_ENABLE; } void spi_reset(SercomSpi* const hw); enum sercom_status_t spi_set_baudrate(SercomSpi* const hw, uint32_t baudrate); /** * This function will check if the SPI master module has shifted out last data, * or if the slave select pin has been drawn high by the master for the SPI * slave module. * * \param[in] module Pointer to the software instance struct * * \return Indication of whether any writes are ongoing * \retval true If the SPI master module has shifted out data, or slave select * has been drawn high for SPI slave * \retval false If the SPI master module has not shifted out data */ static inline bool spi_is_write_complete(SercomSpi* const hw) { /* Sanity check arguments */ assert(hw); /* Check interrupt flag */ return (hw->INTFLAG.reg & SERCOM_SPI_INTFLAG_TXC); } /** * This function will check if the SPI module is ready to write data. * * \param[in] module Pointer to the software instance struct * * \return Indication of whether the module is ready to read data or not * \retval true If the SPI module is ready to write data * \retval false If the SPI module is not ready to write data */ static inline bool spi_is_ready_to_write(SercomSpi* const hw) { /* Sanity check arguments */ assert(hw); /* Check interrupt flag */ return (hw->INTFLAG.reg & SERCOM_SPI_INTFLAG_DRE); } /** * This function will check if the SPI module is ready to read data. * * \param[in] module Pointer to the software instance struct * * \return Indication of whether the module is ready to read data or not * \retval true If the SPI module is ready to read data * \retval false If the SPI module is not ready to read data */ static inline bool spi_is_ready_to_read(SercomSpi* const hw) { /* Sanity check arguments */ assert(hw); /* Check interrupt flag */ return (hw->INTFLAG.reg & SERCOM_SPI_INTFLAG_RXC); } /** * This function will send a single SPI character via SPI and ignore any data * shifted in by the connected device. To both send and receive data, use the * \ref spi_transceive_wait function or use the \ref spi_read function after * writing a character. The \ref spi_is_ready_to_write function * should be called before calling this function. * * Note that this function does not handle the SS (Slave Select) * pin(s) in master mode; this must be handled from the user application. * * \note In slave mode, the data will not be transferred before a master * initiates a transaction. * * \param[in] module Pointer to the software instance struct * \param[in] tx_data Data to transmit * * \return Status of the procedure * \retval STATUS_OK If the data was written * \retval STATUS_BUSY If the last write was not completed */ static inline enum sercom_status_t spi_write(SercomSpi* const hw, uint16_t tx_data) { /* Sanity check arguments */ assert(hw); /* Check if the data register has been copied to the shift register */ if (!spi_is_ready_to_write(hw)) { /* Data register has not been copied to the shift register, return */ return SERCOM_STATUS_BUSY; } /* Write the character to the DATA register */ hw->DATA.reg = tx_data & SERCOM_SPI_DATA_MASK; return SERCOM_STATUS_OK; } enum sercom_status_t spi_write_buffer_wait(SercomSpi* const hw, const uint8_t *tx_data, uint16_t length); /** * This function will return the last SPI character shifted into the receive * register by the \ref spi_write function * * \note The \ref spi_is_ready_to_read function should be called before calling * this function. * * \note Receiver must be enabled in the configuration * * \param[in] module Pointer to the software instance struct * \param[out] rx_data Pointer to store the received data * * \returns Status of the read operation. * \retval STATUS_OK If data was read * \retval STATUS_ERR_IO If no data is available * \retval STATUS_ERR_OVERFLOW If the data is overflown */ static inline enum sercom_status_t spi_read(SercomSpi* const hw, uint16_t *rx_data) { /* Sanity check arguments */ assert(hw); /* Check if data is ready to be read */ if (!spi_is_ready_to_read(hw)) { /* No data has been received, return */ return SERCOM_STATUS_IO; } /* Return value */ enum sercom_status_t retval = SERCOM_STATUS_OK; /* Check if data is overflown */ if (hw->STATUS.reg & SERCOM_SPI_STATUS_BUFOVF) { retval = SERCOM_STATUS_OVERFLOW; /* Clear overflow flag */ hw->STATUS.reg |= SERCOM_SPI_STATUS_BUFOVF; } /* Read the character from the DATA register */ if (hw->CTRLB.bit.CHSIZE) { /* If 9-bit */ *rx_data = (hw->DATA.reg & SERCOM_SPI_DATA_MASK); } else { *rx_data = (uint8_t)hw->DATA.reg; } return retval; } enum sercom_status_t spi_read_buffer_wait(SercomSpi* const hw, uint8_t *rx_data, uint16_t length, uint16_t dummy); enum sercom_status_t spi_transceive_wait(SercomSpi* const hw, uint16_t tx_data, uint16_t *rx_data); enum sercom_status_t spi_transceive_buffer_wait(SercomSpi* const hw, uint8_t *tx_data, uint8_t *rx_data, uint16_t length); enum sercom_status_t spi_select_slave(SercomSpi* const hw, uint8_t ss_pin, bool address_enabled, uint8_t address, const bool select); /** * Mux Settings * * The following lists the possible internal SERCOM module pad function * assignments, for the four SERCOM pads in both SPI Master, and SPI Slave * modes. Note that this is in addition to the physical GPIO pin MUX of the * device, and can be used in conjunction to optimize the serial data pin-out. * * \section asfdoc_sam0_sercom_spi_mux_settings_master Master Mode Settings * The following table describes the SERCOM pin functionalities for the various * MUX settings, whilst in SPI Master mode. * * \note If MISO is unlisted, the SPI receiver must not be enabled for the * given MUX setting. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Mux/PadPAD 0PAD 1PAD 2PAD 3
AMOSISCK--
BMOSISCK--
CMOSISCKMISO-
DMOSISCK-MISO
EMISO-MOSISCK
F-MISOMOSISCK
G--MOSISCK
H--MOSISCK
I (1)MISOSCK-MOSI
J (1)-SCK-MOSI
K (1)-SCKMISOMOSI
L (1)-SCK-MOSI
M (1)MOSI--SCK
N (1)MOSIMISO-SCK
O (1)MOSI-MISOSCK
P (1)MOSI--SCK
* * (1) Not available in all silicon revisions. * * \section asfdoc_sam0_sercom_spi_mux_settings_slave Slave Mode Settings * The following table describes the SERCOM pin functionalities for the various * MUX settings, whilst in SPI Slave mode. * * \note If MISO is unlisted, the SPI receiver must not be enabled for the * given MUX setting. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Mux/PadPAD 0PAD 1PAD 2PAD 3
AMISOSCK/SS-
BMISOSCK/SS-
CMISOSCK/SS-
DMISOSCK/SSMOSI
EMOSI/SSMISOSCK
F-/SSMISOSCK
G-/SSMISOSCK
H-/SSMISOSCK
I (1)MOSISCK/SSMISO
J (1)-SCK/SSMISO
K (1)-SCK/SSMISO
L (1)-SCK/SSMISO
M (1)MISO/SS-SCK
N (1)MISO/SS-SCK
O (1)MISO/SSMOSISCK
P (1)MISO/SS-SCK
* */ #endif /* SPI_H_INCLUDED */