Ver código fonte

add i2c slave files

Jack Humbert 7 anos atrás
pai
commit
c8cc9c6aab

+ 21 - 0
drivers/chibios/i2cslave/I2Cv1/driver.mk

@@ -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

Diferenças do arquivo suprimidas por serem muito extensas
+ 1745 - 0
drivers/chibios/i2cslave/I2Cv1/hal_i2c_lld.c


+ 777 - 0
drivers/chibios/i2cslave/I2Cv1/hal_i2c_lld.h

@@ -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_ */
+
+/** @} */

+ 21 - 0
drivers/chibios/i2cslave/I2Cv2/driver.mk

@@ -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

Diferenças do arquivo suprimidas por serem muito extensas
+ 2065 - 0
drivers/chibios/i2cslave/I2Cv2/hal_i2c_lld.c


+ 806 - 0
drivers/chibios/i2cslave/I2Cv2/hal_i2c_lld.h

@@ -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_ */
+
+/** @} */

+ 480 - 0
drivers/chibios/i2cslave/hal_i2c.c

@@ -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 */
+
+/** @} */

+ 212 - 0
drivers/chibios/i2cslave/hal_i2c.h

@@ -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_ */
+
+/** @} */

+ 423 - 0
drivers/chibios/i2cslave/hal_i2cslave.h

@@ -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_ */