From 5bb1e7869c3c5461c9c789d7e59b31c98bd20420 Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Thu, 7 Jun 2018 19:00:10 -0400 Subject: [PATCH] update chibios, remove extra files --- drivers/chibios/i2cslave/I2Cv1/driver.mk | 21 - drivers/chibios/i2cslave/I2Cv1/hal_i2c_lld.c | 1745 --------------- drivers/chibios/i2cslave/I2Cv1/hal_i2c_lld.h | 777 ------- drivers/chibios/i2cslave/I2Cv2/driver.mk | 21 - drivers/chibios/i2cslave/I2Cv2/hal_i2c_lld.c | 2065 ------------------ drivers/chibios/i2cslave/I2Cv2/hal_i2c_lld.h | 806 ------- drivers/chibios/i2cslave/hal_i2c.c | 480 ---- drivers/chibios/i2cslave/hal_i2c.h | 212 -- drivers/chibios/i2cslave/hal_i2cslave.h | 423 ---- lib/chibios | 2 +- 10 files changed, 1 insertion(+), 6551 deletions(-) delete mode 100644 drivers/chibios/i2cslave/I2Cv1/driver.mk delete mode 100644 drivers/chibios/i2cslave/I2Cv1/hal_i2c_lld.c delete mode 100644 drivers/chibios/i2cslave/I2Cv1/hal_i2c_lld.h delete mode 100644 drivers/chibios/i2cslave/I2Cv2/driver.mk delete mode 100644 drivers/chibios/i2cslave/I2Cv2/hal_i2c_lld.c delete mode 100644 drivers/chibios/i2cslave/I2Cv2/hal_i2c_lld.h delete mode 100644 drivers/chibios/i2cslave/hal_i2c.c delete mode 100644 drivers/chibios/i2cslave/hal_i2c.h delete mode 100644 drivers/chibios/i2cslave/hal_i2cslave.h diff --git a/drivers/chibios/i2cslave/I2Cv1/driver.mk b/drivers/chibios/i2cslave/I2Cv1/driver.mk deleted file mode 100644 index f8cca018e9e..00000000000 --- a/drivers/chibios/i2cslave/I2Cv1/driver.mk +++ /dev/null @@ -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 diff --git a/drivers/chibios/i2cslave/I2Cv1/hal_i2c_lld.c b/drivers/chibios/i2cslave/I2Cv1/hal_i2c_lld.c deleted file mode 100644 index e62e6db1f3a..00000000000 --- a/drivers/chibios/i2cslave/I2Cv1/hal_i2c_lld.c +++ /dev/null @@ -1,1745 +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 mode support added by Brent Roman (brent@mbari.org) - Ported to ChibiOs V3 by steved - Latest updates from original code applied 18.12.15 - - Note that all I2C registers are 16-bit (not 32-bit, as on the later devices in the series) - */ - -/** - * @file STM32/I2Cv1/i2c_lld.c - * @brief STM32 I2C subsystem low level driver source. - * - * @addtogroup I2C - * @{ - */ - -#include "hal.h" - -#if HAL_USE_I2C || defined(__DOXYGEN__) - -// Some master code has been brought in line with V3 - set next define to zero to stick with original code -#define USE_OLD_MASTER_STARTUP 0 - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -#define I2C1_RX_DMA_CHANNEL \ - STM32_DMA_GETCHANNEL(STM32_I2C_I2C1_RX_DMA_STREAM, \ - STM32_I2C1_RX_DMA_CHN) - -#define I2C1_TX_DMA_CHANNEL \ - STM32_DMA_GETCHANNEL(STM32_I2C_I2C1_TX_DMA_STREAM, \ - STM32_I2C1_TX_DMA_CHN) - -#define I2C2_RX_DMA_CHANNEL \ - STM32_DMA_GETCHANNEL(STM32_I2C_I2C2_RX_DMA_STREAM, \ - STM32_I2C2_RX_DMA_CHN) - -#define I2C2_TX_DMA_CHANNEL \ - STM32_DMA_GETCHANNEL(STM32_I2C_I2C2_TX_DMA_STREAM, \ - STM32_I2C2_TX_DMA_CHN) - -#define I2C3_RX_DMA_CHANNEL \ - STM32_DMA_GETCHANNEL(STM32_I2C_I2C3_RX_DMA_STREAM, \ - STM32_I2C3_RX_DMA_CHN) - -#define I2C3_TX_DMA_CHANNEL \ - STM32_DMA_GETCHANNEL(STM32_I2C_I2C3_TX_DMA_STREAM, \ - STM32_I2C3_TX_DMA_CHN) - -/*===========================================================================*/ -/* Driver constants -- see ST document RM0038 figure 208 */ -/*===========================================================================*/ -#define I2C_EV5_MASTER_MODE_SELECT \ - (((uint32_t)I2C_SR2_MSL << 16) | I2C_SR1_SB) - -#define I2C_EV6_MASTER_TRA_MODE_SELECTED \ - (((uint32_t)(I2C_SR2_MSL | I2C_SR2_TRA) << 16) | I2C_SR1_ADDR) - -#define I2C_EV6_MASTER_REC_MODE_SELECTED \ - (((uint32_t)I2C_SR2_MSL << 16) | I2C_SR1_ADDR) - -#define I2C_EV8_2_MASTER_BYTE_TRANSMITTED \ - (((uint32_t)(I2C_SR2_MSL | I2C_SR2_TRA) << 16) | I2C_SR1_BTF) - -#define I2C_EV9_MASTER_ADD10 \ - ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY) << 16) | I2C_SR1_ADD10)) - -#if HAL_USE_I2C_SLAVE -#define I2C_EV1_SLAVE_RXADRMATCH \ - ((uint32_t)I2C_SR1_ADDR) - -#define I2C_EV1_SLAVE_TXADRMATCH \ - (((uint32_t)I2C_SR2_TRA << 16) | I2C_SR1_ADDR) - -#define I2C_EV2_SLAVE_RXSTOP \ - (I2C_SR1_STOPF) -#endif - -#define I2C_EV_MASK ( \ - ((uint32_t)(I2C_SR2_MSL|I2C_SR2_TRA)<<16) | \ - (I2C_SR1_SB|I2C_SR1_ADDR|I2C_SR1_STOPF|I2C_SR1_BTF)) - -#define I2C_ERROR_MASK \ - ((uint16_t)(I2C_SR1_BERR | I2C_SR1_ARLO | I2C_SR1_AF | I2C_SR1_OVR | \ - I2C_SR1_PECERR | I2C_SR1_TIMEOUT | I2C_SR1_SMBALERT)) - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/** @brief I2C1 driver identifier.*/ -#if STM32_I2C_USE_I2C1 || defined(__DOXYGEN__) -I2CDriver I2CD1; -#endif - -/** @brief I2C2 driver identifier.*/ -#if STM32_I2C_USE_I2C2 || defined(__DOXYGEN__) -I2CDriver I2CD2; -#endif - -/** @brief I2C3 driver identifier.*/ -#if STM32_I2C_USE_I2C3 || defined(__DOXYGEN__) -I2CDriver I2CD3; -#endif - -/* quick and dirty queue to record event interrupts */ -#define QEVENTS 32 -#if QEVENTS > 0 -typedef struct i2cQ_t { - uint8_t code; - uint8_t state; - uint16_t param; -} i2cQ_t; -i2cQ_t i2cQ[QEVENTS]; -unsigned i2cI = QEVENTS; -#define qEvt(posn,info) {if (++i2cI >= QEVENTS) i2cI = 0; \ - i2cQ[i2cI].code=(posn); i2cQ[i2cI].state=(i2cp->mode); i2cQ[i2cI].param=(info); } -#else -#define qEvt(posn,info) -#endif - - -#if HAL_USE_I2C_SLAVE /* I2C slave mode support */ - -void I2CSlaveDummyCB(I2CDriver *i2cp) -/* - dummy callback -- placeholder to ignore event -*/ -{(void)i2cp;} - - /* lock bus on receive or reply message */ -const I2CSlaveMsg I2CSlaveLockOnMsg = { - 0, NULL, I2CSlaveDummyCB, I2CSlaveDummyCB, I2CSlaveDummyCB -}; - -#endif - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -/** - * @brief Resets and disables the I2C channel - * - * @param[in] i2cp pointer to the @p I2CDriver object - * - * @notapi - */ -static void i2cReset(I2CDriver *i2cp) { - I2C_TypeDef *dp = i2cp->i2c; - /* reset the I2C registers.*/ - dp->CR1 = I2C_CR1_SWRST; - dp->CR1 = 0; - dp->CR2 = 0; - dp->SR1 = 0; - - /* Stop the associated DMA streams.*/ - dmaStreamDisable(i2cp->dmatx); - dmaStreamDisable(i2cp->dmarx); -} - -/** - * @brief Aborts an I2C transaction. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * - * @notapi - */ -static void i2cAbortOperation(I2CDriver *i2cp) { - /* save control registers */ - I2C_TypeDef *dp = i2cp->i2c; - uint16_t cr2 = dp->CR2, cr1 = dp->CR1; -#if HAL_USE_I2C_SLAVE - uint16_t oar1 = dp->OAR1, oar2 = dp->OAR2; -#endif - uint16_t ccr = dp->CCR, trise = dp->TRISE; - - /* reset the I2C channel */ - i2cReset(i2cp); - - /* restore control registers */ - dp->TRISE = trise; dp->CCR = ccr; -#if HAL_USE_I2C_SLAVE - /* restore address mataching */ - dp->OAR1 = oar1; dp->OAR2 = oar2; -#endif - - /* Enable interrrupts */ - dp->CR2 = (cr2 & 0x3F) | I2C_CR2_ITERREN | I2C_CR2_DMAEN | I2C_CR2_ITEVTEN; - - /* Finish restoring and enable pheripheral */ - dp->CR1 = I2C_CR1_ACK | I2C_CR1_PE | (cr1 & (I2C_CR1_SMBUS | I2C_CR1_SMBTYPE)) -#if HAL_USE_I2C_SLAVE - | (cr1 & I2C_CR1_ENGC) -#endif - ; -} - - -#if HAL_USE_I2C_SLAVE || HAL_USE_I2C_LOCK -/** - * @brief stop transaction timeout countdown - * - * @param[in] i2cp pointer to the @p I2CDriver object - * - * @notapi - */ -static inline void stopTimer(I2CDriver *i2cp) -{ - osalSysLockFromISR(); - chVTResetI(&i2cp->timer); - osalSysUnlockFromISR(); -} -#else -#define stopTimer(ignored) {} -#endif - - -#if HAL_USE_I2C_SLAVE /* I2C slave mode support */ - -/** - * @brief return the address matched - * - * @param[in] dp pointer to the @p I2C registers object - * @param[in] sr2 I2C SR2 register contents - * - * @notapi - * Only supports 7-bit addressing for now - */ -static inline i2caddr_t matchedAdr(I2C_TypeDef *dp, uint32_t sr2) { - if (sr2 & I2C_SR2_GENCALL) - return 0; - if (sr2 & I2C_SR2_DUALF) - return (dp->OAR2>>1) & 0x7f; - return (dp->OAR1>>1) & 0x7f; -} - - -/** - * @brief report error via slave exception callback - * - * @param[in] i2cp pointer to the @p I2CDriver object - * - * @note moves back to the idle mode - * @notapi - */ -static inline void reportSlaveError(I2CDriver *i2cp) { -#if HAL_USE_I2C_STARTFIX - i2cp->config->disarmStartDetect(); -#endif - { - const I2CSlaveMsg *xfer = i2cp->mode >= i2cSlaveReplying ? - i2cp->slaveReply : i2cp->slaveRx; - if (xfer->exception) - xfer->exception(i2cp); /* in this case, i2cp->slaveErrors == 0 */ - } - i2cp->mode = i2cIdle; - i2cp->targetAdr = i2cInvalidAdr; -} - - -/** - * @brief Handling of stalled slave mode I2C transactions. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * - * @notapi - */ -static void slaveTimeExpired(void *i2cv) { - I2CDriver *i2cp = i2cv; - - if (i2cp->mode < i2cIsMaster) - { - i2cAbortOperation(i2cp); - reportSlaveError(i2cp); - } -} - - -/** - * @brief start or restart slave mode transaction - * - * @param[in] i2cp pointer to the @p I2CDriver object - * - * @notapi - */ -static inline void startSlaveAction(I2CDriver *i2cp, i2caddr_t targetAdr) -{ - stopTimer(i2cp); - i2cp->targetAdr = targetAdr; - i2cp->slaveBytes = 0; - i2cp->slaveErrors = 0; - if (i2cp->slaveTimeout != TIME_INFINITE) - { - osalSysLockFromISR(); - chVTSetI(&i2cp->timer, i2cp->slaveTimeout, slaveTimeExpired, i2cp); - osalSysUnlockFromISR(); - } -} - -/** - * @brief end slave receive message DMA - * - * @param[in] i2cp pointer to the @p I2CDriver object - * - * @notapi - */ -static inline void endSlaveRxDMA(I2CDriver *i2cp) -{ - size_t bytesRemaining = dmaStreamGetTransactionSize(i2cp->dmarx); - if (i2cp->slaveBytes) - i2cp->slaveBytes += 0xffff - bytesRemaining; - else - i2cp->slaveBytes = i2cp->slaveRx->size - bytesRemaining; - dmaStreamDisable(i2cp->dmarx); -} - -/** - * @brief end slave transmit DMA - * - * @param[in] i2cp pointer to the @p I2CDriver object - * @param[in] bytesRemaining bytes lost in output queue - * - * @notapi - */ -static inline void endSlaveReplyDMA(I2CDriver *i2cp, size_t bytesRemaining) -{ - bytesRemaining += dmaStreamGetTransactionSize(i2cp->dmatx); - if (i2cp->slaveBytes) - i2cp->slaveBytes += 0xffff - bytesRemaining; - else - i2cp->slaveBytes = i2cp->slaveReply->size - bytesRemaining; - dmaStreamDisable(i2cp->dmatx); -} - -#endif - - -/** - * @brief Wakes up a waiting thread. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * @param[in] msg wakeup message - * - * @notapi - */ -static inline void wakeup_isr(I2CDriver *i2cp, msg_t msg) -{ - do { - osalSysLockFromISR(); - osalThreadResumeI(&(i2cp)->thread, msg); - osalSysUnlockFromISR(); - } while(0); - -#if 0 - chSysLockFromISR(); - thread_t *tp = i2cp->thread; - if (tp != NULL) { - i2cp->thread = NULL; - tp->p_u.rdymsg = msg; - chSchReadyI(tp); - } - chSysUnlockFromISR(); -#endif -} - - -/** - * @brief Set clock speed. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * - * @notapi - */ -static void i2c_lld_set_clock(I2CDriver *i2cp) { - I2C_TypeDef *dp = i2cp->i2c; - uint16_t regCCR, clock_div; - int32_t clock_speed = i2cp->config->clock_speed; - i2cdutycycle_t duty = i2cp->config->duty_cycle; - - osalDbgCheck((i2cp != NULL) && - (clock_speed > 0) && - (clock_speed <= 4000000)); - - /* CR2 Configuration.*/ - dp->CR2 &= (uint16_t)~I2C_CR2_FREQ; - dp->CR2 |= (uint16_t)I2C_CLK_FREQ; - - /* CCR Configuration.*/ - regCCR = 0; - clock_div = I2C_CCR_CCR; - - switch (duty) { - case STD_DUTY_CYCLE: - /* Standard mode clock_div calculate: Tlow/Thigh = 1/1.*/ -#ifndef STM32_I2C_LOOSE_CLK - /* Configure clock_div in standard mode.*/ - osalDbgAssert(clock_speed <= 100000, - "#1 - STD_DUTY_CYCLE limited to 100khz"); - osalDbgAssert(STM32_PCLK1 % (clock_speed * 2) == 0, - "#2 - PCLK1 not divisible by 2*I2Cclk"); -#endif - clock_div = (uint16_t)(STM32_PCLK1 / (clock_speed * 2)); - - - osalDbgAssert(clock_div >= 0x04, - "clock divider less then 0x04 not allowed"); - regCCR |= (clock_div & I2C_CCR_CCR); - - /* Sets the Maximum Rise Time for standard mode.*/ - dp->TRISE = (uint16_t)(I2C_CLK_FREQ + 1); - break; - - case FAST_DUTY_CYCLE_2: - case FAST_DUTY_CYCLE_16_9: - /* Configure clock_div in fast mode.*/ -#ifndef STM32_I2C_LOOSE_CLK - osalDbgAssert(clock_speed > 100000 && clock_speed <= 400000, - "#4 - I2Cclk out of range for FAST_DUTY_CYCLE"); -#endif - if (duty == FAST_DUTY_CYCLE_2) { - /* Fast mode clock_div calculate: Tlow/Thigh = 2/1.*/ -#ifndef STM32_I2C_LOOSE_CLK - osalDbgAssert((STM32_PCLK1 % (clock_speed * 3)) == 0, - "#6 - PCLK1 not divisible by 3*I2Cclk"); -#endif - clock_div = (uint16_t)(STM32_PCLK1 / (clock_speed * 3)); - }else{ /* FAST_DUTY_CYCLE_16_9 */ - /* Fast mode clock_div calculate: Tlow/Thigh = 16/9.*/ -#ifndef STM32_I2C_LOOSE_CLK - osalDbgAssert(STM32_PCLK1 % (clock_speed * 25) == 0, - "#7 - PCLK1 not divisible by 25*I2Cclk"); -#endif - clock_div = (uint16_t)(STM32_PCLK1 / (clock_speed * 25)); - regCCR |= I2C_CCR_DUTY; - } - - osalDbgAssert(clock_div >= 0x01, - "clock divider less then 0x04 not allowed"); - regCCR |= (I2C_CCR_FS | (clock_div & I2C_CCR_CCR)); - - /* Sets the Maximum Rise Time for fast mode.*/ - dp->TRISE = (uint16_t)((I2C_CLK_FREQ * 300 / 1000) + 1); - break; - - default: - osalSysHalt("Invalid I2C duty_cycle"); - } - - osalDbgAssert((clock_div <= I2C_CCR_CCR), "the selected clock is too low"); - - dp->CCR = (uint16_t)regCCR; -} - - -/** - * @brief Set operation mode of I2C hardware. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * - * @notapi - */ -static void i2c_lld_set_opmode(I2CDriver *i2cp) { - I2C_TypeDef *dp = i2cp->i2c; - i2copmode_t opmode = i2cp->config->op_mode; - uint16_t regCR1; - - regCR1 = dp->CR1; - switch (opmode) { - case OPMODE_I2C: - regCR1 &= (uint16_t)~(I2C_CR1_SMBUS|I2C_CR1_SMBTYPE); - break; - case OPMODE_SMBUS_DEVICE: - regCR1 |= I2C_CR1_SMBUS; - regCR1 &= (uint16_t)~(I2C_CR1_SMBTYPE); - break; - case OPMODE_SMBUS_HOST: - regCR1 |= (I2C_CR1_SMBUS|I2C_CR1_SMBTYPE); - } - dp->CR1 = (uint16_t)regCR1; -} - - - -#if USE_OLD_MASTER_STARTUP -/** - * @brief Handling of stalled master mode I2C transactions. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * - * @notapi - */ -static void i2c_lld_safety_timeout(void *p) { - I2CDriver *i2cp = p; - - stopTimer(i2cp); -#if HAL_USE_I2C_SLAVE /* abort any slave operation in progress */ - if (!(i2cp->i2c->SR2 & I2C_SR2_MSL)) - slaveTimeExpired(i2cp); /* in case slave preventing master bus access */ - else -#endif - { - i2cAbortOperation(i2cp); - i2cp->mode = i2cIdle; - } - wakeup_isr(i2cp, I2C_ERR_TIMEOUT); -} -#endif - - -#if HAL_USE_I2C_LOCK /* I2C bus locking support */ - -/** - * @brief Handling of expired master bus lock timer - * - * @param[in] i2cv pointer to the @p I2CDriver object - * - * @notapi - */ -static void lockExpired(void *i2cv) { - I2CDriver *i2cp = i2cv; - - if (i2cp->mode == i2cIsMaster && !i2cp->thread) { /* between transactions */ - i2cp->i2c->CR1 |= (uint16_t)(I2C_CR1_STOP | I2C_CR1_ACK); - i2cp->mode = i2cIdle; - } - i2cp->lockDuration = TIME_IMMEDIATE; -} - - -/** - * @brief Lock I2C bus at the beginning of the next message - * - * @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 - * . - * - * Lock I2C bus at the beginning of the next message sent - * for a maximum of lockDuration ticks. No other I2C masters will - * be allowed to interrupt until i2cUnlock() is called. - * - * @notapi - **/ -void i2c_lld_lock(I2CDriver *i2cp, systime_t lockDuration) -{ - i2cp->lockDuration = lockDuration; - if (i2cp->mode >= i2cIsMaster) { - stopTimer(i2cp); - if (lockDuration == TIME_IMMEDIATE) - lockExpired(i2cp); - else if (lockDuration != TIME_INFINITE) - chVTSetI(&i2cp->timer, lockDuration, lockExpired, i2cp); - } -} - -#endif - - - -/** - * @brief report error waking thread or invoking callback as appropriate - * - * @param[in] i2cp pointer to the @p I2CDriver object - * @param[in] errCode error bit mask or code - * - * @notapi - */ -static void reportErrs(I2CDriver *i2cp, i2cflags_t errCode) -{ -qEvt(0xee,errCode); - I2C_TypeDef *dp = i2cp->i2c; - if (i2cp->mode <= i2cIdle) /* failing to master bus */ - i2cAbortOperation(i2cp); - else if (dp->SR2 & I2C_SR2_MSL) { -#if HAL_USE_I2C_LOCK /* I2C bus locking support */ - i2cp->mode = i2cIsMaster; - switch (i2cp->lockDuration) { - case TIME_INFINITE: - break; - case TIME_IMMEDIATE: - stopTimer(i2cp); - default: - if (!chVTIsArmedI(&i2cp->timer)) { - dp->CR1 |= (uint16_t)(I2C_CR1_STOP | I2C_CR1_ACK); - i2cp->mode = i2cIdle; - i2cp->lockDuration = TIME_IMMEDIATE; - } - } -#else /* signal stop condition on any error */ - dp->CR1 |= (uint16_t)(I2C_CR1_STOP | I2C_CR1_ACK); - i2cp->mode = i2cIdle; -#endif - } -#if HAL_USE_I2C_SLAVE - else if (i2cp->mode < i2cIsMaster) { - i2cp->slaveErrors = errCode; - i2cAbortOperation(i2cp); - stopTimer(i2cp); - reportSlaveError(i2cp); - return; - } -#endif - /* wake any waiting master mode handling thread. */ - i2cp->errors = errCode; - wakeup_isr(i2cp, I2C_ERROR); -} - - -/** - * @brief I2C error handler. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * @param[in] sr content of the SR1 register to be decoded - * - * @notapi - */ -static void i2c_lld_serve_error_interrupt(I2CDriver *i2cp, uint16_t sr) { -#if HAL_USE_I2C_SLAVE -/* NACK of last byte transmitted in slave response is NORMAL -- not an error! */ - if (i2cp->mode == i2cSlaveReplying && (sr & I2C_ERROR_MASK) == I2C_SR1_AF) { -qEvt(0xcc,sr); - endSlaveReplyDMA(i2cp, 1); -#if HAL_USE_I2C_STARTFIX - i2cp->config->disarmStartDetect(); -#endif - if (i2cp->slaveReply->processMsg) - i2cp->slaveReply->processMsg(i2cp); - i2cp->targetAdr = i2cInvalidAdr; - stopTimer(i2cp); - i2cp->mode = i2cIdle; - return; - } -#endif - i2cflags_t errs = 0; - - if (sr & I2C_SR1_BERR) /* Bus error. */ - errs = I2C_BUS_ERROR; - - if (sr & I2C_SR1_ARLO) /* Arbitration lost. */ - errs |= I2C_ARBITRATION_LOST; - - if (sr & I2C_SR1_AF) /* Acknowledge fail. */ - errs |= I2C_ACK_FAILURE; - - if (sr & I2C_SR1_OVR) /* Overrun. */ - errs |= I2C_OVERRUN; - - if (sr & I2C_SR1_TIMEOUT) /* SMBus Timeout. */ - errs |= I2C_TIMEOUT; - - if (sr & I2C_SR1_PECERR) /* PEC error. */ - errs |= I2C_PEC_ERROR; - - if (sr & I2C_SR1_SMBALERT) /* SMBus alert. */ - errs |= I2C_SMB_ALERT; - - if (!errs) - errs = I2C_UNKNOWN_ERROR; -qEvt(0xcb,errs); - - /* Disable any active DMA */ - dmaStreamDisable(i2cp->dmatx); - dmaStreamDisable(i2cp->dmarx); - - reportErrs(i2cp, errs); -} - - -static inline void endMasterAction(I2CDriver *i2cp, uint32_t regCR1) -{ -#if HAL_USE_I2C_LOCK - if (i2cp->lockDuration != TIME_IMMEDIATE && ( - chVTIsArmedI(&i2cp->timer) || i2cp->lockDuration == TIME_INFINITE)) { - i2cp->mode = i2cIsMaster; - return; - } - stopTimer(i2cp); -#endif - i2cp->i2c->CR1 = (regCR1 | I2C_CR1_STOP | I2C_CR1_ACK); - i2cp->mode = i2cIdle; -} - - -/** - * @brief I2C event handler ISR - * - * @param[in] i2cp pointer to the @p I2CDriver object - * - * @notapi - */ -static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) -{ - I2C_TypeDef *dp = i2cp->i2c; - uint16_t regCR1 = dp->CR1; - uint32_t regSR2 = dp->SR2; - uint32_t event = dp->SR1 | (regSR2 << 16); - - - switch (event & I2C_EV_MASK) { - -#define chkTransition(expectedMode) { \ - if (i2cp->mode != (expectedMode)) goto invalidTransition;} - - invalidTransition: /* error on known event out of expected sequence */ - i2cAbortOperation(i2cp); /* reset and reinit */ - qEvt(0x10, (event & 0xffff)); - reportErrs(i2cp, I2C_UNKNOWN_ERROR + i2cp->mode); - break; - -#if HAL_USE_I2C_SLAVE - case I2C_EV1_SLAVE_RXADRMATCH : /* Slave mode - receive a message */ -qEvt(0x11,0); - { - i2caddr_t targetAdr = matchedAdr(dp, regSR2); - switch (i2cp->mode) { - case i2cIdle: -#if HAL_USE_I2C_STARTFIX - i2cp->config->armStartDetect(); -#endif - break; - case i2cSlaveRxing: - endSlaveRxDMA(i2cp); - if (i2cp->slaveRx->processMsg) - i2cp->slaveRx->processMsg(i2cp); - break; - case i2cSlaveReplying: /* Master did not NACK last transmitted byte */ - endSlaveReplyDMA(i2cp, 2); - if (i2cp->slaveReply->processMsg) - i2cp->slaveReply->processMsg(i2cp); - break; - default: - goto invalidTransition; - } - startSlaveAction(i2cp, targetAdr); - } - { - const I2CSlaveMsg *rx = i2cp->slaveNextRx; - if (rx->adrMatched) // Q: Can rx ever be NULL? - rx->adrMatched(i2cp); // Execute callback on address match if specified - rx = i2cp->slaveRx = i2cp->slaveNextRx; - if (rx->body && rx->size) { - (void)dp->SR2; /* clear I2C_SR1_ADDR */ - /* Receive buffer available - can receive immediately. Set up slave RX DMA */ - dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode); - dmaStreamSetMemory0(i2cp->dmarx, rx->body); - dmaStreamSetTransactionSize(i2cp->dmarx, rx->size); - dmaStreamEnable(i2cp->dmarx); - i2cp->mode = i2cSlaveRxing; - }else{ - dp->CR2 &= (uint16_t)(~I2C_CR2_ITEVTEN); /* No reply set up - hold clock low and wait */ - i2cp->mode = i2cLockedRxing; - } - } - break; - - case I2C_EV2_SLAVE_RXSTOP: /* STOP received - possibly without NAK */ -qEvt(0x22,0); - dp->CR1 = (uint16_t)regCR1; /* clear STOPF */ - i2cp->slaveErrors = I2C_STOPPED; /* indicate that bus has been released */ - switch (i2cp->mode) { - case i2cSlaveRxing: - endSlaveRxDMA(i2cp); - if (i2cp->slaveRx->processMsg) - i2cp->slaveRx->processMsg(i2cp); - break; - case i2cSlaveReplying: /* Master did not NACK last transmitted byte */ - endSlaveReplyDMA(i2cp, 2); - if (i2cp->slaveReply->processMsg) - i2cp->slaveReply->processMsg(i2cp); - break; - default: - goto invalidTransition; - } -#if HAL_USE_I2C_STARTFIX - i2cp->config->disarmStartDetect(); -#endif - i2cp->targetAdr = i2cInvalidAdr; - stopTimer(i2cp); - i2cp->mode = i2cIdle; - break; - - case I2C_EV1_SLAVE_TXADRMATCH: /* Slave mode - reply */ -qEvt(0x33,0); - { - i2caddr_t targetAdr = matchedAdr(dp, regSR2); - (void)dp->SR2; /* clear I2C_SR1_ADDR */ // TODO: Check - switch (i2cp->mode) { - case i2cIdle: -#if HAL_USE_I2C_STARTFIX - i2cp->config->armStartDetect(); -#endif - break; - case i2cSlaveRxing: /* Previous transaction not completed properly */ - endSlaveRxDMA(i2cp); - if (i2cp->slaveRx->processMsg) - i2cp->slaveRx->processMsg(i2cp); - break; - default: - goto invalidTransition; - } - startSlaveAction(i2cp, targetAdr); - } - { - const I2CSlaveMsg *reply = i2cp->slaveNextReply; - if (reply->adrMatched) // Q: Can reply be NULL? - reply->adrMatched(i2cp); - reply = i2cp->slaveReply = i2cp->slaveNextReply; // Q: Duplicate action? - if (reply->body && reply->size) { - /* Reply message available - can send immediately. Set up slave TX DMA */ - dmaStreamSetMode(i2cp->dmatx, i2cp->txdmamode); - dmaStreamSetMemory0(i2cp->dmatx, reply->body); - dmaStreamSetTransactionSize(i2cp->dmatx, reply->size); - dmaStreamEnable(i2cp->dmatx); - i2cp->mode = i2cSlaveReplying; - }else{ - dp->CR2 &= (uint16_t)(~I2C_CR2_ITEVTEN); - i2cp->mode = i2cLockedReplying; - } - } - break; -#endif /* HAL_USE_I2C_SLAVE */ - - case I2C_EV5_MASTER_MODE_SELECT: -qEvt(0x55,0); - dp->DR = (uint16_t)i2cp->addr; - switch (i2cp->mode) { - case i2cIdle: -#if HAL_USE_I2C_LOCK - { - systime_t lockDuration = i2cp->lockDuration; - if (lockDuration != TIME_IMMEDIATE && lockDuration != TIME_INFINITE) - { - osalSysLockFromISR(); - chVTSetI(&i2cp->timer, lockDuration, lockExpired, i2cp); - osalSysUnlockFromISR(); - } - } -#endif - break; - case i2cIsMaster: - case i2cMasterStarted: - break; - default: - goto invalidTransition; - } - i2cp->mode = i2cMasterSelecting; - break; - - case I2C_EV6_MASTER_REC_MODE_SELECTED: -qEvt(0x66,0); - chkTransition(i2cMasterSelecting); - if (!i2cp->masterRxbytes) { /* 0-length SMBus style quick read */ - endMasterAction(i2cp, regCR1); - (void)dp->SR2; /* clear I2C_SR1_ADDR */ - wakeup_isr(i2cp, I2C_OK); - break; - } - (void)dp->SR2; /* clear I2C_SR1_ADDR */ - /* RX DMA setup.*/ - dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode); - dmaStreamSetMemory0(i2cp->dmarx, i2cp->masterRxbuf); - dmaStreamSetTransactionSize(i2cp->dmarx, i2cp->masterRxbytes); - dmaStreamEnable(i2cp->dmarx); - dp->CR2 |= I2C_CR2_LAST; /* Needed in receiver mode. */ - if (i2cp->masterRxbytes < 2) - dp->CR1 = (uint16_t)(regCR1 & ~I2C_CR1_ACK); - i2cp->mode = i2cMasterRxing; - break; - - case I2C_EV6_MASTER_TRA_MODE_SELECTED: -qEvt(0x77,0); - (void)dp->SR2; /* clear I2C_SR1_ADDR */ - chkTransition(i2cMasterSelecting); - switch (i2cp->masterTxbytes) { - case 0: - goto doneWriting; - case 1: - dp->DR = i2cp->masterTxbuf[0]; - break; - case 2: - dp->DR = i2cp->masterTxbuf[0]; - dp->DR = i2cp->masterTxbuf[1]; - break; - default: - /* TX DMA setup.*/ - dmaStreamSetMode(i2cp->dmatx, i2cp->txdmamode); - dmaStreamSetMemory0(i2cp->dmatx, i2cp->masterTxbuf); - dmaStreamSetTransactionSize(i2cp->dmatx, i2cp->masterTxbytes); - dmaStreamEnable(i2cp->dmatx); - } - i2cp->mode = i2cMasterTxing; - break; - - case I2C_EV8_2_MASTER_BYTE_TRANSMITTED: -qEvt(0x88,0); - /* Catches BTF event after the end of transmission.*/ - (void)dp->DR; /* clears BTF flag */ - chkTransition(i2cMasterTxing); -doneWriting: - if (i2cp->masterRxbuf) { - /* Starts "read after write" operation, LSB = 1 -> receive.*/ - dp->CR1 = (uint16_t)(regCR1 | I2C_CR1_START | I2C_CR1_ACK); - i2cp->addr |= 1; - i2cp->mode = i2cMasterStarted; - }else{ - endMasterAction(i2cp, regCR1); - wakeup_isr(i2cp, I2C_OK); - } - break; - - case 0: /* quietly ignore "uninteresting" events (i.e. i2c bus busy) */ - qEvt(0x0000); - break; - - default: /* unhandled event -- abort transaction, flag unknown err */ -qEvt(0x9999,0); - //i2cAbortOperation(i2cp); - i2c_lld_serve_error_interrupt(i2cp, event); - } -} - - -#if HAL_USE_I2C_STARTFIX -/** - * @brief external device detected start condition - * - * @param[in] i2cp pointer to the @p I2CDriver object - * - * @details invoked from ISR if a START CONDITION detected during the time - * the startDetector is armed. - * This is a workaround for the STM32's lack of a repeated start event - * - * @notapi - */ -void i2c_lld_startDetected(I2CDriver *i2cp) -{ -qEvt(0xdddd,0); - switch (i2cp->mode) { - case i2cIdle: - i2cAbortOperation(i2cp); /* quietly reset and reinit */ - return; - case i2cSlaveRxing: - endSlaveRxDMA(i2cp); - if (i2cp->slaveRx->processMsg) - i2cp->slaveRx->processMsg(i2cp); - break; - case i2cSlaveReplying: /* Master did not NACK last transmitted byte */ - endSlaveReplyDMA(i2cp, 2); - if (i2cp->slaveReply->processMsg) - i2cp->slaveReply->processMsg(i2cp); - break; - default: - i2cAbortOperation(i2cp); /* reset and reinit */ - reportErrs(i2cp, I2C_UNKNOWN_ERROR + i2cp->mode); - return; - } - i2cp->targetAdr = i2cInvalidAdr; - stopTimer(i2cp); - i2cp->mode = i2cIdle; -} - -/** - * @brief dummy placeholder for armStartDetector() and disarmStartDetector() - * - * @details *MUST* be placed in the configuration struct in cases where - * HAL_USE_I2C_STARTFIX is configured and no startDetector is defined, - * otherwise NULL pointers will be called for these functions! - * - * @notapi - */ -void i2c_lld_noStartDetector(void) {} -#endif - - -/** - * @brief DMA RX end IRQ handler. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * @param[in] flags pre-shifted content of the ISR register - * - * @notapi - */ -static void i2c_lld_serve_rx_end_irq(I2CDriver *i2cp, uint32_t flags) { - I2C_TypeDef *dp = i2cp->i2c; - -qEvt(0xaa,0); - /* DMA errors handling.*/ -#if defined(STM32_I2C_DMA_ERROR_HOOK) - if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) { - STM32_I2C_DMA_ERROR_HOOK(i2cp); - } -#else - (void)flags; -#endif - - dmaStreamDisable(i2cp->dmarx); - -#if HAL_USE_I2C_SLAVE - if (i2cp->mode < i2cIsMaster) { - static uint8_t bitbucket; - if (i2cp->slaveBytes) - i2cp->slaveBytes += 0xffff; // TODO: Why?? (slaveBytes is uint32) - else - i2cp->slaveBytes = i2cp->slaveRx->size; - /* discard data overrunning available rx buffer, but record total length */ - dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode & ~STM32_DMA_CR_MINC); - dmaStreamSetMemory0(i2cp->dmarx, &bitbucket); - dmaStreamSetTransactionSize(i2cp->dmarx, 0xffff); - dmaStreamEnable(i2cp->dmarx); - return; - } -#endif - - dp->CR2 &= (uint16_t)(~I2C_CR2_LAST); - endMasterAction(i2cp, dp->CR1); - wakeup_isr(i2cp, I2C_OK); -} - -/** - * @brief DMA TX end IRQ handler. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * - * @notapi - */ -static void i2c_lld_serve_tx_end_irq(I2CDriver *i2cp, uint32_t flags) { -qEvt(0xbb,0); - /* DMA errors handling.*/ -#if defined(STM32_I2C_DMA_ERROR_HOOK) - if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) { - STM32_I2C_DMA_ERROR_HOOK(i2cp); - } -#else - (void)flags; -#endif - dmaStreamDisable(i2cp->dmatx); - -#if HAL_USE_I2C_SLAVE - if (i2cp->mode < i2cIsMaster) { - const I2CSlaveMsg *reply = i2cp->slaveReply; - if (i2cp->slaveBytes) - i2cp->slaveBytes += 0xffff; // TODO: Why?? (slaveBytes is uint32) - else - i2cp->slaveBytes = reply->size; - /* repeat the last byte in the reply */ - dmaStreamSetMode(i2cp->dmatx, i2cp->txdmamode & ~STM32_DMA_CR_MINC); - dmaStreamSetMemory0(i2cp->dmatx, reply->body+reply->size-1); - dmaStreamSetTransactionSize(i2cp->dmatx, 0xffff); - dmaStreamEnable(i2cp->dmatx); - } -#endif -} - -/*===========================================================================*/ -/* Driver interrupt handlers. */ -/*===========================================================================*/ - -#if STM32_I2C_USE_I2C1 || defined(__DOXYGEN__) -/** - * @brief I2C1 event interrupt handler. - * - * @notapi - */ -OSAL_IRQ_HANDLER(STM32_I2C1_EVENT_HANDLER) { - - OSAL_IRQ_PROLOGUE(); - - i2c_lld_serve_event_interrupt(&I2CD1); - - OSAL_IRQ_EPILOGUE(); -} - -/** - * @brief I2C1 error interrupt handler. - */ -OSAL_IRQ_HANDLER(STM32_I2C1_ERROR_HANDLER) { - uint16_t sr = I2CD1.i2c->SR1; - - OSAL_IRQ_PROLOGUE(); - - I2CD1.i2c->SR1 = ~(sr & I2C_ERROR_MASK); - i2c_lld_serve_error_interrupt(&I2CD1, sr); - - OSAL_IRQ_EPILOGUE(); -} -#endif /* STM32_I2C_USE_I2C1 */ - -#if STM32_I2C_USE_I2C2 || defined(__DOXYGEN__) -/** - * @brief I2C2 event interrupt handler. - * - * @notapi - */ -OSAL_IRQ_HANDLER(STM32_I2C2_EVENT_HANDLER) { - - OSAL_IRQ_PROLOGUE(); - - i2c_lld_serve_event_interrupt(&I2CD2); - - OSAL_IRQ_EPILOGUE(); -} - -/** - * @brief I2C2 error interrupt handler. - * - * @notapi - */ -OSAL_IRQ_HANDLER(STM32_I2C2_ERROR_HANDLER) { - uint16_t sr = I2CD2.i2c->SR1; - - OSAL_IRQ_PROLOGUE(); - - I2CD2.i2c->SR1 = ~(sr & I2C_ERROR_MASK); - i2c_lld_serve_error_interrupt(&I2CD2, sr); - - OSAL_IRQ_EPILOGUE(); -} -#endif /* STM32_I2C_USE_I2C2 */ - -#if STM32_I2C_USE_I2C3 || defined(__DOXYGEN__) -/** - * @brief I2C3 event interrupt handler. - * - * @notapi - */ -OSAL_IRQ_HANDLER(STM32_I2C3_EVENT_HANDLER) { - - OSAL_IRQ_PROLOGUE(); - - i2c_lld_serve_event_interrupt(&I2CD3); - - OSAL_IRQ_EPILOGUE(); -} - -/** - * @brief I2C3 error interrupt handler. - * - * @notapi - */ -OSAL_IRQ_HANDLER(STM32_I2C3_ERROR_HANDLER) { - uint16_t sr = I2CD3.i2c->SR1; - - OSAL_IRQ_PROLOGUE(); - - I2CD3.i2c->SR1 = ~(sr & I2C_ERROR_MASK); - i2c_lld_serve_error_interrupt(&I2CD3, sr); - - OSAL_IRQ_EPILOGUE(); -} -#endif /* STM32_I2C_USE_I2C3 */ - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief Low level I2C driver initialization. - * - * @notapi - */ -void i2c_lld_init(void) { - -#if STM32_I2C_USE_I2C1 - i2cObjectInit(&I2CD1); - I2CD1.thread = NULL; - I2CD1.i2c = I2C1; - I2CD1.dmarx = STM32_DMA_STREAM(STM32_I2C_I2C1_RX_DMA_STREAM); - I2CD1.dmatx = STM32_DMA_STREAM(STM32_I2C_I2C1_TX_DMA_STREAM); -#if HAL_USE_I2C_LOCK || HAL_USE_I2C_SLAVE - chVTObjectInit(&I2CD1.timer); -#endif -#endif /* STM32_I2C_USE_I2C1 */ - -#if STM32_I2C_USE_I2C2 - i2cObjectInit(&I2CD2); - I2CD2.thread = NULL; - I2CD2.i2c = I2C2; - I2CD2.dmarx = STM32_DMA_STREAM(STM32_I2C_I2C2_RX_DMA_STREAM); - I2CD2.dmatx = STM32_DMA_STREAM(STM32_I2C_I2C2_TX_DMA_STREAM); -#if HAL_USE_I2C_LOCK || HAL_USE_I2C_SLAVE - chVTObjectInit(&I2CD2.timer); -#endif -#endif /* STM32_I2C_USE_I2C2 */ - -#if STM32_I2C_USE_I2C3 - i2cObjectInit(&I2CD3); - I2CD3.thread = NULL; - I2CD3.i2c = I2C3; - I2CD3.dmarx = STM32_DMA_STREAM(STM32_I2C_I2C3_RX_DMA_STREAM); - I2CD3.dmatx = STM32_DMA_STREAM(STM32_I2C_I2C3_TX_DMA_STREAM); -#if HAL_USE_I2C_LOCK || HAL_USE_I2C_SLAVE - chVTObjectInit(&I2CD3.timer); -#endif -#endif /* STM32_I2C_USE_I2C3 */ -} - -/** - * @brief Configures and activates the I2C peripheral. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * - * @notapi - */ -void i2c_lld_start(I2CDriver *i2cp) { - I2C_TypeDef *dp = i2cp->i2c; - - i2cp->txdmamode = STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE | - STM32_DMA_CR_MINC | STM32_DMA_CR_DMEIE | - STM32_DMA_CR_TEIE | STM32_DMA_CR_TCIE | - STM32_DMA_CR_DIR_M2P; - i2cp->rxdmamode = STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE | - STM32_DMA_CR_MINC | STM32_DMA_CR_DMEIE | - STM32_DMA_CR_TEIE | STM32_DMA_CR_TCIE | - STM32_DMA_CR_DIR_P2M; - - /* If in stopped state then enables the I2C and DMA clocks.*/ - if (i2cp->state == I2C_STOP) { - -#if STM32_I2C_USE_I2C1 - if (&I2CD1 == i2cp) { - bool b; - - rccResetI2C1(); // **** From trunk - b = dmaStreamAllocate(i2cp->dmarx, - STM32_I2C_I2C1_IRQ_PRIORITY, - (stm32_dmaisr_t)i2c_lld_serve_rx_end_irq, - (void *)i2cp); - osalDbgAssert(!b, "stream already allocated"); - b = dmaStreamAllocate(i2cp->dmatx, - STM32_I2C_I2C1_IRQ_PRIORITY, - (stm32_dmaisr_t)i2c_lld_serve_tx_end_irq, - (void *)i2cp); - osalDbgAssert(!b, "stream already allocated"); - rccEnableI2C1(FALSE); - nvicEnableVector(I2C1_EV_IRQn, STM32_I2C_I2C1_IRQ_PRIORITY); - nvicEnableVector(I2C1_ER_IRQn, STM32_I2C_I2C1_IRQ_PRIORITY); - - i2cp->rxdmamode |= STM32_DMA_CR_CHSEL(I2C1_RX_DMA_CHANNEL) | - STM32_DMA_CR_PL(STM32_I2C_I2C1_DMA_PRIORITY); - i2cp->txdmamode |= STM32_DMA_CR_CHSEL(I2C1_TX_DMA_CHANNEL) | - STM32_DMA_CR_PL(STM32_I2C_I2C1_DMA_PRIORITY); - } -#endif /* STM32_I2C_USE_I2C1 */ - -#if STM32_I2C_USE_I2C2 - if (&I2CD2 == i2cp) { - bool b; - - rccResetI2C2(); // *** From trunk - b = dmaStreamAllocate(i2cp->dmarx, - STM32_I2C_I2C2_IRQ_PRIORITY, - (stm32_dmaisr_t)i2c_lld_serve_rx_end_irq, - (void *)i2cp); - osalDbgAssert(!b, "stream already allocated"); - b = dmaStreamAllocate(i2cp->dmatx, - STM32_I2C_I2C2_IRQ_PRIORITY, - (stm32_dmaisr_t)i2c_lld_serve_tx_end_irq, - (void *)i2cp); - osalDbgAssert(!b, "stream already allocated"); - rccEnableI2C2(FALSE); - nvicEnableVector(I2C2_EV_IRQn, STM32_I2C_I2C2_IRQ_PRIORITY); - nvicEnableVector(I2C2_ER_IRQn, STM32_I2C_I2C2_IRQ_PRIORITY); - - i2cp->rxdmamode |= STM32_DMA_CR_CHSEL(I2C2_RX_DMA_CHANNEL) | - STM32_DMA_CR_PL(STM32_I2C_I2C2_DMA_PRIORITY); - i2cp->txdmamode |= STM32_DMA_CR_CHSEL(I2C2_TX_DMA_CHANNEL) | - STM32_DMA_CR_PL(STM32_I2C_I2C2_DMA_PRIORITY); - } -#endif /* STM32_I2C_USE_I2C2 */ - -#if STM32_I2C_USE_I2C3 - if (&I2CD3 == i2cp) { - bool b; - - rccResetI2C3(); // *** From trunk - b = dmaStreamAllocate(i2cp->dmarx, - STM32_I2C_I2C3_IRQ_PRIORITY, - (stm32_dmaisr_t)i2c_lld_serve_rx_end_irq, - (void *)i2cp); - osalDbgAssert(!b, "stream already allocated"); - b = dmaStreamAllocate(i2cp->dmatx, - STM32_I2C_I2C3_IRQ_PRIORITY, - (stm32_dmaisr_t)i2c_lld_serve_tx_end_irq, - (void *)i2cp); - osalDbgAssert(!b, "stream already allocated"); - rccEnableI2C3(FALSE); - nvicEnableVector(I2C3_EV_IRQn, STM32_I2C_I2C3_IRQ_PRIORITY); - nvicEnableVector(I2C3_ER_IRQn, STM32_I2C_I2C3_IRQ_PRIORITY); - - i2cp->rxdmamode |= STM32_DMA_CR_CHSEL(I2C3_RX_DMA_CHANNEL) | - STM32_DMA_CR_PL(STM32_I2C_I2C3_DMA_PRIORITY); - i2cp->txdmamode |= STM32_DMA_CR_CHSEL(I2C3_TX_DMA_CHANNEL) | - STM32_DMA_CR_PL(STM32_I2C_I2C3_DMA_PRIORITY); - } -#endif /* STM32_I2C_USE_I2C3 */ - } - - /* I2C registers pointed by the DMA.*/ - dmaStreamSetPeripheral(i2cp->dmarx, &dp->DR); - dmaStreamSetPeripheral(i2cp->dmatx, &dp->DR); - - /* Reset i2c peripheral.*/ - dp->CR1 = I2C_CR1_SWRST; - dp->CR1 = 0; - - i2cp->mode = i2cIdle; -#if HAL_USE_I2C_LOCK - i2cp->lockDuration = TIME_IMMEDIATE; -#endif -#if HAL_USE_I2C_SLAVE /* I2C slave mode support */ - i2cp->slaveNextReply = i2cp->slaveNextRx = &I2CSlaveLockOnMsg; - i2cp->targetAdr = i2cInvalidAdr; - i2cp->slaveTimeout = TIME_INFINITE; -#endif - - /* Setup I2C parameters.*/ - i2c_lld_set_clock(i2cp); - i2c_lld_set_opmode(i2cp); - - /* Enable interrrupts */ - dp->CR2 |= I2C_CR2_ITERREN | I2C_CR2_DMAEN | I2C_CR2_ITEVTEN; - /* Ready to go.*/ - dp->CR1 |= I2C_CR1_PE | I2C_CR1_ACK; -} - -/** - * @brief Deactivates the I2C peripheral. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * - * @notapi - */ -void i2c_lld_stop(I2CDriver *i2cp) { - - /* If not in stopped state, then disable the I2C clock.*/ - if (i2cp->state != I2C_STOP) { - - /* I2C disable.*/ - i2cReset(i2cp); - dmaStreamRelease(i2cp->dmatx); - dmaStreamRelease(i2cp->dmarx); - -#if STM32_I2C_USE_I2C1 - if (&I2CD1 == i2cp) { - nvicDisableVector(I2C1_EV_IRQn); - nvicDisableVector(I2C1_ER_IRQn); - rccDisableI2C1(FALSE); - } -#endif - -#if STM32_I2C_USE_I2C2 - if (&I2CD2 == i2cp) { - nvicDisableVector(I2C2_EV_IRQn); - nvicDisableVector(I2C2_ER_IRQn); - rccDisableI2C2(FALSE); - } -#endif - -#if STM32_I2C_USE_I2C3 - if (&I2CD3 == i2cp) { - nvicDisableVector(I2C3_EV_IRQn); - nvicDisableVector(I2C3_ER_IRQn); - rccDisableI2C3(FALSE); - } -#endif - - reportErrs(i2cp, I2C_STOPPED); /* wake any blocked thread */ -#if HAL_USE_I2C_SLAVE /* I2C slave mode support */ - reportErrs(i2cp, I2C_STOPPED); /* ensure both master and slave notified */ -#endif - } -} - - -/** - * @brief Starts an I2C bus master transaction. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * @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 I2C_OK if the function succeeded. - * @retval I2C_ERROR if one or more I2C errors occurred, the errors can - * be retrieved using @p i2cGetErrors(). - * @retval I2C_ERR_TIMEOUT A timeout occurred before operation end. After a - * timeout the driver should be stopped and restarted - * because the bus may in an uncertain state. - * Drivers that support slave mode require only the the driver be restarted - * after a timeout, as stopping and restarting may result in missed events. - * - * There's a system lock active from higher levels when this is called - * - * @notapi - */ -#if USE_OLD_MASTER_STARTUP -// This is the 'original' from the V2.x master/slave code -static msg_t startMasterAction(I2CDriver *i2cp, systime_t timeout) -{ - osalDbgAssert((i2cp->mode <= i2cIsMaster), "busy"); - - i2cp->i2c->CR1 |= I2C_CR1_START | I2C_CR1_ACK; - - virtual_timer_t vt; /* Global timeout for the whole operation.*/ - chVTObjectInit(&vt); - - if (timeout != TIME_INFINITE) - chVTSetI(&vt, timeout, i2c_lld_safety_timeout, i2cp); - i2cp->errors = 0; - i2cp->thread = chThdGetSelfX(); - chSchGoSleepS(CH_STATE_SUSPENDED); - chVTResetI(&vt); - return chThdGetSelfX()->p_u.rdymsg; -} - - -#else - - - -// This version uses same logic as the 'original' V3.x master-only driver. -// Note: may need adjustment to work in multi-master mode as well - see i2c_lld_safety_timeout() -static msg_t startMasterAction(I2CDriver *i2cp, systime_t timeout) -{ - systime_t start, end; - - osalDbgAssert((i2cp->mode <= i2cIsMaster), "busy"); - - osalSysUnlock(); - - /* Calculating the time window for the timeout on the busy bus condition.*/ - start = osalOsGetSystemTimeX(); - end = start + OSAL_MS2ST(STM32_I2C_BUSY_TIMEOUT); - - /* Waits until BUSY flag is reset or, alternatively, for a timeout - condition.*/ - while (true) { - osalSysLock(); - - /* If the bus is not busy then the operation can continue, note, the - loop is exited in the locked state.*/ - if (!(i2cp->i2c->SR2 & I2C_SR2_BUSY) && !(i2cp->i2c->CR1 & I2C_CR1_STOP)) - break; - - /* If the system time went outside the allowed window then a timeout - condition is returned.*/ - if (!osalOsIsTimeWithinX(osalOsGetSystemTimeX(), start, end)) - return MSG_TIMEOUT; - - osalSysUnlock(); - } - - - i2cp->i2c->CR1 |= I2C_CR1_START | I2C_CR1_ACK; - - /* Waits for the operation completion or a timeout.*/ - return osalThreadSuspendTimeoutS(&i2cp->thread, timeout); -} -#endif - -/** - * @brief Receives data via the I2C bus as master. - * @details Number of receiving bytes must be 0 or more than 1 on STM32F1x. - * This is hardware restriction. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * @param[in] addr slave device address - * @param[out] rxbuf pointer to the 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 I2C_OK if the function succeeded. - * @retval I2C_ERROR if one or more I2C errors occurred, the errors can - * be retrieved using @p i2cGetErrors(). - * @retval I2C_ERR_TIMEOUT A timeout occurred before operation end. After a - * timeout the driver should be stopped and restarted - * because the bus may in an uncertain state. - * Drivers that support slave mode require only the the driver be restarted - * after a timeout, as stopping and restarting may result in missed events. - * - * @notapi - */ -msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, - uint8_t *rxbuf, size_t rxbytes, - systime_t timeout) { - osalDbgAssert((rxbytes < (1<<16)), - "#1 - >64Kbytes"); -#if defined(STM32F1XX_I2C) - osalDbgAssert((rxbytes != 1), - "#2 - rxbytes==1"); -#endif - osalDbgAssert((i2cp->thread==NULL), - "#3 - reentry"); - - /* Initializes driver fields, LSB = 1 -> receive.*/ - i2cp->addr = (addr << 1) | 1; - - /* store away DMA info for later activation in event ISR */ - i2cp->masterRxbuf = rxbuf; - i2cp->masterRxbytes = (uint16_t) rxbytes; - return startMasterAction(i2cp, timeout); -} - -/** - * @brief Transmits data via the I2C bus as master. - * @details Number of receiving bytes must be 0 or more than 1 on STM32F1x. - * This is hardware restriction. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * @param[in] addr slave device address - * @param[in] txbuf pointer to the transmit buffer - * @param[in] txbytes number of bytes to be transmitted - * @param[out] rxbuf pointer to the 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 I2C_OK if the function succeeded. - * @retval I2C_ERROR if one or more I2C errors occurred, the errors can - * be retrieved using @p i2cGetErrors(). - * @retval I2C_ERR_TIMEOUT A timeout occurred before operation end. After a - * timeout the driver should be stopped and restarted - * because the bus is in an uncertain state. - * Drivers that support slave mode require only the the driver be restarted - * after a timeout, as stopping and restarting may result in missed events. - * - * There's a system lock active on entry from higher level driver - * - * @notapi - */ -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) { - if (rxbuf == NULL) - rxbytes = 0; - osalDbgAssert(((rxbytes | txbytes) < (1<<16)), "#1 - >64Kbytes"); -#if defined(STM32F1XX_I2C) - osalDbgCheck((rxbytes == 0) || ((rxbytes > 1) && (rxbuf != NULL))); -#endif - osalDbgAssert((i2cp->thread==NULL), "#3 - reentry"); - - /* Initializes driver fields, LSB = 0 -> write.*/ - i2cp->addr = addr << 1; - /* store away DMA info for later activation in event ISR */ - i2cp->masterTxbuf = txbuf; - i2cp->masterTxbytes = (uint16_t) txbytes; - i2cp->masterRxbuf = rxbuf; - i2cp->masterRxbytes = (uint16_t) rxbytes; - return startMasterAction(i2cp, timeout); -} - - -#if HAL_USE_I2C_SLAVE /* I2C slave mode support */ - -/* These bits are undocumented, but used in STM32l1xx I2C example driver */ -#define I2C_OAR1_Ack_7bit (0x4000) /*enable 7 bit address acknowledge*/ -#define I2C_OAR1_Ack_10bit (0xC000) /*enable 10 bit address acknowledge*/ - -/** - * @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. - * - * @notapi - **/ -msg_t i2c_lld_matchAddress(I2CDriver *i2cp, i2caddr_t i2cadr) -{ - I2C_TypeDef *dp = i2cp->i2c; - if (i2cadr == 0) { - dp->CR1 |= I2C_CR1_ENGC; - dp->OAR1 |= I2C_OAR1_Ack_7bit; - }else{ - uint16_t adr = i2cadr << 1; - uint16_t ownAdr = dp->OAR1 & (0x7f<<1); - if (ownAdr == 0 || ownAdr == adr) - dp->OAR1 = adr | I2C_OAR1_Ack_7bit; - else if (!(dp->OAR2 & I2C_OAR2_ENDUAL)) - dp->OAR2 = adr | I2C_OAR2_ENDUAL; - else if ((dp->OAR2 & (0x7f<<1)) != adr) - return I2C_ERROR; /* cannot add this address to set of those matched */ - } - return I2C_OK; -} - - -/** - * @brief Reconfigure I2C channel to no longer match specified address - * - * @param[in] i2cp pointer to the @p I2CDriver object - * @param[in] i2cadr I2C network address - * - * @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. - * Does not support 10-bit addressing. - * - * @notapi - **/ -void i2c_lld_unmatchAddress(I2CDriver *i2cp, i2caddr_t i2cadr) -{ - I2C_TypeDef *dp = i2cp->i2c; - if (i2cadr == 0) { - dp->CR1 &= (uint16_t)~I2C_CR1_ENGC; - if ((dp->OAR1 & (0x7f<<1)) == 0) - dp->OAR1 = 0; - }else{ - uint16_t adr = i2cadr << 1; - if ((dp->OAR1 & (0x7f<<1)) == adr) { - if (dp->OAR2 & I2C_OAR2_ENDUAL) - dp->OAR1 = (dp->OAR2 & (0x7f<<1)) | I2C_OAR1_Ack_7bit; - else - dp->OAR1 = dp->CR1 & I2C_CR1_ENGC ? I2C_OAR1_Ack_7bit : 0; - }else if (dp->OAR2 & I2C_OAR2_ENDUAL && (dp->OAR2 & (0x7f<<1)) == adr) - dp->OAR2 &= ~I2C_OAR2_ENDUAL; - } -} - - -/** - * @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. - * - * @notapi - **/ -void i2c_lld_unmatchAll(I2CDriver *i2cp) -{ - I2C_TypeDef *dp = i2cp->i2c; - dp->CR1 &= (uint16_t)~I2C_CR1_ENGC; - dp->OAR1 = 0; - dp->OAR2 = 0; -} - - -/** - * @brief Configure callbacks & buffers to receive messages - * - * @param[in] i2cp pointer to the @p I2CDriver object - * @param[in] replyMsg @p I2CSlaveMsg struct for processing subsequent received messages - * - * @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 - * - * @notapi - */ -void i2c_lld_slaveReceive(I2CDriver *i2cp, const I2CSlaveMsg *rxMsg) -{ - osalDbgCheck((rxMsg && rxMsg->size <= 0xffff)); - i2cp->slaveNextRx = rxMsg; - if (i2cp->mode == i2cLockedRxing && rxMsg->body && rxMsg->size) { - /* We can receive now! */ - I2C_TypeDef *dp = i2cp->i2c; - (void)dp->SR1, dp->SR2; /* clear I2C_SR1_ADDR */ - i2cp->slaveRx = rxMsg; - /* slave RX DMA setup */ - dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode); - dmaStreamSetMemory0(i2cp->dmarx, rxMsg->body); - dmaStreamSetTransactionSize(i2cp->dmarx, rxMsg->size); - dmaStreamEnable(i2cp->dmarx); - i2cp->mode = i2cSlaveRxing; - dp->CR2 |= I2C_CR2_ITEVTEN; - } -} - - -/** - * @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 - * - * @notapi - */ -void i2c_lld_slaveReply(I2CDriver *i2cp, const I2CSlaveMsg *replyMsg) -{ - osalDbgCheck((replyMsg && replyMsg->size <= 0xffff)); - i2cp->slaveNextReply = replyMsg; - if (i2cp->mode == i2cLockedReplying && replyMsg->body && replyMsg->size) { - i2cp->slaveReply = replyMsg; - /* slave TX DMA setup -- we can reply now! */ - dmaStreamSetMode(i2cp->dmatx, i2cp->txdmamode); - dmaStreamSetMemory0(i2cp->dmatx, replyMsg->body); - dmaStreamSetTransactionSize(i2cp->dmatx, replyMsg->size); - dmaStreamEnable(i2cp->dmatx); - i2cp->mode = i2cSlaveReplying; - i2cp->i2c->CR2 |= I2C_CR2_ITEVTEN; - } -} - -#endif /* HAL_USE_I2C_SLAVE */ - -#endif /* HAL_USE_I2C */ - -/** @} */ diff --git a/drivers/chibios/i2cslave/I2Cv1/hal_i2c_lld.h b/drivers/chibios/i2cslave/I2Cv1/hal_i2c_lld.h deleted file mode 100644 index d45acaa671b..00000000000 --- a/drivers/chibios/i2cslave/I2Cv1/hal_i2c_lld.h +++ /dev/null @@ -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_ */ - -/** @} */ diff --git a/drivers/chibios/i2cslave/I2Cv2/driver.mk b/drivers/chibios/i2cslave/I2Cv2/driver.mk deleted file mode 100644 index 06fb82ff8f6..00000000000 --- a/drivers/chibios/i2cslave/I2Cv2/driver.mk +++ /dev/null @@ -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 diff --git a/drivers/chibios/i2cslave/I2Cv2/hal_i2c_lld.c b/drivers/chibios/i2cslave/I2Cv2/hal_i2c_lld.c deleted file mode 100644 index b6df7c7169e..00000000000 --- a/drivers/chibios/i2cslave/I2Cv2/hal_i2c_lld.c +++ /dev/null @@ -1,2065 +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. -*/ - -/* -TODO: -1. Make sure slave mode registers updated OK -2. Test what of the newly inserted defines etc is actually necessary -3. Check whether all relevant features available on all ports on all processors (they are on F7, F051) -4. Do we need timer to get involved on master mode transactions? (May be multimaster requirement) -5. What about multimaster? Possibly nothing special to do, other than support all transitions round master and slave modes. -(Manual: "By default, it operates in slave mode. The interface automatically switches from slave to -master when it generates a START condition, and from master to slave if an arbitration loss -or a STOP generation occurs, allowing multimaster capability") -6. Understand use of lock timer - may only be relevant for multimaster, or even unnecessary -7. Check slave transfers > 255 bytes - -NOTES: -1. 10-bit addressing, masking options not currently supported in software in slave mode - (OAR1 hardware supports single 10-bit address matching; OAR2 supports 7-bit addressing with mask) -2. Address zero supported by setting 'General Call' flag in CR1 in slave mode (set with call to match address zero) -3. Clock stretching always enabled -4. Relevant configurable bits in CR1: - ANFOFF (analog noise filter) - DNF (digital noise filter bits) -5. Setting STM32_I2C_DEBUG_ENABLE to TRUE logs various events into a short circular buffer, which can then be examined using -the debugger. Alternatively, a call to i2cPrintQ(BaseSequentialStream *chp) prints the buffer. Note that the buffer only -has a write pointer, so once full its necessary to infer the start and end of the data - - */ - -/** - * @file STM32/I2Cv2/i2c_lld.c - * @brief STM32 I2C subsystem low level driver source. - * - * @addtogroup I2C - * @{ - */ - -#include "hal.h" - -#if HAL_USE_I2C || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -#if STM32_I2C_USE_DMA == TRUE -#define DMAMODE_COMMON \ - (STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE | \ - STM32_DMA_CR_MINC | STM32_DMA_CR_DMEIE | \ - STM32_DMA_CR_TEIE | STM32_DMA_CR_TCIE) - -#define I2C1_RX_DMA_CHANNEL \ - STM32_DMA_GETCHANNEL(STM32_I2C_I2C1_RX_DMA_STREAM, \ - STM32_I2C1_RX_DMA_CHN) - -#define I2C1_TX_DMA_CHANNEL \ - STM32_DMA_GETCHANNEL(STM32_I2C_I2C1_TX_DMA_STREAM, \ - STM32_I2C1_TX_DMA_CHN) - -#define I2C2_RX_DMA_CHANNEL \ - STM32_DMA_GETCHANNEL(STM32_I2C_I2C2_RX_DMA_STREAM, \ - STM32_I2C2_RX_DMA_CHN) - -#define I2C2_TX_DMA_CHANNEL \ - STM32_DMA_GETCHANNEL(STM32_I2C_I2C2_TX_DMA_STREAM, \ - STM32_I2C2_TX_DMA_CHN) - -#define I2C3_RX_DMA_CHANNEL \ - STM32_DMA_GETCHANNEL(STM32_I2C_I2C3_RX_DMA_STREAM, \ - STM32_I2C3_RX_DMA_CHN) - -#define I2C3_TX_DMA_CHANNEL \ - STM32_DMA_GETCHANNEL(STM32_I2C_I2C3_TX_DMA_STREAM, \ - STM32_I2C3_TX_DMA_CHN) - -#define I2C4_RX_DMA_CHANNEL \ - STM32_DMA_GETCHANNEL(STM32_I2C_I2C4_RX_DMA_STREAM, \ - STM32_I2C4_RX_DMA_CHN) - -#define I2C4_TX_DMA_CHANNEL \ - STM32_DMA_GETCHANNEL(STM32_I2C_I2C4_TX_DMA_STREAM, \ - STM32_I2C4_TX_DMA_CHN) -#endif /* STM32_I2C_USE_DMA == TRUE */ - -#if STM32_I2C_USE_DMA == TRUE -#define i2c_lld_get_rxbytes(i2cp) dmaStreamGetTransactionSize((i2cp)->dmarx) -#define i2c_lld_get_txbytes(i2cp) dmaStreamGetTransactionSize((i2cp)->dmatx) -#else -#define i2c_lld_get_rxbytes(i2cp) (i2cp)->rxbytes -#define i2c_lld_get_txbytes(i2cp) (i2cp)->txbytes -#endif - -/*===========================================================================*/ -/* Driver constants. */ -/*===========================================================================*/ -#define I2C_ERROR_MASK \ - ((uint32_t)(I2C_ISR_BERR | I2C_ISR_ARLO | I2C_ISR_OVR | I2C_ISR_PECERR | \ - I2C_ISR_TIMEOUT | I2C_ISR_ALERT)) - -#define I2C_INT_MASK \ - ((uint32_t)(I2C_ISR_TCR | I2C_ISR_TC | I2C_ISR_STOPF | I2C_ISR_NACKF | \ - I2C_ISR_ADDR | I2C_ISR_RXNE | I2C_ISR_TXIS)) - -/* Mask of interrupt bits cleared automatically - we mustn't clear ADDR else clock stretching doesn't happen */ -#define I2C_INT_CLEAR_MASK \ - ((uint32_t)(I2C_ISR_TCR | I2C_ISR_TC | I2C_ISR_STOPF | I2C_ISR_NACKF | \ - I2C_ISR_RXNE | I2C_ISR_TXIS)) - - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/** @brief I2C1 driver identifier.*/ -#if STM32_I2C_USE_I2C1 || defined(__DOXYGEN__) -I2CDriver I2CD1; -#endif - -/** @brief I2C2 driver identifier.*/ -#if STM32_I2C_USE_I2C2 || defined(__DOXYGEN__) -I2CDriver I2CD2; -#endif - -/** @brief I2C3 driver identifier.*/ -#if STM32_I2C_USE_I2C3 || defined(__DOXYGEN__) -I2CDriver I2CD3; -#endif - -/** @brief I2C4 driver identifier.*/ -#if STM32_I2C_USE_I2C4 || defined(__DOXYGEN__) -I2CDriver I2CD4; -#endif - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -#if STM32_I2C_DEBUG_ENABLE -/* - * Quick and dirty queue to record event interrupts (useful for debug) - * - * Assigned codes (may be others not noted here): - * 0x02 - NAK received - * 0x03 - transfer complete received - * 0x04 - Address match (records current mode before any error recovery etc) - * 0x05 - STOP received - * 0x06 - Part transfer complete interrupt - * 0x07 - Recovery from untidily finished previous transaction - * 0x08 - Recovery from untidily finished previous transaction - * 0x09 - Recovery from untidily finished previous transaction - * 0x10 - error in slave address match - send - * 0x11 - error in slave address match - receive - * 0x12 - address match - send - * 0x13 - address match - receive - * 0x14 - start slave receive operation - * 0x15 - lock on pending slave receive operation (no buffer) - * 0x16 - start slave transmit operation - * 0x17 - lock on pending slave transmit operation (no buffer available) - * 0x80 - new reply set - * 0x81 - reply used immediately - * 0x82 - new receive buffer set - * 0x83 - receive buffer used immediately - * 0xcc - clearing down after transmission - triggered by NAK received (usually valid) - * 0xd0 - Slave error being signalled - * 0xd1 - Slave error due to timeout -*/ -#define QEVENTS 32 - -typedef struct i2cQ_t { - uint8_t code; - uint8_t state; // Channel state - uint8_t mode; // Mode (mostly for slave) - uint16_t param; // Parameter sometimes used -} i2cQ_t; -i2cQ_t i2cQ[QEVENTS]; -unsigned i2cI = QEVENTS; -#define qEvt(posn,info) {if (++i2cI >= QEVENTS) i2cI = 0; \ - i2cQ[i2cI].code=(posn); i2cQ[i2cI].state=(i2cp->state); i2cQ[i2cI].mode=(i2cp->mode); i2cQ[i2cI].param=(info); } - -#include "chprintf.h" - -void i2cPrintQ(BaseSequentialStream *chp) -{ - uint8_t i; - if (QEVENTS == 0) - { - chprintf(chp, "I2C Debug queue disabled\r\n"); - } - else - { - chprintf(chp, "I2C debug ring - write pointer currently %02d\r\n", i2cI); - } - for (i = 0; i < QEVENTS; i++) - { - chprintf(chp, "%02d: %02x->%02x %02x %04x\r\n", i, i2cQ[i].code, i2cQ[i].state, i2cQ[i].mode, i2cQ[i].param); - if (i2cQ[i].code == 0) break; // Handle partially filled queue - } -} - -#else -#define qEvt(posn,info) -#endif - - - - -#if HAL_USE_I2C_SLAVE /* I2C slave mode support */ - - -void I2CSlaveDummyCB(I2CDriver *i2cp) -/* - dummy callback -- placeholder to ignore event -*/ -{(void)i2cp;} - - /* lock bus on receive or reply message */ -const I2CSlaveMsg I2CSlaveLockOnMsg = { - 0, NULL, I2CSlaveDummyCB, I2CSlaveDummyCB, I2CSlaveDummyCB -}; - -#endif - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -#if HAL_USE_I2C_MASTER -/** - * @brief Slave (remote) address setup in master mode. - * @note The RW bit is set to zero internally. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * @param[in] addr slave device address - * - * @notapi - */ -static void i2c_lld_set_address(I2CDriver *i2cp, i2caddr_t addr) { - I2C_TypeDef *dp = i2cp->i2c; - - /* Address alignment depends on the addressing mode selected.*/ - if ((i2cp->config->cr2 & I2C_CR2_ADD10) == 0U) - dp->CR2 = (uint32_t)addr << 1U; - else - dp->CR2 = (uint32_t)addr; -} -#endif - - - -/** - * @brief I2C RX transfer setup. - * @note Configures transfer count and related flags - * - * @param[in] i2cp pointer to the @p I2CDriver object - * - * @notapi - */ -static void i2c_lld_setup_rx_transfer(I2CDriver *i2cp) { - I2C_TypeDef *dp = i2cp->i2c; - uint32_t reload; - size_t n; - - /* The unit can transfer 255 bytes maximum in a single operation (device constraint). */ -#if STM32_I2C_USE_DMA - if (i2cp->config->rxchar_cb) - { - n = i2cp->rxbytes; // Always interrupt-driven if we have a receive callback - } - else - { - n = i2c_lld_get_rxbytes(i2cp); // Otherwise get length from DMA or counter as appropriate - } -#else - n = i2cp->rxbytes; -#endif - if (n > 255U) { - n = 255U; - reload = I2C_CR2_RELOAD; - } - else { - reload = 0U; - } - - /* Configures the CR2 registers with both the calculated and static - settings. (Nothing much relevant in static settings - just PEC for SMBUS? */ - dp->CR2 = (dp->CR2 & ~(I2C_CR2_NBYTES | I2C_CR2_RELOAD)) | i2cp->config->cr2 | I2C_CR2_RD_WRN | - (n << 16U) | reload; -} - - - -/** - * @brief I2C TX transfer setup. - * @note Configures transfer count and related flags - * - * @param[in] i2cp pointer to the @p I2CDriver object - * - * @notapi - */ -static void i2c_lld_setup_tx_transfer(I2CDriver *i2cp) { - I2C_TypeDef *dp = i2cp->i2c; - uint32_t reload; - size_t n; - - /* The unit can transfer 255 bytes maximum in a single operation. */ - n = i2c_lld_get_txbytes(i2cp); // Get transaction size from DMA or buffer as configured - if (n > 255U) { - n = 255U; - reload = I2C_CR2_RELOAD; - } - else { - reload = 0U; - } - - /* Configures the CR2 registers with both the calculated and static - settings.*/ - dp->CR2 = (dp->CR2 & ~(I2C_CR2_NBYTES | I2C_CR2_RELOAD)) | i2cp->config->cr2 | - (n << 16U) | reload; -} - - - -/** - * @brief Aborts an I2C transaction. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * - * @notapi - */ -static void i2c_lld_abort_operation(I2CDriver *i2cp) { - I2C_TypeDef *dp = i2cp->i2c; - -// Note: clearing PE doesn't affect configuration bits (including slave addresses) - if (dp->CR1 & I2C_CR1_PE) { - /* Stops the I2C peripheral.*/ - dp->CR1 &= ~I2C_CR1_PE; - while (dp->CR1 & I2C_CR1_PE) - dp->CR1 &= ~I2C_CR1_PE; - dp->CR1 |= I2C_CR1_PE; - } - -#if STM32_I2C_USE_DMA == TRUE - /* Stops the associated DMA streams.*/ - dmaStreamDisable(i2cp->dmatx); - dmaStreamDisable(i2cp->dmarx); -#else - dp->CR1 &= ~(I2C_CR1_TXIE | I2C_CR1_RXIE); // Stop byte-orientated interrupts -#endif -} - - - -#if HAL_USE_I2C_SLAVE || HAL_USE_I2C_LOCK -/** - * @brief stop transaction timeout countdown - * - * @param[in] i2cp pointer to the @p I2CDriver object - * - * @notapi - */ -static inline void stopTimer(I2CDriver *i2cp) -{ - osalSysLockFromISR(); - chVTResetI(&i2cp->timer); - osalSysUnlockFromISR(); -} -#else -#define stopTimer(ignored) {} -#endif - - - -#if HAL_USE_I2C_SLAVE /* I2C slave mode support */ - -/** - * @brief report error via slave exception callback - * - * @param[in] i2cp pointer to the @p I2CDriver object - * - * @note moves back to the idle mode - * @notapi - */ -static inline void reportSlaveError(I2CDriver *i2cp) { - if (i2cp->mode >= i2cIsMaster) return; - qEvt(0xd0, i2cp->slaveErrors); - const I2CSlaveMsg *xfer = i2cp->mode >= i2cSlaveReplying ? - i2cp->slaveReply : i2cp->slaveRx; - if (xfer->exception) - xfer->exception(i2cp); - i2cp->mode = i2cIdle; - i2cp->targetAdr = i2cInvalidAdr; -} - - -/** - * @brief Handling of stalled slave mode I2C transactions - timer handler. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * - * @notapi - */ -static void slaveTimeExpired(void *i2cv) { - I2CDriver *i2cp = i2cv; - - if (i2cp->mode < i2cIsMaster) - { - i2c_lld_abort_operation(i2cp); - reportSlaveError(i2cp); - qEvt(0xd1, 0); - } -} - - -/** - * @brief start or restart slave mode transaction - * - * @param[in] i2cp pointer to the @p I2CDriver object - * @param[in] targetAdr slave address which was matched - * - * @notapi - */ -static inline void i2cStartSlaveAction(I2CDriver *i2cp, i2caddr_t targetAdr) -{ - stopTimer(i2cp); - i2cp->targetAdr = targetAdr; - i2cp->slaveBytes = 0; - i2cp->slaveErrors = 0; - if (i2cp->slaveTimeout != TIME_INFINITE) - { - osalSysLockFromISR(); - chVTSetI(&i2cp->timer, i2cp->slaveTimeout, slaveTimeExpired, i2cp); - osalSysUnlockFromISR(); - } -} - - -/** - * @brief end slave receive message DMA - * - * @param[in] i2cp pointer to the @p I2CDriver object - * - * @notapi - */ -static inline void i2cEndSlaveRxDMA(I2CDriver *i2cp) -{ - size_t bytesRemaining = i2c_lld_get_rxbytes(i2cp); - if (i2cp->slaveBytes) - i2cp->slaveBytes += 0xffff - bytesRemaining; - else - i2cp->slaveBytes = i2cp->slaveRx->size - bytesRemaining; -#if STM32_I2C_USE_DMA == TRUE - /* Disabling RX DMA channel.*/ - dmaStreamDisable(i2cp->dmarx); -#else - i2cp->i2c->CR1 &= ~(I2C_CR1_RXIE); -#endif -} - - - -/** - * @brief end slave transmit DMA - * - * @param[in] i2cp pointer to the @p I2CDriver object - * @param[in] bytesRemaining bytes lost in output queue - * - * @notapi - */ -static inline void i2cEndSlaveTxDMA(I2CDriver *i2cp, size_t bytesRemaining) -{ - bytesRemaining += i2c_lld_get_rxbytes(i2cp); - if (i2cp->slaveBytes) - i2cp->slaveBytes += 0xffff - bytesRemaining; - else - i2cp->slaveBytes = i2cp->slaveReply->size - bytesRemaining; -#if STM32_I2C_USE_DMA == TRUE - /* Disabling TX DMA channel.*/ - dmaStreamDisable(i2cp->dmatx); -#else - i2cp->i2c->CR1 &= ~(I2C_CR1_TXIE); -#endif -} - -#endif - - - - -/** - * @brief Start a receive transaction (by enabling DMA, or enabling Rx character interrupts) - * - * @note All registers etc must be set up first - */ -static inline void i2cStartReceive(I2CDriver *i2cp) -{ -#if STM32_I2C_USE_DMA == TRUE - if (i2cp->config->rxchar_cb) - { - // Callback in use - use interrupt-driven transfer - i2cp->i2c->CR1 |= I2C_CR1_TCIE | I2C_CR1_RXIE; - } - else - { - /* Enabling RX DMA.*/ - dmaStreamEnable(i2cp->dmarx); - - /* Transfer complete interrupt enabled.*/ - i2cp->i2c->CR1 |= I2C_CR1_TCIE; - } -#else - - /* Transfer complete and RX interrupts enabled.*/ - i2cp->i2c->CR1 |= I2C_CR1_TCIE | I2C_CR1_RXIE; -#endif -} - - -/** - * @brief Disable transmit data transfer, whether DMA or interrupt-driven - */ -static inline void i2cDisableTransmitOperation(I2CDriver *i2cp) -{ -#if STM32_I2C_USE_DMA == TRUE - /* Disabling TX DMA channel.*/ - dmaStreamDisable(i2cp->dmatx); -#else - i2cp->i2c->CR1 &= ~(I2C_CR1_TXIE); -#endif -} - - -/** - * @brief Disable receive data transfer, whether DMA or interrupt-driven - */ -static inline void i2cDisableReceiveOperation(I2CDriver *i2cp) -{ -#if STM32_I2C_USE_DMA == TRUE - /* Disabling RX DMA channel.*/ - dmaStreamDisable(i2cp->dmarx); -#else - i2cp->i2c->CR1 &= ~(I2C_CR1_RXIE); -#endif -} - - - -/*===========================================================================*/ -/* Shared ISR Code */ -/*===========================================================================*/ - -/** - * @brief I2C shared ISR code - 'Normal' (non-error) interrupts. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * @param[in] isr content of the ISR register to be decoded (no masking applied) - * - * @notapi - */ -static void i2c_lld_serve_interrupt(I2CDriver *i2cp, uint32_t isr) { - I2C_TypeDef *dp = i2cp->i2c; - - /* Check for received NACK, the transfer is aborted. Do this in all modes */ - if ((isr & I2C_ISR_NACKF) != 0U) - { - qEvt(2, 0); - - i2cDisableReceiveOperation(i2cp); - i2cDisableTransmitOperation(i2cp); - #if HAL_USE_I2C_SLAVE - /* NACK of last byte transmitted in slave response is NORMAL -- not an error! */ - if (i2cp->mode == i2cSlaveReplying) - { - qEvt(0xcc,0); - i2cEndSlaveTxDMA(i2cp, 1); - if (i2cp->slaveReply->processMsg) - i2cp->slaveReply->processMsg(i2cp); - i2cp->targetAdr = i2cInvalidAdr; - stopTimer(i2cp); - return; - } - #endif - - /* Error flag.*/ - i2cp->errors |= I2C_ACK_FAILURE; - - /* Transaction finished, send the STOP. */ - dp->CR2 |= I2C_CR2_STOP; - - /* Make sure no more interrupts.*/ - dp->CR1 &= ~(I2C_CR1_TCIE | I2C_CR1_TXIE | I2C_CR1_RXIE | I2C_CR1_STOPIE); - - if (i2cp->mode < i2cIsMaster) - { - i2cp->mode = i2cIdle; - } - else - { - /* Master mode - Errors are signalled to the upper layer.*/ - i2cp->mode = i2cIdle; - // Must only wake up thread in master mode. - _i2c_wakeup_isr(i2cp); // This is a normal completion - } - - return; - } - - -#if STM32_I2C_USE_DMA == FALSE - /* Handling of data transfer if the DMA mode is disabled - done character by character. Mode should be irrelevant */ - { - uint32_t cr1 = dp->CR1; - - if ((i2cp->state == I2C_ACTIVE_TX) || (i2cp->mode == i2cSlaveReplying)) - { - /* Transmission phase.*/ - if (((cr1 &I2C_CR1_TXIE) != 0U) && ((isr & I2C_ISR_TXIS) != 0U)) { - dp->TXDR = (uint32_t)*i2cp->txptr; - i2cp->txptr++; - i2cp->txbytes--; - if (i2cp->txbytes == 0U) { - dp->CR1 &= ~I2C_CR1_TXIE; // Last byte sent - stop Tx interrupt - } - } - } - else - { - /* Receive phase.*/ - if (((cr1 & I2C_CR1_RXIE) != 0U) && ((isr & I2C_ISR_RXNE) != 0U)) { - uint8_t c; - *i2cp->rxptr = c = (uint8_t)dp->RXDR; - i2cp->rxptr++; - i2cp->rxbytes--; - if (i2cp->config->rxchar_cb) - { - if (i2cp->config->rxchar_cb(i2cp, c) > 0) - { - /* Transaction finished, send the STOP. */ - dp->CR2 |= I2C_CR2_STOP; - - /* Make sure no more interrupts.*/ - dp->CR1 &= ~(I2C_CR1_TCIE | I2C_CR1_TXIE | I2C_CR1_RXIE | I2C_CR1_STOPIE); - - if (i2cp->mode < i2cIsMaster) - { - i2cp->mode = i2cIdle; - } - else - { - /* Master mode - Errors are signalled to the upper layer.*/ - i2cp->mode = i2cIdle; - // Must only wake up thread in master mode. - _i2c_wakeup_isr(i2cp); // This is a normal completion - } - - return; - } - } - if (i2cp->rxbytes == 0U) { - dp->CR1 &= ~I2C_CR1_RXIE; // Buffer full - stop reception (TODO: Should we send NAK?? Only possible in slave mode) - } - } - } - } -#else - /* Receive character phase with callback enabled. */ - if ((i2cp->state == I2C_ACTIVE_RX) || (i2cp->mode == i2cMasterRxing)) - { - uint32_t cr1 = dp->CR1; - if (((cr1 & I2C_CR1_RXIE) != 0U) && ((isr & I2C_ISR_RXNE) != 0U)) { - uint8_t c; - c = (uint8_t)dp->RXDR; - *i2cp->rxptr = c; - i2cp->rxptr++; - i2cp->rxbytes--; - if (i2cp->config->rxchar_cb) - { - if (i2cp->config->rxchar_cb(i2cp, c) > 0) - { - /* Transaction finished, send the STOP. */ - dp->CR2 |= I2C_CR2_STOP; - - /* Make sure no more interrupts.*/ - dp->CR1 &= ~(I2C_CR1_TCIE | I2C_CR1_TXIE | I2C_CR1_RXIE | I2C_CR1_STOPIE); - - if (i2cp->mode < i2cIsMaster) - { - i2cp->mode = i2cIdle; - } - else - { - /* Master mode - Errors are signalled to the upper layer.*/ - i2cp->mode = i2cIdle; - // Must only wake up thread in master mode. - _i2c_wakeup_isr(i2cp); // This is a normal completion - } - - return; - } - } - if (i2cp->rxbytes == 0U) { - dp->CR1 &= ~I2C_CR1_RXIE; // Buffer full - stop reception (TODO: Should we send NAK?? Only possible in slave mode) - } - } - } -#endif - - - - /* Partial transfer handling, restarting the transfer and returning. */ - if ((isr & I2C_ISR_TCR) != 0U) - { - qEvt(0x06, 0); - if ((i2cp->state == I2C_ACTIVE_TX) || (i2cp->mode == i2cSlaveReplying)) { - i2c_lld_setup_tx_transfer(i2cp); - } - if ((i2cp->state == I2C_ACTIVE_RX) || (i2cp->mode == i2cSlaveRxing)) { - i2c_lld_setup_rx_transfer(i2cp); - } - return; - } - - - - /* The following condition is true if a transfer phase has been completed. */ - if ((isr & I2C_ISR_TC) != 0U) - { - qEvt(3,i2cp->state); -#if HAL_USE_I2C_SLAVE - switch (i2cp->mode) - { - case i2cLockedRxing : /* stretching clock before receiving message - Rx buffer might be full */ - case i2cLockedReplying : - break; // TODO: Two unsupported cases to consider - maybe they can't happen - case i2cSlaveReplying : // Must have just finished sending a reply in slave mode - break; // Just go on to send STOP bit and tidy up - - case i2cSlaveRxing : // Must have just received a message - process if we can - i2cEndSlaveRxDMA(i2cp); - qEvt(0x20, 0); - if (i2cp->slaveRx->processMsg) - i2cp->slaveRx->processMsg(i2cp); - // TODO: Should get a reply message set - if so, start to send it and return - return; // For now, see what happens if we just return - break; - default : // Assume a master mode -#endif - if (i2cp->state == I2C_ACTIVE_TX) { - /* End of the transmit phase.*/ - - i2cDisableTransmitOperation(i2cp); // Disable - - /* Starting receive phase if necessary.*/ - if (i2c_lld_get_rxbytes(i2cp) > 0U) { - /* Setting up the peripheral.*/ - i2c_lld_setup_rx_transfer(i2cp); - - #if STM32_I2C_USE_DMA == TRUE - // If receive callback enabled, always transfer using interrupts - if (i2cp->config->rxchar_cb) - { - /* RX interrupt enabled.*/ - dp->CR1 |= I2C_CR1_RXIE; - } - else - { - /* Enabling RX DMA.*/ - dmaStreamEnable(i2cp->dmarx); - } - #else - /* RX interrupt enabled.*/ - dp->CR1 |= I2C_CR1_RXIE; - #endif - - /* Starts the read operation.*/ - dp->CR2 |= I2C_CR2_START; - - /* State change.*/ - i2cp->state = I2C_ACTIVE_RX; - i2cp->mode = i2cMasterRxing; - - /* Note, returning because the transaction is not over yet.*/ - return; - } - } - else - { - /* End of the receive phase.*/ - i2cDisableReceiveOperation(i2cp); - } - -#if HAL_USE_I2C_SLAVE - } -#endif - - /* Transaction finished sending the STOP. */ - dp->CR2 |= I2C_CR2_STOP; - - /* Make sure no more 'Transfer Complete' interrupts. */ - dp->CR1 &= ~I2C_CR1_TCIE; - - /* Normal transaction end.*/ - if (i2cp->mode < i2cIsMaster) - { - // Slave mode - just move to idle state - i2cp->mode = i2cIdle; - } - else - { - i2cp->mode = i2cIdle; - // Must only wake up thread in master mode - _i2c_wakeup_isr(i2cp); - } - } - - -#if HAL_USE_I2C_SLAVE - uint8_t abort = 0; - /* Check for address match - if so, we're slave */ - if ((isr & I2C_ISR_ADDR) != 0U) - { - i2caddr_t targetAdr = (isr & I2C_ISR_ADDCODE) >> 17; // Identify which slave address used - uint8_t xferDir = (isr & I2C_ISR_DIR) ? 0 : 1; // Status bit is 0 for receive, 1 for transmit. xferDir inverts sense - dp->CR1 |= I2C_CR1_STOPIE; // Enable STOP interrupt so we know when slave transaction done - - /* First, tidy up from previous transactions as necessary */ - qEvt(0x04, 0); - switch (i2cp->mode) { - case i2cIdle: - break; - case i2cSlaveRxing: /* Previous transaction not completed properly, or - maybe we were sent a message without being asked for a reply */ - qEvt(0x07, 0); - i2cEndSlaveRxDMA(i2cp); - if (i2cp->slaveRx->processMsg) - i2cp->slaveRx->processMsg(i2cp); // Execute callback if defined - break; - case i2cSlaveReplying: /* Master did not NACK last transmitted byte (most likely picked up by NAK handler) */ - qEvt(0x08, 0); - if (!xferDir) - { - qEvt(0x09, 0); - i2cEndSlaveTxDMA(i2cp, 2); - if (i2cp->slaveReply->processMsg) - i2cp->slaveReply->processMsg(i2cp); - break; - } - // Intentionally don't break if we're addressed to receive - default: - // todo: Does this lot happen in the right order? Is an abort appropriate? Or should we just continue? - qEvt(0x10 + xferDir, 0); - i2cp->slaveErrors = I2C_UNKNOWN_ERROR + i2cp->mode; - i2c_lld_abort_operation(i2cp); /* reset and reinit */ - stopTimer(i2cp); - reportSlaveError(i2cp); // This clears down to idle - abort = 1; - } - if (!abort) - { - qEvt(0x12 + xferDir, (i2cp->slaveNextRx->size)); - if (xferDir) - { - /* Start Receive */ - /* If receive buffer still full, need to extend clock for timeout. Otherwise set up to receive */ - dp->CR1 &= ~I2C_CR1_SBC; // Not needed with receive - i2cStartSlaveAction(i2cp, targetAdr); - - const I2CSlaveMsg *rx = i2cp->slaveNextRx; - if (rx->adrMatched) // Q: Can rx ever be NULL? - rx->adrMatched(i2cp); // Execute callback on address match if specified - rx = i2cp->slaveRx = i2cp->slaveNextRx; // Reload message pointer in case callback changed it - if (rx->body && rx->size) - { - /* Receive buffer available - can receive immediately. Set up slave RX DMA */ - i2c_lld_setup_rx_transfer(i2cp); - #if STM32_I2C_USE_DMA == TRUE - /* RX DMA setup.*/ - dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode); - dmaStreamSetMemory0(i2cp->dmarx, rx->body); - dmaStreamSetTransactionSize(i2cp->dmarx, rx->size); - #else - i2cp->rxptr = rx->body; - i2cp->rxbytes = rx->size; - #endif - - i2cStartReceive(i2cp); - dp->ICR = I2C_ISR_ADDR; // We can release the clock stretch now - i2cp->mode = i2cSlaveRxing; - qEvt(0x14,0); - } - else - { - /* No reply set up - hold clock low and wait (happens automatically) */ - qEvt(0x15,0); - i2cp->mode = i2cLockedRxing; - } - } - else - { - /* Start Transmit */ - i2cStartSlaveAction(i2cp, targetAdr); - const I2CSlaveMsg *reply = i2cp->slaveNextReply; - const I2CSlaveMsg *rx = i2cp->slaveNextRx; // Receive control block - if (rx->adrMatched) // Q: Can rx ever be NULL? - rx->adrMatched(i2cp); // Execute callback on address match if specified - reply = i2cp->slaveReply = i2cp->slaveNextReply; // Reload message pointer in case callback changed it - if (reply->body && reply->size) - { - /* Reply message available - can send immediately. Set up slave TX DMA */ - #if STM32_I2C_USE_DMA == TRUE - dmaStreamSetMode(i2cp->dmatx, i2cp->txdmamode); - dmaStreamSetMemory0(i2cp->dmatx, reply->body); - dmaStreamSetTransactionSize(i2cp->dmatx, reply->size); - /* Start transmission */ - i2c_lld_setup_tx_transfer(i2cp); - - /* Enabling TX DMA.*/ - dmaStreamEnable(i2cp->dmatx); - - /* Transfer complete interrupt enabled.*/ - dp->CR1 |= I2C_CR1_TCIE; - #else - /* Start transmission */ - i2cp->txptr = reply->body; - i2cp->txbytes = reply->size; - i2c_lld_setup_tx_transfer(i2cp); - /* Transfer complete and TX character interrupts enabled.*/ - dp->CR1 |= I2C_CR1_TCIE | I2C_CR1_TXIE; - #endif - qEvt(0x16,0); - i2cp->mode = i2cSlaveReplying; - dp->CR1 |= I2C_CR1_SBC; // Need this to enable byte counter in transmit mode - dp->ICR = I2C_ISR_ADDR; // We can release the clock stretch now - } - else - { - // clock is automatically stretched if we don't clear the status bit - //dp->CR2 &= (uint16_t)(~I2C_CR2_ITEVTEN); - qEvt(0x17, 0); - i2cp->mode = i2cLockedReplying; - } - } - } /* if !abort */ - } - if ((isr & I2C_ISR_STOPF) != 0U) { - /* - * STOP received: - * in master mode, if generated by peripheral - can probably just ignore - * in slave mode, if detected on bus (from any source?) - * - * Clear everything down - particularly relevant in slave mode - */ - qEvt(0x05, 0); - dp->CR1 &= ~I2C_CR1_STOPIE; // Disable STOP interrupt - i2cDisableReceiveOperation(i2cp); // These two may not be necessary - i2cDisableTransmitOperation(i2cp); - stopTimer(i2cp); - i2cp->mode = i2cIdle; - } -#endif -} - - - -/** - * @brief I2C error handler. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * @param[in] isr content of the ISR register to be decoded (no masking applied) - * - * @notapi - */ -static void i2c_lld_serve_error_interrupt(I2CDriver *i2cp, uint32_t isr) { - - i2cDisableReceiveOperation(i2cp); - i2cDisableTransmitOperation(i2cp); - stopTimer(i2cp); - -#if HAL_USE_I2C_SLAVE - // In slave mode, just clock errors and return - if (i2cp->mode < i2cIsMaster) - { - reportSlaveError(i2cp); // This clears down to idle - return; - } -#endif - - if (isr & I2C_ISR_BERR) - i2cp->errors |= I2C_BUS_ERROR; - - if (isr & I2C_ISR_ARLO) - i2cp->errors |= I2C_ARBITRATION_LOST; - - if (isr & I2C_ISR_OVR) - i2cp->errors |= I2C_OVERRUN; - - if (isr & I2C_ISR_TIMEOUT) - i2cp->errors |= I2C_TIMEOUT; - - /* If some error has been identified then wake up the waiting thread.*/ - if (i2cp->errors != I2C_NO_ERROR) - { - i2cp->mode = i2cIdle; - _i2c_wakeup_error_isr(i2cp); - } -} - - - - - -#if HAL_USE_I2C_LOCK /* I2C bus locking support */ - -/** - * @brief Handling of expired master bus lock timer - * - * @param[in] i2cv pointer to the @p I2CDriver object - * - * @notapi - */ -static void lockExpired(void *i2cv) { - I2CDriver *i2cp = i2cv; - - if (i2cp->mode == i2cIsMaster && !i2cp->thread) { /* between transactions */ - i2cp->i2c->CR2 |= I2C_CR2_STOP; - i2cp->mode = i2cIdle; - } - i2cp->lockDuration = TIME_IMMEDIATE; -} - - - - -/** - * @brief Lock I2C bus at the beginning of the next message - * - * @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 - * . - * - * Lock I2C bus at the beginning of the next message sent - * for a maximum of lockDuration ticks. No other I2C masters will - * be allowed to interrupt until i2cUnlock() is called. - * - * @notapi - **/ -void i2c_lld_lock(I2CDriver *i2cp, systime_t lockDuration) -{ - i2cp->lockDuration = lockDuration; - if (i2cp->mode >= i2cIsMaster) { - stopTimer(i2cp); - if (lockDuration == TIME_IMMEDIATE) - lockExpired(i2cp); - else if (lockDuration != TIME_INFINITE) - chVTSetI(&i2cp->timer, lockDuration, lockExpired, i2cp); - } -} - -#endif - -/*===========================================================================*/ -/* Driver interrupt handlers. */ -/*===========================================================================*/ - -#if STM32_I2C_USE_I2C1 || defined(__DOXYGEN__) -#if defined(STM32_I2C1_GLOBAL_HANDLER) || defined(__DOXYGEN__) -/** - * @brief I2C1 event interrupt handler. - * - * @notapi - */ -OSAL_IRQ_HANDLER(STM32_I2C1_GLOBAL_HANDLER) { - uint32_t isr = I2CD1.i2c->ISR; - - OSAL_IRQ_PROLOGUE(); - - /* Clearing IRQ bits.*/ - I2CD1.i2c->ICR = isr & ~I2C_ISR_ADDR; - - if (isr & I2C_ERROR_MASK) - i2c_lld_serve_error_interrupt(&I2CD1, isr); - else if (isr & I2C_INT_MASK) - i2c_lld_serve_interrupt(&I2CD1, isr); - - OSAL_IRQ_EPILOGUE(); -} - -#elif defined(STM32_I2C1_EVENT_HANDLER) && defined(STM32_I2C1_ERROR_HANDLER) -OSAL_IRQ_HANDLER(STM32_I2C1_EVENT_HANDLER) { - uint32_t isr = I2CD1.i2c->ISR; - - OSAL_IRQ_PROLOGUE(); - - /* Clearing IRQ bits.*/ - I2CD1.i2c->ICR = isr & I2C_INT_CLEAR_MASK; - - i2c_lld_serve_interrupt(&I2CD1, isr); - - OSAL_IRQ_EPILOGUE(); -} - -OSAL_IRQ_HANDLER(STM32_I2C1_ERROR_HANDLER) { - uint32_t isr = I2CD1.i2c->ISR; - - OSAL_IRQ_PROLOGUE(); - - /* Clearing IRQ bits.*/ - I2CD1.i2c->ICR = isr & I2C_ERROR_MASK; - - i2c_lld_serve_error_interrupt(&I2CD1, isr); - - OSAL_IRQ_EPILOGUE(); -} - -#else -#error "I2C1 interrupt handlers not defined" -#endif -#endif /* STM32_I2C_USE_I2C1 */ - -#if STM32_I2C_USE_I2C2 || defined(__DOXYGEN__) -#if defined(STM32_I2C2_GLOBAL_HANDLER) || defined(__DOXYGEN__) -/** - * @brief I2C2 event interrupt handler. - * - * @notapi - */ -OSAL_IRQ_HANDLER(STM32_I2C2_GLOBAL_HANDLER) { - uint32_t isr = I2CD2.i2c->ISR; - - OSAL_IRQ_PROLOGUE(); - - /* Clearing IRQ bits.*/ - I2CD2.i2c->ICR = isr & ~I2C_ISR_ADDR; - - if (isr & I2C_ERROR_MASK) - i2c_lld_serve_error_interrupt(&I2CD2, isr); - else if (isr & I2C_INT_MASK) - i2c_lld_serve_interrupt(&I2CD2, isr); - - OSAL_IRQ_EPILOGUE(); -} - -#elif defined(STM32_I2C2_EVENT_HANDLER) && defined(STM32_I2C2_ERROR_HANDLER) -OSAL_IRQ_HANDLER(STM32_I2C2_EVENT_HANDLER) { - uint32_t isr = I2CD2.i2c->ISR; - - OSAL_IRQ_PROLOGUE(); - - /* Clearing IRQ bits.*/ - I2CD2.i2c->ICR = isr & I2C_INT_CLEAR_MASK; - - i2c_lld_serve_interrupt(&I2CD2, isr); - - OSAL_IRQ_EPILOGUE(); -} - -OSAL_IRQ_HANDLER(STM32_I2C2_ERROR_HANDLER) { - uint32_t isr = I2CD2.i2c->ISR; - - OSAL_IRQ_PROLOGUE(); - - /* Clearing IRQ bits.*/ - I2CD2.i2c->ICR = isr & I2C_ERROR_MASK; - - i2c_lld_serve_error_interrupt(&I2CD2, isr); - - OSAL_IRQ_EPILOGUE(); -} - -#else -#error "I2C2 interrupt handlers not defined" -#endif -#endif /* STM32_I2C_USE_I2C2 */ - -#if STM32_I2C_USE_I2C3 || defined(__DOXYGEN__) -#if defined(STM32_I2C3_GLOBAL_HANDLER) || defined(__DOXYGEN__) -/** - * @brief I2C3 event interrupt handler. - * - * @notapi - */ -OSAL_IRQ_HANDLER(STM32_I2C3_GLOBAL_HANDLER) { - uint32_t isr = I2CD3.i2c->ISR; - - OSAL_IRQ_PROLOGUE(); - - /* Clearing IRQ bits.*/ - I2CD3.i2c->ICR = isr & ~I2C_ISR_ADDR; - - if (isr & I2C_ERROR_MASK) - i2c_lld_serve_error_interrupt(&I2CD3, isr); - else if (isr & I2C_INT_MASK) - i2c_lld_serve_interrupt(&I2CD3, isr); - - OSAL_IRQ_EPILOGUE(); -} - -#elif defined(STM32_I2C3_EVENT_HANDLER) && defined(STM32_I2C3_ERROR_HANDLER) -OSAL_IRQ_HANDLER(STM32_I2C3_EVENT_HANDLER) { - uint32_t isr = I2CD3.i2c->ISR; - - OSAL_IRQ_PROLOGUE(); - - /* Clearing IRQ bits.*/ - I2CD3.i2c->ICR = isr & I2C_INT_CLEAR_MASK; - - i2c_lld_serve_interrupt(&I2CD3, isr); - - OSAL_IRQ_EPILOGUE(); -} - -OSAL_IRQ_HANDLER(STM32_I2C3_ERROR_HANDLER) { - uint32_t isr = I2CD3.i2c->ISR; - - OSAL_IRQ_PROLOGUE(); - - /* Clearing IRQ bits.*/ - I2CD3.i2c->ICR = isr & I2C_ERROR_MASK; - - i2c_lld_serve_error_interrupt(&I2CD3, isr); - - OSAL_IRQ_EPILOGUE(); -} - -#else -#error "I2C3 interrupt handlers not defined" -#endif -#endif /* STM32_I2C_USE_I2C3 */ - -#if STM32_I2C_USE_I2C4 || defined(__DOXYGEN__) -#if defined(STM32_I2C4_GLOBAL_HANDLER) || defined(__DOXYGEN__) -/** - * @brief I2C4 event interrupt handler. - * - * @notapi - */ -OSAL_IRQ_HANDLER(STM32_I2C4_GLOBAL_HANDLER) { - uint32_t isr = I2CD4.i2c->ISR; - - OSAL_IRQ_PROLOGUE(); - - /* Clearing IRQ bits.*/ - I2CD4.i2c->ICR = isr & ~I2C_ISR_ADDR; - - if (isr & I2C_ERROR_MASK) - i2c_lld_serve_error_interrupt(&I2CD4, isr); - else if (isr & I2C_INT_MASK) - i2c_lld_serve_interrupt(&I2CD4, isr); - - OSAL_IRQ_EPILOGUE(); -} - -#elif defined(STM32_I2C4_EVENT_HANDLER) && defined(STM32_I2C4_ERROR_HANDLER) -OSAL_IRQ_HANDLER(STM32_I2C4_EVENT_HANDLER) { - uint32_t isr = I2CD4.i2c->ISR; - - OSAL_IRQ_PROLOGUE(); - - /* Clearing IRQ bits.*/ - I2CD4.i2c->ICR = isr & I2C_INT_CLEAR_MASK; - - i2c_lld_serve_interrupt(&I2CD4, isr); - - OSAL_IRQ_EPILOGUE(); -} - -OSAL_IRQ_HANDLER(STM32_I2C4_ERROR_HANDLER) { - uint32_t isr = I2CD4.i2c->ISR; - - OSAL_IRQ_PROLOGUE(); - - /* Clearing IRQ bits.*/ - I2CD4.i2c->ICR = isr & I2C_ERROR_MASK; - - i2c_lld_serve_error_interrupt(&I2CD4, isr); - - OSAL_IRQ_EPILOGUE(); -} - -#else -#error "I2C4 interrupt handlers not defined" -#endif -#endif /* STM32_I2C_USE_I2C4 */ - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief Low level I2C driver initialization. - * - * @notapi - */ -void i2c_lld_init(void) { - -#if STM32_I2C_USE_I2C1 - i2cObjectInit(&I2CD1); - I2CD1.thread = NULL; - I2CD1.i2c = I2C1; -#if STM32_I2C_USE_DMA == TRUE - I2CD1.dmarx = STM32_DMA_STREAM(STM32_I2C_I2C1_RX_DMA_STREAM); - I2CD1.dmatx = STM32_DMA_STREAM(STM32_I2C_I2C1_TX_DMA_STREAM); -#endif -#endif /* STM32_I2C_USE_I2C1 */ - -#if STM32_I2C_USE_I2C2 - i2cObjectInit(&I2CD2); - I2CD2.thread = NULL; - I2CD2.i2c = I2C2; -#if STM32_I2C_USE_DMA == TRUE - I2CD2.dmarx = STM32_DMA_STREAM(STM32_I2C_I2C2_RX_DMA_STREAM); - I2CD2.dmatx = STM32_DMA_STREAM(STM32_I2C_I2C2_TX_DMA_STREAM); -#endif -#endif /* STM32_I2C_USE_I2C2 */ - -#if STM32_I2C_USE_I2C3 - i2cObjectInit(&I2CD3); - I2CD3.thread = NULL; - I2CD3.i2c = I2C3; -#if STM32_I2C_USE_DMA == TRUE - I2CD3.dmarx = STM32_DMA_STREAM(STM32_I2C_I2C3_RX_DMA_STREAM); - I2CD3.dmatx = STM32_DMA_STREAM(STM32_I2C_I2C3_TX_DMA_STREAM); -#endif -#endif /* STM32_I2C_USE_I2C3 */ - -#if STM32_I2C_USE_I2C4 - i2cObjectInit(&I2CD4); - I2CD4.thread = NULL; - I2CD4.i2c = I2C4; -#if STM32_I2C_USE_DMA == TRUE - I2CD4.dmarx = STM32_DMA_STREAM(STM32_I2C_I2C4_RX_DMA_STREAM); - I2CD4.dmatx = STM32_DMA_STREAM(STM32_I2C_I2C4_TX_DMA_STREAM); -#endif -#endif /* STM32_I2C_USE_I2C4 */ -} - -/** - * @brief Configures and activates the I2C peripheral. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * - * @notapi - */ -void i2c_lld_start(I2CDriver *i2cp) { - I2C_TypeDef *dp = i2cp->i2c; - -#if STM32_I2C_USE_DMA == TRUE - /* Common DMA modes.*/ - i2cp->txdmamode = DMAMODE_COMMON | STM32_DMA_CR_DIR_M2P; - i2cp->rxdmamode = DMAMODE_COMMON | STM32_DMA_CR_DIR_P2M; -#endif - - /* Make sure I2C peripheral is disabled */ - dp->CR1 &= ~I2C_CR1_PE; - i2cp->mode = i2cStopped; - - /* If in stopped state then enables the I2C and DMA clocks.*/ - if (i2cp->state == I2C_STOP) { - -#if STM32_I2C_USE_I2C1 - if (&I2CD1 == i2cp) { - - rccResetI2C1(); - rccEnableI2C1(FALSE); -#if STM32_I2C_USE_DMA == TRUE - { - bool b; - - b = dmaStreamAllocate(i2cp->dmarx, - STM32_I2C_I2C1_IRQ_PRIORITY, - NULL, - (void *)i2cp); - osalDbgAssert(!b, "stream already allocated"); - b = dmaStreamAllocate(i2cp->dmatx, - STM32_I2C_I2C1_IRQ_PRIORITY, - NULL, - (void *)i2cp); - osalDbgAssert(!b, "stream already allocated"); - - i2cp->rxdmamode |= STM32_DMA_CR_CHSEL(I2C1_RX_DMA_CHANNEL) | - STM32_DMA_CR_PL(STM32_I2C_I2C1_DMA_PRIORITY); - i2cp->txdmamode |= STM32_DMA_CR_CHSEL(I2C1_TX_DMA_CHANNEL) | - STM32_DMA_CR_PL(STM32_I2C_I2C1_DMA_PRIORITY); - } -#endif /* STM32_I2C_USE_DMA == TRUE */ - -#if defined(STM32_I2C1_GLOBAL_NUMBER) || defined(__DOXYGEN__) - nvicEnableVector(STM32_I2C1_GLOBAL_NUMBER, STM32_I2C_I2C1_IRQ_PRIORITY); -#elif defined(STM32_I2C1_EVENT_NUMBER) && defined(STM32_I2C1_ERROR_NUMBER) - nvicEnableVector(STM32_I2C1_EVENT_NUMBER, STM32_I2C_I2C1_IRQ_PRIORITY); - nvicEnableVector(STM32_I2C1_ERROR_NUMBER, STM32_I2C_I2C1_IRQ_PRIORITY); -#else -#error "I2C1 interrupt numbers not defined" -#endif - } -#endif /* STM32_I2C_USE_I2C1 */ - -#if STM32_I2C_USE_I2C2 - if (&I2CD2 == i2cp) { - - rccResetI2C2(); - rccEnableI2C2(FALSE); -#if STM32_I2C_USE_DMA == TRUE - { - bool b; - - b = dmaStreamAllocate(i2cp->dmarx, - STM32_I2C_I2C2_IRQ_PRIORITY, - NULL, - (void *)i2cp); - osalDbgAssert(!b, "stream already allocated"); - b = dmaStreamAllocate(i2cp->dmatx, - STM32_I2C_I2C2_IRQ_PRIORITY, - NULL, - (void *)i2cp); - osalDbgAssert(!b, "stream already allocated"); - - i2cp->rxdmamode |= STM32_DMA_CR_CHSEL(I2C2_RX_DMA_CHANNEL) | - STM32_DMA_CR_PL(STM32_I2C_I2C2_DMA_PRIORITY); - i2cp->txdmamode |= STM32_DMA_CR_CHSEL(I2C2_TX_DMA_CHANNEL) | - STM32_DMA_CR_PL(STM32_I2C_I2C2_DMA_PRIORITY); - } -#endif /*STM32_I2C_USE_DMA == TRUE */ - -#if defined(STM32_I2C2_GLOBAL_NUMBER) || defined(__DOXYGEN__) - nvicEnableVector(STM32_I2C2_GLOBAL_NUMBER, STM32_I2C_I2C2_IRQ_PRIORITY); -#elif defined(STM32_I2C2_EVENT_NUMBER) && defined(STM32_I2C2_ERROR_NUMBER) - nvicEnableVector(STM32_I2C2_EVENT_NUMBER, STM32_I2C_I2C2_IRQ_PRIORITY); - nvicEnableVector(STM32_I2C2_ERROR_NUMBER, STM32_I2C_I2C2_IRQ_PRIORITY); -#else -#error "I2C2 interrupt numbers not defined" -#endif - } -#endif /* STM32_I2C_USE_I2C2 */ - -#if STM32_I2C_USE_I2C3 - if (&I2CD3 == i2cp) { - - rccResetI2C3(); - rccEnableI2C3(FALSE); -#if STM32_I2C_USE_DMA == TRUE - { - bool b; - - b = dmaStreamAllocate(i2cp->dmarx, - STM32_I2C_I2C3_IRQ_PRIORITY, - NULL, - (void *)i2cp); - osalDbgAssert(!b, "stream already allocated"); - b = dmaStreamAllocate(i2cp->dmatx, - STM32_I2C_I2C3_IRQ_PRIORITY, - NULL, - (void *)i2cp); - osalDbgAssert(!b, "stream already allocated"); - - i2cp->rxdmamode |= STM32_DMA_CR_CHSEL(I2C3_RX_DMA_CHANNEL) | - STM32_DMA_CR_PL(STM32_I2C_I2C3_DMA_PRIORITY); - i2cp->txdmamode |= STM32_DMA_CR_CHSEL(I2C3_TX_DMA_CHANNEL) | - STM32_DMA_CR_PL(STM32_I2C_I2C3_DMA_PRIORITY); - } -#endif /*STM32_I2C_USE_DMA == TRUE */ - -#if defined(STM32_I2C3_GLOBAL_NUMBER) || defined(__DOXYGEN__) - nvicEnableVector(STM32_I2C3_GLOBAL_NUMBER, STM32_I2C_I2C3_IRQ_PRIORITY); -#elif defined(STM32_I2C3_EVENT_NUMBER) && defined(STM32_I2C3_ERROR_NUMBER) - nvicEnableVector(STM32_I2C3_EVENT_NUMBER, STM32_I2C_I2C3_IRQ_PRIORITY); - nvicEnableVector(STM32_I2C3_ERROR_NUMBER, STM32_I2C_I2C3_IRQ_PRIORITY); -#else -#error "I2C3 interrupt numbers not defined" -#endif - } -#endif /* STM32_I2C_USE_I2C3 */ - -#if STM32_I2C_USE_I2C4 - if (&I2CD4 == i2cp) { - - rccResetI2C4(); - rccEnableI2C4(FALSE); -#if STM32_I2C_USE_DMA == TRUE - { - bool b; - - b = dmaStreamAllocate(i2cp->dmarx, - STM32_I2C_I2C4_IRQ_PRIORITY, - NULL, - (void *)i2cp); - osalDbgAssert(!b, "stream already allocated"); - b = dmaStreamAllocate(i2cp->dmatx, - STM32_I2C_I2C4_IRQ_PRIORITY, - NULL, - (void *)i2cp); - osalDbgAssert(!b, "stream already allocated"); - - i2cp->rxdmamode |= STM32_DMA_CR_CHSEL(I2C4_RX_DMA_CHANNEL) | - STM32_DMA_CR_PL(STM32_I2C_I2C4_DMA_PRIORITY); - i2cp->txdmamode |= STM32_DMA_CR_CHSEL(I2C4_TX_DMA_CHANNEL) | - STM32_DMA_CR_PL(STM32_I2C_I2C4_DMA_PRIORITY); - } -#endif /*STM32_I2C_USE_DMA == TRUE */ - -#if defined(STM32_I2C4_GLOBAL_NUMBER) || defined(__DOXYGEN__) - nvicEnableVector(STM32_I2C4_GLOBAL_NUMBER, STM32_I2C_I2C4_IRQ_PRIORITY); -#elif defined(STM32_I2C4_EVENT_NUMBER) && defined(STM32_I2C4_ERROR_NUMBER) - nvicEnableVector(STM32_I2C4_EVENT_NUMBER, STM32_I2C_I2C4_IRQ_PRIORITY); - nvicEnableVector(STM32_I2C4_ERROR_NUMBER, STM32_I2C_I2C4_IRQ_PRIORITY); -#else -#error "I2C4 interrupt numbers not defined" -#endif - } -#endif /* STM32_I2C_USE_I2C4 */ - } - -#if STM32_I2C_USE_DMA == TRUE - /* I2C registers pointed by the DMA.*/ - dmaStreamSetPeripheral(i2cp->dmarx, &dp->RXDR); - dmaStreamSetPeripheral(i2cp->dmatx, &dp->TXDR); - /* Reset i2c peripheral, the TCIE bit will be handled separately. */ - // TODO: Mask out config bits which user mustn't fiddle with - dp->CR1 = (i2cp->config->cr1 | I2C_CR1_ERRIE | I2C_CR1_NACKIE | - I2C_CR1_TXDMAEN | I2C_CR1_RXDMAEN); -#else - /* Reset i2c peripheral, the TCIE bit will be handled separately. No DMA interrupts */ - dp->CR1 = (i2cp->config->cr1 | I2C_CR1_ERRIE | I2C_CR1_NACKIE); -#endif - - /* Setup I2C parameters.*/ - dp->TIMINGR = i2cp->config->timingr; - - /* Ready to go.*/ - i2cp->mode = i2cIdle; -#if HAL_USE_I2C_LOCK - i2cp->lockDuration = TIME_IMMEDIATE; -#endif -#if HAL_USE_I2C_SLAVE /* I2C slave mode support */ - i2cp->slaveNextReply = i2cp->slaveNextRx = &I2CSlaveLockOnMsg; - i2cp->targetAdr = i2cInvalidAdr; - i2cp->slaveTimeout = TIME_INFINITE; -#endif - - dp->CR1 |= I2C_CR1_PE; // Enable peripheral -} - - -/** - * @brief Deactivates the I2C peripheral. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * - * @notapi - */ -void i2c_lld_stop(I2CDriver *i2cp) { - - /* If not in stopped state then disables the I2C clock.*/ - if (i2cp->state != I2C_STOP) { - i2cp->mode = i2cStopped; - - /* I2C disable.*/ - stopTimer(i2cp); - i2c_lld_abort_operation(i2cp); -#if STM32_I2C_USE_DMA == TRUE - dmaStreamRelease(i2cp->dmatx); - dmaStreamRelease(i2cp->dmarx); -#endif - -#if STM32_I2C_USE_I2C1 - if (&I2CD1 == i2cp) { -#if defined(STM32_I2C1_GLOBAL_NUMBER) || defined(__DOXYGEN__) - nvicDisableVector(STM32_I2C1_GLOBAL_NUMBER); -#elif defined(STM32_I2C1_EVENT_NUMBER) && defined(STM32_I2C1_ERROR_NUMBER) - nvicDisableVector(STM32_I2C1_EVENT_NUMBER); - nvicDisableVector(STM32_I2C1_ERROR_NUMBER); -#else -#error "I2C1 interrupt numbers not defined" -#endif - - rccDisableI2C1(FALSE); - } -#endif - -#if STM32_I2C_USE_I2C2 - if (&I2CD2 == i2cp) { -#if defined(STM32_I2C2_GLOBAL_NUMBER) || defined(__DOXYGEN__) - nvicDisableVector(STM32_I2C2_GLOBAL_NUMBER); -#elif defined(STM32_I2C2_EVENT_NUMBER) && defined(STM32_I2C2_ERROR_NUMBER) - nvicDisableVector(STM32_I2C2_EVENT_NUMBER); - nvicDisableVector(STM32_I2C2_ERROR_NUMBER); -#else -#error "I2C2 interrupt numbers not defined" -#endif - - rccDisableI2C2(FALSE); - } -#endif - -#if STM32_I2C_USE_I2C3 - if (&I2CD3 == i2cp) { -#if defined(STM32_I2C3_GLOBAL_NUMBER) || defined(__DOXYGEN__) - nvicDisableVector(STM32_I2C3_GLOBAL_NUMBER); -#elif defined(STM32_I2C3_EVENT_NUMBER) && defined(STM32_I2C3_ERROR_NUMBER) - nvicDisableVector(STM32_I2C3_EVENT_NUMBER); - nvicDisableVector(STM32_I2C3_ERROR_NUMBER); -#else -#error "I2C3 interrupt numbers not defined" -#endif - - rccDisableI2C3(FALSE); - } -#endif - -#if STM32_I2C_USE_I2C4 - if (&I2CD4 == i2cp) { -#if defined(STM32_I2C4_GLOBAL_NUMBER) || defined(__DOXYGEN__) - nvicDisableVector(STM32_I2C4_GLOBAL_NUMBER); -#elif defined(STM32_I2C4_EVENT_NUMBER) && defined(STM32_I2C4_ERROR_NUMBER) - nvicDisableVector(STM32_I2C4_EVENT_NUMBER); - nvicDisableVector(STM32_I2C4_ERROR_NUMBER); -#else -#error "I2C4 interrupt numbers not defined" -#endif - - rccDisableI2C4(FALSE); - } -#endif - } -} - - - -#if HAL_USE_I2C_MASTER == TRUE -/** - * Utility routine brings out common code for master timeout - */ -static msg_t calcMasterTimeout(I2CDriver *i2cp) -{ - systime_t start, end; - - osalDbgAssert((i2cp->mode <= i2cIsMaster), "busy"); - - /* Calculating the time window for the timeout on the busy bus condition.*/ - start = osalOsGetSystemTimeX(); - end = start + OSAL_MS2ST(STM32_I2C_BUSY_TIMEOUT); - - /* Waits until BUSY flag is reset or, alternatively, for a timeout - condition.*/ - while (true) { - osalSysLock(); - - /* If the bus is not busy then the operation can continue, note, the - loop is exited in the locked state.*/ -// if (!(i2cp->i2c->ISR & I2C_ISR_BUSY) && !(i2cp->i2c->CR1 & I2C_CR1_STOP)) - if (!(i2cp->i2c->ISR & I2C_ISR_BUSY)) - break; - - /* If the system time went outside the allowed window then a timeout - condition is returned.*/ - if (!osalOsIsTimeWithinX(osalOsGetSystemTimeX(), start, end)) - return MSG_TIMEOUT; - - osalSysUnlock(); - // TODO: Should we relinquish thread here for a while? - chThdSleepMilliseconds(2); - } - i2cp->mode = i2cIsMaster; // We can set master mode now - return MSG_OK; -} - - -/** - * Start a master mode transaction - * - * Note: may need adjustment to work in multi-master mode as well - see i2c_lld_safety_timeout() - */ -static msg_t startMasterAction(I2CDriver *i2cp, systime_t timeout) -{ -#if STM32_I2C_USE_DMA == TRUE -#else -#endif - msg_t msg; - - /* Starts the operation.*/ - i2cp->i2c->CR2 |= I2C_CR2_START; - - /* Waits for the operation completion or a timeout.*/ - msg = osalThreadSuspendTimeoutS(&i2cp->thread, timeout); - - /* In case of a software timeout a STOP is sent as an extreme attempt - to release the bus.*/ - if (msg == MSG_TIMEOUT) { - i2cp->i2c->CR2 |= I2C_CR2_STOP; - i2cp->mode = i2cIdle; // TODO: Is this enough? - } - return msg; -} - - -/** - * @brief Receives data via the I2C bus as master. - * @details Number of receiving bytes must be more than 1 on STM32F1x. This is - * hardware restriction. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * @param[in] addr slave device address - * @param[out] rxbuf pointer to the 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. After a - * timeout the driver must be stopped and restarted - * because the bus is in an uncertain state. - * - * @notapi - */ -msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, - uint8_t *rxbuf, size_t rxbytes, - systime_t timeout) { -// I2C_TypeDef *dp = i2cp->i2c; - - osalDbgAssert((i2cp->thread==NULL), "#3 - reentry"); - - /* Resetting error flags for this transfer.*/ - i2cp->errors = I2C_NO_ERROR; - - /* Releases the lock from high level driver.*/ - osalSysUnlock(); - - calcMasterTimeout(i2cp); // This has to be done before we change the state of the connection - - -#if STM32_I2C_USE_DMA == TRUE - /* RX DMA setup.*/ - dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode); - dmaStreamSetMemory0(i2cp->dmarx, rxbuf); - dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes); -#endif - // Always set up the receive buffer in case callbacks enabled - i2cp->rxptr = rxbuf; - i2cp->rxbytes = rxbytes; - - /* Setting up the slave address.*/ - i2c_lld_set_address(i2cp, addr); - - /* Setting up the peripheral.*/ - i2c_lld_setup_rx_transfer(i2cp); - - i2cStartReceive(i2cp); - i2cp->mode = i2cMasterRxing; - - return startMasterAction(i2cp, timeout); -} - - - -/** - * @brief Transmits data via the I2C bus as master. - * @details Number of receiving bytes must be 0 or more than 1 on STM32F1x. - * This is hardware restriction. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * @param[in] addr slave device address - * @param[in] txbuf pointer to the transmit buffer - * @param[in] txbytes number of bytes to be transmitted - * @param[out] rxbuf pointer to the 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. After a - * timeout the driver must be stopped and restarted - * because the bus is in an uncertain state. - * - * @notapi - */ -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) { - I2C_TypeDef *dp = i2cp->i2c; - - osalDbgAssert((i2cp->thread==NULL), "#3 - reentry"); - - /* Resetting error flags for this transfer.*/ - i2cp->errors = I2C_NO_ERROR; - - /* Releases the lock from high level driver.*/ - osalSysUnlock(); - - calcMasterTimeout(i2cp); // This has to be done before we change the state of the connection - - -#if STM32_I2C_USE_DMA == TRUE - /* TX DMA setup.*/ - dmaStreamSetMode(i2cp->dmatx, i2cp->txdmamode); - dmaStreamSetMemory0(i2cp->dmatx, txbuf); - dmaStreamSetTransactionSize(i2cp->dmatx, txbytes); - - /* RX DMA setup, note, rxbytes can be zero but we write the value anyway.*/ - dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode); - dmaStreamSetMemory0(i2cp->dmarx, rxbuf); - dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes); -#else - i2cp->txptr = txbuf; - i2cp->txbytes = txbytes; -#endif - // Always set up the receive buffer in case callbacks enabled - i2cp->rxptr = rxbuf; - i2cp->rxbytes = rxbytes; - - /* Setting up the slave address.*/ - i2c_lld_set_address(i2cp, addr); - - /* Preparing the transfer.*/ - i2c_lld_setup_tx_transfer(i2cp); - -#if STM32_I2C_USE_DMA == TRUE - /* Enabling TX DMA.*/ - dmaStreamEnable(i2cp->dmatx); - - /* Transfer complete interrupt enabled.*/ - dp->CR1 |= I2C_CR1_TCIE; -#else - /* Transfer complete and TX interrupts enabled.*/ - dp->CR1 |= I2C_CR1_TCIE | I2C_CR1_TXIE; -#endif - - i2cp->mode = i2cMasterTxing; - - return startMasterAction(i2cp, timeout); -} -#endif /* #if HAL_USE_I2C_MASTER == TRUE */ - - - - -#if HAL_USE_I2C_SLAVE -/************************************************************************/ -/* SLAVE MODE SUPPORT */ -/************************************************************************/ - -/** - * @brief Reconfigure I2C channel to respond to passed address - * in addition to those previously made active - * - * @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. - * Number of supported addresses is chip-dependent - 2+general call on I2CV2 - * Address masking capabilities of OAR2 not supported - * - * @notapi - **/ -msg_t i2c_lld_matchAddress(I2CDriver *i2cp, i2caddr_t i2cadr) -{ - I2C_TypeDef *dp = i2cp->i2c; - if (i2cadr == 0) { - dp->CR1 |= I2C_CR1_GCEN; // Just enable General Call - dp->CR1 |= I2C_CR1_ADDRIE; // Make sure address match interrupt enabled - } - else - { - uint32_t adr = i2cadr << 1; - if ((dp->OAR1 & (0x7f<<1)) == adr) { return I2C_OK; }; // Already matched in OAR1 - if ((dp->OAR2 & (0x7f<<1)) == adr) { return I2C_OK; }; // Already matched in OAR2 - - if (!(dp->OAR1 & I2C_OAR1_OA1EN)) { - dp->OAR1 = adr | I2C_OAR1_OA1EN; // OAR1 previously unused - dp->CR1 |= I2C_CR1_ADDRIE; // Make sure address match interrupt enabled - } - else - if (!(dp->OAR2 & I2C_OAR2_OA2EN)) { - dp->OAR2 = adr | I2C_OAR2_OA2EN; // OAR2 previously unused - dp->CR1 |= I2C_CR1_ADDRIE; // Make sure address match interrupt enabled - } - else - return I2C_ERROR; /* cannot add this address to set of those matched */ - } - return I2C_OK; -} - - -/** - * @brief Reconfigure I2C channel to no longer match specified address - * - * @param[in] i2cp pointer to the @p I2CDriver object - * @param[in] i2cadr I2C network address - * - * @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. - * Does not support 10-bit addressing. - * - * @notapi - **/ -void i2c_lld_unmatchAddress(I2CDriver *i2cp, i2caddr_t i2cadr) -{ - I2C_TypeDef *dp = i2cp->i2c; - if (i2cadr == 0) { - dp->CR1 &= (uint32_t)~I2C_CR1_GCEN; // Disable General Call - } - else { - uint32_t adr = i2cadr << 1; - if ((dp->OAR1 & (0x7f<<1)) == adr) { - // Matched in OAR1 - dp->OAR1 &= ~I2C_OAR1_OA1EN; // Just disable - OAR2 is a bit different - } - else - if ((dp->OAR2 & I2C_OAR2_OA2EN) && (dp->OAR2 & (0x7f<<1)) == adr) - dp->OAR2 &= ~I2C_OAR2_OA2EN; - } - if (!((dp->CR1 & (uint32_t)I2C_CR1_GCEN) || (dp->OAR1 & I2C_OAR1_OA1EN) || (dp->OAR2 & I2C_OAR2_OA2EN))) { - dp->CR1 &= (uint32_t)~(I2C_CR1_ADDRIE); // Disable Address match interrupts if nothing can generate them (strictly necessary??) - } -} - - -/** - * @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. - * - * @notapi - **/ -void i2c_lld_unmatchAll(I2CDriver *i2cp) -{ - I2C_TypeDef *dp = i2cp->i2c; - dp->CR1 &= (uint32_t)~(I2C_CR1_GCEN | I2C_CR1_ADDRIE); // Disable General Call - dp->OAR1 = 0; - dp->OAR2 = 0; -} - - -/** - * @brief Configure callbacks & buffers to receive messages - * - * @param[in] i2cp pointer to the @p I2CDriver object - * @param[in] replyMsg @p I2CSlaveMsg struct for processing subsequent received messages - * - * @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 - * - * @notapi - */ -void i2c_lld_slaveReceive(I2CDriver *i2cp, const I2CSlaveMsg *rxMsg) -{ - osalDbgCheck((rxMsg && rxMsg->size <= 0xffff)); - qEvt(0x82, rxMsg->size); - i2cp->slaveNextRx = rxMsg; - if (i2cp->mode == i2cLockedRxing && rxMsg->body && rxMsg->size) { - /* We can receive now! */ - i2cp->slaveRx = rxMsg; - /* slave RX DMA setup */ -#if STM32_I2C_USE_DMA == TRUE - /* RX DMA setup.*/ - dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode); - dmaStreamSetMemory0(i2cp->dmarx, rxMsg->body); - dmaStreamSetTransactionSize(i2cp->dmarx, rxMsg->size); -#else - i2cp->rxptr = rxMsg->body; - i2cp->rxbytes = rxMsg->size; -#endif - - i2cp->mode = i2cSlaveRxing; - i2c_lld_setup_rx_transfer(i2cp); // Set up the transfer - qEvt(0x83, 0); - i2cStartReceive(i2cp); - i2cp->i2c->CR1 &= ~I2C_CR1_SBC; // Not needed with receive - i2cp->i2c->ICR = I2C_ISR_ADDR; // We can release the clock stretch now - } -} - - -/** - * @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 - * - * @notapi - */ -void i2c_lld_slaveReply(I2CDriver *i2cp, const I2CSlaveMsg *replyMsg) -{ - osalDbgCheck((replyMsg && replyMsg->size <= 0xffff)); - qEvt(0x80, replyMsg->size); - i2cp->slaveNextReply = replyMsg; - if (i2cp->mode == i2cLockedReplying && replyMsg->body && replyMsg->size) - { - i2cp->slaveReply = replyMsg; - /* slave TX setup -- we can reply now! */ - #if STM32_I2C_USE_DMA == TRUE - dmaStreamSetMode(i2cp->dmatx, i2cp->txdmamode); - dmaStreamSetMemory0(i2cp->dmatx, replyMsg->body); - dmaStreamSetTransactionSize(i2cp->dmatx, replyMsg->size); - i2cp->mode = i2cSlaveReplying; - /* Start transmission */ - i2c_lld_setup_tx_transfer(i2cp); - - /* Enabling TX DMA.*/ - dmaStreamEnable(i2cp->dmatx); - - /* Transfer complete interrupt enabled.*/ - i2cp->i2c->CR1 |= I2C_CR1_TCIE; - #else - /* Start transmission */ - i2cp->txptr = replyMsg->body; - i2cp->txbytes = replyMsg->size; - i2c_lld_setup_tx_transfer(i2cp); - /* Transfer complete and TX character interrupts enabled.*/ - i2cp->i2c->CR1 |= I2C_CR1_TCIE | I2C_CR1_TXIE; - #endif - qEvt(0x81, 0); - i2cp->i2c->CR1 |= I2C_CR1_SBC; // Need this to enable byte counter in transmit mode - i2cp->i2c->ICR = I2C_ISR_ADDR; // We can release the clock stretch now - } -} - -#endif /* HAL_USE_I2C_SLAVE */ - - -#endif /* HAL_USE_I2C */ - -/** @} */ diff --git a/drivers/chibios/i2cslave/I2Cv2/hal_i2c_lld.h b/drivers/chibios/i2cslave/I2Cv2/hal_i2c_lld.h deleted file mode 100644 index c4df28fb2ea..00000000000 --- a/drivers/chibios/i2cslave/I2Cv2/hal_i2c_lld.h +++ /dev/null @@ -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_ */ - -/** @} */ diff --git a/drivers/chibios/i2cslave/hal_i2c.c b/drivers/chibios/i2cslave/hal_i2c.c deleted file mode 100644 index 5e4e6438c2c..00000000000 --- a/drivers/chibios/i2cslave/hal_i2c.c +++ /dev/null @@ -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 */ - -/** @} */ diff --git a/drivers/chibios/i2cslave/hal_i2c.h b/drivers/chibios/i2cslave/hal_i2c.h deleted file mode 100644 index 325941b953f..00000000000 --- a/drivers/chibios/i2cslave/hal_i2c.h +++ /dev/null @@ -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_ */ - -/** @} */ diff --git a/drivers/chibios/i2cslave/hal_i2cslave.h b/drivers/chibios/i2cslave/hal_i2cslave.h deleted file mode 100644 index 955b41e25c5..00000000000 --- a/drivers/chibios/i2cslave/hal_i2cslave.h +++ /dev/null @@ -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 . - - --- - - 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 - -#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_ */ diff --git a/lib/chibios b/lib/chibios index 84a65901f0d..c846437e394 160000 --- a/lib/chibios +++ b/lib/chibios @@ -1 +1 @@ -Subproject commit 84a65901f0d4784f10210637478c769e0ee6c415 +Subproject commit c846437e39423ef9394aecd3a96393db24c51ebf