summaryrefslogtreecommitdiff
path: root/nuttx/arch
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2014-12-11 09:34:03 -0600
committerGregory Nutt <gnutt@nuttx.org>2014-12-11 09:34:03 -0600
commitf3c2f225d557d409a77e04133356c0d2c6c2f02b (patch)
tree12ea3a3be4341caef825c20174b2ee1852bea3b4 /nuttx/arch
parent26b35e2cc892afe5544a24cb2d761ed129a17c91 (diff)
downloadnuttx-f3c2f225d557d409a77e04133356c0d2c6c2f02b.tar.gz
nuttx-f3c2f225d557d409a77e04133356c0d2c6c2f02b.tar.bz2
nuttx-f3c2f225d557d409a77e04133356c0d2c6c2f02b.zip
Tiva I2C: Add register-level debug capability
Diffstat (limited to 'nuttx/arch')
-rw-r--r--nuttx/arch/arm/src/tiva/Kconfig8
-rw-r--r--nuttx/arch/arm/src/tiva/tiva_i2c.c194
2 files changed, 169 insertions, 33 deletions
diff --git a/nuttx/arch/arm/src/tiva/Kconfig b/nuttx/arch/arm/src/tiva/Kconfig
index 016bd8bd0..5f220edd9 100644
--- a/nuttx/arch/arm/src/tiva/Kconfig
+++ b/nuttx/arch/arm/src/tiva/Kconfig
@@ -355,6 +355,14 @@ config TIVA_I2C_TIMEOTICKS
depends on !TIVA_I2C_DYNTIMEO
endif # !TIVA_I2C_DYNTIMEO
+
+config TIVA_I2C_REGDEBUG
+ bool "Register level debug"
+ default n
+ depends on DEBUG
+ ---help---
+ Enables extremely detailed register access debug output.
+
endmenu # I2C Configuration
endif # TIVA_I2C
diff --git a/nuttx/arch/arm/src/tiva/tiva_i2c.c b/nuttx/arch/arm/src/tiva/tiva_i2c.c
index 56d704787..77609e8d1 100644
--- a/nuttx/arch/arm/src/tiva/tiva_i2c.c
+++ b/nuttx/arch/arm/src/tiva/tiva_i2c.c
@@ -52,6 +52,7 @@
#include <stdbool.h>
#include <semaphore.h>
#include <errno.h>
+#include <assert.h>
#include <debug.h>
#include <nuttx/arch.h>
@@ -105,6 +106,7 @@
# define CONFIG_TIVA_I2C_DYNTIMEO_STARTSTOP TICK2USEC(CONFIG_TIVA_I2C_TIMEOTICKS)
#endif
+/* GPIO pins ************************************************************************/
/* Macros to convert a I2C pin to a GPIO output */
#define I2C_INPUT (GPIO_FUNC_INPUT)
@@ -124,6 +126,10 @@
# define i2cvdbg(x...)
#endif
+#ifndef CONFIG_DEBUG
+# undef CONFIG_TIVA_I2C_REGDEBUG
+#endif
+
/* I2C event trace logic. NOTE: trace uses the internal, non-standard, low-level
* debug interface syslog() but does not require that any other debug
* is enabled.
@@ -166,6 +172,7 @@ enum tiva_trace_e
I2CEVENT_SENDBYTE, /* Send byte, param = dcnt */
I2CEVENT_SPURIOUS, /* Spurious interrupt received, param = msgc */
I2CEVENT_NEXTMSG, /* Starting next message, param = msgc */
+ I2CEVENT_TIMEOUT, /* Software detectected timeout, param = RIS */
I2CEVENT_DONE /* All messages transferred, param = intstate */
};
@@ -216,9 +223,18 @@ struct tiva_i2c_priv_s
uint16_t flags; /* Current message flags */
uint32_t status; /* MCS register at the end of the transfer */
- /* I2C trace support */
+#ifdef CONFIG_TIVA_I2C_REGDEBUG
+ /* Register level debug */
+
+ bool wrlast; /* Last was a write */
+ uintptr_t addrlast; /* Last address */
+ uint32_t vallast; /* Last value */
+ int ntimes; /* Number of times */
+#endif
#ifdef CONFIG_I2C_TRACE
+ /* I2C trace support */
+
int tndx; /* Trace array index */
int tcount; /* Number of events with this status */
uint32_t ttime; /* Time when the trace was started */
@@ -246,13 +262,18 @@ struct tiva_i2c_inst_s
* Private Function Prototypes
************************************************************************************/
+#ifdef CONFIG_TIVA_I2C_REGDEBUG
+static bool tiva_i2c_checkreg(struct tiva_i2c_priv_s *priv, bool wr,
+ uint32_t regval, uintptr_t regaddr);
+static uint32_t tiva_i2c_getreg(struct tiva_i2c_priv_s *priv, unsigned int offset);
+static void tiva_i2c_putreg(struct tiva_i2c_priv_s *priv, unsigned int offset,
+ uint32_t value);
+#else
static inline uint32_t tiva_i2c_getreg(struct tiva_i2c_priv_s *priv,
unsigned int offset);
static inline void tiva_i2c_putreg(struct tiva_i2c_priv_s *priv,
unsigned int offset, uint32_t value);
-static inline void tiva_i2c_modifyreg(struct tiva_i2c_priv_s *priv,
- uint8_t offset, uint16_t clearbits,
- uint16_t setbits);
+#endif
static inline void tiva_i2c_sem_wait(struct i2c_dev_s *dev);
#ifdef CONFIG_TIVA_I2C_DYNTIMEO
@@ -464,6 +485,60 @@ static const struct i2c_ops_s tiva_i2c_ops =
************************************************************************************/
/************************************************************************************
+ * Name: sam_checkreg
+ *
+ * Description:
+ * Check if the current register access is a duplicate of the preceding.
+ *
+ * Input Parameters:
+ * regval - The value to be written
+ * regaddr - The address of the register to write to
+ *
+ * Returned Value:
+ * true: This is the first register access of this type.
+ * flase: This is the same as the preceding register access.
+ *
+ ************************************************************************************/
+
+#ifdef CONFIG_TIVA_I2C_REGDEBUG
+static bool tiva_i2c_checkreg(struct tiva_i2c_priv_s *priv, bool wr,
+ uint32_t regval, uintptr_t regaddr)
+{
+ if (wr == priv->wrlast && /* Same kind of access? */
+ regval == priv->vallast && /* Same value? */
+ regaddr == priv->addrlast) /* Same address? */
+ {
+ /* Yes, then just keep a count of the number of times we did this. */
+
+ priv->ntimes++;
+ return false;
+ }
+ else
+ {
+ /* Did we do the previous operation more than once? */
+
+ if (priv->ntimes > 0)
+ {
+ /* Yes... show how many times we did it */
+
+ lldbg("...[Repeats %d times]...\n", priv->ntimes);
+ }
+
+ /* Save information about the new access */
+
+ priv->wrlast = wr;
+ priv->vallast = regval;
+ priv->addrlast = regaddr;
+ priv->ntimes = 0;
+ }
+
+ /* Return true if this is the first time that we have done this operation */
+
+ return true;
+}
+#endif
+
+/************************************************************************************
* Name: tiva_i2c_getreg
*
* Description:
@@ -471,11 +546,26 @@ static const struct i2c_ops_s tiva_i2c_ops =
*
************************************************************************************/
+#ifdef CONFIG_TIVA_I2C_REGDEBUG
+static uint32_t tiva_i2c_getreg(struct tiva_i2c_priv_s *priv, unsigned int offset)
+{
+ uintptr_t regaddr = priv->config->base + offset;
+ uint32_t regval = getreg32(regaddr);
+
+ if (tiva_i2c_checkreg(priv, false, regval, regaddr))
+ {
+ lldbg("%08x->%08x\n", regaddr, regval);
+ }
+
+ return regval;
+}
+#else
static inline uint32_t tiva_i2c_getreg(struct tiva_i2c_priv_s *priv,
unsigned int offset)
{
return getreg32(priv->config->base + offset);
}
+#endif
/************************************************************************************
* Name: tiva_i2c_putreg
@@ -485,26 +575,26 @@ static inline uint32_t tiva_i2c_getreg(struct tiva_i2c_priv_s *priv,
*
************************************************************************************/
-static inline void tiva_i2c_putreg(struct tiva_i2c_priv_s *priv,
- unsigned int offset, uint32_t regval)
+#ifdef CONFIG_TIVA_I2C_REGDEBUG
+static void tiva_i2c_putreg(struct tiva_i2c_priv_s *priv, unsigned int offset,
+ uint32_t regval)
{
- putreg32(regval, priv->config->base + offset);
-}
+ uintptr_t regaddr = priv->config->base + offset;
-/************************************************************************************
- * Name: tiva_i2c_modifyreg
- *
- * Description:
- * Modify a 16-bit register value by offset
- *
- ************************************************************************************/
+ if (tiva_i2c_checkreg(priv, true, regval, regaddr))
+ {
+ lldbg("%08x<-%08x\n", regaddr, regval);
+ }
-static inline void tiva_i2c_modifyreg(struct tiva_i2c_priv_s *priv,
- uint8_t offset, uint16_t clearbits,
- uint16_t setbits)
+ putreg32(regval, regaddr);
+}
+#else
+static inline void tiva_i2c_putreg(struct tiva_i2c_priv_s *priv,
+ unsigned int offset, uint32_t regval)
{
- modifyreg16(priv->config->base + offset, clearbits, setbits);
+ putreg32(regval, priv->config->base + offset);
}
+#endif
/************************************************************************************
* Name: tiva_i2c_sem_wait
@@ -623,6 +713,8 @@ static inline int tiva_i2c_sem_waitdone(struct tiva_i2c_priv_s *priv)
* NOTE that we try again if we are awakened by a signal (EINTR).
*/
+ tiva_i2c_traceevent(priv, I2CEVENT_TIMEOUT,
+ tiva_i2c_getreg(priv, TIVA_I2CM_RIS_OFFSET));
break;
}
}
@@ -750,7 +842,7 @@ static inline void tiva_i2c_sem_destroy(struct i2c_dev_s *dev)
}
/************************************************************************************
- * Name: tiva_i2c_trace*
+ * Name: tiva_i2c_trace
*
* Description:
* I2C trace instrumentation
@@ -796,7 +888,7 @@ static void tiva_i2c_tracenew(struct tiva_i2c_priv_s *priv, uint32_t status)
if (priv->tndx >= (CONFIG_I2C_NTRACE-1))
{
- i2cdbg("Trace table overflow\n");
+ i2cdbg("ERROR: Trace table overflow\n");
return;
}
@@ -845,7 +937,7 @@ static void tiva_i2c_traceevent(struct tiva_i2c_priv_s *priv,
if (priv->tndx >= (CONFIG_I2C_NTRACE-1))
{
- i2cdbg("Trace table overflow\n");
+ i2cdbg("ERROR: Trace table overflow\n");
return;
}
@@ -1376,12 +1468,22 @@ static int tiva_i2c_initialize(struct tiva_i2c_priv_s *priv)
uint32_t regval;
int ret;
+ i2cvdbg("I2C%d:\n", priv->config->devno);
+
/* Enable clocking to the I2C peripheral */
#ifdef TIVA_SYSCON_RCGCI2C
modifyreg32(TIVA_SYSCON_RCGCI2C, 0, SYSCON_RCGCI2C(priv->config->devno));
+
+ i2cvdbg("I2C%d: RCGI2C[%08x]=%08lx\n",
+ priv->config->devno, TIVA_SYSCON_RCGCI2C,
+ (unsigned long)getreg32(TIVA_SYSCON_RCGCI2C));
#else
modifyreg32(TIVA_SYSCON_RCGC1, 0, priv->rcgbit);
+
+ i2cvdbg("I2C%d: RCGC1[%08x]=%08lx\n",
+ priv->config->devno, TIVA_SYSCON_RCGC1,
+ (unsigned long)getreg32(TIVA_SYSCON_RCGC1));
#endif
/* Configure pins */
@@ -1432,6 +1534,8 @@ static int tiva_i2c_uninitialize(struct tiva_i2c_priv_s *priv)
{
uint32_t regval;
+ i2cvdbg("I2C%d:\n", priv->config->devno);
+
/* Disable I2C */
regval = tiva_i2c_getreg(priv, TIVA_I2CM_CR_OFFSET);
@@ -1474,6 +1578,8 @@ static uint32_t tiva_i2c_setclock(struct tiva_i2c_priv_s *priv, uint32_t frequen
uint32_t regval;
uint32_t tmp;
+ i2cvdbg("I2C%d: frequency: %lu\n", priv->config->devno, (unsigned long)frequency);
+
/* Calculate the clock divider that results in the highest frequency that
* is than or equal to the desired speed.
*/
@@ -1517,6 +1623,8 @@ static uint32_t tiva_i2c_setfrequency(struct i2c_dev_s *dev, uint32_t frequency)
DEBUGASSERT(inst && inst->priv);
priv = inst->priv;
+ i2cvdbg("I2C%d: frequency: %lu\n", inst->priv->config->devno, (unsigned long)frequency);
+
/* Get exclusive access to the I2C device */
tiva_i2c_sem_wait(dev);
@@ -1540,6 +1648,10 @@ static uint32_t tiva_i2c_setfrequency(struct i2c_dev_s *dev, uint32_t frequency)
static int tiva_i2c_setaddress(struct i2c_dev_s *dev, int addr, int nbits)
{
struct tiva_i2c_inst_s *inst = (struct tiva_i2c_inst_s *)dev;
+
+ DEBUGASSERT(inst && inst->priv && inst->priv->config);
+ i2cvdbg("I2C%d: addr: %02x nbits=%d\n", inst->priv->config->devno, addr, nbits);
+
tiva_i2c_sem_wait(dev);
inst->address = addr;
@@ -1558,7 +1670,7 @@ static int tiva_i2c_setaddress(struct i2c_dev_s *dev, int addr, int nbits)
************************************************************************************/
static int tiva_i2c_process(struct i2c_dev_s *dev, struct i2c_msg_s *msgs,
- int count)
+ int count)
{
struct tiva_i2c_inst_s *inst = (struct tiva_i2c_inst_s *)dev;
struct tiva_i2c_priv_s *priv = inst->priv;
@@ -1566,6 +1678,8 @@ static int tiva_i2c_process(struct i2c_dev_s *dev, struct i2c_msg_s *msgs,
ASSERT(count);
+ i2cvdbg("I2C%d: count=%d\n", priv->config->devno, count);
+
/* Reset ptr and dcnt to ensure an unexpected data interrupt doesn't
* overwrite stale data.
*/
@@ -1676,9 +1790,6 @@ static int tiva_i2c_process(struct i2c_dev_s *dev, struct i2c_msg_s *msgs,
static int tiva_i2c_write(struct i2c_dev_s *dev, const uint8_t *buffer, int buflen)
{
struct tiva_i2c_inst_s *inst = (struct tiva_i2c_inst_s *)dev;
-
- tiva_i2c_sem_wait(dev); /* ensure that address or flags don't change meanwhile */
-
struct i2c_msg_s msgv =
{
.addr = inst->address,
@@ -1687,6 +1798,10 @@ static int tiva_i2c_write(struct i2c_dev_s *dev, const uint8_t *buffer, int bufl
.length = buflen
};
+ DEBUGASSERT(inst && inst->priv && inst->priv->config);
+ i2cvdbg("I2C%d: buflen=%d\n", inst->priv->config->devno, buflen);
+
+ tiva_i2c_sem_wait(dev); /* ensure that address or flags don't change meanwhile */
return tiva_i2c_process(dev, &msgv, 1);
}
@@ -1701,9 +1816,6 @@ static int tiva_i2c_write(struct i2c_dev_s *dev, const uint8_t *buffer, int bufl
int tiva_i2c_read(struct i2c_dev_s *dev, uint8_t *buffer, int buflen)
{
struct tiva_i2c_inst_s *inst = (struct tiva_i2c_inst_s *)dev;
-
- tiva_i2c_sem_wait(dev); /* ensure that address or flags don't change meanwhile */
-
struct i2c_msg_s msgv =
{
.addr = inst->address,
@@ -1712,6 +1824,10 @@ int tiva_i2c_read(struct i2c_dev_s *dev, uint8_t *buffer, int buflen)
.length = buflen
};
+ DEBUGASSERT(inst && inst->priv && inst->priv->config);
+ i2cvdbg("I2C%d: buflen=%d\n", inst->priv->config->devno, buflen);
+
+ tiva_i2c_sem_wait(dev); /* ensure that address or flags don't change meanwhile */
return tiva_i2c_process(dev, &msgv, 1);
}
@@ -1729,8 +1845,6 @@ static int tiva_i2c_writeread(struct i2c_dev_s *dev,
uint8_t *buffer, int buflen)
{
struct tiva_i2c_inst_s *inst = (struct tiva_i2c_inst_s *)dev;
- tiva_i2c_sem_wait(dev); /* Ensure that address or flags don't change meanwhile */
-
struct i2c_msg_s msgv[2] =
{
{
@@ -1747,6 +1861,10 @@ static int tiva_i2c_writeread(struct i2c_dev_s *dev,
}
};
+ DEBUGASSERT(inst && inst->priv && inst->priv->config);
+ i2cvdbg("I2C%d: wbuflen=%d buflen=%d\n", inst->priv->config->devno, wbuflen, buflen);
+
+ tiva_i2c_sem_wait(dev); /* Ensure that address or flags don't change meanwhile */
return tiva_i2c_process(dev, msgv, 2);
}
#endif
@@ -1763,6 +1881,12 @@ static int tiva_i2c_writeread(struct i2c_dev_s *dev,
static int tiva_i2c_transfer(struct i2c_dev_s *dev, struct i2c_msg_s *msgs,
int count)
{
+ struct tiva_i2c_inst_s *inst = (struct tiva_i2c_inst_s *)dev;
+
+ DEBUGASSERT(inst && inst->priv && inst->priv->config);
+ i2cvdbg("I2C%d: count=%d\n", inst->priv->config->devno, count);
+ UNUSED(inst);
+
tiva_i2c_sem_wait(dev); /* Ensure that address or flags don't change meanwhile */
return tiva_i2c_process(dev, msgs, count);
}
@@ -1787,6 +1911,8 @@ struct i2c_dev_s *up_i2cinitialize(int port)
const struct tiva_i2c_config_s *config; /* Constant configuration */
int irqs;
+ i2cvdbg("I2C%d: port=%d\n", port, port);
+
/* Get I2C private structure */
switch (port)
@@ -1879,7 +2005,8 @@ int up_i2cuninitialize(struct i2c_dev_s *dev)
struct tiva_i2c_inst_s *inst = (struct tiva_i2c_inst_s *)dev;
int irqs;
- ASSERT(dev);
+ DEBUGASSERT(inst && inst->priv && inst->priv->config);
+ i2cvdbg("I2C%d:\n", inst->priv->config->devno);
/* Decrement reference count and check for underflow */
@@ -1930,7 +2057,8 @@ int up_i2creset(struct i2c_dev_s *dev)
uint32_t sda_gpio;
int ret = ERROR;
- ASSERT(dev);
+ DEBUGASSERT(inst && inst->priv && inst->priv->config);
+ i2cvdbg("I2C%d:\n", inst->priv->config->devno);
/* Get I2C private structure */