Fixed bug 3607549.

git-svn-id: svn://svn.code.sf.net/p/chibios/svn/branches/stable_2.4.x@5561 35acf78f-673a-0410-8e92-d51de3d6d3f4
This commit is contained in:
gdisirio 2013-04-07 10:41:45 +00:00
parent 4e966709c6
commit b68482253f
3 changed files with 82 additions and 74 deletions

View File

@ -76,16 +76,24 @@
#define I2C_EV5_MASTER_MODE_SELECT \ #define I2C_EV5_MASTER_MODE_SELECT \
((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY) << 16) | I2C_SR1_SB)) ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY) << 16) | I2C_SR1_SB))
#define I2C_EV6_MASTER_TRA_MODE_SELECTED \ #define I2C_EV6_MASTER_TRA_MODE_SELECTED \
((uint32_t)(((I2C_SR2_MSL|I2C_SR2_BUSY|I2C_SR2_TRA) << 16) | \ ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY | I2C_SR2_TRA) << 16) | \
I2C_SR1_ADDR|I2C_SR1_TXE)) I2C_SR1_ADDR | I2C_SR1_TXE))
#define I2C_EV6_MASTER_REC_MODE_SELECTED \ #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 \ #define I2C_EV8_2_MASTER_BYTE_TRANSMITTED \
((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY | I2C_SR2_TRA) << 16) | \ ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY | I2C_SR2_TRA) << 16) | \
I2C_SR1_BTF | I2C_SR1_TXE)) I2C_SR1_BTF | I2C_SR1_TXE))
#define I2C_EV_MASK 0x00FFFFFF #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. */ /* Driver exported variables. */
/*===========================================================================*/ /*===========================================================================*/
@ -106,18 +114,9 @@ I2CDriver I2CD3;
#endif #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. */ /* Driver local functions. */
/*===========================================================================*/ /*===========================================================================*/
@ -299,13 +298,13 @@ static void i2c_lld_set_opmode(I2CDriver *i2cp) {
*/ */
static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) { static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) {
I2C_TypeDef *dp = i2cp->i2c; I2C_TypeDef *dp = i2cp->i2c;
uint32_t regSR = dp->SR2; uint32_t regSR2 = dp->SR2;
uint32_t event = dp->SR1; uint32_t event = dp->SR1;
/* Interrupts are disabled just before dmaStreamEnable() because there /* Interrupts are disabled just before dmaStreamEnable() because there
is no need of interrupts until next transaction begin. All the work is is no need of interrupts until next transaction begin. All the work is
done by the DMA.*/ done by the DMA.*/
switch (I2C_EV_MASK & (event | (regSR << 16))) { switch (I2C_EV_MASK & (event | (regSR2 << 16))) {
case I2C_EV5_MASTER_MODE_SELECT: case I2C_EV5_MASTER_MODE_SELECT:
dp->DR = i2cp->addr; dp->DR = i2cp->addr;
break; break;
@ -398,57 +397,45 @@ static void i2c_lld_serve_tx_end_irq(I2CDriver *i2cp, uint32_t flags) {
* @brief I2C error handler. * @brief I2C error handler.
* *
* @param[in] i2cp pointer to the @p I2CDriver object * @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] sr content of the SR1 register to be decoded
* *
* @notapi * @notapi
*/ */
static void i2c_lld_serve_error_interrupt(I2CDriver *i2cp) { static void i2c_lld_serve_error_interrupt(I2CDriver *i2cp, uint16_t sr) {
I2C_TypeDef *dp = i2cp->i2c;
i2cflags_t errors;
/* Clears interrupt flags just to be safe.*/ /* Clears interrupt flags just to be safe.*/
chSysLockFromIsr();
dmaStreamDisable(i2cp->dmatx); dmaStreamDisable(i2cp->dmatx);
dmaStreamDisable(i2cp->dmarx); dmaStreamDisable(i2cp->dmarx);
chSysUnlockFromIsr();
errors = I2CD_NO_ERROR; i2cp->errors = I2CD_NO_ERROR;
if (dp->SR1 & I2C_SR1_BERR) { /* Bus error. */ if (sr & I2C_SR1_BERR) /* Bus error. */
dp->SR1 &= ~I2C_SR1_BERR; i2cp->errors |= I2CD_BUS_ERROR;
errors |= I2CD_BUS_ERROR;
} if (sr & I2C_SR1_ARLO) /* Arbitration lost. */
if (dp->SR1 & I2C_SR1_ARLO) { /* Arbitration lost. */ i2cp->errors |= I2CD_ARBITRATION_LOST;
dp->SR1 &= ~I2C_SR1_ARLO;
errors |= I2CD_ARBITRATION_LOST; if (sr & I2C_SR1_AF) { /* Acknowledge fail. */
} i2cp->i2c->CR2 &= ~I2C_CR2_ITEVTEN;
if (dp->SR1 & I2C_SR1_AF) { /* Acknowledge fail. */ i2cp->i2c->CR1 |= I2C_CR1_STOP; /* Setting stop bit. */
dp->SR1 &= ~I2C_SR1_AF; i2cp->errors |= I2CD_ACK_FAILURE;
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_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 some error has been identified then sends wakes the waiting thread.*/
if (errors != I2CD_NO_ERROR) { if (i2cp->errors != I2CD_NO_ERROR)
i2cp->errors = errors;
wakeup_isr(i2cp, RDY_RESET); wakeup_isr(i2cp, RDY_RESET);
}
} }
/*===========================================================================*/ /*===========================================================================*/
@ -474,10 +461,12 @@ CH_IRQ_HANDLER(I2C1_EV_IRQHandler) {
* @brief I2C1 error interrupt handler. * @brief I2C1 error interrupt handler.
*/ */
CH_IRQ_HANDLER(I2C1_ER_IRQHandler) { CH_IRQ_HANDLER(I2C1_ER_IRQHandler) {
uint16_t sr = I2CD1.i2c->SR1;
CH_IRQ_PROLOGUE(); 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(); CH_IRQ_EPILOGUE();
} }
@ -504,10 +493,12 @@ CH_IRQ_HANDLER(I2C2_EV_IRQHandler) {
* @notapi * @notapi
*/ */
CH_IRQ_HANDLER(I2C2_ER_IRQHandler) { CH_IRQ_HANDLER(I2C2_ER_IRQHandler) {
uint16_t sr = I2CD2.i2c->SR1;
CH_IRQ_PROLOGUE(); 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(); CH_IRQ_EPILOGUE();
} }
@ -534,10 +525,12 @@ CH_IRQ_HANDLER(I2C3_EV_IRQHandler) {
* @notapi * @notapi
*/ */
CH_IRQ_HANDLER(I2C3_ER_IRQHandler) { CH_IRQ_HANDLER(I2C3_ER_IRQHandler) {
uint16_t sr = I2CD3.i2c->SR1;
CH_IRQ_PROLOGUE(); 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(); CH_IRQ_EPILOGUE();
} }
@ -589,9 +582,14 @@ void i2c_lld_init(void) {
void i2c_lld_start(I2CDriver *i2cp) { void i2c_lld_start(I2CDriver *i2cp) {
I2C_TypeDef *dp = i2cp->i2c; I2C_TypeDef *dp = i2cp->i2c;
i2cp->dmamode = STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE | 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_MINC | STM32_DMA_CR_DMEIE |
STM32_DMA_CR_TCIE; 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 in stopped state then enables the I2C and DMA clocks.*/
if (i2cp->state == I2C_STOP) { if (i2cp->state == I2C_STOP) {
@ -617,7 +615,9 @@ void i2c_lld_start(I2CDriver *i2cp) {
nvicEnableVector(I2C1_ER_IRQn, nvicEnableVector(I2C1_ER_IRQn,
CORTEX_PRIORITY_MASK(STM32_I2C_I2C1_IRQ_PRIORITY)); 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); STM32_DMA_CR_PL(STM32_I2C_I2C1_DMA_PRIORITY);
} }
#endif /* STM32_I2C_USE_I2C1 */ #endif /* STM32_I2C_USE_I2C1 */
@ -643,7 +643,9 @@ void i2c_lld_start(I2CDriver *i2cp) {
nvicEnableVector(I2C2_ER_IRQn, nvicEnableVector(I2C2_ER_IRQn,
CORTEX_PRIORITY_MASK(STM32_I2C_I2C2_IRQ_PRIORITY)); 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); STM32_DMA_CR_PL(STM32_I2C_I2C2_DMA_PRIORITY);
} }
#endif /* STM32_I2C_USE_I2C2 */ #endif /* STM32_I2C_USE_I2C2 */
@ -669,16 +671,14 @@ void i2c_lld_start(I2CDriver *i2cp) {
nvicEnableVector(I2C3_ER_IRQn, nvicEnableVector(I2C3_ER_IRQn,
CORTEX_PRIORITY_MASK(STM32_I2C_I2C3_IRQ_PRIORITY)); 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); STM32_DMA_CR_PL(STM32_I2C_I2C3_DMA_PRIORITY);
} }
#endif /* STM32_I2C_USE_I2C3 */ #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.*/ /* I2C registers pointed by the DMA.*/
dmaStreamSetPeripheral(i2cp->dmarx, &dp->DR); dmaStreamSetPeripheral(i2cp->dmarx, &dp->DR);
dmaStreamSetPeripheral(i2cp->dmatx, &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. * @brief Receives data via the I2C bus as master.
* @details Number of receiving bytes must be more than 1 because of stm32 * @details Number of receiving bytes must be more than 1 on STM32F1x. This is
* hardware restrictions. * hardware restriction.
* *
* @param[in] i2cp pointer to the @p I2CDriver object * @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] addr slave device address * @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; i2cp->errors = 0;
/* RX DMA setup.*/ /* RX DMA setup.*/
dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode);
dmaStreamSetMemory0(i2cp->dmarx, rxbuf); dmaStreamSetMemory0(i2cp->dmarx, rxbuf);
dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes); 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. * @brief Transmits data via the I2C bus as master.
* @details Number of receiving bytes must be 0 or more than 1 because of stm32 * @details Number of receiving bytes must be 0 or more than 1 on STM32F1x.
* hardware restrictions. * This is hardware restriction.
* *
* @param[in] i2cp pointer to the @p I2CDriver object * @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] addr slave device address * @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; i2cp->errors = 0;
/* TX DMA setup.*/ /* TX DMA setup.*/
dmaStreamSetMode(i2cp->dmatx, i2cp->txdmamode);
dmaStreamSetMemory0(i2cp->dmatx, txbuf); dmaStreamSetMemory0(i2cp->dmatx, txbuf);
dmaStreamSetTransactionSize(i2cp->dmatx, txbytes); dmaStreamSetTransactionSize(i2cp->dmatx, txbytes);
/* RX DMA setup.*/ /* RX DMA setup.*/
dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode);
dmaStreamSetMemory0(i2cp->dmarx, rxbuf); dmaStreamSetMemory0(i2cp->dmarx, rxbuf);
dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes); dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes);

View File

@ -207,7 +207,7 @@
#endif /* !STM32_ADVANCED_DMA*/ #endif /* !STM32_ADVANCED_DMA*/
/* Flag for whole STM32F1XX family. */ /* Flag for the whole STM32F1XX family. */
#if defined(STM32F10X_LD_VL) || defined(STM32F10X_MD_VL) || \ #if defined(STM32F10X_LD_VL) || defined(STM32F10X_MD_VL) || \
defined(STM32F10X_LD) || defined(STM32F10X_MD) || \ defined(STM32F10X_LD) || defined(STM32F10X_MD) || \
defined(STM32F10X_HD) || defined(STM32F10X_XL) || \ defined(STM32F10X_HD) || defined(STM32F10X_XL) || \
@ -362,7 +362,7 @@ typedef struct I2CDriver I2CDriver;
/** /**
* @brief Structure representing an I2C driver. * @brief Structure representing an I2C driver.
*/ */
struct I2CDriver{ struct I2CDriver {
/** /**
* @brief Driver state. * @brief Driver state.
*/ */
@ -398,9 +398,13 @@ struct I2CDriver{
*/ */
i2caddr_t addr; 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. * @brief Receive DMA channel.
*/ */

View File

@ -79,6 +79,7 @@
***************************************************************************** *****************************************************************************
*** 2.4.4 *** *** 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 spurious interrupt disabling an STM32 DMA stream (bug 3607518).
- FIX: Fixed start of any ADC disables VREF and VBAT (bug 3607467). - FIX: Fixed start of any ADC disables VREF and VBAT (bug 3607467).
- FIX: Fixed CAN_USE_SLEEP_MODE compilation problem (bug 3606616). - FIX: Fixed CAN_USE_SLEEP_MODE compilation problem (bug 3606616).