diff --git a/os/hal/platforms/STM32/i2c_lld.c b/os/hal/platforms/STM32/i2c_lld.c index c81fdad28..589c8018e 100644 --- a/os/hal/platforms/STM32/i2c_lld.c +++ b/os/hal/platforms/STM32/i2c_lld.c @@ -76,16 +76,24 @@ #define I2C_EV5_MASTER_MODE_SELECT \ ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY) << 16) | I2C_SR1_SB)) + #define I2C_EV6_MASTER_TRA_MODE_SELECTED \ - ((uint32_t)(((I2C_SR2_MSL|I2C_SR2_BUSY|I2C_SR2_TRA) << 16) | \ - I2C_SR1_ADDR|I2C_SR1_TXE)) + ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY | I2C_SR2_TRA) << 16) | \ + I2C_SR1_ADDR | I2C_SR1_TXE)) + #define I2C_EV6_MASTER_REC_MODE_SELECTED \ - ((uint32_t)(((I2C_SR2_MSL|I2C_SR2_BUSY)<< 16) | I2C_SR1_ADDR)) + ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY)<< 16) | I2C_SR1_ADDR)) + #define I2C_EV8_2_MASTER_BYTE_TRANSMITTED \ ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY | I2C_SR2_TRA) << 16) | \ I2C_SR1_BTF | I2C_SR1_TXE)) + #define I2C_EV_MASK 0x00FFFFFF +#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. */ /*===========================================================================*/ @@ -106,18 +114,9 @@ I2CDriver I2CD3; #endif /*===========================================================================*/ -/* Driver local variables. */ +/* Driver local variables and types. */ /*===========================================================================*/ -/* The following variables have debugging purpose only and are included when - the option CH_DBG_ENABLE_ASSERTS is enabled.*/ -#if CH_DBG_ENABLE_ASSERTS -static volatile uint16_t dbgSR1; -static volatile uint16_t dbgSR2; -static volatile uint16_t dbgCR1; -static volatile uint16_t dbgCR2; -#endif /* CH_DBG_ENABLE_ASSERTS */ - /*===========================================================================*/ /* Driver local functions. */ /*===========================================================================*/ @@ -299,13 +298,13 @@ static void i2c_lld_set_opmode(I2CDriver *i2cp) { */ static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) { I2C_TypeDef *dp = i2cp->i2c; - uint32_t regSR = dp->SR2; + uint32_t regSR2 = dp->SR2; uint32_t event = dp->SR1; /* 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 | (regSR << 16))) { + switch (I2C_EV_MASK & (event | (regSR2 << 16))) { case I2C_EV5_MASTER_MODE_SELECT: dp->DR = i2cp->addr; break; @@ -398,57 +397,45 @@ static void i2c_lld_serve_tx_end_irq(I2CDriver *i2cp, uint32_t flags) { * @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) { - I2C_TypeDef *dp = i2cp->i2c; - i2cflags_t errors; +static void i2c_lld_serve_error_interrupt(I2CDriver *i2cp, uint16_t sr) { /* Clears interrupt flags just to be safe.*/ - chSysLockFromIsr(); dmaStreamDisable(i2cp->dmatx); dmaStreamDisable(i2cp->dmarx); - chSysUnlockFromIsr(); - errors = I2CD_NO_ERROR; + i2cp->errors = I2CD_NO_ERROR; - if (dp->SR1 & I2C_SR1_BERR) { /* Bus error. */ - dp->SR1 &= ~I2C_SR1_BERR; - errors |= I2CD_BUS_ERROR; - } - if (dp->SR1 & I2C_SR1_ARLO) { /* Arbitration lost. */ - dp->SR1 &= ~I2C_SR1_ARLO; - errors |= I2CD_ARBITRATION_LOST; - } - if (dp->SR1 & I2C_SR1_AF) { /* Acknowledge fail. */ - dp->SR1 &= ~I2C_SR1_AF; - dp->CR2 &= ~I2C_CR2_ITEVTEN; - dp->CR1 |= I2C_CR1_STOP; /* Setting stop bit. */ - errors |= I2CD_ACK_FAILURE; - } - if (dp->SR1 & I2C_SR1_OVR) { /* Overrun. */ - dp->SR1 &= ~I2C_SR1_OVR; - errors |= I2CD_OVERRUN; - } - if (dp->SR1 & I2C_SR1_PECERR) { /* PEC error. */ - dp->SR1 &= ~I2C_SR1_PECERR; - errors |= I2CD_PEC_ERROR; - } - if (dp->SR1 & I2C_SR1_TIMEOUT) { /* SMBus Timeout. */ - dp->SR1 &= ~I2C_SR1_TIMEOUT; - errors |= I2CD_TIMEOUT; - } - if (dp->SR1 & I2C_SR1_SMBALERT) { /* SMBus alert. */ - dp->SR1 &= ~I2C_SR1_SMBALERT; - errors |= I2CD_SMB_ALERT; + if (sr & I2C_SR1_BERR) /* Bus error. */ + i2cp->errors |= I2CD_BUS_ERROR; + + if (sr & I2C_SR1_ARLO) /* Arbitration lost. */ + i2cp->errors |= I2CD_ARBITRATION_LOST; + + if (sr & I2C_SR1_AF) { /* Acknowledge fail. */ + i2cp->i2c->CR2 &= ~I2C_CR2_ITEVTEN; + i2cp->i2c->CR1 |= I2C_CR1_STOP; /* Setting stop bit. */ + i2cp->errors |= I2CD_ACK_FAILURE; } + if (sr & I2C_SR1_OVR) /* Overrun. */ + i2cp->errors |= I2CD_OVERRUN; + + if (sr & I2C_SR1_TIMEOUT) /* SMBus Timeout. */ + i2cp->errors |= I2CD_TIMEOUT; + + if (sr & I2C_SR1_PECERR) /* PEC error. */ + i2cp->errors |= I2CD_PEC_ERROR; + + if (sr & I2C_SR1_SMBALERT) /* SMBus alert. */ + i2cp->errors |= I2CD_SMB_ALERT; + /* If some error has been identified then sends wakes the waiting thread.*/ - if (errors != I2CD_NO_ERROR) { - i2cp->errors = errors; + if (i2cp->errors != I2CD_NO_ERROR) wakeup_isr(i2cp, RDY_RESET); - } } /*===========================================================================*/ @@ -474,10 +461,12 @@ CH_IRQ_HANDLER(I2C1_EV_IRQHandler) { * @brief I2C1 error interrupt handler. */ CH_IRQ_HANDLER(I2C1_ER_IRQHandler) { + uint16_t sr = I2CD1.i2c->SR1; CH_IRQ_PROLOGUE(); - i2c_lld_serve_error_interrupt(&I2CD1); + I2CD1.i2c->SR1 = ~(sr & I2C_ERROR_MASK); + i2c_lld_serve_error_interrupt(&I2CD1, sr); CH_IRQ_EPILOGUE(); } @@ -504,10 +493,12 @@ CH_IRQ_HANDLER(I2C2_EV_IRQHandler) { * @notapi */ CH_IRQ_HANDLER(I2C2_ER_IRQHandler) { + uint16_t sr = I2CD2.i2c->SR1; CH_IRQ_PROLOGUE(); - i2c_lld_serve_error_interrupt(&I2CD2); + I2CD2.i2c->SR1 = ~(sr & I2C_ERROR_MASK); + i2c_lld_serve_error_interrupt(&I2CD2, sr); CH_IRQ_EPILOGUE(); } @@ -534,10 +525,12 @@ CH_IRQ_HANDLER(I2C3_EV_IRQHandler) { * @notapi */ CH_IRQ_HANDLER(I2C3_ER_IRQHandler) { + uint16_t sr = I2CD3.i2c->SR1; CH_IRQ_PROLOGUE(); - i2c_lld_serve_error_interrupt(&I2CD3); + I2CD3.i2c->SR1 = ~(sr & I2C_ERROR_MASK); + i2c_lld_serve_error_interrupt(&I2CD3, sr); CH_IRQ_EPILOGUE(); } @@ -589,9 +582,14 @@ void i2c_lld_init(void) { void i2c_lld_start(I2CDriver *i2cp) { I2C_TypeDef *dp = i2cp->i2c; - i2cp->dmamode = 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; + 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) { @@ -617,7 +615,9 @@ void i2c_lld_start(I2CDriver *i2cp) { nvicEnableVector(I2C1_ER_IRQn, CORTEX_PRIORITY_MASK(STM32_I2C_I2C1_IRQ_PRIORITY)); - i2cp->dmamode |= STM32_DMA_CR_CHSEL(I2C1_RX_DMA_CHANNEL) | + 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 */ @@ -643,7 +643,9 @@ void i2c_lld_start(I2CDriver *i2cp) { nvicEnableVector(I2C2_ER_IRQn, CORTEX_PRIORITY_MASK(STM32_I2C_I2C2_IRQ_PRIORITY)); - i2cp->dmamode |= STM32_DMA_CR_CHSEL(I2C2_RX_DMA_CHANNEL) | + 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 */ @@ -669,16 +671,14 @@ void i2c_lld_start(I2CDriver *i2cp) { nvicEnableVector(I2C3_ER_IRQn, CORTEX_PRIORITY_MASK(STM32_I2C_I2C3_IRQ_PRIORITY)); - i2cp->dmamode |= STM32_DMA_CR_CHSEL(I2C3_RX_DMA_CHANNEL) | + 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 */ } - /* DMA streams mode preparation in advance.*/ - dmaStreamSetMode(i2cp->dmatx, i2cp->dmamode | STM32_DMA_CR_DIR_M2P); - dmaStreamSetMode(i2cp->dmarx, i2cp->dmamode | STM32_DMA_CR_DIR_P2M); - /* I2C registers pointed by the DMA.*/ dmaStreamSetPeripheral(i2cp->dmarx, &dp->DR); dmaStreamSetPeripheral(i2cp->dmatx, &dp->DR); @@ -741,8 +741,8 @@ void i2c_lld_stop(I2CDriver *i2cp) { /** * @brief Receives data via the I2C bus as master. - * @details Number of receiving bytes must be more than 1 because of stm32 - * hardware restrictions. + * @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 @@ -784,6 +784,7 @@ msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, i2cp->errors = 0; /* RX DMA setup.*/ + dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode); dmaStreamSetMemory0(i2cp->dmarx, rxbuf); dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes); @@ -819,8 +820,8 @@ msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, /** * @brief Transmits data via the I2C bus as master. - * @details Number of receiving bytes must be 0 or more than 1 because of stm32 - * hardware restrictions. + * @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 @@ -866,10 +867,12 @@ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr, i2cp->errors = 0; /* TX DMA setup.*/ + dmaStreamSetMode(i2cp->dmatx, i2cp->txdmamode); dmaStreamSetMemory0(i2cp->dmatx, txbuf); dmaStreamSetTransactionSize(i2cp->dmatx, txbytes); /* RX DMA setup.*/ + dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode); dmaStreamSetMemory0(i2cp->dmarx, rxbuf); dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes); diff --git a/os/hal/platforms/STM32/i2c_lld.h b/os/hal/platforms/STM32/i2c_lld.h index 0bc19bfe1..563375c70 100644 --- a/os/hal/platforms/STM32/i2c_lld.h +++ b/os/hal/platforms/STM32/i2c_lld.h @@ -207,7 +207,7 @@ #endif /* !STM32_ADVANCED_DMA*/ -/* Flag for whole STM32F1XX family. */ +/* Flag for the whole STM32F1XX family. */ #if defined(STM32F10X_LD_VL) || defined(STM32F10X_MD_VL) || \ defined(STM32F10X_LD) || defined(STM32F10X_MD) || \ defined(STM32F10X_HD) || defined(STM32F10X_XL) || \ @@ -362,7 +362,7 @@ typedef struct I2CDriver I2CDriver; /** * @brief Structure representing an I2C driver. */ -struct I2CDriver{ +struct I2CDriver { /** * @brief Driver state. */ @@ -398,9 +398,13 @@ struct I2CDriver{ */ i2caddr_t addr; /** - * @brief DMA mode bit mask. + * @brief RX DMA mode bit mask. */ - uint32_t dmamode; + uint32_t rxdmamode; + /** + * @brief TX DMA mode bit mask. + */ + uint32_t txdmamode; /** * @brief Receive DMA channel. */ diff --git a/readme.txt b/readme.txt index 314f71736..3e4df282c 100644 --- a/readme.txt +++ b/readme.txt @@ -79,6 +79,7 @@ ***************************************************************************** *** 2.4.4 *** +- FIX: Fixed fixed I2C malfunction after fixing bug 3607518 (bug 3607549). - FIX: Fixed spurious interrupt disabling an STM32 DMA stream (bug 3607518). - FIX: Fixed start of any ADC disables VREF and VBAT (bug 3607467). - FIX: Fixed CAN_USE_SLEEP_MODE compilation problem (bug 3606616).