From e96a625352d7a8a18a6246d4229ff77b0775811f Mon Sep 17 00:00:00 2001 From: Andy Piper Date: Sun, 27 Nov 2022 16:04:35 +0000 Subject: [PATCH] I2Cv1: support I2C transactions without DMA disable interrupts on error when there is no DMA ensure that all byte read conditions are handled in both RxNE and BTF ensure tx path deals with both TxE and BTF enable/disable error interrupts on startup --- os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c | 247 ++++++++++++++++++--- os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.h | 28 +++ 2 files changed, 245 insertions(+), 30 deletions(-) diff --git a/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c b/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c index 48a5c4497e..2b09016e31 100644 --- a/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c +++ b/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c @@ -34,6 +34,7 @@ /* Driver local definitions. */ /*===========================================================================*/ +#if STM32_I2C_USE_DMA == TRUE #define I2C1_RX_DMA_CHANNEL \ STM32_DMA_GETCHANNEL(STM32_I2C_I2C1_RX_DMA_STREAM, \ STM32_I2C1_RX_DMA_CHN) @@ -57,6 +58,23 @@ #define I2C3_TX_DMA_CHANNEL \ STM32_DMA_GETCHANNEL(STM32_I2C_I2C3_TX_DMA_STREAM, \ STM32_I2C3_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 +#define i2c_lld_write_byte(i2cp) \ + i2cp->i2c->DR = *i2cp->txptr; \ + i2cp->txptr++; \ + i2cp->txbytes-- +#define i2c_lld_read_byte(i2cp) \ + *i2cp->rxptr = (uint8_t)i2cp->i2c->DR; \ + i2cp->rxptr++; \ + i2cp->rxbytes-- +#endif /*===========================================================================*/ /* Driver constants. */ @@ -79,6 +97,21 @@ ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY | I2C_SR2_TRA) << 16) | \ I2C_SR1_BTF | I2C_SR1_TXE)) +#define I2C_EV8_MASTER_BYTE_TRANSMIT \ + ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY | I2C_SR2_TRA) << 16) | \ + I2C_SR1_TXE)) + +#define I2C_EV8_1_MASTER_BYTE_TRANSMIT \ + ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY | I2C_SR2_TRA) << 16))) + +#define I2C_EV7_MASTER_BYTE_RECEIVE \ + ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY) << 16) | \ + I2C_SR1_RXNE)) + +#define I2C_EV7_1_MASTER_LAST_BYTES_RECEIVED \ + ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY) << 16) | \ + I2C_SR1_BTF | I2C_SR1_RXNE)) + #define I2C_EV9_MASTER_ADD10 \ ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY) << 16) | I2C_SR1_ADD10)) @@ -135,9 +168,38 @@ static void i2c_lld_abort_operation(I2CDriver *i2cp) { dp->CR2 = 0; dp->SR1 = 0; +#if STM32_I2C_USE_DMA == TRUE /* Stops the associated DMA streams.*/ dmaStreamDisable(i2cp->dmatx); dmaStreamDisable(i2cp->dmarx); +#else + i2cp->txbytes = 0; + i2cp->rxbytes = 0; +#endif +} + +/** + * @brief Stops an I2C transaction. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +static void i2c_lld_stop_operation(I2CDriver *i2cp, uint32_t rxbytes) { + I2C_TypeDef *dp = i2cp->i2c; + + dp->CR2 &= ~(I2C_CR2_ITEVTEN | I2C_CR2_ITBUFEN | I2C_CR2_ITERREN); + dp->CR1 |= I2C_CR1_STOP; /* stop will clear TxE / RxNE */ +#if STM32_I2C_USE_DMA == FALSE + while (rxbytes-- > 0) { /* read pending bytes if necessary */ + i2c_lld_read_byte(i2cp); + } + i2cp->txbytes = 0; + i2cp->rxbytes = 0; +#else + (void)rxbytes; +#endif + _i2c_wakeup_isr(i2cp); } /** @@ -320,15 +382,18 @@ static void i2c_lld_reset(I2CDriver *i2cp) { static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) { I2C_TypeDef *dp = i2cp->i2c; uint32_t regSR2 = dp->SR2; - uint32_t event = dp->SR1; + uint32_t regSR1 = dp->SR1; + uint32_t event = I2C_EV_MASK & (regSR2 << 16 | regSR1); #ifdef STM32_I2C_ISR_LIMIT if (i2cp->isr_count++ > i2cp->isr_limit) { i2cp->errors |= I2C_ISR_LIMIT; +#if STM32_I2C_USE_DMA == TRUE if (i2cp->dmatx) dmaStreamDisable(i2cp->dmatx); if (i2cp->dmarx) dmaStreamDisable(i2cp->dmarx); +#endif dp->CR1 |= I2C_CR1_SWRST; dp->CR1 &= ~I2C_CR1_PE; i2c_lld_reset(i2cp); @@ -349,7 +414,7 @@ static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) { /* Interrupts are disabled just before dmaStreamEnable() because there is no need of interrupts until next transaction begin. All the work is done by the DMA.*/ - switch (I2C_EV_MASK & (event | (regSR2 << 16))) { + switch (event) { case I2C_EV5_MASTER_MODE_SELECT: case I2C_EV5_MASTER_MODE_SELECT_NO_BUSY: if ((i2cp->addr >> 8) > 0) { @@ -364,49 +429,124 @@ static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) { dp->DR = (0xFF & (i2cp->addr >> 1)); break; case I2C_EV6_MASTER_REC_MODE_SELECTED: +#if STM32_I2C_USE_DMA == TRUE dp->CR2 &= ~I2C_CR2_ITEVTEN; dmaStreamEnable(i2cp->dmarx); - dp->CR2 |= I2C_CR2_LAST; /* Needed in receiver mode. */ - if (dmaStreamGetTransactionSize(i2cp->dmarx) < 2) + dp->CR2 |= I2C_CR2_LAST; /* Needed in receiver mode for NACK generation. */ +#endif + switch (i2c_lld_get_rxbytes(i2cp)) { + case 2: /* special treatment for 1-2-byte reception */ + dp->CR1 |= I2C_CR1_POS; + dp->CR1 &= ~I2C_CR1_ACK; + break; + case 1: dp->CR1 &= ~I2C_CR1_ACK; + dp->CR2 |= I2C_CR2_ITBUFEN; /* start per-byte interrupt generation */ + break; + default: + dp->CR2 |= I2C_CR2_ITBUFEN; /* start per-byte interrupt generation */ + break; + } break; case I2C_EV6_MASTER_TRA_MODE_SELECTED: +#if STM32_I2C_USE_DMA == TRUE dp->CR2 &= ~I2C_CR2_ITEVTEN; dmaStreamEnable(i2cp->dmatx); +#else + dp->CR2 |= I2C_CR2_ITBUFEN; /* start per-byte interrupt generation */ +#endif + break; + case I2C_EV8_MASTER_BYTE_TRANSMIT: +#if STM32_I2C_USE_DMA == FALSE + if (i2cp->txbytes > 0U) { + i2c_lld_write_byte(i2cp); + } else { /* ref: Stop condition should be programmed during EV8_2 event, when either TxE or BTF is set */ + dp->CR2 &= ~I2C_CR2_ITBUFEN; /* stop receiving any more TxE interrupts */ + if (i2c_lld_get_rxbytes(i2cp) > 0U) { + i2cp->addr |= 0x01; + /* start will clear TxE and generate ReStart at end of current byte transfer */ + dp->CR1 |= I2C_CR1_START | I2C_CR1_ACK; + return; + } + i2c_lld_stop_operation(i2cp, 0); + } break; case I2C_EV8_2_MASTER_BYTE_TRANSMITTED: + if (i2cp->txbytes > 0U) { + i2c_lld_write_byte(i2cp); + return; + } +#else + case I2C_EV8_2_MASTER_BYTE_TRANSMITTED: +#endif /* Catches BTF event after the end of transmission.*/ (void)dp->DR; /* Clear BTF.*/ - if (dmaStreamGetTransactionSize(i2cp->dmarx) > 0) { + + if (i2c_lld_get_rxbytes(i2cp) > 0U) { /* Starts "read after write" operation, LSB = 1 -> receive.*/ i2cp->addr |= 0x01; dp->CR1 |= I2C_CR1_START | I2C_CR1_ACK; return; } - dp->CR2 &= ~I2C_CR2_ITEVTEN; - dp->CR1 |= I2C_CR1_STOP; - _i2c_wakeup_isr(i2cp); + i2c_lld_stop_operation(i2cp, 0); break; +#if STM32_I2C_USE_DMA == FALSE + case I2C_EV7_MASTER_BYTE_RECEIVE: { + uint32_t rxbytes = i2c_lld_get_rxbytes(i2cp); + if (rxbytes > 3U) { + i2c_lld_read_byte(i2cp); + if (i2c_lld_get_rxbytes(i2cp) == 3U) { + dp->CR2 &= ~I2C_CR2_ITBUFEN; /* stop receiving any more RxNE interrupts */ + } + } else if (i2c_lld_get_rxbytes(i2cp) == 3U) { + dp->CR2 &= ~I2C_CR2_ITBUFEN; /* stop receiving any more RxNE interrupts */ + } else if (rxbytes <= 1) { + i2c_lld_stop_operation(i2cp, rxbytes); + } + break; + } + case I2C_EV7_1_MASTER_LAST_BYTES_RECEIVED: { + uint32_t rxbytes = i2c_lld_get_rxbytes(i2cp); + switch (rxbytes) { + case 4: + dp->CR2 &= ~I2C_CR2_ITBUFEN; + i2c_lld_read_byte(i2cp); + break; + case 3: + dp->CR2 &= ~I2C_CR2_ITBUFEN; + dp->CR1 &= ~I2C_CR1_ACK; /* generate NACK on next read */ + i2c_lld_read_byte(i2cp); + break; + case 2: + case 1: + i2c_lld_stop_operation(i2cp, rxbytes); + break; + default: + i2c_lld_read_byte(i2cp); + } + break; + } +#endif case I2C_EV5_MASTER_MODE_INVALID: i2c_lld_abort_operation(i2cp); - dp->CR2 &= ~I2C_CR2_ITEVTEN; break; default: - break; + break; } /* Clear ADDR flag. */ - if (event & (I2C_SR1_ADDR | I2C_SR1_ADD10)) + if (regSR1 & (I2C_SR1_ADDR | I2C_SR1_ADD10)) (void)dp->SR2; /* BERR flag doesn�t happen anymore in event handling */ #if 0 /* Errata 2.4.6 for STM32F40x, Spurious Bus Error detection in Master mode.*/ - if (event & I2C_SR1_BERR) { + if (regSR1 & I2C_SR1_BERR) { dp->SR1 &= ~I2C_SR1_BERR; } #endif } +#if STM32_I2C_USE_DMA == TRUE /** * @brief DMA RX end IRQ handler. * @@ -460,6 +600,7 @@ static void i2c_lld_serve_tx_end_irq(I2CDriver *i2cp, uint32_t flags) { of R/W transaction itself.*/ dp->CR2 |= I2C_CR2_ITEVTEN; } +#endif /** * @brief I2C error handler. @@ -471,11 +612,18 @@ static void i2c_lld_serve_tx_end_irq(I2CDriver *i2cp, uint32_t flags) { */ static void i2c_lld_serve_error_interrupt(I2CDriver *i2cp, uint16_t sr) { +#if STM32_I2C_USE_DMA == TRUE /* Clears interrupt flags just to be safe.*/ if (i2cp->dmatx) dmaStreamDisable(i2cp->dmatx); if (i2cp->dmarx) dmaStreamDisable(i2cp->dmarx); +#else + /* Clear interrupt flags. DMA-path will have already cleared I2C_CR2_ITEVTEN */ + i2cp->i2c->CR2 &= ~(I2C_CR2_ITEVTEN | I2C_CR2_ITBUFEN); + i2cp->txbytes = 0; + i2cp->rxbytes = 0; +#endif #ifdef STM32_I2C_ISR_LIMIT if (i2cp->isr_count++ > i2cp->isr_limit) { @@ -648,24 +796,30 @@ void i2c_lld_init(void) { i2cObjectInit(&I2CD1); I2CD1.thread = NULL; I2CD1.i2c = I2C1; +#if STM32_I2C_USE_DMA == TRUE I2CD1.dmarx = NULL; I2CD1.dmatx = NULL; +#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 = NULL; I2CD2.dmatx = NULL; +#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 = NULL; I2CD3.dmatx = NULL; +#endif #endif /* STM32_I2C_USE_I2C3 */ } @@ -682,6 +836,7 @@ void i2c_lld_start(I2CDriver *i2cp) { /* If in stopped state then enables the I2C and DMA clocks.*/ if (i2cp->state == I2C_STOP) { +#if STM32_I2C_USE_DMA == TRUE 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 | @@ -690,11 +845,12 @@ void i2c_lld_start(I2CDriver *i2cp) { STM32_DMA_CR_MINC | STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_TCIE | STM32_DMA_CR_DIR_P2M; +#endif #if STM32_I2C_USE_I2C1 if (&I2CD1 == i2cp) { rccResetI2C1(); - +#if STM32_I2C_USE_DMA == TRUE i2cp->dmarx = dmaStreamAllocI(STM32_I2C_I2C1_RX_DMA_STREAM, STM32_I2C_I2C1_IRQ_PRIORITY, (stm32_dmaisr_t)i2c_lld_serve_rx_end_irq, @@ -706,21 +862,21 @@ void i2c_lld_start(I2CDriver *i2cp) { (void *)i2cp); osalDbgAssert(i2cp->dmatx != NULL, "unable to allocate stream"); - rccEnableI2C1(true); - 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_DMA == TRUE */ + rccEnableI2C1(true); + nvicEnableVector(I2C1_EV_IRQn, STM32_I2C_I2C1_IRQ_PRIORITY); + nvicEnableVector(I2C1_ER_IRQn, STM32_I2C_I2C1_IRQ_PRIORITY); } #endif /* STM32_I2C_USE_I2C1 */ #if STM32_I2C_USE_I2C2 if (&I2CD2 == i2cp) { rccResetI2C2(); - +#if STM32_I2C_USE_DMA == TRUE i2cp->dmarx = dmaStreamAllocI(STM32_I2C_I2C2_RX_DMA_STREAM, STM32_I2C_I2C2_IRQ_PRIORITY, (stm32_dmaisr_t)i2c_lld_serve_rx_end_irq, @@ -732,21 +888,21 @@ void i2c_lld_start(I2CDriver *i2cp) { (void *)i2cp); osalDbgAssert(i2cp->dmatx != NULL, "unable to allocate stream"); - rccEnableI2C2(true); - 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_DMA == TRUE */ + rccEnableI2C2(true); + nvicEnableVector(I2C2_EV_IRQn, STM32_I2C_I2C2_IRQ_PRIORITY); + nvicEnableVector(I2C2_ER_IRQn, STM32_I2C_I2C2_IRQ_PRIORITY); } #endif /* STM32_I2C_USE_I2C2 */ #if STM32_I2C_USE_I2C3 if (&I2CD3 == i2cp) { rccResetI2C3(); - +#if STM32_I2C_USE_DMA == TRUE i2cp->dmarx = dmaStreamAllocI(STM32_I2C_I2C3_RX_DMA_STREAM, STM32_I2C_I2C3_IRQ_PRIORITY, (stm32_dmaisr_t)i2c_lld_serve_rx_end_irq, @@ -758,26 +914,33 @@ void i2c_lld_start(I2CDriver *i2cp) { (void *)i2cp); osalDbgAssert(i2cp->dmatx != NULL, "unable to allocate stream"); - rccEnableI2C3(true); - 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_DMA == TRUE */ + rccEnableI2C3(true); + nvicEnableVector(I2C3_EV_IRQn, STM32_I2C_I2C3_IRQ_PRIORITY); + nvicEnableVector(I2C3_ER_IRQn, STM32_I2C_I2C3_IRQ_PRIORITY); } #endif /* STM32_I2C_USE_I2C3 */ } +#if STM32_I2C_USE_DMA == TRUE /* I2C registers pointed by the DMA.*/ dmaStreamSetPeripheral(i2cp->dmarx, &dp->DR); dmaStreamSetPeripheral(i2cp->dmatx, &dp->DR); +#else + i2cp->txbytes = 0; + i2cp->rxbytes = 0; +#endif /* Reset i2c peripheral.*/ dp->CR1 = I2C_CR1_SWRST; dp->CR1 = 0; - dp->CR2 = I2C_CR2_ITERREN | I2C_CR2_DMAEN; +#if STM32_I2C_USE_DMA == TRUE + dp->CR2 = I2C_CR2_DMAEN; +#endif /* Setup I2C parameters.*/ i2c_lld_set_clock(i2cp); @@ -804,10 +967,12 @@ void i2c_lld_stop(I2CDriver *i2cp) { /* I2C disable.*/ i2c_lld_abort_operation(i2cp); +#if STM32_I2C_USE_DMA == TRUE dmaStreamFreeI(i2cp->dmatx); dmaStreamFreeI(i2cp->dmarx); i2cp->dmatx = NULL; i2cp->dmarx = NULL; +#endif #if STM32_I2C_USE_I2C1 if (&I2CD1 == i2cp) { @@ -847,11 +1012,16 @@ void i2c_lld_soft_stop(I2CDriver *i2cp) { /* If not in stopped state then disables the I2C clock.*/ if (i2cp->state != I2C_STOP) { +#if STM32_I2C_USE_DMA == TRUE /* I2C disable.*/ dmaStreamFreeI(i2cp->dmatx); dmaStreamFreeI(i2cp->dmarx); i2cp->dmatx = NULL; i2cp->dmarx = NULL; +#else + i2cp->txbytes = 0; + i2cp->rxbytes = 0; +#endif #if STM32_I2C_USE_I2C1 if (&I2CD1 == i2cp) { @@ -931,22 +1101,29 @@ msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, /* Releases the lock from high level driver.*/ osalSysUnlock(); +#if STM32_I2C_USE_DMA == TRUE /* RX DMA setup.*/ dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode); dmaStreamSetMemory0(i2cp->dmarx, rxbuf); dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes); +#else + i2cp->rxptr = rxbuf; + i2cp->rxbytes = rxbytes; +#endif osalSysLock(); i2cp->in_transaction = true; /* Starts the operation.*/ - dp->CR2 |= I2C_CR2_ITEVTEN; + dp->CR2 |= I2C_CR2_ITEVTEN | I2C_CR2_ITERREN; dp->CR1 |= I2C_CR1_START | I2C_CR1_ACK; /* Waits for the operation completion or a timeout.*/ msg = osalThreadSuspendTimeoutS(&i2cp->thread, timeout); +#if STM32_I2C_USE_DMA == TRUE dmaStreamDisable(i2cp->dmarx); +#endif i2cp->in_transaction = false; @@ -1010,6 +1187,7 @@ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr, /* Releases the lock from high level driver.*/ osalSysUnlock(); +#if STM32_I2C_USE_DMA == TRUE /* TX DMA setup.*/ dmaStreamSetMode(i2cp->dmatx, i2cp->txdmamode); dmaStreamSetMemory0(i2cp->dmatx, txbuf); @@ -1019,19 +1197,28 @@ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr, dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode); dmaStreamSetMemory0(i2cp->dmarx, rxbuf); dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes); +#else + i2cp->txptr = txbuf; + i2cp->txbytes = txbytes; + i2cp->rxptr = rxbuf; + i2cp->rxbytes = rxbytes; +#endif osalSysLock(); i2cp->in_transaction = true; /* Starts the operation.*/ - dp->CR2 |= I2C_CR2_ITEVTEN; + dp->CR2 |= I2C_CR2_ITEVTEN | I2C_CR2_ITERREN; dp->CR1 |= I2C_CR1_START; /* Waits for the operation completion or a timeout.*/ msg = osalThreadSuspendTimeoutS(&i2cp->thread, timeout); + +#if STM32_I2C_USE_DMA == TRUE dmaStreamDisable(i2cp->dmatx); dmaStreamDisable(i2cp->dmarx); +#endif i2cp->in_transaction = false; diff --git a/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.h b/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.h index 6575a6576d..aa2d223441 100644 --- a/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.h +++ b/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.h @@ -104,6 +104,13 @@ #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 @@ -253,6 +260,7 @@ #error "Invalid IRQ priority assigned to I2C3" #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" @@ -323,6 +331,7 @@ #if !defined(STM32_DMA_REQUIRED) #define STM32_DMA_REQUIRED #endif +#endif /* STM32_I2C_USE_DMA == TRUE */ /* Check clock range. */ #if defined(STM32F4XX) @@ -445,6 +454,7 @@ struct hal_i2c_driver { * @brief Current slave address without R/W bit. */ i2caddr_t addr; +#if (STM32_I2C_USE_DMA == TRUE) || defined(__DOXYGEN__) /** * @brief RX DMA mode bit mask. */ @@ -461,6 +471,24 @@ struct hal_i2c_driver { * @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; + /** + * @brief Pointer to the next RX buffer location. + */ + uint8_t *rxptr; + /** + * @brief Number of bytes in RX phase. + */ + size_t rxbytes; +#endif /* STM32_I2C_USE_DMA == FALSE */ /** * @brief Pointer to the I2Cx registers block. */