Merged in david_s5/nuttx/master_f7_i2c_txe_fix (pull request #854)

stm32f7:i2c track bad state

The previous commit was true draconian.
   Now we track bad state and so the SW
   reset only when it occurs.

Approved-by: Gregory Nutt <gnutt@nuttx.org>
This commit is contained in:
David Sidrane
2019-04-17 13:50:11 +00:00
committed by Gregory Nutt
parent 53a94594d6
commit 9c08d7fa42
+39 -20
View File
@@ -112,7 +112,7 @@
* *
* - Private: Private data of an I2C Hardware * - Private: Private data of an I2C Hardware
* *
* High Level Functional Desecription * High Level Functional Description
* *
* This driver works with I2C "messages" (struct i2c_msg_s), which carry a buffer * This driver works with I2C "messages" (struct i2c_msg_s), which carry a buffer
* intended to transfer data to, or store data read from, the I2C bus. * intended to transfer data to, or store data read from, the I2C bus.
@@ -137,7 +137,7 @@
* Interrupt mode relies on the following interrupt events: * Interrupt mode relies on the following interrupt events:
* *
* TXIS - Transmit interrupt * TXIS - Transmit interrupt
* (data transmitted to bus and acknowedged) * (data transmitted to bus and acknowledged)
* NACKF - Not Acknowledge Received * NACKF - Not Acknowledge Received
* (data transmitted to bus and NOT acknowledged) * (data transmitted to bus and NOT acknowledged)
* RXNE - Receive interrupt * RXNE - Receive interrupt
@@ -324,8 +324,14 @@
#define MKI2C_OUTPUT(p) (((p) & (GPIO_PORT_MASK | GPIO_PIN_MASK)) | I2C_OUTPUT) #define MKI2C_OUTPUT(p) (((p) & (GPIO_PORT_MASK | GPIO_PIN_MASK)) | I2C_OUTPUT)
#define I2C_CR1_TXRX (I2C_CR1_RXIE | I2C_CR1_TXIE) #define I2C_CR1_TXRX (I2C_CR1_RXIE | I2C_CR1_TXIE)
#define I2C_CR1_ALLINTS (I2C_CR1_TXRX | I2C_CR1_TCIE | I2C_CR1_ERRIE) #define I2C_CR1_ALLINTS (I2C_CR1_TXRX | I2C_CR1_TCIE | I2C_CR1_ERRIE)
/* Unused bit in I2c_ISR used to communicate a bad state has occurred in
* the isr processing
*/
#define I2C_INT_BAD_STATE 0x8000000
/* I2C event tracing /* I2C event tracing
* *
@@ -421,7 +427,7 @@ struct stm32_i2c_config_s
struct stm32_i2c_priv_s struct stm32_i2c_priv_s
{ {
const struct stm32_i2c_config_s *config; /* Port configuration */ const struct stm32_i2c_config_s *config; /* Port configuration */
int refs; /* Referernce count */ int refs; /* Reference count */
sem_t sem_excl; /* Mutual exclusion semaphore */ sem_t sem_excl; /* Mutual exclusion semaphore */
#ifndef CONFIG_I2C_POLLED #ifndef CONFIG_I2C_POLLED
sem_t sem_isr; /* Interrupt wait semaphore */ sem_t sem_isr; /* Interrupt wait semaphore */
@@ -1597,9 +1603,9 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv)
i2cinfo("ENTER: status = 0x%08x\n", status); i2cinfo("ENTER: status = 0x%08x\n", status);
/* Update private version of the state */ /* Update private version of the state assuming a good state */
priv->status = status; priv->status = status & ~I2C_INT_BAD_STATE;
/* If this is a new transmission set up the trace table accordingly */ /* If this is a new transmission set up the trace table accordingly */
@@ -1677,7 +1683,7 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv)
* interrupt will only fire when the I2C_CR1->TXIE bit is 1. * interrupt will only fire when the I2C_CR1->TXIE bit is 1.
* *
* This indicates the transmit data register I2C_TXDR has been emptied * This indicates the transmit data register I2C_TXDR has been emptied
* following the successful transmission of a byte and slave acknowledgement. * following the successful transmission of a byte and slave acknowledgment.
* In this state the I2C_TXDR register is ready to accept another byte for * In this state the I2C_TXDR register is ready to accept another byte for
* transmission. The TXIS bit will be cleared automatically when the next * transmission. The TXIS bit will be cleared automatically when the next
* byte is written to I2C_TXDR. * byte is written to I2C_TXDR.
@@ -1768,6 +1774,10 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv)
i2cerr("ERROR: TXIS Unsupported state detected, dcnt=%i, status 0x%08x\n", i2cerr("ERROR: TXIS Unsupported state detected, dcnt=%i, status 0x%08x\n",
priv->dcnt, status); priv->dcnt, status);
stm32_i2c_traceevent(priv, I2CEVENT_WRITE_ERROR, 0); stm32_i2c_traceevent(priv, I2CEVENT_WRITE_ERROR, 0);
/* Indicate the bad state, so that on termination HW will be reset */
priv->status |= I2C_INT_BAD_STATE;
} }
i2cinfo("TXIS: EXIT dcnt = %i msgc = %i status 0x%08x\n", i2cinfo("TXIS: EXIT dcnt = %i msgc = %i status 0x%08x\n",
@@ -1856,6 +1866,7 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv)
/* Set signals that will terminate ISR and wake waiting thread */ /* Set signals that will terminate ISR and wake waiting thread */
priv->status |= I2C_INT_BAD_STATE;
priv->dcnt = -1; priv->dcnt = -1;
priv->msgc = 0; priv->msgc = 0;
} }
@@ -2101,7 +2112,7 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv)
* *
* We get to this branch only if we can't handle the current state. * We get to this branch only if we can't handle the current state.
* *
* This should not happen in interrupt based operation. * This can happen in interrupt based operation on ARLO & BUSY.
* *
* This will happen during polled operation when the device is not * This will happen during polled operation when the device is not
* in one of the supported states when polled. * in one of the supported states when polled.
@@ -2120,6 +2131,7 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv)
/* set condition to terminate ISR and wake waiting thread */ /* set condition to terminate ISR and wake waiting thread */
priv->status |= I2C_INT_BAD_STATE;
priv->dcnt = -1; priv->dcnt = -1;
priv->msgc = 0; priv->msgc = 0;
stm32_i2c_traceevent(priv, I2CEVENT_STATE_ERROR, 0); stm32_i2c_traceevent(priv, I2CEVENT_STATE_ERROR, 0);
@@ -2150,25 +2162,32 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv)
priv->intstate = INTSTATE_DONE; priv->intstate = INTSTATE_DONE;
#else #else
status = stm32_i2c_getreg32(priv, STM32_I2C_ISR_OFFSET); /* We will update private state to capture NACK which is used in
* combination with the astart flag to report the type of NACK received
/* Update private state to capture NACK which is used in combination * (address vs data) to the upper layers once we exit the ISR.
* with the astart flag to report the type of NACK received (address
* vs data) to the upper layers once we exit the ISR.
* *
* Note: We do this prior to clearing interrupts because the NACKF * Note: status is captured prior to clearing interrupts because
* flag will naturally be cleared by that process. * the NACKF flag will naturally be cleared by that process.
*/ */
priv->status = status; status = stm32_i2c_getreg32(priv, STM32_I2C_ISR_OFFSET);
/* Clear all interrupts */ /* Clear all interrupts */
stm32_i2c_modifyreg32(priv, STM32_I2C_ICR_OFFSET, 0, I2C_ICR_CLEARMASK); stm32_i2c_modifyreg32(priv, STM32_I2C_ICR_OFFSET, 0, I2C_ICR_CLEARMASK);
/* SW reset device */ /* Was a bad state detected in the processing? */
stm32_i2c_modifyreg32(priv, STM32_I2C_CR1_OFFSET, I2C_CR1_PE, 0); if (priv->status & I2C_INT_BAD_STATE)
{
/* SW reset device */
stm32_i2c_modifyreg32(priv, STM32_I2C_CR1_OFFSET, I2C_CR1_PE, 0);
}
/* Update private status from above sans I2C_INT_BAD_STATE */
priv->status = status;
/* If a thread is waiting then inform it transfer is complete */ /* If a thread is waiting then inform it transfer is complete */
@@ -2333,7 +2352,7 @@ static int stm32_i2c_process(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s
stm32_i2c_tracereset(priv); stm32_i2c_tracereset(priv);
/* Set I2C clock frequency toggles I2C_CR1_PE !) */ /* Set I2C clock frequency toggles I2C_CR1_PE performing a SW reset! */
stm32_i2c_setclock(priv, msgs->frequency); stm32_i2c_setclock(priv, msgs->frequency);