xtensa/esp32: Add support for I2C tracing
This commit is contained in:
parent
48493dac5b
commit
cd02fd1700
@ -83,6 +83,22 @@
|
||||
I2C_ARBITRATION_LOST_INT_ENA | \
|
||||
I2C_RXFIFO_OVF_INT_ENA)
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_I2C_TRACE
|
||||
# define esp32_i2c_tracereset(p)
|
||||
# define esp32_i2c_tracenew(p,s)
|
||||
# define esp32_i2c_traceevent(p,e,a,s)
|
||||
# define esp32_i2c_tracedump(p)
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_I2C_NTRACE
|
||||
# define CONFIG_I2C_NTRACE 32
|
||||
#endif
|
||||
|
||||
/* I2C state */
|
||||
|
||||
enum esp32_i2cstate_e
|
||||
@ -104,6 +120,34 @@ enum i2c_opmode_e
|
||||
I2C_CMD_END /* I2C end command */
|
||||
};
|
||||
|
||||
#ifdef CONFIG_I2C_TRACE
|
||||
|
||||
/* Trace events */
|
||||
|
||||
enum esp32_trace_e
|
||||
{
|
||||
I2CEVENT_NONE = 0, /* No events have occurred with this status */
|
||||
I2CEVENT_SENDADDR, /* Start/Master bit set and address sent, param = addr */
|
||||
I2CEVENT_SENDBYTE, /* Send byte, param = bytes */
|
||||
I2CEVENT_RCVMODEEN, /* Receive mode enabled, param = 0 */
|
||||
I2CEVENT_RCVBYTE, /* Read more dta, param = bytes */
|
||||
I2CEVENT_STOP, /* Last byte sten, send stop, param = length */
|
||||
I2CEVENT_ERROR /* Error occurred, param = 0 */
|
||||
};
|
||||
|
||||
/* Trace data */
|
||||
|
||||
struct esp32_trace_s
|
||||
{
|
||||
uint32_t status; /* I2C 32-bit SR status */
|
||||
uint32_t count; /* Interrupt count when status change */
|
||||
enum esp32_i2cstate_e event; /* Last event that occurred with this status */
|
||||
uint32_t parm; /* Parameter associated with the event */
|
||||
clock_t time; /* First of event or first status */
|
||||
};
|
||||
|
||||
#endif /* CONFIG_I2C_TRACE */
|
||||
|
||||
/* I2C Device hardware configuration */
|
||||
|
||||
struct esp32_i2c_config_s
|
||||
@ -158,6 +202,17 @@ struct esp32_i2c_priv_s
|
||||
bool ready_read; /* If I2C has can read date */
|
||||
|
||||
uint32_t clk_freq; /* Current I2C Clock frequency */
|
||||
|
||||
/* I2C trace support */
|
||||
|
||||
#ifdef CONFIG_I2C_TRACE
|
||||
int tndx; /* Trace array index */
|
||||
clock_t start_time; /* Time when the trace was started */
|
||||
|
||||
/* The actual trace data */
|
||||
|
||||
struct esp32_trace_s trace[CONFIG_I2C_NTRACE];
|
||||
#endif
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
@ -175,6 +230,17 @@ static int esp32_i2c_transfer(FAR struct i2c_master_s *dev,
|
||||
static int esp32_i2c_reset(FAR struct i2c_master_s *dev);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_I2C_TRACE
|
||||
static void esp32_i2c_tracereset(struct esp32_i2c_priv_s *priv);
|
||||
static void esp32_i2c_tracenew(struct esp32_i2c_priv_s *priv,
|
||||
uint32_t status);
|
||||
static void esp32_i2c_traceevent(struct esp32_i2c_priv_s *priv,
|
||||
enum esp32_trace_e event,
|
||||
uint32_t parm,
|
||||
uint32_t status);
|
||||
static void esp32_i2c_tracedump(struct esp32_i2c_priv_s *priv);
|
||||
#endif /* CONFIG_I2C_TRACE */
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
@ -253,6 +319,21 @@ static struct esp32_i2c_priv_s esp32_i2c1_priv =
|
||||
};
|
||||
#endif /* CONFIG_ESP32_I2C1 */
|
||||
|
||||
/* Trace events strings */
|
||||
|
||||
#ifdef CONFIG_I2C_TRACE
|
||||
static const char *g_trace_names[] =
|
||||
{
|
||||
"NONE ",
|
||||
"SENDADDR ",
|
||||
"SENDBYTE ",
|
||||
"RCVMODEEN ",
|
||||
"RCVBYTE ",
|
||||
"STOP ",
|
||||
"ERROR "
|
||||
};
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
@ -701,6 +782,13 @@ static int esp32_i2c_transfer(FAR struct i2c_master_s *dev,
|
||||
|
||||
esp32_i2c_init_clock(priv, msgs[i].frequency);
|
||||
|
||||
/* Reset I2C trace logic */
|
||||
|
||||
esp32_i2c_tracereset(priv);
|
||||
|
||||
esp32_i2c_traceevent(priv, I2CEVENT_SENDADDR, msgs[i].addr,
|
||||
esp32_i2c_get_reg(priv, I2C_SR_OFFSET));
|
||||
|
||||
esp32_i2c_sendstart(priv);
|
||||
|
||||
if (esp32_i2c_sem_waitdone(priv) < 0)
|
||||
@ -723,6 +811,10 @@ static int esp32_i2c_transfer(FAR struct i2c_master_s *dev,
|
||||
}
|
||||
}
|
||||
|
||||
/* Dump the trace result */
|
||||
|
||||
esp32_i2c_tracedump(priv);
|
||||
|
||||
esp32_i2c_sem_post(priv);
|
||||
|
||||
return ret;
|
||||
@ -767,6 +859,185 @@ static int esp32_i2c_reset(FAR struct i2c_master_s *dev)
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32_i2c_traceclear
|
||||
*
|
||||
* Description:
|
||||
* Set I2C trace fields to default value.
|
||||
*
|
||||
* Parameters:
|
||||
* priv - Pointer to the internal driver state structure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_I2C_TRACE
|
||||
static void esp32_i2c_traceclear(struct esp32_i2c_priv_s *priv)
|
||||
{
|
||||
struct esp32_trace_s *trace = &priv->trace[priv->tndx];
|
||||
|
||||
trace->status = 0;
|
||||
trace->count = 0;
|
||||
trace->event = I2CEVENT_NONE;
|
||||
trace->parm = 0;
|
||||
trace->time = 0;
|
||||
}
|
||||
#endif /* CONFIG_I2C_TRACE */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32_i2c_tracereset
|
||||
*
|
||||
* Description:
|
||||
* Reset the trace info for a new data collection.
|
||||
*
|
||||
* Parameters:
|
||||
* priv - Pointer to the internal driver state structure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_I2C_TRACE
|
||||
static void esp32_i2c_tracereset(struct esp32_i2c_priv_s *priv)
|
||||
{
|
||||
priv->tndx = 0;
|
||||
priv->start_time = clock_systime_ticks();
|
||||
esp32_i2c_traceclear(priv);
|
||||
}
|
||||
#endif /* CONFIG_I2C_TRACE */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32_i2c_tracenew
|
||||
*
|
||||
* Description:
|
||||
* Create a new trace entry.
|
||||
*
|
||||
* Parameters:
|
||||
* priv - Pointer to the internal driver state structure.
|
||||
* status - Current value of I2C status register.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_I2C_TRACE
|
||||
static void esp32_i2c_tracenew(struct esp32_i2c_priv_s *priv,
|
||||
uint32_t status)
|
||||
{
|
||||
struct esp32_trace_s *trace = &priv->trace[priv->tndx];
|
||||
|
||||
/* Check if the current entry is already initialized or if its status had
|
||||
* already changed
|
||||
*/
|
||||
|
||||
if (trace->count == 0 || status != trace->status)
|
||||
{
|
||||
/* Check whether the status changed */
|
||||
|
||||
if (trace->count != 0)
|
||||
{
|
||||
/* Bump up the trace index (unless we are out of trace entries) */
|
||||
|
||||
if (priv->tndx >= (CONFIG_I2C_NTRACE - 1))
|
||||
{
|
||||
i2cerr("ERROR: Trace table overflow\n");
|
||||
return;
|
||||
}
|
||||
|
||||
priv->tndx++;
|
||||
trace = &priv->trace[priv->tndx];
|
||||
}
|
||||
|
||||
/* Initialize the new trace entry */
|
||||
|
||||
esp32_i2c_traceclear(priv);
|
||||
trace->status = status;
|
||||
trace->count = 1;
|
||||
trace->time = clock_systime_ticks();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Just increment the count of times that we have seen this status */
|
||||
|
||||
trace->count++;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_I2C_TRACE */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32_i2c_traceevent
|
||||
*
|
||||
* Description:
|
||||
* Record a new trace event.
|
||||
*
|
||||
* Parameters:
|
||||
* priv - Pointer to the internal driver state structure.
|
||||
* event - Event to be recorded on the trace.
|
||||
* parm - Parameter associated with the event.
|
||||
* status - Current value of I2C status register.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_I2C_TRACE
|
||||
static void esp32_i2c_traceevent(struct esp32_i2c_priv_s *priv,
|
||||
enum esp32_trace_e event,
|
||||
uint32_t parm,
|
||||
uint32_t status)
|
||||
{
|
||||
/* Check for new trace setup */
|
||||
|
||||
esp32_i2c_tracenew(priv, status);
|
||||
|
||||
if (event != I2CEVENT_NONE)
|
||||
{
|
||||
struct esp32_trace_s *trace = &priv->trace[priv->tndx];
|
||||
|
||||
/* Initialize the new trace entry */
|
||||
|
||||
trace->event = event;
|
||||
trace->parm = parm;
|
||||
|
||||
/* Bump up the trace index (unless we are out of trace entries) */
|
||||
|
||||
if (priv->tndx >= (CONFIG_I2C_NTRACE - 1))
|
||||
{
|
||||
i2cerr("ERROR: Trace table overflow\n");
|
||||
return;
|
||||
}
|
||||
|
||||
priv->tndx++;
|
||||
esp32_i2c_traceclear(priv);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_I2C_TRACE */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32_i2c_tracedump
|
||||
*
|
||||
* Description:
|
||||
* Dump the trace results.
|
||||
*
|
||||
* Parameters:
|
||||
* priv - Pointer to the internal driver state structure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_I2C_TRACE
|
||||
static void esp32_i2c_tracedump(struct esp32_i2c_priv_s *priv)
|
||||
{
|
||||
struct esp32_trace_s *trace;
|
||||
int i;
|
||||
|
||||
syslog(LOG_DEBUG, "Elapsed time: %" PRIu32 "\n",
|
||||
(clock_systime_ticks() - priv->start_time));
|
||||
|
||||
for (i = 0; i < priv->tndx; i++)
|
||||
{
|
||||
trace = &priv->trace[i];
|
||||
syslog(LOG_DEBUG,
|
||||
"%2d. STATUS: %08" PRIx32 " COUNT: %3" PRIu32 " EVENT: %s(%2d)"
|
||||
" PARM: %08" PRIx32 " TIME: %" PRIu32 "\n",
|
||||
i + 1, trace->status, trace->count, g_trace_names[trace->event],
|
||||
trace->event, trace->parm, trace->time - priv->start_time);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_I2C_TRACE */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32_i2c_irq
|
||||
*
|
||||
@ -787,6 +1058,8 @@ static int esp32_i2c_irq(int cpuint, void *context, FAR void *arg)
|
||||
if (I2C_INT_ERR_EN_BITS & status)
|
||||
{
|
||||
priv->error = status & I2C_INT_ERR_EN_BITS;
|
||||
esp32_i2c_traceevent(priv, I2CEVENT_ERROR, priv->error,
|
||||
esp32_i2c_get_reg(priv, I2C_SR_OFFSET));
|
||||
esp32_i2c_set_reg(priv, I2C_INT_ENA_OFFSET, 0);
|
||||
nxsem_post(&priv->sem_isr);
|
||||
}
|
||||
@ -798,6 +1071,8 @@ static int esp32_i2c_irq(int cpuint, void *context, FAR void *arg)
|
||||
{
|
||||
if (priv->ready_read)
|
||||
{
|
||||
esp32_i2c_traceevent(priv, I2CEVENT_RCVBYTE, priv->bytes,
|
||||
esp32_i2c_get_reg(priv, I2C_SR_OFFSET));
|
||||
esp32_i2c_recvdata(priv);
|
||||
|
||||
priv->ready_read = 0;
|
||||
@ -805,12 +1080,16 @@ static int esp32_i2c_irq(int cpuint, void *context, FAR void *arg)
|
||||
|
||||
if (priv->bytes == msg->length)
|
||||
{
|
||||
esp32_i2c_traceevent(priv, I2CEVENT_STOP, msg->length,
|
||||
esp32_i2c_get_reg(priv, I2C_SR_OFFSET));
|
||||
esp32_i2c_sendstop(priv);
|
||||
|
||||
priv->i2cstate = I2CSTATE_FINISH;
|
||||
}
|
||||
else
|
||||
{
|
||||
esp32_i2c_traceevent(priv, I2CEVENT_RCVMODEEN, 0,
|
||||
esp32_i2c_get_reg(priv, I2C_SR_OFFSET));
|
||||
esp32_i2c_startrecv(priv);
|
||||
|
||||
priv->ready_read = 1;
|
||||
@ -818,6 +1097,8 @@ static int esp32_i2c_irq(int cpuint, void *context, FAR void *arg)
|
||||
}
|
||||
else
|
||||
{
|
||||
esp32_i2c_traceevent(priv, I2CEVENT_SENDBYTE, priv->bytes,
|
||||
esp32_i2c_get_reg(priv, I2C_SR_OFFSET));
|
||||
esp32_i2c_senddata(priv);
|
||||
|
||||
if (priv->bytes == msg->length)
|
||||
@ -828,6 +1109,8 @@ static int esp32_i2c_irq(int cpuint, void *context, FAR void *arg)
|
||||
}
|
||||
else if (priv->i2cstate == I2CSTATE_STOP)
|
||||
{
|
||||
esp32_i2c_traceevent(priv, I2CEVENT_STOP, msg->length,
|
||||
esp32_i2c_get_reg(priv, I2C_SR_OFFSET));
|
||||
esp32_i2c_sendstop(priv);
|
||||
|
||||
priv->i2cstate = I2CSTATE_FINISH;
|
||||
|
Loading…
Reference in New Issue
Block a user