@ -1,21 +0,0 @@ | |||
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 |
@ -1,777 +0,0 @@ | |||
/* | |||
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_ */ | |||
/** @} */ |
@ -1,21 +0,0 @@ | |||
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 |
@ -1,806 +0,0 @@ | |||
/* | |||
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_ */ | |||
/** @} */ |
@ -1,480 +0,0 @@ | |||
/* | |||
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 */ | |||
/** @} */ |
@ -1,212 +0,0 @@ | |||
/* | |||
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_ */ | |||
/** @} */ |
@ -1,423 +0,0 @@ | |||
/* | |||
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_ */ |
@ -1 +1 @@ | |||
Subproject commit 84a65901f0d4784f10210637478c769e0ee6c415 | |||
Subproject commit c846437e39423ef9394aecd3a96393db24c51ebf |