mbed library sources
Fork of mbed-src by
Diff: targets/hal/TARGET_Atmel/TARGET_SAM21/drivers/sercom/i2c/i2c_slave.h
- Revision:
- 613:bc40b8d2aec4
- Parent:
- 612:fba1c7dc54c0
- Child:
- 614:9d86c2ae5de0
--- a/targets/hal/TARGET_Atmel/TARGET_SAM21/drivers/sercom/i2c/i2c_slave.h Tue Aug 18 15:00:09 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,617 +0,0 @@ -#ifndef I2C_SLAVE_H_INCLUDED -#define I2C_SLAVE_H_INCLUDED - -#include "i2c_common.h" -#include <sercom.h> -#include <pinmux.h> - -#if I2C_SLAVE_CALLBACK_MODE == true -# include <sercom_interrupt.h> -#endif - -#ifndef PINMUX_DEFAULT -# define PINMUX_DEFAULT 0 -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \addtogroup asfdoc_sam0_sercom_i2c_group - * - * @{ - * - */ - -/** - * \name I2C Slave Status Flags - * - * I<SUP>2</SUP>C slave status flags, returned by \ref i2c_slave_get_status() and cleared - * by \ref i2c_slave_clear_status(). - * @{ - */ - -/** Address Match. - * \note Should only be cleared internally by driver. - */ -#define I2C_SLAVE_STATUS_ADDRESS_MATCH (1UL << 0) -/** Data Ready. */ -#define I2C_SLAVE_STATUS_DATA_READY (1UL << 1) -/** Stop Received. */ -#define I2C_SLAVE_STATUS_STOP_RECEIVED (1UL << 2) -/** Clock Hold. - * \note Cannot be cleared, only valid when I2C_SLAVE_STATUS_ADDRESS_MATCH is - * set. - */ -#define I2C_SLAVE_STATUS_CLOCK_HOLD (1UL << 3) -/** SCL Low Timeout. */ -#define I2C_SLAVE_STATUS_SCL_LOW_TIMEOUT (1UL << 4) -/** Repeated Start. - * \note Cannot be cleared, only valid when I2C_SLAVE_STATUS_ADDRESS_MATCH is - * set. - */ -#define I2C_SLAVE_STATUS_REPEATED_START (1UL << 5) -/** Received not acknowledge. - * \note Cannot be cleared. - */ -#define I2C_SLAVE_STATUS_RECEIVED_NACK (1UL << 6) -/** Transmit Collision. */ -#define I2C_SLAVE_STATUS_COLLISION (1UL << 7) -/** Bus error. */ -#define I2C_SLAVE_STATUS_BUS_ERROR (1UL << 8) - -/** @} */ - -/** - * \brief I<SUP>2</SUP>C slave packet for read/write - * - * Structure to be used when transferring I<SUP>2</SUP>C slave packets. - */ -struct i2c_slave_packet { - /** Length of data array. */ - uint16_t data_length; - /** Data array containing all data to be transferred. */ - uint8_t *data; -}; - -#if I2C_SLAVE_CALLBACK_MODE == true -/** -* \brief Callback types -* -* The available callback types for the I<SUP>2</SUP>C slave. -*/ -enum i2c_slave_callback { - /** Callback for packet write complete. */ - I2C_SLAVE_CALLBACK_WRITE_COMPLETE, - /** Callback for packet read complete. */ - I2C_SLAVE_CALLBACK_READ_COMPLETE, - /** - * Callback for read request from master - can be used to - * issue a write. - */ - I2C_SLAVE_CALLBACK_READ_REQUEST, - /** - * Callback for write request from master - can be used to issue a read. - */ - I2C_SLAVE_CALLBACK_WRITE_REQUEST, - /** Callback for error. */ - I2C_SLAVE_CALLBACK_ERROR, - /** - * Callback for error in last transfer. Discovered on a new address - * interrupt. - */ - I2C_SLAVE_CALLBACK_ERROR_LAST_TRANSFER, -# if !defined(__DOXYGEN__) - /** Total number of callbacks. */ - _I2C_SLAVE_CALLBACK_N, -# endif -}; - -# if !defined(__DOXYGEN__) -/** Software module prototype. */ -struct i2c_slave_module; - -/** Callback type. */ -typedef void (*i2c_slave_callback_t)( - struct i2c_slave_module *const module); -# endif -#endif - -/** - * \brief Enum for the possible SDA hold times with respect to the negative - * edge of SCL - * - * Enum for the possible SDA hold times with respect to the negative edge - * of SCL. - */ -enum i2c_slave_sda_hold_time { - /** SDA hold time disabled. */ - I2C_SLAVE_SDA_HOLD_TIME_DISABLED = - ((SERCOM_I2CS_CTRLA_SDAHOLD_Msk & ((0) << SERCOM_I2CS_CTRLA_SDAHOLD_Pos))), - /** SDA hold time 50ns - 100ns. */ - I2C_SLAVE_SDA_HOLD_TIME_50NS_100NS = - ((SERCOM_I2CS_CTRLA_SDAHOLD_Msk & ((1) << SERCOM_I2CS_CTRLA_SDAHOLD_Pos))), - /** SDA hold time 300ns - 600ns. */ - I2C_SLAVE_SDA_HOLD_TIME_300NS_600NS = - ((SERCOM_I2CS_CTRLA_SDAHOLD_Msk & ((2) << SERCOM_I2CS_CTRLA_SDAHOLD_Pos))), - /** SDA hold time 400ns - 800ns. */ - I2C_SLAVE_SDA_HOLD_TIME_400NS_800NS = - ((SERCOM_I2CS_CTRLA_SDAHOLD_Msk & ((3) << SERCOM_I2CS_CTRLA_SDAHOLD_Pos))), -}; - -/** - * \brief Enum for the possible address modes - * - * Enum for the possible address modes. - */ -enum i2c_slave_address_mode { - /** Address match on address_mask used as a mask to address. */ - I2C_SLAVE_ADDRESS_MODE_MASK = SERCOM_I2CS_CTRLB_AMODE(0), - /** Address math on both address and address_mask. */ - I2C_SLAVE_ADDRESS_MODE_TWO_ADDRESSES = SERCOM_I2CS_CTRLB_AMODE(1), - /** - * Address match on range of addresses between and including address and - * address_mask. - */ - I2C_SLAVE_ADDRESS_MODE_RANGE = SERCOM_I2CS_CTRLB_AMODE(2), -}; - -/** - * \brief Enum for the direction of a request - * - * Enum for the direction of a request. - */ -enum i2c_slave_direction { - /** Read. */ - I2C_SLAVE_DIRECTION_READ, - /** Write. */ - I2C_SLAVE_DIRECTION_WRITE, - /** No direction. */ - I2C_SLAVE_DIRECTION_NONE, -}; - -#ifdef FEATURE_I2C_FAST_MODE_PLUS_AND_HIGH_SPEED -/** - * \brief Enum for the transfer speed - * - * Enum for the transfer speed. - */ -enum i2c_slave_transfer_speed { - /** Standard-mode (Sm) up to 100KHz and Fast-mode (Fm) up to 400KHz. */ - I2C_SLAVE_SPEED_STANDARD_AND_FAST = SERCOM_I2CS_CTRLA_SPEED(0), - /** Fast-mode Plus (Fm+) up to 1MHz. */ - I2C_SLAVE_SPEED_FAST_MODE_PLUS = SERCOM_I2CS_CTRLA_SPEED(1), - /** High-speed mode (Hs-mode) up to 3.4MHz. */ - I2C_SLAVE_SPEED_HIGH_SPEED = SERCOM_I2CS_CTRLA_SPEED(2), -}; -#endif - -/** - * \brief SERCOM I<SUP>2</SUP>C Slave driver software device instance structure. - * - * SERCOM I<SUP>2</SUP>C Slave driver software instance structure, used to - * retain software state information of an associated hardware module instance. - * - * \note The fields of this structure should not be altered by the user - * application; they are reserved for module-internal use only. - */ -struct i2c_slave_module { -#if !defined(__DOXYGEN__) - /** Hardware instance initialized for the struct. */ - Sercom *hw; - /** Module lock. */ - volatile bool locked; - /** Timeout value for polled functions. */ - uint16_t buffer_timeout; -# ifdef FEATURE_I2C_10_BIT_ADDRESS - /** Using 10-bit addressing for the slave. */ - bool ten_bit_address; -# endif -# if I2C_SLAVE_CALLBACK_MODE == true - /** Nack on address match. */ - bool nack_on_address; - /** Pointers to callback functions. */ - volatile i2c_slave_callback_t callbacks[_I2C_SLAVE_CALLBACK_N]; - /** Mask for registered callbacks. */ - volatile uint8_t registered_callback; - /** Mask for enabled callbacks. */ - volatile uint8_t enabled_callback; - /** The total number of bytes to transfer. */ - volatile uint16_t buffer_length; - /** - * Counter used for bytes left to send in write and to count number of - * obtained bytes in read. - */ - uint16_t buffer_remaining; - /** Data buffer for packet write and read. */ - volatile uint8_t *buffer; - /** Save direction of request from master. 1 = read, 0 = write. */ - volatile enum i2c_transfer_direction transfer_direction; - /** Status for status read back in error callback. */ - volatile enum status_code status; -# endif -#endif -}; - -/** - * \brief Configuration structure for the I<SUP>2</SUP>C Slave device - * - * This is the configuration structure for the I<SUP>2</SUP>C Slave device. It is used - * as an argument for \ref i2c_slave_init to provide the desired - * configurations for the module. The structure should be initialized using the - * \ref i2c_slave_get_config_defaults. - */ -struct i2c_slave_config { - /** Set to enable the SCL low timeout. */ - bool enable_scl_low_timeout; - /** SDA hold time with respect to the negative edge of SCL. */ - enum i2c_slave_sda_hold_time sda_hold_time; - /** Timeout to wait for master in polled functions. */ - uint16_t buffer_timeout; - /** Addressing mode. */ - enum i2c_slave_address_mode address_mode; - /** Address or upper limit of address range. */ - uint16_t address; - /** Address mask, second address or lower limit of address range. */ - uint16_t address_mask; -#ifdef FEATURE_I2C_10_BIT_ADDRESS - /** Enable 10-bit addressing. */ - bool ten_bit_address; -#endif - /** - * Enable general call address recognition (general call address - * is defined as 0000000 with direction bit 0). - */ - bool enable_general_call_address; - -#ifdef FEATURE_I2C_FAST_MODE_PLUS_AND_HIGH_SPEED - /** Transfer speed mode. */ - enum i2c_slave_transfer_speed transfer_speed; -#endif - -#if I2C_SLAVE_CALLBACK_MODE == true - /** - * Enable NACK on address match (this can be changed after initialization - * via the \ref i2c_slave_enable_nack_on_address and - * \ref i2c_slave_disable_nack_on_address functions). - */ - bool enable_nack_on_address; -#endif - /** GCLK generator to use as clock source. */ - enum gclk_generator generator_source; - /** Set to keep module active in sleep modes. */ - bool run_in_standby; - /** PAD0 (SDA) pinmux. */ - uint32_t pinmux_pad0; - /** PAD1 (SCL) pinmux. */ - uint32_t pinmux_pad1; - /** Set to enable SCL low time-out. */ - bool scl_low_timeout; -#ifdef FEATURE_I2C_SCL_STRETCH_MODE - /** Set to enable SCL stretch only after ACK bit (required for high speed). */ - bool scl_stretch_only_after_ack_bit; -#endif -#ifdef FEATURE_I2C_SCL_EXTEND_TIMEOUT - /** Set to enable slave SCL low extend time-out. */ - bool slave_scl_low_extend_timeout; -#endif -}; - - -/** - * \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 i2c_slave_lock( - struct i2c_slave_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 - * - * \retval STATUS_OK If the module was locked - * \retval STATUS_BUSY If the module was already locked - */ -static inline void i2c_slave_unlock(struct i2c_slave_module *const module) -{ - module->locked = false; -} - -/** @} */ - -/** - * \name Configuration and Initialization - * @{ - */ - -/** - * \brief Returns the synchronization status of the module - * - * Returns the synchronization status of the module. - * - * \param[out] module Pointer to software module structure - * - * \return Status of the synchronization. - * \retval true Module is busy synchronizing - * \retval false Module is not synchronizing - */ -static inline bool i2c_slave_is_syncing( - const struct i2c_slave_module *const module) -{ - /* Sanity check */ - Assert(module); - Assert(module->hw); - - SercomI2cs *const i2c_hw = &(module->hw->I2CS); - - /* Return sync status */ -#if defined(FEATURE_SERCOM_SYNCBUSY_SCHEME_VERSION_1) - return (i2c_hw->STATUS.reg & SERCOM_I2CS_STATUS_SYNCBUSY); -#elif defined(FEATURE_SERCOM_SYNCBUSY_SCHEME_VERSION_2) - return (i2c_hw->SYNCBUSY.reg & SERCOM_I2CS_SYNCBUSY_MASK); -#else -# error Unknown SERCOM SYNCBUSY scheme! -#endif -} - -#if !defined(__DOXYGEN__) -/** - * \internal Wait for hardware module to sync - * - * \param[in] module Pointer to software module structure - */ -static void _i2c_slave_wait_for_sync( - const struct i2c_slave_module *const module) -{ - /* Sanity check. */ - Assert(module); - - while (i2c_slave_is_syncing(module)) { - /* Wait for I2C module to sync */ - } -} -#endif - -/** - * \brief Gets the I<SUP>2</SUP>C slave default configurations - * - * This will initialize the configuration structure to known default values. - * - * The default configuration is as follows: - * - Disable SCL low timeout - * - 300ns - 600ns SDA hold time - * - Buffer timeout = 65535 - * - Address with mask - * - Address = 0 - * - Address mask = 0 (one single address) - * - General call address disabled - * - Address nack disabled if the interrupt driver is used - * - GCLK generator 0 - * - Do not run in standby - * - PINMUX_DEFAULT for SERCOM pads - * - * Those default configuration only availale if the device supports it: - * - Not using 10-bit addressing - * - Standard-mode and Fast-mode transfer speed - * - SCL stretch disabled - * - slave SCL low extend time-out disabled - * - * \param[out] config Pointer to configuration structure to be initialized - */ -static inline void i2c_slave_get_config_defaults( - struct i2c_slave_config *const config) -{ - /*Sanity check argument. */ - Assert(config); - config->enable_scl_low_timeout = false; - config->sda_hold_time = I2C_SLAVE_SDA_HOLD_TIME_300NS_600NS; - config->buffer_timeout = 65535; - config->address_mode = I2C_SLAVE_ADDRESS_MODE_MASK; - config->address = 0; - config->address_mask = 0; -#ifdef FEATURE_I2C_10_BIT_ADDRESS - config->ten_bit_address = false; -#endif - config->enable_general_call_address = false; -#ifdef FEATURE_I2C_FAST_MODE_PLUS_AND_HIGH_SPEED - config->transfer_speed = I2C_SLAVE_SPEED_STANDARD_AND_FAST; -#endif -#if I2C_SLAVE_CALLBACK_MODE == true - config->enable_nack_on_address = false; -#endif - config->generator_source = GCLK_GENERATOR_0; - config->run_in_standby = false; - config->pinmux_pad0 = PINMUX_DEFAULT; - config->pinmux_pad1 = PINMUX_DEFAULT; - config->scl_low_timeout = false; -#ifdef FEATURE_I2C_SCL_STRETCH_MODE - config->scl_stretch_only_after_ack_bit = false; -#endif -#ifdef FEATURE_I2C_SCL_EXTEND_TIMEOUT - config->slave_scl_low_extend_timeout = false; -#endif -} - -enum status_code i2c_slave_init(struct i2c_slave_module *const module, - Sercom *const hw, - const struct i2c_slave_config *const config); - -/** - * \brief Enables the I<SUP>2</SUP>C module - * - * This will enable the requested I<SUP>2</SUP>C module. - * - * \param[in] module Pointer to the software module struct - */ -static inline void i2c_slave_enable( - const struct i2c_slave_module *const module) -{ - /* Sanity check of arguments. */ - Assert(module); - Assert(module->hw); - - SercomI2cs *const i2c_hw = &(module->hw->I2CS); - -#if I2C_SLAVE_CALLBACK_MODE == true - /* Enable global interrupt for module */ - system_interrupt_enable(_sercom_get_interrupt_vector(module->hw)); -#endif - - /* Wait for module to sync */ - _i2c_slave_wait_for_sync(module); - - /* Enable module */ - i2c_hw->CTRLA.reg |= SERCOM_I2CS_CTRLA_ENABLE; -} - - -/** - * \brief Disables the I<SUP>2</SUP>C module - * - * This will disable the I<SUP>2</SUP>C module specified in the provided software module - * structure. - * - * \param[in] module Pointer to the software module struct - */ -static inline void i2c_slave_disable( - const struct i2c_slave_module *const module) -{ - /* Sanity check of arguments. */ - Assert(module); - Assert(module->hw); - - SercomI2cs *const i2c_hw = &(module->hw->I2CS); - -#if I2C_SLAVE_CALLBACK_MODE == true - /* Disable interrupts */ - i2c_hw->INTENCLR.reg = SERCOM_I2CS_INTENSET_PREC | - SERCOM_I2CS_INTENSET_AMATCH | SERCOM_I2CS_INTENSET_DRDY; - - /* Clear interrupt flags */ - i2c_hw->INTFLAG.reg = SERCOM_I2CS_INTFLAG_PREC | SERCOM_I2CS_INTFLAG_AMATCH | - SERCOM_I2CS_INTFLAG_DRDY; - - /* Disable global interrupt for module */ - system_interrupt_disable(_sercom_get_interrupt_vector(module->hw)); -#endif - - /* Wait for module to sync */ - _i2c_slave_wait_for_sync(module); - - /* Disable module */ - i2c_hw->CTRLA.reg &= ~SERCOM_I2CS_CTRLA_ENABLE; -} - -void i2c_slave_reset( - struct i2c_slave_module *const module); - -/** @} */ - -/** - * \name Read and Write - * @{ - */ - -enum status_code i2c_slave_write_packet_wait( - struct i2c_slave_module *const module, - struct i2c_slave_packet *const packet); -enum status_code i2c_slave_read_packet_wait( - struct i2c_slave_module *const module, - struct i2c_slave_packet *const packet); -enum i2c_slave_direction i2c_slave_get_direction_wait( - struct i2c_slave_module *const module); - -/** @} */ - -/** - * \name Status Management - * @{ - */ -uint32_t i2c_slave_get_status( - struct i2c_slave_module *const module); -void i2c_slave_clear_status( - struct i2c_slave_module *const module, - uint32_t status_flags); -/** @} */ - -#ifdef FEATURE_I2C_DMA_SUPPORT -/** - * \name SERCOM I2C Slave with DMA Interfaces - * @{ - */ - -/** - * \brief Read SERCOM I<SUP>2</SUP>C interrupt status. - * - * Read I<SUP>2</SUP>C interrupt status for DMA transfer. - * - * \param[in,out] module Pointer to the driver instance to lock - * - */ -static inline uint8_t i2c_slave_dma_read_interrupt_status(struct i2c_slave_module *const module) -{ - return (uint8_t)module->hw->I2CS.INTFLAG.reg; -} - -/** - * \brief Write SERCOM I<SUP>2</SUP>C interrupt status. - * - * Write I<SUP>2</SUP>C interrupt status for DMA transfer. - * - * \param[in,out] module Pointer to the driver instance to lock - * \param[in] flag Interrupt flag status - * - */ -static inline void i2c_slave_dma_write_interrupt_status(struct i2c_slave_module *const module, - uint8_t flag) -{ - module->hw->I2CS.INTFLAG.reg = flag; -} - -/** @} */ -#endif - -/** @} */ - -#ifdef __cplusplus -} -#endif - -#endif /* I2C_SLAVE_H_INCLUDED */