add i2c slave files

This commit is contained in:
Jack Humbert 2018-06-07 17:21:35 -04:00
parent c53a8ead93
commit c8cc9c6aab
9 changed files with 6550 additions and 0 deletions

View file

@ -0,0 +1,21 @@
ifeq ($(USE_HAL_I2C_FALLBACK),yes)
# Fallback SW driver.
ifeq ($(USE_SMART_BUILD),yes)
ifneq ($(findstring HAL_USE_I2C TRUE,$(HALCONF)),)
PLATFORMSRC += $(CHIBIOS)/os/hal/lib/fallback/I2C/hal_i2c_lld.c
endif
else
PLATFORMSRC += $(CHIBIOS)/os/hal/lib/fallback/I2C/hal_i2c_lld.c
endif
PLATFORMINC += $(CHIBIOS)/os/hal/lib/fallback/I2C
else
# Default HW driver.
ifeq ($(USE_SMART_BUILD),yes)
ifneq ($(findstring HAL_USE_I2C TRUE,$(HALCONF)),)
PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c
endif
else
PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c
endif
PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv1
endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,777 @@
/*
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
Concepts and parts of this file have been contributed by Uladzimir Pylinsky
aka barthess. I2C Slave API contributed by Brent Roman (brent@mbari.org)
*/
/**
* @file STM32/I2Cv1/i2c_lld.h
* @brief STM32 I2C subsystem low level driver header.
*
* @addtogroup I2C
* @{
*/
#ifndef _I2C_LLD_H_
#define _I2C_LLD_H_
#if HAL_USE_I2C || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @brief Peripheral clock frequency.
*/
#define I2C_CLK_FREQ ((STM32_PCLK1) / 1000000)
/**
* @brief Invalid I2C bus address
*/
#define i2cInvalidAdr ((i2caddr_t) -1)
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief I2C1 driver enable switch.
* @details If set to @p TRUE the support for I2C1 is included.
* @note The default is @p FALSE.
*/
#if !defined(STM32_I2C_USE_I2C1) || defined(__DOXYGEN__)
#define STM32_I2C_USE_I2C1 FALSE
#endif
/**
* @brief I2C2 driver enable switch.
* @details If set to @p TRUE the support for I2C2 is included.
* @note The default is @p FALSE.
*/
#if !defined(STM32_I2C_USE_I2C2) || defined(__DOXYGEN__)
#define STM32_I2C_USE_I2C2 FALSE
#endif
/**
* @brief I2C3 driver enable switch.
* @details If set to @p TRUE the support for I2C3 is included.
* @note The default is @p FALSE.
*/
#if !defined(STM32_I2C_USE_I2C3) || defined(__DOXYGEN__)
#define STM32_I2C_USE_I2C3 FALSE
#endif
/**
* @brief Enables support for I2C slave mode operation
*/
#if !defined(HAL_USE_I2C_SLAVE) || defined(__DOXYGEN__)
#define HAL_USE_I2C_SLAVE FALSE
#define HAL_USE_I2C_STARTFIX FALSE
#endif
/**
* @brief Enables additional code needed with V1 I2C
*/
#if !defined(HAL_USE_I2C_STARTFIX) || defined(__DOXYGEN__)
#define HAL_USE_I2C_STARTFIX FALSE
#endif
/**
* @brief I2C timeout on busy condition in milliseconds.
*/
#if !defined(STM32_I2C_BUSY_TIMEOUT) || defined(__DOXYGEN__)
#define STM32_I2C_BUSY_TIMEOUT 50
#endif
/**
* @brief I2C1 interrupt priority level setting.
*/
#if !defined(STM32_I2C_I2C1_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_I2C_I2C1_IRQ_PRIORITY 10
#endif
/**
* @brief I2C2 interrupt priority level setting.
*/
#if !defined(STM32_I2C_I2C2_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_I2C_I2C2_IRQ_PRIORITY 10
#endif
/**
* @brief I2C3 interrupt priority level setting.
*/
#if !defined(STM32_I2C_I2C3_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_I2C_I2C3_IRQ_PRIORITY 10
#endif
/**
* @brief I2C1 DMA priority (0..3|lowest..highest).
* @note The priority level is used for both the TX and RX DMA streams but
* because of the streams ordering the RX stream has always priority
* over the TX stream.
*/
#if !defined(STM32_I2C_I2C1_DMA_PRIORITY) || defined(__DOXYGEN__)
#define STM32_I2C_I2C1_DMA_PRIORITY 1
#endif
/**
* @brief I2C2 DMA priority (0..3|lowest..highest).
* @note The priority level is used for both the TX and RX DMA streams but
* because of the streams ordering the RX stream has always priority
* over the TX stream.
*/
#if !defined(STM32_I2C_I2C2_DMA_PRIORITY) || defined(__DOXYGEN__)
#define STM32_I2C_I2C2_DMA_PRIORITY 1
#endif
/**
* @brief I2C3 DMA priority (0..3|lowest..highest).
* @note The priority level is used for both the TX and RX DMA streams but
* because of the streams ordering the RX stream has always priority
* over the TX stream.
*/
#if !defined(STM32_I2C_I2C3_DMA_PRIORITY) || defined(__DOXYGEN__)
#define STM32_I2C_I2C3_DMA_PRIORITY 1
#endif
/**
* @brief I2C DMA error hook.
* @note The default action for DMA errors is a system halt because DMA
* error can only happen because programming errors.
*/
#if !defined(STM32_I2C_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
#define STM32_I2C_DMA_ERROR_HOOK(i2cp) osalSysHalt("DMA failure")
#endif
#if STM32_ADVANCED_DMA || defined(__DOXYGEN__)
/**
* @brief DMA stream used for I2C1 RX operations.
* @note This option is only available on platforms with enhanced DMA.
*/
#if !defined(STM32_I2C_I2C1_RX_DMA_STREAM) || defined(__DOXYGEN__)
#define STM32_I2C_I2C1_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0)
#endif
/**
* @brief DMA stream used for I2C1 TX operations.
* @note This option is only available on platforms with enhanced DMA.
*/
#if !defined(STM32_I2C_I2C1_TX_DMA_STREAM) || defined(__DOXYGEN__)
#define STM32_I2C_I2C1_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6)
#endif
/**
* @brief DMA stream used for I2C2 RX operations.
* @note This option is only available on platforms with enhanced DMA.
*/
#if !defined(STM32_I2C_I2C2_RX_DMA_STREAM) || defined(__DOXYGEN__)
#define STM32_I2C_I2C2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2)
#endif
/**
* @brief DMA stream used for I2C2 TX operations.
* @note This option is only available on platforms with enhanced DMA.
*/
#if !defined(STM32_I2C_I2C2_TX_DMA_STREAM) || defined(__DOXYGEN__)
#define STM32_I2C_I2C2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7)
#endif
/**
* @brief DMA stream used for I2C3 RX operations.
* @note This option is only available on platforms with enhanced DMA.
*/
#if !defined(STM32_I2C_I2C3_RX_DMA_STREAM) || defined(__DOXYGEN__)
#define STM32_I2C_I2C3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2)
#endif
/**
* @brief DMA stream used for I2C3 TX operations.
* @note This option is only available on platforms with enhanced DMA.
*/
#if !defined(STM32_I2C_I2C3_TX_DMA_STREAM) || defined(__DOXYGEN__)
#define STM32_I2C_I2C3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4)
#endif
#else /* !STM32_ADVANCED_DMA */
/* Fixed streams for platforms using the old DMA peripheral, the values are
valid for both STM32F1xx and STM32L1xx.*/
#define STM32_I2C_I2C1_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7)
#define STM32_I2C_I2C1_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6)
#define STM32_I2C_I2C2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 5)
#define STM32_I2C_I2C2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4)
#endif /* !STM32_ADVANCED_DMA*/
/* Flag for the whole STM32F1XX family. */
#if defined(STM32F10X_LD_VL) || defined(STM32F10X_MD_VL) || \
defined(STM32F10X_HD_VL) || defined(STM32F10X_LD) || \
defined(STM32F10X_MD) || defined(STM32F10X_HD) || \
defined(STM32F10X_XL) || defined(STM32F10X_CL)
#define STM32F1XX_I2C
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/** @brief error checks */
#if STM32_I2C_USE_I2C1 && !STM32_HAS_I2C1
#error "I2C1 not present in the selected device"
#endif
#if STM32_I2C_USE_I2C2 && !STM32_HAS_I2C2
#error "I2C2 not present in the selected device"
#endif
#if STM32_I2C_USE_I2C3 && !STM32_HAS_I2C3
#error "I2C3 not present in the selected device"
#endif
#if !STM32_I2C_USE_I2C1 && !STM32_I2C_USE_I2C2 && \
!STM32_I2C_USE_I2C3
#error "I2C driver activated but no I2C peripheral assigned"
#endif
#if STM32_I2C_USE_I2C1 && \
!OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2C_I2C1_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to I2C1"
#endif
#if STM32_I2C_USE_I2C2 && \
!OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2C_I2C2_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to I2C2"
#endif
#if STM32_I2C_USE_I2C3 && \
!OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2C_I2C3_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to I2C3"
#endif
#if STM32_I2C_USE_I2C1 && \
!STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C1_DMA_PRIORITY)
#error "Invalid DMA priority assigned to I2C1"
#endif
#if STM32_I2C_USE_I2C2 && \
!STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C2_DMA_PRIORITY)
#error "Invalid DMA priority assigned to I2C2"
#endif
#if STM32_I2C_USE_I2C3 && \
!STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C3_DMA_PRIORITY)
#error "Invalid DMA priority assigned to I2C3"
#endif
/* The following checks are only required when there is a DMA able to
reassign streams to different channels.*/
#if STM32_ADVANCED_DMA
/* Check on the presence of the DMA streams settings in mcuconf.h.*/
#if STM32_I2C_USE_I2C1 && (!defined(STM32_I2C_I2C1_RX_DMA_STREAM) || \
!defined(STM32_I2C_I2C1_TX_DMA_STREAM))
#error "I2C1 DMA streams not defined"
#endif
#if STM32_I2C_USE_I2C2 && (!defined(STM32_I2C_I2C2_RX_DMA_STREAM) || \
!defined(STM32_I2C_I2C2_TX_DMA_STREAM))
#error "I2C2 DMA streams not defined"
#endif
/* Check on the validity of the assigned DMA channels.*/
#if STM32_I2C_USE_I2C1 && \
!STM32_DMA_IS_VALID_ID(STM32_I2C_I2C1_RX_DMA_STREAM, \
STM32_I2C1_RX_DMA_MSK)
#error "invalid DMA stream associated to I2C1 RX"
#endif
#if STM32_I2C_USE_I2C1 && \
!STM32_DMA_IS_VALID_ID(STM32_I2C_I2C1_TX_DMA_STREAM, \
STM32_I2C1_TX_DMA_MSK)
#error "invalid DMA stream associated to I2C1 TX"
#endif
#if STM32_I2C_USE_I2C2 && \
!STM32_DMA_IS_VALID_ID(STM32_I2C_I2C2_RX_DMA_STREAM, \
STM32_I2C2_RX_DMA_MSK)
#error "invalid DMA stream associated to I2C2 RX"
#endif
#if STM32_I2C_USE_I2C2 && \
!STM32_DMA_IS_VALID_ID(STM32_I2C_I2C2_TX_DMA_STREAM, \
STM32_I2C2_TX_DMA_MSK)
#error "invalid DMA stream associated to I2C2 TX"
#endif
#if STM32_I2C_USE_I2C3 && \
!STM32_DMA_IS_VALID_ID(STM32_I2C_I2C3_RX_DMA_STREAM, \
STM32_I2C3_RX_DMA_MSK)
#error "invalid DMA stream associated to I2C3 RX"
#endif
#if STM32_I2C_USE_I2C3 && \
!STM32_DMA_IS_VALID_ID(STM32_I2C_I2C3_TX_DMA_STREAM, \
STM32_I2C3_TX_DMA_MSK)
#error "invalid DMA stream associated to I2C3 TX"
#endif
#endif /* STM32_ADVANCED_DMA */
#if !defined(STM32_DMA_REQUIRED)
#define STM32_DMA_REQUIRED
#endif
/* Check clock range. */
#if defined(STM32F4XX)
#if !(I2C_CLK_FREQ >= 2) && (I2C_CLK_FREQ <= 42)
#error "I2C peripheral clock frequency out of range."
#endif
#elif defined(STM32L1XX)
#if !(I2C_CLK_FREQ >= 2) && (I2C_CLK_FREQ <= 32)
#error "I2C peripheral clock frequency out of range."
#endif
#elif defined(STM32F2XX)
#if !(I2C_CLK_FREQ >= 2) && (I2C_CLK_FREQ <= 30)
#error "I2C peripheral clock frequency out of range."
#endif
#elif defined(STM32F10X_LD_VL) || defined(STM32F10X_MD_VL) || \
defined(STM32F10X_HD_VL)
#if !(I2C_CLK_FREQ >= 2) && (I2C_CLK_FREQ <= 24)
#error "I2C peripheral clock frequency out of range."
#endif
#elif defined(STM32F10X_LD) || defined(STM32F10X_MD) || \
defined(STM32F10X_HD) || defined(STM32F10X_XL) || \
defined(STM32F10X_CL)
#if !(I2C_CLK_FREQ >= 2) && (I2C_CLK_FREQ <= 36)
#error "I2C peripheral clock frequency out of range."
#endif
#else
#error "unspecified, unsupported or invalid STM32 platform"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type representing an I2C address.
*/
typedef uint16_t i2caddr_t;
/**
* @brief Type of I2C driver condition flags.
*/
typedef uint32_t i2cflags_t;
/**
* @brief Supported modes for the I2C bus.
*/
typedef enum {
OPMODE_I2C = 1,
OPMODE_SMBUS_DEVICE = 2,
OPMODE_SMBUS_HOST = 3,
} i2copmode_t;
/**
* @brief Supported duty cycle modes for the I2C bus.
*/
typedef enum {
STD_DUTY_CYCLE = 1,
FAST_DUTY_CYCLE_2 = 2,
FAST_DUTY_CYCLE_16_9 = 3,
} i2cdutycycle_t;
/**
* @brief Type of a structure representing an I2C driver.
*/
typedef struct I2CDriver I2CDriver;
/**
* @brief Driver configuration structure.
*/
typedef struct {
i2copmode_t op_mode; /**< @brief Specifies the I2C mode. */
uint32_t clock_speed; /**< @brief Specifies the clock frequency.
@note Must be set to a value lower
than 400kHz. */
i2cdutycycle_t duty_cycle; /**< @brief Specifies the I2C fast mode
duty cycle. */
#if HAL_USE_I2C_STARTFIX && HAL_USE_I2C_SLAVE
void (*armStartDetect)(void); /**< @brief Arm Start Condition Detector */
void (*disarmStartDetect)(void);/**< @brief Disarm Start Condition Detector */
#endif
} I2CConfig;
#if HAL_USE_I2C_SLAVE /* I2C slave mode support */
typedef struct I2CSlaveMsg I2CSlaveMsg;
/*
returns the current I2C slave message receive configuration
*/
I2CSlaveMsg *i2cSlaveGetReceiveMsg(I2CDriver *i2cp);
/*
returns the current I2C slave message reply configuration
*/
I2CSlaveMsg *i2cSlaveGetReplyMsg(I2CDriver *i2cp);
/*
I2C Slave Message Call Back.
Invoked from interrupt context just after
the last byte of the message is transferred or slaveAdr is matched.
Use i2cSlaveReceiveMsg() or i2cSlaveReplyMsg() to access
the relevant message handling configuration
*/
typedef void I2CSlaveMsgCB(I2CDriver *i2cp);
/*
I2CSlaveMsg message handling configurations are normally
stored in read-only memory.
They describe either a buffer to contain incoming messages from
a bus master and associated callback functions, or one
preloaded with an outgoing reply to a read request and its callbacks.
*/
struct I2CSlaveMsg {
size_t size; /* sizeof(body) -- zero if master must wait */
uint8_t *body; /* message contents -- or NULL if master must wait */
I2CSlaveMsgCB *adrMatched; /* invoked when slave address matches */
I2CSlaveMsgCB *processMsg; /* invoked after message is transferred */
I2CSlaveMsgCB *exception; /* invoked if error or timeout during transfer */
};
I2CSlaveMsgCB I2CSlaveDummyCB;
/*
dummy callback -- placeholder to ignore event
*/
/* lock bus on receive or reply -- force master to wait */
extern const I2CSlaveMsg I2CSlaveLockOnMsg;
#endif /* HAL_USE_I2C_SLAVE */
/**
* @brief Structure representing an I2C driver.
*/
struct I2CDriver {
/**
* @brief Driver state.
*/
i2cstate_t state;
/**
* @brief Current configuration data.
*/
const I2CConfig *config;
/**
* @brief Error flags.
*/
i2cflags_t errors;
#if I2C_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
#if CH_CFG_USE_MUTEXES || defined(__DOXYGEN__)
/**
* @brief Mutex protecting the bus.
*/
mutex_t mutex;
#elif CH_CFG_USE_SEMAPHORES
semaphore_t semaphore;
#endif
#endif /* I2C_USE_MUTUAL_EXCLUSION */
#if defined(I2C_DRIVER_EXT_FIELDS)
I2C_DRIVER_EXT_FIELDS
#endif
/* End of the mandatory fields.*/
/**
* @brief Thread waiting for I/O completion.
*/
thread_reference_t thread;
/**
* @brief Current slave address without R/W bit.
*/
i2caddr_t addr;
/**
* @brief Master RX DMA buffer size.
*/
uint16_t masterRxbytes;
/**
* @brief Master TX DMA buffer size.
*/
uint16_t masterTxbytes;
/**
* @brief Master RX DMA buffer base.
*/
uint8_t *masterRxbuf;
/**
* @brief Master TX DMA buffer base.
*/
const uint8_t *masterTxbuf;
/**
* @brief RX DMA mode bit mask.
*/
uint32_t rxdmamode;
/**
* @brief TX DMA mode bit mask.
*/
uint32_t txdmamode;
/**
* @brief Receive DMA channel.
*/
const stm32_dma_stream_t *dmarx;
/**
* @brief Transmit DMA channel.
*/
const stm32_dma_stream_t *dmatx;
/**
* @brief Pointer to the I2Cx registers block.
*/
I2C_TypeDef *i2c;
/**
* @brief low level I2C interface / protocol state
*/
enum i2cMode {
i2cIdle=1, /* awaiting address or inactive */
i2cSlaveRxing, /* receiving message */
i2cLockedRxing, /* stretching clock before receiving message */
i2cSlaveReplying, /* replying to query */
i2cLockedReplying, /* stretching clock before replying to query */
i2cIsMaster=0x11, /* sent start bit (mastering bus) */
i2cMasterStarted, /* repeated start after write */
i2cMasterSelecting, /* sending slave address */
i2cMasterRxing, /* receiving reply from slave */
i2cMasterTxing /* sending message to slave */
} mode;
#if HAL_USE_I2C_LOCK || HAL_USE_I2C_SLAVE
/**
* @brief I2C transaction timer
*/
virtual_timer_t timer;
#endif
#if HAL_USE_I2C_LOCK
/**
* @brief I2C bus lock duration
*/
systime_t lockDuration;
#endif
#if HAL_USE_I2C_SLAVE
/* additional fields to support I2C slave transactions */
/**
* @brief slave address of message being processed
*/
i2caddr_t targetAdr;
/**
* @brief Error Mask for last slave message
*/
i2cflags_t slaveErrors;
/**
* @brief Length of most recently transferred slave message
*/
uint32_t slaveBytes;
/**
* @brief Maximum # of ticks slave may stretch the I2C clock
*/
systime_t slaveTimeout;
/**
* @brief Pointer to slave message reception handler
*/
const I2CSlaveMsg *slaveRx;
/**
* @brief Pointer to slave message Reply handler
*/
const I2CSlaveMsg *slaveReply;
/**
* @brief Pointer to handler for next slave received message
*/
const I2CSlaveMsg *slaveNextRx;
/**
* @brief Pointer to handler for next slave reply message
*/
const I2CSlaveMsg *slaveNextReply;
#endif
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @brief Get errors from I2C driver.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
#define i2c_lld_get_errors(i2cp) ((i2cp)->errors)
#if HAL_USE_I2C_LOCK
/**
* @brief Unlock I2C bus after the end of the next transaction
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
**/
#define i2c_lld_unlock(i2cp) (i2cp->lockDuration = TIME_IMMEDIATE)
#endif
#if HAL_USE_I2C_SLAVE /* I2C slave mode support */
/**
* @brief Get slave errors from I2C driver.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
#define i2c_lld_get_slaveErrors(i2cp) ((i2cp)->slaveErrors)
/**
* @brief Get slave message bytes transferred from I2C driver.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
#define i2c_lld_get_slaveBytes(i2cp) ((i2cp)->slaveBytes)
/**
* @brief Get slave timeout in ticks from I2C driver.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
#define i2c_lld_get_slaveTimeout(i2cp) ((i2cp)->slaveTimeout)
/**
* @brief Set slave timeout in ticks for I2C driver.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
#define i2c_lld_set_slaveTimeout(i2cp,ticks) ((i2cp)->slaveTimeout=(ticks))
/**
* @brief Get slave target address from I2C driver.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
#define i2c_lld_get_slaveTargetAdr(i2cp) ((i2cp)->targetAdr)
/**
* @brief Get slave receive message descriptor from I2C driver.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
#define i2c_lld_get_slaveReceive(i2cp) ((i2cp)->slaveNextRx)
/**
* @brief Get slave reply message descriptor from I2C driver.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
#define i2c_lld_get_slaveReply(i2cp) ((i2cp)->slaveNextReply)
#endif
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if !defined(__DOXYGEN__)
#if STM32_I2C_USE_I2C1
extern I2CDriver I2CD1;
#endif
#if STM32_I2C_USE_I2C2
extern I2CDriver I2CD2;
#endif
#if STM32_I2C_USE_I2C3
extern I2CDriver I2CD3;
#endif
#endif /* !defined(__DOXYGEN__) */
#ifdef __cplusplus
extern "C" {
#endif
void i2c_lld_init(void);
void i2c_lld_start(I2CDriver *i2cp);
void i2c_lld_stop(I2CDriver *i2cp);
msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
const uint8_t *txbuf, size_t txbytes,
uint8_t *rxbuf, size_t rxbytes,
systime_t timeout);
msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
uint8_t *rxbuf, size_t rxbytes,
systime_t timeout);
#if HAL_USE_I2C_LOCK /* I2C slave mode support */
void i2c_lld_lock(I2CDriver *i2cp, systime_t lockDuration);
#endif
#if HAL_USE_I2C_SLAVE /* I2C slave mode support */
msg_t i2c_lld_matchAddress(I2CDriver *i2cp, i2caddr_t i2cadr);
void i2c_lld_unmatchAddress(I2CDriver *i2cp, i2caddr_t i2cadr);
void i2c_lld_unmatchAll(I2CDriver *i2cp);
void i2c_lld_slaveReceive(I2CDriver *i2cp, const I2CSlaveMsg *rxMsg);
void i2c_lld_slaveReply(I2CDriver *i2cp, const I2CSlaveMsg *replyMsg);
#if HAL_USE_I2C_STARTFIX
void i2c_lld_startDetected(I2CDriver *i2cp);
void i2c_lld_noStartDetector(void);
#define i2cNoStartDetector i2c_lld_noStartDetector
#endif
#endif /* HAL_USE_I2C_SLAVE */
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_I2C */
#endif /* _I2C_LLD_H_ */
/** @} */

View file

@ -0,0 +1,21 @@
ifeq ($(USE_HAL_I2C_FALLBACK),yes)
# Fallback SW driver.
ifeq ($(USE_SMART_BUILD),yes)
ifneq ($(findstring HAL_USE_I2C TRUE,$(HALCONF)),)
PLATFORMSRC += $(CHIBIOS)/os/hal/lib/fallback/I2C/hal_i2c_lld.c
endif
else
PLATFORMSRC += $(CHIBIOS)/os/hal/lib/fallback/I2C/hal_i2c_lld.c
endif
PLATFORMINC += $(CHIBIOS)/os/hal/lib/fallback/I2C
else
# Default HW driver.
ifeq ($(USE_SMART_BUILD),yes)
ifneq ($(findstring HAL_USE_I2C TRUE,$(HALCONF)),)
PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv2/hal_i2c_lld.c
endif
else
PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv2/hal_i2c_lld.c
endif
PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv2
endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,806 @@
/*
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
Concepts and parts of this file have been contributed by Uladzimir Pylinsky
aka barthess. I2C Slave API for Chibios V2.x V1 I2C originally contributed
by Brent Roman (brent@mbari.org), ported to Chibios V3, V2 I2C by steved
*/
/**
* @file STM32/I2Cv2/i2c_lld.h
* @brief STM32 I2C subsystem low level driver header.
*
* @addtogroup I2C
* @{
*/
#ifndef _I2C_LLD_H_
#define _I2C_LLD_H_
#if HAL_USE_I2C || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @name TIMINGR register definitions
* @{
*/
#define STM32_TIMINGR_PRESC_MASK (15U << 28)
#define STM32_TIMINGR_PRESC(n) ((n) << 28)
#define STM32_TIMINGR_SCLDEL_MASK (15U << 20)
#define STM32_TIMINGR_SCLDEL(n) ((n) << 20)
#define STM32_TIMINGR_SDADEL_MASK (15U << 16)
#define STM32_TIMINGR_SDADEL(n) ((n) << 16)
#define STM32_TIMINGR_SCLH_MASK (255U << 8)
#define STM32_TIMINGR_SCLH(n) ((n) << 8)
#define STM32_TIMINGR_SCLL_MASK (255U << 0)
#define STM32_TIMINGR_SCLL(n) ((n) << 0)
/** @} */
/**
* Driver clears down tidily after a timeout
*/
#define I2C_SUPPORT_BUS_CLEAR TRUE
/**
* @brief Invalid I2C bus address
*/
#define i2cInvalidAdr ((i2caddr_t) -1)
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief I2C1 driver enable switch.
* @details If set to @p TRUE the support for I2C1 is included.
* @note The default is @p FALSE.
*/
#if !defined(STM32_I2C_USE_I2C1) || defined(__DOXYGEN__)
#define STM32_I2C_USE_I2C1 FALSE
#endif
/**
* @brief I2C2 driver enable switch.
* @details If set to @p TRUE the support for I2C2 is included.
* @note The default is @p FALSE.
*/
#if !defined(STM32_I2C_USE_I2C2) || defined(__DOXYGEN__)
#define STM32_I2C_USE_I2C2 FALSE
#endif
/**
* @brief I2C3 driver enable switch.
* @details If set to @p TRUE the support for I2C3 is included.
* @note The default is @p FALSE.
*/
#if !defined(STM32_I2C_USE_I2C3) || defined(__DOXYGEN__)
#define STM32_I2C_USE_I2C3 FALSE
#endif
/**
* @brief I2C4 driver enable switch.
* @details If set to @p TRUE the support for I2C4 is included.
* @note The default is @p FALSE.
*/
#if !defined(STM32_I2C_USE_I2C4) || defined(__DOXYGEN__)
#define STM32_I2C_USE_I2C4 FALSE
#endif
/**
* @brief Enables support for I2C slave mode operation
*/
#if !defined(HAL_USE_I2C_SLAVE) || defined(__DOXYGEN__)
#define HAL_USE_I2C_SLAVE FALSE
#endif
/**
* @brief Turns on some debugging options
*/
#if !defined(STM32_I2C_DEBUG_ENABLE) || defined(__DOXYGEN__)
#define STM32_I2C_DEBUG_ENABLE FALSE
#endif
/**
* @brief I2C timeout on busy condition in milliseconds.
*/
#if !defined(STM32_I2C_BUSY_TIMEOUT) || defined(__DOXYGEN__)
#define STM32_I2C_BUSY_TIMEOUT 50
#endif
/**
* @brief I2C1 interrupt priority level setting.
*/
#if !defined(STM32_I2C_I2C1_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_I2C_I2C1_IRQ_PRIORITY 10
#endif
/**
* @brief I2C2 interrupt priority level setting.
*/
#if !defined(STM32_I2C_I2C2_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_I2C_I2C2_IRQ_PRIORITY 10
#endif
/**
* @brief I2C3 interrupt priority level setting.
*/
#if !defined(STM32_I2C_I2C3_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_I2C_I2C3_IRQ_PRIORITY 10
#endif
/**
* @brief I2C4 interrupt priority level setting.
*/
#if !defined(STM32_I2C_I2C4_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_I2C_I2C4_IRQ_PRIORITY 10
#endif
/**
* @brief DMA use switch.
*/
#if !defined(STM32_I2C_USE_DMA) || defined(__DOXYGEN__)
#define STM32_I2C_USE_DMA TRUE
#endif
/**
* @brief I2C1 DMA priority (0..3|lowest..highest).
* @note The priority level is used for both the TX and RX DMA streams but
* because of the streams ordering the RX stream has always priority
* over the TX stream.
*/
#if !defined(STM32_I2C_I2C1_DMA_PRIORITY) || defined(__DOXYGEN__)
#define STM32_I2C_I2C1_DMA_PRIORITY 1
#endif
/**
* @brief I2C2 DMA priority (0..3|lowest..highest).
* @note The priority level is used for both the TX and RX DMA streams but
* because of the streams ordering the RX stream has always priority
* over the TX stream.
*/
#if !defined(STM32_I2C_I2C2_DMA_PRIORITY) || defined(__DOXYGEN__)
#define STM32_I2C_I2C2_DMA_PRIORITY 1
#endif
/**
* @brief I2C3 DMA priority (0..3|lowest..highest).
* @note The priority level is used for both the TX and RX DMA streams but
* because of the streams ordering the RX stream has always priority
* over the TX stream.
*/
#if !defined(STM32_I2C_I2C3_DMA_PRIORITY) || defined(__DOXYGEN__)
#define STM32_I2C_I2C3_DMA_PRIORITY 1
#endif
/**
* @brief I2C4 DMA priority (0..3|lowest..highest).
* @note The priority level is used for both the TX and RX DMA streams but
* because of the streams ordering the RX stream has always priority
* over the TX stream.
*/
#if !defined(STM32_I2C_I2C4_DMA_PRIORITY) || defined(__DOXYGEN__)
#define STM32_I2C_I2C4_DMA_PRIORITY 1
#endif
/**
* @brief I2C DMA error hook.
* @note The default action for DMA errors is a system halt because DMA
* error can only happen because programming errors.
*/
#if !defined(STM32_I2C_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
#define STM32_I2C_DMA_ERROR_HOOK(i2cp) osalSysHalt("DMA failure")
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/** @brief error checks */
#if STM32_I2C_USE_I2C1 && !STM32_HAS_I2C1
#error "I2C1 not present in the selected device"
#endif
#if STM32_I2C_USE_I2C2 && !STM32_HAS_I2C2
#error "I2C2 not present in the selected device"
#endif
#if STM32_I2C_USE_I2C3 && !STM32_HAS_I2C3
#error "I2C3 not present in the selected device"
#endif
#if STM32_I2C_USE_I2C4 && !STM32_HAS_I2C4
#error "I2C4 not present in the selected device"
#endif
#if !STM32_I2C_USE_I2C1 && !STM32_I2C_USE_I2C2 && !STM32_I2C_USE_I2C3 && \
!STM32_I2C_USE_I2C4
#error "I2C driver activated but no I2C peripheral assigned"
#endif
#if STM32_I2C_USE_I2C1 && \
!OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2C_I2C1_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to I2C1"
#endif
#if STM32_I2C_USE_I2C2 && \
!OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2C_I2C2_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to I2C2"
#endif
#if STM32_I2C_USE_I2C3 && \
!OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2C_I2C3_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to I2C3"
#endif
#if STM32_I2C_USE_I2C4 && \
!OSAL_IRQ_IS_VALID_PRIORITY(STM32_I2C_I2C4_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to I2C4"
#endif
#if STM32_I2C_USE_DMA == TRUE
#if STM32_I2C_USE_I2C1 && \
!STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C1_DMA_PRIORITY)
#error "Invalid DMA priority assigned to I2C1"
#endif
#if STM32_I2C_USE_I2C2 && \
!STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C2_DMA_PRIORITY)
#error "Invalid DMA priority assigned to I2C2"
#endif
#if STM32_I2C_USE_I2C3 && \
!STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C3_DMA_PRIORITY)
#error "Invalid DMA priority assigned to I2C3"
#endif
#if STM32_I2C_USE_I2C4 && \
!STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C4_DMA_PRIORITY)
#error "Invalid DMA priority assigned to I2C4"
#endif
/* The following checks are only required when there is a DMA able to
reassign streams to different channels.*/
#if STM32_ADVANCED_DMA
/* Check on the presence of the DMA streams settings in mcuconf.h.*/
#if STM32_I2C_USE_I2C1 && (!defined(STM32_I2C_I2C1_RX_DMA_STREAM) || \
!defined(STM32_I2C_I2C1_TX_DMA_STREAM))
#error "I2C1 DMA streams not defined"
#endif
#if STM32_I2C_USE_I2C2 && (!defined(STM32_I2C_I2C2_RX_DMA_STREAM) || \
!defined(STM32_I2C_I2C2_TX_DMA_STREAM))
#error "I2C2 DMA streams not defined"
#endif
#if STM32_I2C_USE_I2C3 && (!defined(STM32_I2C_I2C3_RX_DMA_STREAM) || \
!defined(STM32_I2C_I2C3_TX_DMA_STREAM))
#error "I2C3 DMA streams not defined"
#endif
#if STM32_I2C_USE_I2C4 && (!defined(STM32_I2C_I2C4_RX_DMA_STREAM) || \
!defined(STM32_I2C_I2C4_TX_DMA_STREAM))
#error "I2C4 DMA streams not defined"
#endif
/* Check on the validity of the assigned DMA channels.*/
#if STM32_I2C_USE_I2C1 && \
!STM32_DMA_IS_VALID_ID(STM32_I2C_I2C1_RX_DMA_STREAM, \
STM32_I2C1_RX_DMA_MSK)
#error "invalid DMA stream associated to I2C1 RX"
#endif
#if STM32_I2C_USE_I2C1 && \
!STM32_DMA_IS_VALID_ID(STM32_I2C_I2C1_TX_DMA_STREAM, \
STM32_I2C1_TX_DMA_MSK)
#error "invalid DMA stream associated to I2C1 TX"
#endif
#if STM32_I2C_USE_I2C2 && \
!STM32_DMA_IS_VALID_ID(STM32_I2C_I2C2_RX_DMA_STREAM, \
STM32_I2C2_RX_DMA_MSK)
#error "invalid DMA stream associated to I2C2 RX"
#endif
#if STM32_I2C_USE_I2C2 && \
!STM32_DMA_IS_VALID_ID(STM32_I2C_I2C2_TX_DMA_STREAM, \
STM32_I2C2_TX_DMA_MSK)
#error "invalid DMA stream associated to I2C2 TX"
#endif
#if STM32_I2C_USE_I2C3 && \
!STM32_DMA_IS_VALID_ID(STM32_I2C_I2C3_RX_DMA_STREAM, \
STM32_I2C3_RX_DMA_MSK)
#error "invalid DMA stream associated to I2C3 RX"
#endif
#if STM32_I2C_USE_I2C3 && \
!STM32_DMA_IS_VALID_ID(STM32_I2C_I2C3_TX_DMA_STREAM, \
STM32_I2C3_TX_DMA_MSK)
#error "invalid DMA stream associated to I2C3 TX"
#endif
#if STM32_I2C_USE_I2C4 && \
!STM32_DMA_IS_VALID_ID(STM32_I2C_I2C4_RX_DMA_STREAM, \
STM32_I2C4_RX_DMA_MSK)
#error "invalid DMA stream associated to I2C4 RX"
#endif
#if STM32_I2C_USE_I2C4 && \
!STM32_DMA_IS_VALID_ID(STM32_I2C_I2C4_TX_DMA_STREAM, \
STM32_I2C4_TX_DMA_MSK)
#error "invalid DMA stream associated to I2C4 TX"
#endif
#endif /* STM32_ADVANCED_DMA */
#if !defined(STM32_DMA_REQUIRED)
#define STM32_DMA_REQUIRED
#endif
#endif /* STM32_I2C_USE_DMA == TRUE */
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type representing an I2C address.
* @note For a 7-bit address, this takes values 0..0x7f, which are then
* shifted left one and the R/W bit added when required
*/
typedef uint16_t i2caddr_t;
/**
* @brief Type of I2C driver condition flags.
*/
typedef uint32_t i2cflags_t;
/**
* @brief Type of a structure representing an I2C driver.
*/
typedef struct I2CDriver I2CDriver;
/**
* @brief Supported modes for the I2C bus.
* @note Currently not used; retained for future enhancements
*/
typedef enum {
OPMODE_I2C = 1,
OPMODE_SMBUS_DEVICE = 2,
OPMODE_SMBUS_HOST = 3,
} i2copmode_t;
/**
* @brief Character received I2C notification callback type.
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] c received character
*
* @param[out] Return 0 if transfer to continue. 1 if transfer to be stopped
*
* @note Use only in master mode, to stop a read transaction
* once a particular character (or sequence of characters) has been received
*/
typedef uint8_t (*i2cccb_t)(I2CDriver *i2cp, uint16_t c);
/**
* @brief Type of I2C driver configuration structure.
*/
typedef struct {
/**
* @brief TIMINGR register initialization.
* @note Refer to the STM32 reference manual, the values are affected
* by the system clock settings in mcuconf.h.
*/
uint32_t timingr;
/**
* @brief CR1 register initialization.
* @note Leave to zero unless you know what you are doing.
*/
uint32_t cr1;
/**
* @brief CR2 register initialization.
* @note Leave at zero except in special circumstances - most bits controlled via API
*/
uint32_t cr2;
/**
* @brief Character received callback. Return 0 if transfer to continue. 1 if transfer to be stopped
* @note Use only in master mode. Set to NULL if not used.
*/
i2cccb_t rxchar_cb;
} I2CConfig;
#if HAL_USE_I2C_SLAVE /* I2C slave mode support */
typedef struct I2CSlaveMsg I2CSlaveMsg;
/*
returns the current I2C slave message receive configuration
*/
I2CSlaveMsg *i2cSlaveGetReceiveMsg(I2CDriver *i2cp);
/*
returns the current I2C slave message reply configuration
*/
I2CSlaveMsg *i2cSlaveGetReplyMsg(I2CDriver *i2cp);
/*
I2C Slave Message Call Back.
Invoked from interrupt context just after
the last byte of the message is transferred or slaveAdr is matched.
Use i2cSlaveReceiveMsg() or i2cSlaveReplyMsg() to access
the relevant message handling configuration
*/
typedef void I2CSlaveMsgCB(I2CDriver *i2cp);
/*
I2CSlaveMsg message handling configurations are normally
stored in read-only memory.
They describe either a buffer to contain incoming messages from
a bus master and associated callback functions, or one
preloaded with an outgoing reply to a read request and its callbacks.
*/
struct I2CSlaveMsg {
size_t size; /* sizeof(body) -- zero if master must wait */
uint8_t *body; /* message contents -- or NULL if master must wait */
I2CSlaveMsgCB *adrMatched; /* invoked when slave address matches */
I2CSlaveMsgCB *processMsg; /* invoked after message is transferred */
I2CSlaveMsgCB *exception; /* invoked if error or timeout during transfer */
};
/*
dummy callback -- placeholder to ignore event
*/
I2CSlaveMsgCB I2CSlaveDummyCB;
/* lock bus on receive or reply -- force master to wait */
extern const I2CSlaveMsg I2CSlaveLockOnMsg;
#endif /* HAL_USE_I2C_SLAVE */
/**
* @brief Structure representing an I2C driver.
*/
struct I2CDriver {
/**
* @brief Driver state.
*/
i2cstate_t state;
/**
* @brief Current configuration data.
*/
const I2CConfig *config;
/**
* @brief Error flags.
*/
i2cflags_t errors;
#if I2C_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
mutex_t mutex;
#endif /* I2C_USE_MUTUAL_EXCLUSION */
#if defined(I2C_DRIVER_EXT_FIELDS)
I2C_DRIVER_EXT_FIELDS
#endif
/* End of the mandatory fields.*/
/**
* @brief Thread waiting for I/O completion.
*/
thread_reference_t thread;
#if (STM32_I2C_USE_DMA == TRUE) || defined(__DOXYGEN__)
/**
* @brief RX DMA mode bit mask.
*/
uint32_t rxdmamode;
/**
* @brief TX DMA mode bit mask.
*/
uint32_t txdmamode;
/**
* @brief Receive DMA channel.
*/
const stm32_dma_stream_t *dmarx;
/**
* @brief Transmit DMA channel.
*/
const stm32_dma_stream_t *dmatx;
#else /* STM32_I2C_USE_DMA == FALSE */
/**
* @brief Pointer to the next TX buffer location.
*/
const uint8_t *txptr;
/**
* @brief Number of bytes in TX phase.
*/
size_t txbytes;
#endif /* STM32_I2C_USE_DMA == FALSE */
/**
* @brief Pointer to the next RX buffer location.
*/
uint8_t *rxptr;
/**
* @brief Number of bytes in RX phase.
*/
size_t rxbytes;
/**
* @brief Pointer to the I2Cx registers block.
*/
I2C_TypeDef *i2c;
/**
* @brief low level I2C interface / protocol state
*/
enum i2cMode {
i2cStopped = 0, /* Port not initialised, or not started */
i2cIdle=1, /* awaiting address or inactive */
i2cSlaveRxing, /* receiving message */
i2cLockedRxing, /* stretching clock before receiving message - Rx buffer might be full */
i2cSlaveReplying, /* replying to query (transmitting, slave mode) */
i2cLockedReplying, /* stretching clock before replying to query (no response available from main code) */
i2cIsMaster=0x11, /* sent start bit (mastering bus) */
i2cMasterStarted, /* repeated start after write */
i2cMasterSelecting, /* sending slave address */
i2cMasterRxing, /* receiving reply from slave */
i2cMasterTxing /* sending message to slave */
} mode;
#if HAL_USE_I2C_LOCK || HAL_USE_I2C_SLAVE
/**
* @brief I2C transaction timer
* @note USed for slave mode, lock
*/
virtual_timer_t timer;
#endif
#if HAL_USE_I2C_LOCK
/**
* @brief I2C bus lock duration
*/
systime_t lockDuration;
#endif
#if HAL_USE_I2C_SLAVE
/* additional fields to support I2C slave transactions */
/**
* @brief slave address of message being processed
*/
i2caddr_t targetAdr;
/**
* @brief Error Mask for last slave message
*/
i2cflags_t slaveErrors;
/**
* @brief Length of most recently transferred slave message
*/
size_t slaveBytes;
/**
* @brief Maximum # of ticks slave may stretch the I2C clock
*/
systime_t slaveTimeout;
/**
* @brief Pointer to slave message reception handler
*/
const I2CSlaveMsg *slaveRx;
/**
* @brief Pointer to slave message Reply (transmit) handler
*
* @note This is the currently active/just completed reply
*/
const I2CSlaveMsg *slaveReply;
/**
* @brief Pointer to handler for next slave received message
*/
const I2CSlaveMsg *slaveNextRx;
/**
* @brief Pointer to handler for next slave reply (transmit) message
*
* @note This is used for a reply if no message received first
*/
const I2CSlaveMsg *slaveNextReply;
#endif
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @brief Get errors from I2C driver.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
#define i2c_lld_get_errors(i2cp) ((i2cp)->errors)
#if HAL_USE_I2C_LOCK
/**
* @brief Unlock I2C bus after the end of the next transaction
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
**/
#define i2c_lld_unlock(i2cp) (i2cp->lockDuration = TIME_IMMEDIATE)
#endif
#if HAL_USE_I2C_SLAVE /* I2C slave mode support */
/**
* @brief Get slave errors from I2C driver.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
#define i2c_lld_get_slaveErrors(i2cp) ((i2cp)->slaveErrors)
/**
* @brief Get slave message bytes transferred from I2C driver.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
#define i2c_lld_get_slaveBytes(i2cp) ((i2cp)->slaveBytes)
/**
* @brief Get slave timeout in ticks from I2C driver.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
#define i2c_lld_get_slaveTimeout(i2cp) ((i2cp)->slaveTimeout)
/**
* @brief Set slave timeout in ticks for I2C driver.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
#define i2c_lld_set_slaveTimeout(i2cp,ticks) ((i2cp)->slaveTimeout=(ticks))
/**
* @brief Get slave target address from I2C driver.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
#define i2c_lld_get_slaveTargetAdr(i2cp) ((i2cp)->targetAdr)
/**
* @brief Get slave receive message descriptor from I2C driver.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
#define i2c_lld_get_slaveReceive(i2cp) ((i2cp)->slaveNextRx)
/**
* @brief Get slave reply message descriptor from I2C driver.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
#define i2c_lld_get_slaveReply(i2cp) ((i2cp)->slaveNextReply)
#endif
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if !defined(__DOXYGEN__)
#if STM32_I2C_USE_I2C1
extern I2CDriver I2CD1;
#endif
#if STM32_I2C_USE_I2C2
extern I2CDriver I2CD2;
#endif
#if STM32_I2C_USE_I2C3
extern I2CDriver I2CD3;
#endif
#if STM32_I2C_USE_I2C4
extern I2CDriver I2CD4;
#endif
#endif /* !defined(__DOXYGEN__) */
#ifdef __cplusplus
extern "C" {
#endif
void i2c_lld_init(void);
void i2c_lld_start(I2CDriver *i2cp);
void i2c_lld_stop(I2CDriver *i2cp);
msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
const uint8_t *txbuf, size_t txbytes,
uint8_t *rxbuf, size_t rxbytes,
systime_t timeout);
msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
uint8_t *rxbuf, size_t rxbytes,
systime_t timeout);
#if HAL_USE_I2C_LOCK /* I2C slave mode support */
void i2c_lld_lock(I2CDriver *i2cp, systime_t lockDuration);
#endif
#if HAL_USE_I2C_SLAVE /* I2C slave mode support */
msg_t i2c_lld_matchAddress(I2CDriver *i2cp, i2caddr_t i2cadr);
void i2c_lld_unmatchAddress(I2CDriver *i2cp, i2caddr_t i2cadr);
void i2c_lld_unmatchAll(I2CDriver *i2cp);
void i2c_lld_slaveReceive(I2CDriver *i2cp, const I2CSlaveMsg *rxMsg);
void i2c_lld_slaveReply(I2CDriver *i2cp, const I2CSlaveMsg *replyMsg);
#if STM32_I2C_DEBUG_ENABLE
void i2cPrintQ(BaseSequentialStream *chp); // Debugging routine
#endif /* STM32_I2C_DEBUG_ENABLE */
#endif /* HAL_USE_I2C_SLAVE */
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_I2C */
#endif /* _I2C_LLD_H_ */
/** @} */

View file

@ -0,0 +1,480 @@
/*
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
Concepts and parts of this file have been contributed by Uladzimir Pylinsky
aka barthess.
*/
/**
* @file i2c.c
* @brief I2C Driver code.
*
* @addtogroup I2C
* @{
*/
#include "hal.h"
#if (HAL_USE_I2C == TRUE) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief I2C Driver initialization.
* @note This function is implicitly invoked by @p halInit(), there is
* no need to explicitly initialize the driver.
*
* @init
*/
void i2cInit(void) {
i2c_lld_init();
}
/**
* @brief Initializes the standard part of a @p I2CDriver structure.
*
* @param[out] i2cp pointer to the @p I2CDriver object
*
* @init
*/
void i2cObjectInit(I2CDriver *i2cp) {
i2cp->state = I2C_STOP;
i2cp->config = NULL;
#if I2C_USE_MUTUAL_EXCLUSION == TRUE
#if CH_CFG_USE_MUTEXES
osalMutexObjectInit(&i2cp->mutex);
#else
osalSemObjectInit(&i2cp->semaphore, 1);
#endif /* CH_CFG_USE_MUTEXES */
#endif /* I2C_USE_MUTUAL_EXCLUSION */
#if defined(I2C_DRIVER_EXT_INIT_HOOK)
I2C_DRIVER_EXT_INIT_HOOK(i2cp);
#endif
}
/**
* @brief Configures and activates the I2C peripheral.
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] config pointer to the @p I2CConfig object
*
* @api
*/
void i2cStart(I2CDriver *i2cp, const I2CConfig *config) {
osalDbgCheck((i2cp != NULL) && (config != NULL));
osalDbgAssert((i2cp->state == I2C_STOP) || (i2cp->state == I2C_READY) ||
(i2cp->state == I2C_LOCKED), "invalid state");
osalSysLock();
i2cp->config = config;
i2c_lld_start(i2cp);
i2cp->state = I2C_READY;
osalSysUnlock();
}
/**
* @brief Deactivates the I2C peripheral.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @api
*/
void i2cStop(I2CDriver *i2cp) {
osalDbgCheck(i2cp != NULL);
osalDbgAssert((i2cp->state == I2C_STOP) || (i2cp->state == I2C_READY) ||
(i2cp->state == I2C_LOCKED), "invalid state");
osalSysLock();
i2c_lld_stop(i2cp);
i2cp->state = I2C_STOP;
osalSysUnlock();
}
/**
* @brief Returns the errors mask associated to the previous operation.
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @return The errors mask.
*
* @api
*/
i2cflags_t i2cGetErrors(I2CDriver *i2cp) {
osalDbgCheck(i2cp != NULL);
return i2c_lld_get_errors(i2cp);
}
/**
* @brief Sends data via the I2C bus.
* @details Function designed to realize "read-through-write" transfer
* paradigm. If you want transmit data without any further read,
* than set @b rxbytes field to 0.
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] addr slave device address (7 bits) without R/W bit
* @param[in] txbuf pointer to transmit buffer
* @param[in] txbytes number of bytes to be transmitted
* @param[out] rxbuf pointer to receive buffer
* @param[in] rxbytes number of bytes to be received, set it to 0 if
* you want transmit only
* @param[in] timeout the number of ticks before the operation timeouts,
* the following special values are allowed:
* - @a TIME_INFINITE no timeout.
* .
*
* @return The operation status.
* @retval MSG_OK if the function succeeded.
* @retval MSG_RESET if one or more I2C errors occurred, the errors can
* be retrieved using @p i2cGetErrors().
* @retval MSG_TIMEOUT if a timeout occurred before operation end.
*
* @api
*/
msg_t i2cMasterTransmitTimeout(I2CDriver *i2cp,
i2caddr_t addr,
const uint8_t *txbuf,
size_t txbytes,
uint8_t *rxbuf,
size_t rxbytes,
systime_t timeout) {
msg_t rdymsg;
osalDbgCheck((i2cp != NULL) && (addr != 0U) &&
(txbytes > 0U) && (txbuf != NULL) &&
((rxbytes == 0U) || ((rxbytes > 0U) && (rxbuf != NULL))) &&
(timeout != TIME_IMMEDIATE));
osalDbgAssert(i2cp->state == I2C_READY, "not ready");
osalSysLock();
i2cp->errors = I2C_NO_ERROR;
i2cp->state = I2C_ACTIVE_TX;
rdymsg = i2c_lld_master_transmit_timeout(i2cp, addr, txbuf, txbytes,
rxbuf, rxbytes, timeout);
if (rdymsg == MSG_TIMEOUT) {
i2cp->state = I2C_LOCKED;
}
else {
i2cp->state = I2C_READY;
}
osalSysUnlock();
return rdymsg;
}
/**
* @brief Receives data from the I2C bus.
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] addr slave device address (7 bits) without R/W bit
* @param[out] rxbuf pointer to receive buffer
* @param[in] rxbytes number of bytes to be received
* @param[in] timeout the number of ticks before the operation timeouts,
* the following special values are allowed:
* - @a TIME_INFINITE no timeout.
* .
*
* @return The operation status.
* @retval MSG_OK if the function succeeded.
* @retval MSG_RESET if one or more I2C errors occurred, the errors can
* be retrieved using @p i2cGetErrors().
* @retval MSG_TIMEOUT if a timeout occurred before operation end.
*
* @api
*/
msg_t i2cMasterReceiveTimeout(I2CDriver *i2cp,
i2caddr_t addr,
uint8_t *rxbuf,
size_t rxbytes,
systime_t timeout){
msg_t rdymsg;
osalDbgCheck((i2cp != NULL) && (addr != 0U) &&
(rxbytes > 0U) && (rxbuf != NULL) &&
(timeout != TIME_IMMEDIATE));
osalDbgAssert(i2cp->state == I2C_READY, "not ready");
osalSysLock();
i2cp->errors = I2C_NO_ERROR;
i2cp->state = I2C_ACTIVE_RX;
rdymsg = i2c_lld_master_receive_timeout(i2cp, addr, rxbuf, rxbytes, timeout);
if (rdymsg == MSG_TIMEOUT) {
i2cp->state = I2C_LOCKED;
}
else {
i2cp->state = I2C_READY;
}
osalSysUnlock();
return rdymsg;
}
#if HAL_USE_I2C_LOCK /* I2C slave mode support */
/**
* @brief Lock I2C bus at the beginning of the next message sent
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] lockDuration max number of ticks to hold bus locked
* - @a TIME_INFINITE no timeout.
* - @a TIME_IMMEDIATE unlock the bus immediately
* .
*
* @api
*/
void i2cLock(I2CDriver *i2cp, systime_t lockDuration)
{
chDbgCheck((i2cp != NULL), "i2cLock");
chSysLock();
i2c_lld_lock(i2cp, lockDuration);
chSysUnlock();
}
/**
* @brief Unlock I2C bus after the end of the next transaction
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @api
**/
void i2cUnlock(I2CDriver *i2cp)
{
chDbgCheck((i2cp != NULL), "i2cUnlock");
chSysLock();
i2c_lld_unlock(i2cp);
chSysUnlock();
}
#endif
#if HAL_USE_I2C_SLAVE /* I2C slave mode support */
/**
* @brief Reconfigure I2C channel to respond to indicated address
* in addition to those already matched
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] i2cadr I2C network address
*
* @return Length of message OR the type of event received
* @retval I2C_OK Success
* @retval I2C_ERROR Cannot match address in addition of those already
*
* @details MatchAddress calls are cumulative.
* Specify address zero to match I2C "all call"
* Does not support 10-bit addressing.
*
* @api
**/
msg_t i2cMatchAddress(I2CDriver *i2cp, i2caddr_t i2cadr)
{
osalDbgCheck((i2cp != NULL));
chSysLock();
msg_t result = i2c_lld_matchAddress(i2cp, i2cadr);
chSysUnlock();
return result;
}
/**
* @brief Configure to ignore messages directed to the given i2cadr
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] i2cadr I2C bus address
* - @a 0 matches "all call"
* .
* @details A message being transferred that has already matched the
* specified address will continue being processed.
* Requests to unmatch an address that is not currently being matched
* are ignored.
*
* @api
*/
void i2cUnmatchAddress(I2CDriver *i2cp, i2caddr_t i2cadr)
{
osalDbgCheck((i2cp != NULL));
chSysLock();
i2c_lld_unmatchAddress(i2cp, i2cadr);
chSysUnlock();
}
/**
* @brief Reconfigure I2C channel to no longer match any address
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @details Causes all subsequent messages to be ignored.
* A message being transferred that has already matched a
* slave address will continue being processed.
*
* @api
**/
void i2cUnmatchAll(I2CDriver *i2cp)
{
osalDbgCheck((i2cp != NULL));
chSysLock();
i2c_lld_unmatchAll(i2cp);
chSysUnlock();
}
/**
* @brief Configure callbacks & buffers for message reception & query reply
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] rxMsg @p I2CSlaveMsg struct for processing subsequent messages
* @param[in] replyMsg @p I2CSlaveMsg struct for processing subsequent queries
*
* @details Must be called from a thread
* Call i2cMatchAddress() after this to start processing
* Enabling match addresses before installing handler callbacks can
* result in locking the I2C bus when a master accesses those
* unconfigured slave addresses
*
* @api
*/
void i2cSlaveConfigure(I2CDriver *i2cp,
const I2CSlaveMsg *rxMsg, const I2CSlaveMsg *replyMsg)
{
osalDbgCheck((i2cp != NULL));
chSysLock();
i2c_lld_slaveReceive(i2cp, rxMsg);
i2c_lld_slaveReply(i2cp, replyMsg);
chSysUnlock();
}
/**
* @brief Configure callbacks & buffers for query reply
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] replyMsg @p I2CSlaveMsg struct for processing subsequent queries
*
* @details Call i2cMatchAddress() after this to start processing
* Enabling match addresses before installing handler callbacks can
* result in locking the I2C bus when a master accesses those
* unconfigured slave addresses
*
* @api
*/
void i2cSlaveReceive(I2CDriver *i2cp, const I2CSlaveMsg *rxMsg)
{
osalDbgCheck((i2cp != NULL && rxMsg != NULL));
chSysLock();
i2c_lld_slaveReceive(i2cp, rxMsg);
chSysUnlock();
}
/**
* @brief Configure callbacks & buffers for query reply
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] replyMsg @p I2CSlaveMsg struct for processing subsequent queries
*
* @details Call i2cMatchAddress() after this to start processing
* Enabling match addresses before installing handler callbacks can
* result in locking the I2C bus when a master accesses those
* unconfigured slave addresses
*
* @api
*/
void i2cSlaveReply(I2CDriver *i2cp, const I2CSlaveMsg *replyMsg)
{
osalDbgCheck((i2cp != NULL && replyMsg != NULL));
chSysLock();
i2c_lld_slaveReply(i2cp, replyMsg);
chSysUnlock();
}
#endif /* HAL_USE_I2C_SLAVE */
#if I2C_USE_MUTUAL_EXCLUSION == TRUE || defined(__DOXYGEN__)
/**
* @brief Gains exclusive access to the I2C bus.
* @details This function tries to gain ownership to the I2C bus, if the bus
* is already being used then the invoking thread is queued.
* @pre In order to use this function the option @p I2C_USE_MUTUAL_EXCLUSION
* must be enabled.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @api
*/
void i2cAcquireBus(I2CDriver *i2cp) {
osalDbgCheck(i2cp != NULL);
#if CH_CFG_USE_MUTEXES
osalMutexLock(&i2cp->mutex);
#elif CH_CFG_USE_SEMAPHORES
osalSemWait(&i2cp->semaphore);
#endif /* CH_CFG_USE_MUTEXES */
}
/**
* @brief Releases exclusive access to the I2C bus.
* @pre In order to use this function the option @p I2C_USE_MUTUAL_EXCLUSION
* must be enabled.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @api
*/
void i2cReleaseBus(I2CDriver *i2cp) {
osalDbgCheck(i2cp != NULL);
#if CH_CFG_USE_MUTEXES
osalMutexUnlock(&i2cp->mutex);
#elif CH_CFG_USE_SEMAPHORES
osalSemSignal(&i2cp->semaphore);
#endif /* CH_CFG_USE_MUTEXES */
}
#endif /* I2C_USE_MUTUAL_EXCLUSION == TRUE */
#endif /* HAL_USE_I2C == TRUE */
/** @} */

View file

@ -0,0 +1,212 @@
/*
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
Concepts and parts of this file have been contributed by Uladzimir Pylinsky
aka barthess.
*/
/**
* @file i2c.h
* @brief I2C Driver macros and structures.
*
* @addtogroup I2C
* @{
*/
#ifndef _I2C_H_
#define _I2C_H_
#if (HAL_USE_I2C == TRUE) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @name I2C bus error conditions
* @{
*/
#define I2C_NO_ERROR 0x00 /**< @brief No error. */
#define I2C_BUS_ERROR 0x01 /**< @brief Bus Error. */
#define I2C_ARBITRATION_LOST 0x02 /**< @brief Arbitration Lost. */
#define I2C_ACK_FAILURE 0x04 /**< @brief Acknowledge Failure. */
#define I2C_OVERRUN 0x08 /**< @brief Overrun/Underrun. */
#define I2C_PEC_ERROR 0x10 /**< @brief PEC Error in
reception. */
#define I2C_TIMEOUT 0x20 /**< @brief Hardware timeout. */
#define I2C_SMB_ALERT 0x40 /**< @brief SMBus Alert. */
#define I2C_UNKNOWN_ERROR 0x80 /**< @brief internal error (base value - current mode value added) */
#define I2C_STOPPED ((i2cflags_t)(-1))
/**< @brief stop condition or i2cStop() called */
/** @} */
/**
* @name I2C function return codes
* @{
*/
#define I2C_OK (MSG_OK)
#define I2C_ERR_TIMEOUT (MSG_TIMEOUT)
#define I2C_ERROR (MSG_RESET)
/** @} */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @brief Enables the mutual exclusion APIs on the I2C bus.
*/
#if !defined(I2C_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
#define I2C_USE_MUTUAL_EXCLUSION TRUE
#endif
/**
* @brief Enables 'lock' capability needed in I2C slave mode
*/
#if !defined(HAL_USE_I2C_LOCK) || defined(__DOXYGEN__)
#define HAL_USE_I2C_LOCK FALSE
#endif
/**
* @brief Determines whether master mode required to be supported
*/
#if !defined(HAL_USE_I2C_MASTER) || defined(__DOXYGEN__)
#define HAL_USE_I2C_MASTER TRUE
#endif
/**
* @brief Determines whether slave mode required to be supported
*/
#if !defined(HAL_USE_I2C_SLAVE) || defined(__DOXYGEN__)
#define HAL_USE_I2C_SLAVE FALSE
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if I2C_USE_MUTUAL_EXCLUSION && !CH_CFG_USE_MUTEXES && !CH_CFG_USE_SEMAPHORES
#error "I2C_USE_MUTUAL_EXCLUSION requires CH_CFG_USE_MUTEXES and/or CH_CFG_USE_SEMAPHORES"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Driver state machine possible states.
*/
typedef enum {
I2C_UNINIT = 0, /**< Not initialized. */
I2C_STOP = 1, /**< Stopped. */
I2C_READY = 2, /**< Ready. */
I2C_ACTIVE_TX = 3, /**< Transmitting. */
I2C_ACTIVE_RX = 4, /**< Receiving. */
I2C_LOCKED = 5 /**> Bus or driver locked. */
} i2cstate_t;
#include "hal_i2c_lld.h"
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @brief Wakes up the waiting thread notifying no errors.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
#define _i2c_wakeup_isr(i2cp) do { \
osalSysLockFromISR(); \
osalThreadResumeI(&(i2cp)->thread, MSG_OK); \
osalSysUnlockFromISR(); \
} while(0)
/**
* @brief Wakes up the waiting thread notifying errors.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
#define _i2c_wakeup_error_isr(i2cp) do { \
osalSysLockFromISR(); \
osalThreadResumeI(&(i2cp)->thread, MSG_RESET); \
osalSysUnlockFromISR(); \
} while(0)
/**
* @brief Wrap i2cMasterTransmitTimeout function with TIME_INFINITE timeout.
* @api
*/
#define i2cMasterTransmit(i2cp, addr, txbuf, txbytes, rxbuf, rxbytes) \
(i2cMasterTransmitTimeout(i2cp, addr, txbuf, txbytes, rxbuf, rxbytes, \
TIME_INFINITE))
/**
* @brief Wrap i2cMasterReceiveTimeout function with TIME_INFINITE timeout.
* @api
*/
#define i2cMasterReceive(i2cp, addr, rxbuf, rxbytes) \
(i2cMasterReceiveTimeout(i2cp, addr, rxbuf, rxbytes, TIME_INFINITE))
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void i2cInit(void);
void i2cObjectInit(I2CDriver *i2cp);
void i2cStart(I2CDriver *i2cp, const I2CConfig *config);
void i2cStop(I2CDriver *i2cp);
i2cflags_t i2cGetErrors(I2CDriver *i2cp);
msg_t i2cMasterTransmitTimeout(I2CDriver *i2cp,
i2caddr_t addr,
const uint8_t *txbuf, size_t txbytes,
uint8_t *rxbuf, size_t rxbytes,
systime_t timeout);
msg_t i2cMasterReceiveTimeout(I2CDriver *i2cp,
i2caddr_t addr,
uint8_t *rxbuf, size_t rxbytes,
systime_t timeout);
#if HAL_USE_I2C_LOCK /* I2C slave mode support */
void i2cLock(I2CDriver *i2cp, systime_t lockDuration);
void i2cUnlock(I2CDriver *i2cp);
#endif
#if I2C_USE_MUTUAL_EXCLUSION == TRUE
void i2cAcquireBus(I2CDriver *i2cp);
void i2cReleaseBus(I2CDriver *i2cp);
#endif /* I2C_USE_MUTUAL_EXCLUSION */
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_I2C == TRUE */
#endif /* _I2C_H_ */
/** @} */

View file

@ -0,0 +1,423 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/*
Slave I2C support contributed by Brent Roman of the
Monterey Bay Aquarium Research Institute
*/
/**
* @file i2cslave.h
* @brief Slave Mode for the I2C Driver.
*
* @addtogroup I2C
* @{
*/
#ifndef _I2CSLAVE_H_
#define _I2CSLAVE_H_
#if HAL_USE_I2C_SLAVE || defined(__DOXYGEN__)
#include <hal_i2c.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Configure to respond to messages directed to the given i2cadr
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] i2cadr I2C bus address
* - @a 0 matches "all call"
* .
* @return Length of message OR the type of event received
* @retval I2C_OK Success
* @retval I2C_ERROR Cannot match address in addition of those already
*
* @details MatchAddress calls are cumulative.
* Specify address zero to match I2C "all call"
* Most hardware supports matching only a signle nonzero address.
*
* @api
*/
int i2cMatchAddress(I2CDriver *i2cp, i2caddr_t i2cadr);
/**
* @brief Configure to ignore messages directed to the given i2cadr
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] i2cadr I2C bus address
* - @a 0 matches "all call"
* .
* @details A message being transferred that has already matched the
* specified address will continue being processed.
* Requests to unmatch an address that is not currently being matched
* are ignored.
*
* @api
*/
void i2cUnmatchAddress(I2CDriver *i2cp, i2caddr_t i2cadr);
/**
* @brief Configure to ignore all messages
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @details A message being transferred that has already matched the
* specified address will continue being processed.
*
* @api
*/
void i2cUnmatchAll(I2CDriver *i2cp);
/**
* @brief Configure to respond to messages directed to the given i2cadr
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] i2cadr I2C bus address
* - @a 0 matches "all call"
* .
* @return non-zero implies failure.
*
* @details Identical to i2cMatchAddress(), but called from interrupt context
*
* @api
*/
static inline msg_t
i2cMatchAddressI(I2CDriver *i2cp, i2caddr_t i2cadr)
{
osalDbgCheck(i2cp != NULL);
return i2c_lld_matchAddress(i2cp, i2cadr);
}
/**
* @brief Configure to ignore messages directed to the given i2cadr
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] i2cadr I2C bus address
* - @a 0 matches "all call"
* .
* @details Identical to i2cUnmatchAddress(), but called from interrupt context
*
* @api
*/
static inline void
i2cUnmatchAddressI(I2CDriver *i2cp, i2caddr_t i2cadr)
{
osalDbgCheck(i2cp != NULL);
i2c_lld_unmatchAddress(i2cp, i2cadr);
}
/**
* @brief Configure to ignore all messages
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @details Identical to i2cUnmatchAll(), but called from interrupt context
*
* @api
*/
static inline void
i2cUnmatchAllI(I2CDriver *i2cp)
/*
Notes:
Must be called from interrupt context
Does not affect the processing of any message currently being received
*/
{
osalDbgCheck(i2cp != NULL);
i2c_lld_unmatchAll(i2cp);
}
/* I2C Bus activity timeout configuration */
/**
* @brief return maximum number of ticks a slave bus transaction may last
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @return maximum number of ticks a slave bus transaction my last
*
* @details initialized to TIME_INFINITE (disabling slave mode bus timeouts)
*
* @api
*/
static inline
systime_t i2cSlaveTimeout(I2CDriver *i2cp)
{
osalDbgCheck(i2cp != NULL);
return i2c_lld_get_slaveTimeout(i2cp);
}
/**
* @brief set the maximum number of ticks a slave bus transaction may last
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] ticks maximum number of ticks a slave bus transaction my last
* - @a TIME_INFINITE disables slave mode bus timeouts
* - @a TIME_IMMEDIATE is invalid
* .
*
* @api
*/
static inline
void i2cSlaveSetTimeout(I2CDriver *i2cp, systime_t ticks)
{
osalDbgCheck(i2cp != NULL && ticks != TIME_IMMEDIATE);
i2c_lld_set_slaveTimeout(i2cp, ticks);
}
/* bus transaction attributes */
/**
* @brief return bit mask of errors associated with this slave transaction
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @return I2C bus error conditions described in i2c.h
*
* @api
*/
static inline
i2cflags_t i2cSlaveErrors(I2CDriver *i2cp)
{
osalDbgCheck(i2cp != NULL);
return i2c_lld_get_slaveErrors(i2cp);
}
/**
* @brief return number of bytes transferred during this slave transaction
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @return number of bytes actually transferred on the bus
*
* @api
*/
static inline
size_t i2cSlaveBytes(I2CDriver *i2cp)
{
osalDbgCheck(i2cp != NULL);
return i2c_lld_get_slaveBytes(i2cp);
}
/**
* @brief return i2c address to which this message was targetted
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @return i2c address to which this message was targetted
*
* @details The address returns will be one of those
* specified earlier as an argument to i2cMatchAddress()
*
* @api
*/
static inline
i2caddr_t i2cSlaveTargetAdr(I2CDriver *i2cp)
{
osalDbgCheck(i2cp != NULL);
return i2c_lld_get_slaveTargetAdr(i2cp);
}
/*
An event service thread based API library called i2cevent supports processing
slave messages on a dedicated thread. This facility is built upon the
low-level driver's asynchronous callback functions described below:
Each callback function may alter the processing of subsequent I2C
messages and read requests by calling i2cSlaveReceive() and
i2cSlaveReply(), respectively. Further, callbacks may alter their
i2cSlaveMsg structs in RAM, but only those for their own channel.
Such changes take immediate affect. This facility can be used to
avoid copying message buffers.
If receive buffers become full or a reply to a read request cannot be
generated immediately, the relevant I2CSlaveMsg struct may be substituted
for another whose body pointer is NULL or whose body size is zero.
Note that, I2CSlaveMsg structs may be modified
in place within a channel's callbacks to the same effect.
A NULL body pointer or zero size causes the slave to signal the master node
to wait by holding the I2C clock signal low, "stretching it", during the next
transaction to which that I2CSlaveMsg applies.
The I2C clock resumes only after a i2cSlaveSetReceive() or SetReply() is
called with an I2CSlaveMsg containing a non-NULL body,
or after the transaction timeout expires.
Therefore, if a NULL body pointer is replaced with a non-NULL one or
a zero length is replaced with a non-zero one, i2cSlaveReceive() or
i2cSlaveReply() MUST be called -- even if with the same pointer values --
to inform the i2c driver that the transaction may resume.
Note that Receive and Reply processing is initially "locked".
*/
/**
* @brief Configure callbacks & buffers for message reception & query reply
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] rxMsg @p I2CSlaveMsg struct for processing subsequent messages
* @param[in] replyMsg @p I2CSlaveMsg struct for processing subsequent queries
*
* @details Must be called from a thread
* Call i2cMatchAddress() after this to start processing
* Enabling match addresses before installing handler callbacks can
* result in locking the I2C bus when a master accesses those
* unconfigured slave addresses
*
* @api
*/
void i2cSlaveConfigure(I2CDriver *i2cp,
const I2CSlaveMsg *rxMsg, const I2CSlaveMsg *replyMsg);
/**
* @brief Configure callbacks & buffers for message reception
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] rxMsg @p I2CSlaveMsg struct for processing subsequent messages
* @param[in] replyMsg @p I2CSlaveMsg struct for processing subsequent queries
*
* @details Must be called from a thread
* Call i2cMatchAddress() after this to start processing
* Enabling match addresses before installing handler callbacks can
* result in locking the I2C bus when a master accesses those
* unconfigured slave addresses
*
* @api
*/
void i2cSlaveReceive(I2CDriver *i2cp, const I2CSlaveMsg *rxMsg);
/**
* @brief return @p I2CSlaveMsg for processing received messages
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @returns @p I2CSlaveMsg struct for processing subsequent messages
*
* @api
*/
static inline
const I2CSlaveMsg *i2cSlaveReceiveMsg(I2CDriver *i2cp)
{
osalDbgCheck(i2cp != NULL);
return i2c_lld_get_slaveReceive(i2cp);
}
/**
* @brief Configure callbacks & buffers for query reply
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] replyMsg @p I2CSlaveMsg struct for processing subsequent queries
*
* @details Must be called from a thread
* Call i2cMatchAddress() after this to start processing
* Enabling match addresses before installing handler callbacks can
* result in locking the I2C bus when a master accesses those
* unconfigured slave addresses
*
* @api
*/
void i2cSlaveReply(I2CDriver *i2cp, const I2CSlaveMsg *replyMsg);
/**
* @brief return @p I2CSlaveMsg for processing received messages
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @returns @p I2CSlaveMsg struct for processing subsequent messages
*
* @api
*/
static inline
const I2CSlaveMsg *i2cSlaveReplyMsg(I2CDriver *i2cp)
/*
processing descriptor for the next reply message
*/
{
osalDbgCheck(i2cp != NULL);
return i2c_lld_get_slaveReply(i2cp);
}
/**
* @brief Configure callbacks & buffers for message reception
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] rxMsg @p I2CSlaveMsg struct for processing subsequent messages
*
* @details Must be called from an interrupt context
*
* @api
*/
static inline void
i2cSlaveReceiveI(I2CDriver *i2cp, const I2CSlaveMsg *rxMsg)
{
osalDbgCheck(i2cp != NULL && rxMsg != NULL);
i2c_lld_slaveReceive(i2cp, rxMsg);
}
/**
* @brief Configure callbacks & buffers for query reply
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] replyMsg @p I2CSlaveMsg struct for processing subsequent messages
*
* @details Must be called from an interrupt context
*
* @api
*/
static inline void
i2cSlaveReplyI(I2CDriver *i2cp, const I2CSlaveMsg *replyMsg)
/*
Prepare to reply to I2C read requests from bus masters
according to the replyMsg configuration.
Notes:
Must be called from interrupt context
Does not affect the processing of any message reply being sent
*/
{
osalDbgCheck(i2cp != NULL && replyMsg != NULL);
i2c_lld_slaveReply(i2cp, replyMsg);
}
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_I2C_SLAVE */
#endif /* _I2CSLAVE_H_ */