risc-v/esp32c3: Add support for I2C tracing

This commit is contained in:
Gustavo Henrique Nihei 2021-03-03 11:53:27 -03:00 committed by Alan Carvalho de Assis
parent 0f508c1a5f
commit cb1c415b46

View File

@ -54,7 +54,7 @@
#include "hardware/esp32c3_system.h"
/****************************************************************************
* Private Functions
* Pre-processor Definitions
****************************************************************************/
/* Helper for applying the mask for a given register field.
@ -95,6 +95,26 @@
I2C_TIME_OUT_INT_ENA_M | \
I2C_ARBITRATION_LOST_INT_ENA_M)
/* 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 esp32c3_i2c_tracereset(p)
# define esp32c3_i2c_tracenew(p,s)
# define esp32c3_i2c_traceevent(p,e,a,s)
# define esp32c3_i2c_tracedump(p)
#endif
#ifndef CONFIG_I2C_NTRACE
# define CONFIG_I2C_NTRACE 32
#endif
/****************************************************************************
* Private Types
****************************************************************************/
/* I2C state */
enum esp32c3_i2cstate_e
@ -108,7 +128,7 @@ enum esp32c3_i2cstate_e
/* I2C hardware command */
enum i2c_opmode_e
enum esp32c3_i2c_opmode_e
{
I2C_CMD_RESTART = 6, /* I2C restart command */
I2C_CMD_WRITE = 1, /* I2C write command */
@ -117,6 +137,34 @@ enum i2c_opmode_e
I2C_CMD_END = 4 /* I2C end command */
};
#ifdef CONFIG_I2C_TRACE
/* Trace events */
enum esp32c3_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 esp32c3_trace_s
{
uint32_t status; /* I2C 32-bit SR status */
uint32_t count; /* Interrupt count when status change */
enum esp32c3_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 esp32c3_i2c_config_s
@ -170,6 +218,17 @@ struct esp32c3_i2c_priv_s
bool ready_read; /* If I2C is ready for receiving data */
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 esp32c3_trace_s trace[CONFIG_I2C_NTRACE];
#endif
};
/****************************************************************************
@ -185,7 +244,18 @@ static int esp32c3_i2c_transfer(struct i2c_master_s *dev,
int count);
#ifdef CONFIG_I2C_RESET
static int esp32c3_i2c_reset(struct i2c_master_s *dev);
#endif
#endif /* CONFIG_I2C_RESET */
#ifdef CONFIG_I2C_TRACE
static void esp32c3_i2c_tracereset(struct esp32c3_i2c_priv_s *priv);
static void esp32c3_i2c_tracenew(struct esp32c3_i2c_priv_s *priv,
uint32_t status);
static void esp32c3_i2c_traceevent(struct esp32c3_i2c_priv_s *priv,
enum esp32c3_trace_e event,
uint32_t parm,
uint32_t status);
static void esp32c3_i2c_tracedump(struct esp32c3_i2c_priv_s *priv);
#endif /* CONFIG_I2C_TRACE */
/****************************************************************************
* Private Data
@ -238,6 +308,21 @@ static struct esp32c3_i2c_priv_s esp32c3_i2c0_priv =
#endif
/* Trace events strings */
#ifdef CONFIG_I2C_TRACE
static const char *g_trace_names[] =
{
"NONE ",
"SENDADDR ",
"SENDBYTE ",
"RCVMODEEN ",
"RCVBYTE ",
"STOP ",
"ERROR "
};
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
@ -824,6 +909,13 @@ static int esp32c3_i2c_transfer(struct i2c_master_s *dev,
esp32c3_i2c_init_clock(priv, msgs[i].frequency);
/* Reset I2C trace logic */
esp32c3_i2c_tracereset(priv);
esp32c3_i2c_traceevent(priv, I2CEVENT_SENDADDR, msgs[i].addr,
getreg32(I2C_SR_REG(priv->id)));
esp32c3_i2c_sendstart(priv);
if (esp32c3_i2c_sem_waitdone(priv) < 0)
@ -850,6 +942,10 @@ static int esp32c3_i2c_transfer(struct i2c_master_s *dev,
i2cinfo("Message %" PRIu8 " transfer complete.\n", priv->msgid);
}
/* Dump the trace result */
esp32c3_i2c_tracedump(priv);
esp32c3_i2c_sem_post(priv);
return ret;
@ -895,6 +991,185 @@ static int esp32c3_i2c_reset(struct i2c_master_s *dev)
}
#endif
/****************************************************************************
* Name: esp32c3_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 esp32c3_i2c_traceclear(struct esp32c3_i2c_priv_s *priv)
{
struct esp32c3_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: esp32c3_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 esp32c3_i2c_tracereset(struct esp32c3_i2c_priv_s *priv)
{
priv->tndx = 0;
priv->start_time = clock_systime_ticks();
esp32c3_i2c_traceclear(priv);
}
#endif /* CONFIG_I2C_TRACE */
/****************************************************************************
* Name: esp32c3_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 esp32c3_i2c_tracenew(struct esp32c3_i2c_priv_s *priv,
uint32_t status)
{
struct esp32c3_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 */
esp32c3_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: esp32c3_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 esp32c3_i2c_traceevent(struct esp32c3_i2c_priv_s *priv,
enum esp32c3_trace_e event,
uint32_t parm,
uint32_t status)
{
/* Check for new trace setup */
esp32c3_i2c_tracenew(priv, status);
if (event != I2CEVENT_NONE)
{
struct esp32c3_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++;
esp32c3_i2c_traceclear(priv);
}
}
#endif /* CONFIG_I2C_TRACE */
/****************************************************************************
* Name: esp32c3_i2c_tracedump
*
* Description:
* Dump the trace results.
*
* Parameters:
* priv - Pointer to the internal driver state structure.
*
****************************************************************************/
#ifdef CONFIG_I2C_TRACE
static void esp32c3_i2c_tracedump(struct esp32c3_i2c_priv_s *priv)
{
struct esp32c3_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: esp32c3_i2c_irq
*
@ -918,13 +1193,15 @@ static int esp32c3_i2c_irq(int cpuint, void *context, void *arg)
struct esp32c3_i2c_priv_s *priv = (struct esp32c3_i2c_priv_s *)arg;
struct i2c_msg_s *msg = &priv->msgv[priv->msgid];
uint32_t status = getreg32(I2C_INT_STATUS_REG(priv->id));
putreg32(status, I2C_INT_CLR_REG(priv->id));
uint32_t irq_status = getreg32(I2C_INT_STATUS_REG(priv->id));
putreg32(irq_status, I2C_INT_CLR_REG(priv->id));
if (I2C_INT_ERR_MASK & status)
if (I2C_INT_ERR_MASK & irq_status)
{
priv->error = status & I2C_INT_ERR_MASK;
priv->error = irq_status & I2C_INT_ERR_MASK;
priv->i2cstate = I2CSTATE_ERROR;
esp32c3_i2c_traceevent(priv, I2CEVENT_ERROR, priv->error,
getreg32(I2C_SR_REG(priv->id)));
esp32c3_i2c_intr_disable(priv);
nxsem_post(&priv->sem_isr);
}
@ -936,6 +1213,8 @@ static int esp32c3_i2c_irq(int cpuint, void *context, void *arg)
{
if (priv->ready_read)
{
esp32c3_i2c_traceevent(priv, I2CEVENT_RCVBYTE, priv->bytes,
getreg32(I2C_SR_REG(priv->id)));
esp32c3_i2c_recvdata(priv);
priv->ready_read = false;
@ -943,12 +1222,16 @@ static int esp32c3_i2c_irq(int cpuint, void *context, void *arg)
if (priv->bytes == msg->length)
{
esp32c3_i2c_traceevent(priv, I2CEVENT_STOP, msg->length,
getreg32(I2C_SR_REG(priv->id)));
esp32c3_i2c_sendstop(priv);
priv->i2cstate = I2CSTATE_FINISH;
}
else
{
esp32c3_i2c_traceevent(priv, I2CEVENT_RCVMODEEN, 0,
getreg32(I2C_SR_REG(priv->id)));
esp32c3_i2c_startrecv(priv);
priv->ready_read = true;
@ -956,6 +1239,8 @@ static int esp32c3_i2c_irq(int cpuint, void *context, void *arg)
}
else
{
esp32c3_i2c_traceevent(priv, I2CEVENT_SENDBYTE, priv->bytes,
getreg32(I2C_SR_REG(priv->id)));
esp32c3_i2c_senddata(priv);
if (priv->bytes == msg->length)
@ -966,6 +1251,8 @@ static int esp32c3_i2c_irq(int cpuint, void *context, void *arg)
}
else if (priv->i2cstate == I2CSTATE_STOP)
{
esp32c3_i2c_traceevent(priv, I2CEVENT_STOP, msg->length,
getreg32(I2C_SR_REG(priv->id)));
esp32c3_i2c_sendstop(priv);
priv->i2cstate = I2CSTATE_FINISH;