summaryrefslogtreecommitdiff
path: root/nuttx/arch/arm/src/tiva/tiva_i2c.c
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2014-12-12 12:13:31 -0600
committerGregory Nutt <gnutt@nuttx.org>2014-12-12 12:13:31 -0600
commitbce5d15aa7cbc8de58e03f615a7d5926dee95937 (patch)
tree83cafe10564b87656ac04504bd0493e4d20cf2a9 /nuttx/arch/arm/src/tiva/tiva_i2c.c
parent2066928f1b7e0393d52f7f7b675d87176c9f726f (diff)
downloadnuttx-bce5d15aa7cbc8de58e03f615a7d5926dee95937.tar.gz
nuttx-bce5d15aa7cbc8de58e03f615a7d5926dee95937.tar.bz2
nuttx-bce5d15aa7cbc8de58e03f615a7d5926dee95937.zip
Tiva I2C: Don't try to ACK and STOP on the same byte. Improve logic that suppresses STOP on a repeated start
Diffstat (limited to 'nuttx/arch/arm/src/tiva/tiva_i2c.c')
-rw-r--r--nuttx/arch/arm/src/tiva/tiva_i2c.c55
1 files changed, 47 insertions, 8 deletions
diff --git a/nuttx/arch/arm/src/tiva/tiva_i2c.c b/nuttx/arch/arm/src/tiva/tiva_i2c.c
index 4e3838b25..b75fdc3a8 100644
--- a/nuttx/arch/arm/src/tiva/tiva_i2c.c
+++ b/nuttx/arch/arm/src/tiva/tiva_i2c.c
@@ -1044,27 +1044,65 @@ static void tiva_i2c_startxfr(struct tiva_i2c_priv_s *priv)
static void tiva_i2c_nextxfr(struct tiva_i2c_priv_s *priv, uint32_t cmd)
{
- /* Set up the basic command. The STOP bit should be set on the last transfer
- * UNLESS this there is a repeated start.
+ /* Set up the basic command. The STOP bit should be set on the last byte transfer.
+ *
+ * - CASE 1: If this is the last message in the sequence, then the stop bit should
+ * always be set.
+ * - CASE 2.1.1: The next message may be another read or write of the SAME
+ * direction (read or write) and to the SAME address WITHOUT repeated start, in
+ * which case this is really just a continuation of the message. No STOP is
+ * needed.
+ * - CASE 2.x.2: The next message may be to the SAME address WITH repeated start.
+ * Because the repeated start, a direction change is possible. This is still
+ * a continuation of the same message sequence and so no STOP is needed.
+ * - CASE 2.2.x: The next message may be a DIFFERENT address WITHOUT repeated
+ * start. This would be an error; The STOP will be sent, the next message will
+ * fail.
*/
cmd |= I2CM_CS_RUN;
- if (priv->msgc < 2 && priv->mcnt < 2)
+ if (priv->mcnt < 2)
{
- /* This is the last byte of the last message... add the STOP bit */
+ /* Are there more messages in this sequence? */
+
+ if (priv->msgc < 2)
+ {
+ /* No.. send the STOP */
+
+ cmd |= I2CM_CS_STOP;
+ }
+ else
+ {
+ /* Yes.. peek at the next message */
+
+ struct i2c_msg_s *curr = priv->msgv;
+ struct i2c_msg_s *next = curr + 1;
- cmd |= I2CM_CS_STOP;
+ /* Same address as the current message? */
+
+ if (curr->addr != next->addr)
+ {
+ /* No.. send the STOP */
+
+ cmd |= I2CM_CS_STOP;
+ }
+ }
}
/* Set up to transfer the next byte. Are we sending or receiving? */
if ((priv->mflags & I2C_M_READ) != 0)
{
- /* We are receiving data. Write the command to the control register to
- * receive the next byte.
+ /* We are receiving data. We need to ACK UNLESS we are going to send
+ * STOP.
*/
- cmd |= I2CM_CS_ACK;
+ if ((cmd & I2CM_CS_STOP) == 0)
+ {
+ cmd |= I2CM_CS_ACK;
+ }
+
+ /* Write the command to the control register to receive the next byte. */
tiva_i2c_putreg(priv, TIVA_I2CM_CS_OFFSET, cmd);
tiva_i2c_traceevent(priv, I2CEVENT_RECVSETUP, priv->mcnt);
@@ -2078,6 +2116,7 @@ int up_i2cuninitialize(struct i2c_dev_s *dev)
/* Yes.. Disable power and other HW resource (GPIO's) */
tiva_i2c_uninitialize(priv);
+ priv->refs = 0;
/* Release unused resources */