Tiva I2C: Fix how I2C transactions are started and some I2C error reporting
This commit is contained in:
parent
a190aeeeba
commit
b818691a3a
@ -154,8 +154,7 @@
|
|||||||
enum tiva_intstate_e
|
enum tiva_intstate_e
|
||||||
{
|
{
|
||||||
INTSTATE_IDLE = 0, /* No I2C activity */
|
INTSTATE_IDLE = 0, /* No I2C activity */
|
||||||
INTSTATE_ADDRESS, /* Address sent, waiting for completion */
|
INTSTATE_WAITING, /* Waiting for data transfer to complete */
|
||||||
INTSTATE_XFRWAIT, /* Waiting for data transfer to complete */
|
|
||||||
INTSTATE_DONE /* Interrupt activity complete */
|
INTSTATE_DONE /* Interrupt activity complete */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -209,11 +208,11 @@ struct tiva_i2c_config_s
|
|||||||
struct tiva_i2c_priv_s
|
struct tiva_i2c_priv_s
|
||||||
{
|
{
|
||||||
const struct tiva_i2c_config_s *config; /* Port configuration */
|
const struct tiva_i2c_config_s *config; /* Port configuration */
|
||||||
int refs; /* Reference count */
|
|
||||||
sem_t exclsem; /* Mutual exclusion semaphore */
|
sem_t exclsem; /* Mutual exclusion semaphore */
|
||||||
#ifndef CONFIG_I2C_POLLED
|
#ifndef CONFIG_I2C_POLLED
|
||||||
sem_t waitsem; /* Interrupt wait semaphore */
|
sem_t waitsem; /* Interrupt wait semaphore */
|
||||||
#endif
|
#endif
|
||||||
|
uint8_t refs; /* Reference count */
|
||||||
volatile uint8_t intstate; /* Interrupt handshake (see enum tiva_intstate_e) */
|
volatile uint8_t intstate; /* Interrupt handshake (see enum tiva_intstate_e) */
|
||||||
|
|
||||||
uint8_t msgc; /* Message count */
|
uint8_t msgc; /* Message count */
|
||||||
@ -293,8 +292,8 @@ static void tiva_i2c_traceevent(struct tiva_i2c_priv_s *priv,
|
|||||||
static void tiva_i2c_tracedump(struct tiva_i2c_priv_s *priv);
|
static void tiva_i2c_tracedump(struct tiva_i2c_priv_s *priv);
|
||||||
#endif /* CONFIG_I2C_TRACE */
|
#endif /* CONFIG_I2C_TRACE */
|
||||||
|
|
||||||
static void tiva_i2c_sendaddress(struct tiva_i2c_priv_s *priv);
|
static void tiva_i2c_startxfr(struct tiva_i2c_priv_s *priv);
|
||||||
static void tiva_i2c_nextxfr(struct tiva_i2c_priv_s *priv);
|
static void tiva_i2c_nextxfr(struct tiva_i2c_priv_s *priv, uint32_t cmd);
|
||||||
static int tiva_i2c_interrupt(struct tiva_i2c_priv_s * priv, uint32_t status);
|
static int tiva_i2c_interrupt(struct tiva_i2c_priv_s * priv, uint32_t status);
|
||||||
|
|
||||||
#ifndef CONFIG_I2C_POLLED
|
#ifndef CONFIG_I2C_POLLED
|
||||||
@ -888,7 +887,7 @@ static void tiva_i2c_tracenew(struct tiva_i2c_priv_s *priv, uint32_t status)
|
|||||||
|
|
||||||
if (priv->tndx >= (CONFIG_I2C_NTRACE-1))
|
if (priv->tndx >= (CONFIG_I2C_NTRACE-1))
|
||||||
{
|
{
|
||||||
i2cdbg("ERROR: Trace table overflow\n");
|
i2cdbg("I2C%d: ERROR: Trace table overflow\n", priv->config->devno);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -937,7 +936,7 @@ static void tiva_i2c_traceevent(struct tiva_i2c_priv_s *priv,
|
|||||||
|
|
||||||
if (priv->tndx >= (CONFIG_I2C_NTRACE-1))
|
if (priv->tndx >= (CONFIG_I2C_NTRACE-1))
|
||||||
{
|
{
|
||||||
i2cdbg("ERROR: Trace table overflow\n");
|
i2cdbg("I2C%d: ERROR: Trace table overflow\n", priv->config->devno);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -946,7 +945,7 @@ static void tiva_i2c_traceevent(struct tiva_i2c_priv_s *priv,
|
|||||||
tiva_i2c_traceclear(priv);
|
tiva_i2c_traceclear(priv);
|
||||||
|
|
||||||
trace = &priv->trace[priv->tndx];
|
trace = &priv->trace[priv->tndx];
|
||||||
trace->status = priv->status;
|
trace->status = priv->tstatus;
|
||||||
trace->count = priv->tcount;
|
trace->count = priv->tcount;
|
||||||
trace->time = clock_systimer();
|
trace->time = clock_systimer();
|
||||||
}
|
}
|
||||||
@ -977,14 +976,14 @@ static void tiva_i2c_tracedump(struct tiva_i2c_priv_s *priv)
|
|||||||
#endif /* CONFIG_I2C_TRACE */
|
#endif /* CONFIG_I2C_TRACE */
|
||||||
|
|
||||||
/************************************************************************************
|
/************************************************************************************
|
||||||
* Name: tiva_i2c_sendaddress
|
* Name: tiva_i2c_startxfr
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Send the START conditions/force Master mode
|
* Send the START conditions/force Master mode
|
||||||
*
|
*
|
||||||
************************************************************************************/
|
************************************************************************************/
|
||||||
|
|
||||||
static void tiva_i2c_sendaddress(struct tiva_i2c_priv_s *priv)
|
static void tiva_i2c_startxfr(struct tiva_i2c_priv_s *priv)
|
||||||
{
|
{
|
||||||
struct i2c_msg_s *msg;
|
struct i2c_msg_s *msg;
|
||||||
uint32_t regval;
|
uint32_t regval;
|
||||||
@ -1007,24 +1006,11 @@ static void tiva_i2c_sendaddress(struct tiva_i2c_priv_s *priv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
tiva_i2c_putreg(priv, TIVA_I2CM_SA_OFFSET, regval);
|
tiva_i2c_putreg(priv, TIVA_I2CM_SA_OFFSET, regval);
|
||||||
|
|
||||||
/* Write the command to the control register */
|
|
||||||
|
|
||||||
regval = I2CM_CS_RUN;
|
|
||||||
if ((msg->flags & I2C_M_NORESTART) == 0)
|
|
||||||
{
|
|
||||||
regval |= I2CM_CS_START;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (priv->dcnt < 1)
|
|
||||||
{
|
|
||||||
regval |= I2CM_CS_STOP;
|
|
||||||
}
|
|
||||||
|
|
||||||
tiva_i2c_putreg(priv, TIVA_I2CM_CS_OFFSET, regval);
|
|
||||||
|
|
||||||
tiva_i2c_traceevent(priv, I2CEVENT_SENDADDRESS, msg->addr);
|
tiva_i2c_traceevent(priv, I2CEVENT_SENDADDRESS, msg->addr);
|
||||||
priv->intstate = INTSTATE_ADDRESS;
|
|
||||||
|
/* Then initiate the transfer */
|
||||||
|
|
||||||
|
tiva_i2c_nextxfr(priv, I2CM_CS_START);
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************************************************
|
/************************************************************************************
|
||||||
@ -1035,15 +1021,13 @@ static void tiva_i2c_sendaddress(struct tiva_i2c_priv_s *priv)
|
|||||||
*
|
*
|
||||||
************************************************************************************/
|
************************************************************************************/
|
||||||
|
|
||||||
static void tiva_i2c_nextxfr(struct tiva_i2c_priv_s *priv)
|
static void tiva_i2c_nextxfr(struct tiva_i2c_priv_s *priv, uint32_t cmd)
|
||||||
{
|
{
|
||||||
uint32_t cmd;
|
|
||||||
|
|
||||||
/* Set up the basic command. The STOP bit should be set on the last transfer
|
/* Set up the basic command. The STOP bit should be set on the last transfer
|
||||||
* UNLESS this there is a repeated start.
|
* UNLESS this there is a repeated start.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
cmd = I2CM_CS_RUN;
|
cmd |= I2CM_CS_RUN;
|
||||||
if (priv->msgc < 2 && priv->dcnt < 2)
|
if (priv->msgc < 2 && priv->dcnt < 2)
|
||||||
{
|
{
|
||||||
/* This is the last byte of the last message... add the STOP bit */
|
/* This is the last byte of the last message... add the STOP bit */
|
||||||
@ -1081,7 +1065,7 @@ static void tiva_i2c_nextxfr(struct tiva_i2c_priv_s *priv)
|
|||||||
tiva_i2c_traceevent(priv, I2CEVENT_SENDBYTE, priv->dcnt);
|
tiva_i2c_traceevent(priv, I2CEVENT_SENDBYTE, priv->dcnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->intstate = INTSTATE_XFRWAIT;
|
priv->intstate = INTSTATE_WAITING;
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************************************************
|
/************************************************************************************
|
||||||
@ -1136,7 +1120,11 @@ static int tiva_i2c_interrupt(struct tiva_i2c_priv_s *priv, uint32_t status)
|
|||||||
|
|
||||||
/* Check for errors, in which case, stop the transfer and return. */
|
/* Check for errors, in which case, stop the transfer and return. */
|
||||||
|
|
||||||
else if ((mcs & I2CM_CS_ERROR) != 0)
|
#if 0 /* I2CM_CS_CLKTO */
|
||||||
|
else if ((mcs & (I2CM_CS_ERROR | I2CM_CS_ARBLST | I2CM_CS_CLKTO)) != 0)
|
||||||
|
#else
|
||||||
|
else if ((mcs & (I2CM_CS_ERROR | I2CM_CS_ARBLST)) != 0)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
tiva_i2c_traceevent(priv, I2CEVENT_ERROR, mcs);
|
tiva_i2c_traceevent(priv, I2CEVENT_ERROR, mcs);
|
||||||
|
|
||||||
@ -1189,7 +1177,7 @@ static int tiva_i2c_interrupt(struct tiva_i2c_priv_s *priv, uint32_t status)
|
|||||||
|
|
||||||
DEBUGASSERT(priv->dcnt > 0);
|
DEBUGASSERT(priv->dcnt > 0);
|
||||||
|
|
||||||
if (priv->intstate == INTSTATE_XFRWAIT)
|
if (priv->intstate == INTSTATE_WAITING)
|
||||||
{
|
{
|
||||||
/* Data transfer completed. Are we sending or receiving data? */
|
/* Data transfer completed. Are we sending or receiving data? */
|
||||||
|
|
||||||
@ -1213,7 +1201,7 @@ static int tiva_i2c_interrupt(struct tiva_i2c_priv_s *priv, uint32_t status)
|
|||||||
{
|
{
|
||||||
/* Send the next byte */
|
/* Send the next byte */
|
||||||
|
|
||||||
tiva_i2c_nextxfr(priv);
|
tiva_i2c_nextxfr(priv, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1232,7 +1220,7 @@ static int tiva_i2c_interrupt(struct tiva_i2c_priv_s *priv, uint32_t status)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
tiva_i2c_traceevent(priv, I2CEVENT_NEXTMSG, priv->msgc);
|
tiva_i2c_traceevent(priv, I2CEVENT_NEXTMSG, priv->msgc);
|
||||||
if (priv->msgv->flags & I2C_M_NORESTART)
|
if ((priv->msgv->flags & I2C_M_NORESTART) != 0)
|
||||||
{
|
{
|
||||||
/* Just continue transferring data. In this case,
|
/* Just continue transferring data. In this case,
|
||||||
* no STOP was sent at the end of the last message
|
* no STOP was sent at the end of the last message
|
||||||
@ -1243,7 +1231,7 @@ static int tiva_i2c_interrupt(struct tiva_i2c_priv_s *priv, uint32_t status)
|
|||||||
* change
|
* change
|
||||||
*/
|
*/
|
||||||
|
|
||||||
tiva_i2c_nextxfr(priv);
|
tiva_i2c_nextxfr(priv, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1251,7 +1239,7 @@ static int tiva_i2c_interrupt(struct tiva_i2c_priv_s *priv, uint32_t status)
|
|||||||
* end of the previous message.
|
* end of the previous message.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
tiva_i2c_sendaddress(priv);
|
tiva_i2c_startxfr(priv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1277,11 +1265,11 @@ static int tiva_i2c_interrupt(struct tiva_i2c_priv_s *priv, uint32_t status)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
sem_post(&priv->waitsem);
|
sem_post(&priv->waitsem);
|
||||||
priv->status = mcs;
|
priv->status = 0;
|
||||||
priv->intstate = INTSTATE_DONE;
|
priv->intstate = INTSTATE_DONE;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
priv->status = mcs;
|
priv->status = 0;
|
||||||
priv->intstate = INTSTATE_DONE;
|
priv->intstate = INTSTATE_DONE;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -1465,39 +1453,45 @@ static int tiva_i2c5_interrupt(int irq, void *context)
|
|||||||
|
|
||||||
static int tiva_i2c_initialize(struct tiva_i2c_priv_s *priv)
|
static int tiva_i2c_initialize(struct tiva_i2c_priv_s *priv)
|
||||||
{
|
{
|
||||||
|
const struct tiva_i2c_config_s *config = priv->config;
|
||||||
uint32_t regval;
|
uint32_t regval;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
i2cvdbg("I2C%d:\n", priv->config->devno);
|
i2cvdbg("I2C%d: refs=%d\n", config->devno, priv->refs);
|
||||||
|
|
||||||
/* Enable clocking to the I2C peripheral */
|
/* Enable clocking to the I2C peripheral */
|
||||||
|
|
||||||
#ifdef TIVA_SYSCON_RCGCI2C
|
#ifdef TIVA_SYSCON_RCGCI2C
|
||||||
modifyreg32(TIVA_SYSCON_RCGCI2C, 0, SYSCON_RCGCI2C(priv->config->devno));
|
modifyreg32(TIVA_SYSCON_RCGCI2C, 0, SYSCON_RCGCI2C(config->devno));
|
||||||
|
|
||||||
i2cvdbg("I2C%d: RCGI2C[%08x]=%08lx\n",
|
i2cvdbg("I2C%d: RCGI2C[%08x]=%08x\n",
|
||||||
priv->config->devno, TIVA_SYSCON_RCGCI2C,
|
config->devno, TIVA_SYSCON_RCGCI2C, getreg32(TIVA_SYSCON_RCGCI2C));
|
||||||
(unsigned long)getreg32(TIVA_SYSCON_RCGCI2C));
|
|
||||||
#else
|
#else
|
||||||
modifyreg32(TIVA_SYSCON_RCGC1, 0, priv->rcgbit);
|
modifyreg32(TIVA_SYSCON_RCGC1, 0, priv->rcgbit);
|
||||||
|
|
||||||
i2cvdbg("I2C%d: RCGC1[%08x]=%08lx\n",
|
i2cvdbg("I2C%d: RCGC1[%08x]=%08x\n",
|
||||||
priv->config->devno, TIVA_SYSCON_RCGC1,
|
config->devno, TIVA_SYSCON_RCGC1, getreg32(TIVA_SYSCON_RCGC1));
|
||||||
(unsigned long)getreg32(TIVA_SYSCON_RCGC1));
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Configure pins */
|
/* Configure pins */
|
||||||
|
|
||||||
ret = tiva_configgpio(priv->config->scl_pin);
|
i2cvdbg("I2C%d: SCL=%08x SDA=%08x\n",
|
||||||
|
config->devno, config->scl_pin, config->sda_pin);
|
||||||
|
|
||||||
|
ret = tiva_configgpio(config->scl_pin);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
|
i2cvdbg("I2C%d: tiva_configgpio(%08x) failed: %d\n",
|
||||||
|
config->scl_pin, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = tiva_configgpio(priv->config->sda_pin);
|
ret = tiva_configgpio(config->sda_pin);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
tiva_configgpio(MKI2C_INPUT(priv->config->scl_pin));
|
i2cvdbg("I2C%d: tiva_configgpio(%08x) failed: %d\n",
|
||||||
|
config->sda_pin, ret);
|
||||||
|
tiva_configgpio(MKI2C_INPUT(config->scl_pin));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1516,8 +1510,8 @@ static int tiva_i2c_initialize(struct tiva_i2c_priv_s *priv)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef CONFIG_I2C_POLLED
|
#ifndef CONFIG_I2C_POLLED
|
||||||
irq_attach(priv->config->irq, priv->config->isr);
|
irq_attach(config->irq, config->isr);
|
||||||
up_enable_irq(priv->config->irq);
|
up_enable_irq(config->irq);
|
||||||
#endif
|
#endif
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@ -1534,7 +1528,7 @@ static int tiva_i2c_uninitialize(struct tiva_i2c_priv_s *priv)
|
|||||||
{
|
{
|
||||||
uint32_t regval;
|
uint32_t regval;
|
||||||
|
|
||||||
i2cvdbg("I2C%d:\n", priv->config->devno);
|
i2cvdbg("I2C%d: refs=%d\n", priv->config->devno, priv->refs);
|
||||||
|
|
||||||
/* Disable I2C */
|
/* Disable I2C */
|
||||||
|
|
||||||
@ -1578,7 +1572,7 @@ static uint32_t tiva_i2c_setclock(struct tiva_i2c_priv_s *priv, uint32_t frequen
|
|||||||
uint32_t regval;
|
uint32_t regval;
|
||||||
uint32_t tmp;
|
uint32_t tmp;
|
||||||
|
|
||||||
i2cvdbg("I2C%d: frequency: %lu\n", priv->config->devno, (unsigned long)frequency);
|
i2cvdbg("I2C%d: frequency: %u\n", priv->config->devno, frequency);
|
||||||
|
|
||||||
/* Calculate the clock divider that results in the highest frequency that
|
/* Calculate the clock divider that results in the highest frequency that
|
||||||
* is than or equal to the desired speed.
|
* is than or equal to the desired speed.
|
||||||
@ -1623,7 +1617,7 @@ static uint32_t tiva_i2c_setfrequency(struct i2c_dev_s *dev, uint32_t frequency)
|
|||||||
DEBUGASSERT(inst && inst->priv);
|
DEBUGASSERT(inst && inst->priv);
|
||||||
priv = inst->priv;
|
priv = inst->priv;
|
||||||
|
|
||||||
i2cvdbg("I2C%d: frequency: %lu\n", inst->priv->config->devno, (unsigned long)frequency);
|
i2cvdbg("I2C%d: frequency: %u\n", inst->priv->config->devno, frequency);
|
||||||
|
|
||||||
/* Get exclusive access to the I2C device */
|
/* Get exclusive access to the I2C device */
|
||||||
|
|
||||||
@ -1674,6 +1668,7 @@ static int tiva_i2c_process(struct i2c_dev_s *dev, struct i2c_msg_s *msgs,
|
|||||||
{
|
{
|
||||||
struct tiva_i2c_inst_s *inst = (struct tiva_i2c_inst_s *)dev;
|
struct tiva_i2c_inst_s *inst = (struct tiva_i2c_inst_s *)dev;
|
||||||
struct tiva_i2c_priv_s *priv = inst->priv;
|
struct tiva_i2c_priv_s *priv = inst->priv;
|
||||||
|
uint32_t regval;
|
||||||
int errval = 0;
|
int errval = 0;
|
||||||
|
|
||||||
ASSERT(count);
|
ASSERT(count);
|
||||||
@ -1705,7 +1700,7 @@ static int tiva_i2c_process(struct i2c_dev_s *dev, struct i2c_msg_s *msgs,
|
|||||||
* interrupts will be enabled within tiva_i2c_waitdone().
|
* interrupts will be enabled within tiva_i2c_waitdone().
|
||||||
*/
|
*/
|
||||||
|
|
||||||
tiva_i2c_sendaddress(priv);
|
tiva_i2c_startxfr(priv);
|
||||||
|
|
||||||
/* Wait for an ISR, if there was a timeout, fetch latest status to get
|
/* Wait for an ISR, if there was a timeout, fetch latest status to get
|
||||||
* the BUSY flag.
|
* the BUSY flag.
|
||||||
@ -1713,15 +1708,18 @@ static int tiva_i2c_process(struct i2c_dev_s *dev, struct i2c_msg_s *msgs,
|
|||||||
|
|
||||||
if (tiva_i2c_sem_waitdone(priv) < 0)
|
if (tiva_i2c_sem_waitdone(priv) < 0)
|
||||||
{
|
{
|
||||||
i2cdbg("ERROR: Timed out\n");
|
i2cdbg("I2C%d: ERROR: Timed out\n", priv->config->devno);
|
||||||
errval = ETIMEDOUT;
|
errval = ETIMEDOUT;
|
||||||
}
|
}
|
||||||
#ifdef I2CM_CS_CLKTO
|
#if 0 /* I2CM_CS_CLKTO */
|
||||||
else if ((priv->status & (I2CM_CS_ERROR | I2CM_CS_ARBLST | I2CM_CS_CLKTO)) != 0)
|
else if ((priv->status & (I2CM_CS_ERROR | I2CM_CS_ARBLST | I2CM_CS_CLKTO)) != 0)
|
||||||
#else
|
#else
|
||||||
else if ((priv->status & (I2CM_CS_ERROR | I2CM_CS_ARBLST)) != 0)
|
else if ((priv->status & (I2CM_CS_ERROR | I2CM_CS_ARBLST)) != 0)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
i2cdbg("I2C%d: ERROR: I2C error status: %08x\n",
|
||||||
|
priv->config->devno, priv->status);
|
||||||
|
|
||||||
if ((priv->status & I2CM_CS_ARBLST) != 0)
|
if ((priv->status & I2CM_CS_ARBLST) != 0)
|
||||||
{
|
{
|
||||||
/* Arbitration Lost */
|
/* Arbitration Lost */
|
||||||
@ -1734,7 +1732,7 @@ static int tiva_i2c_process(struct i2c_dev_s *dev, struct i2c_msg_s *msgs,
|
|||||||
|
|
||||||
errval = ENXIO;
|
errval = ENXIO;
|
||||||
}
|
}
|
||||||
#ifdef I2CM_CS_CLKTO
|
#if 0 /* I2CM_CS_CLKTO */
|
||||||
else if ((priv->status & I2CM_CS_CLKTO) != 0)
|
else if ((priv->status & I2CM_CS_CLKTO) != 0)
|
||||||
{
|
{
|
||||||
/* Timeout */
|
/* Timeout */
|
||||||
@ -1750,18 +1748,26 @@ static int tiva_i2c_process(struct i2c_dev_s *dev, struct i2c_msg_s *msgs,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is not an error, but should not happen. The BUSY signal can hang,
|
/* This is not an error, but should not happen. The I2CM_CS_BUSBSY signal
|
||||||
* however, if there are unhealthy devices on the bus that need to be reset.
|
* can hang, however, if there are unhealthy devices on the bus that need
|
||||||
* NOTE: We will only see this busy indication if tiva_i2c_sem_waitdone()
|
* to be reset.
|
||||||
* fails above; Otherwise it is cleared.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ((tiva_i2c_getreg(priv, TIVA_I2CM_CS_OFFSET) & (I2CM_CS_BUSY | I2CM_CS_BUSBSY)) != 0)
|
regval = tiva_i2c_getreg(priv, TIVA_I2CM_CS_OFFSET);
|
||||||
|
|
||||||
|
/* The status bits are not valid if BUSY is set. We will just have to
|
||||||
|
* assume that everything went OK.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ((regval & I2CM_CS_BUSY) != 0 && (regval & I2CM_CS_BUSBSY) != 0)
|
||||||
{
|
{
|
||||||
/* I2C Bus is for some reason busy. If I2CM_CS_BUSY then none of the
|
/* I2C Bus is for some reason busy. If I2CM_CS_BUSY then none of the
|
||||||
* other bits are valid.
|
* other bits are valid.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
i2cdbg("I2C%d: ERROR: I2C still busy: %08x\n",
|
||||||
|
priv->config->devno, regval);
|
||||||
|
|
||||||
errval = EBUSY;
|
errval = EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1772,7 +1778,7 @@ static int tiva_i2c_process(struct i2c_dev_s *dev, struct i2c_msg_s *msgs,
|
|||||||
/* Ensure that any ISR happening after we finish can't overwrite any user data */
|
/* Ensure that any ISR happening after we finish can't overwrite any user data */
|
||||||
|
|
||||||
priv->dcnt = 0;
|
priv->dcnt = 0;
|
||||||
priv->ptr = NULL;
|
priv->ptr = NULL;
|
||||||
|
|
||||||
tiva_i2c_sem_post(dev);
|
tiva_i2c_sem_post(dev);
|
||||||
|
|
||||||
@ -1855,9 +1861,9 @@ static int tiva_i2c_writeread(struct i2c_dev_s *dev,
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
.addr = inst->address,
|
.addr = inst->address,
|
||||||
.flags = inst->flags | ((buflen>0) ? I2C_M_READ : I2C_M_NORESTART),
|
.flags = inst->flags | ((buflen > 0) ? I2C_M_READ : I2C_M_NORESTART),
|
||||||
.buffer = buffer,
|
.buffer = buffer,
|
||||||
.length = (buflen>0) ? buflen : -buflen
|
.length = (buflen > 0) ? buflen : -buflen
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1906,12 +1912,12 @@ static int tiva_i2c_transfer(struct i2c_dev_s *dev, struct i2c_msg_s *msgs,
|
|||||||
|
|
||||||
struct i2c_dev_s *up_i2cinitialize(int port)
|
struct i2c_dev_s *up_i2cinitialize(int port)
|
||||||
{
|
{
|
||||||
struct tiva_i2c_priv_s * priv = NULL; /* Private data of device with multiple instances */
|
struct tiva_i2c_priv_s *priv = NULL; /* Private data of device with multiple instances */
|
||||||
struct tiva_i2c_inst_s * inst = NULL; /* Device, single instance */
|
struct tiva_i2c_inst_s *inst = NULL; /* Device, single instance */
|
||||||
const struct tiva_i2c_config_s *config; /* Constant configuration */
|
const struct tiva_i2c_config_s *config; /* Constant configuration */
|
||||||
int irqs;
|
int irqs;
|
||||||
|
|
||||||
i2cvdbg("I2C%d: port=%d\n", port, port);
|
i2cvdbg("I2C%d: Initialize\n", port);
|
||||||
|
|
||||||
/* Get I2C private structure */
|
/* Get I2C private structure */
|
||||||
|
|
||||||
@ -1954,6 +1960,7 @@ struct i2c_dev_s *up_i2cinitialize(int port)
|
|||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
|
i2cdbg("I2C%d: ERROR: Not supported\n", port);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1964,10 +1971,6 @@ struct i2c_dev_s *up_i2cinitialize(int port)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure that the device structure is inialized */
|
|
||||||
|
|
||||||
priv->config = config;
|
|
||||||
|
|
||||||
/* Initialize instance */
|
/* Initialize instance */
|
||||||
|
|
||||||
inst->ops = &tiva_i2c_ops;
|
inst->ops = &tiva_i2c_ops;
|
||||||
@ -1982,9 +1985,16 @@ struct i2c_dev_s *up_i2cinitialize(int port)
|
|||||||
|
|
||||||
irqs = irqsave();
|
irqs = irqsave();
|
||||||
|
|
||||||
if ((volatile int)priv->refs++ == 0)
|
priv->refs++;
|
||||||
|
if (priv->refs == 1)
|
||||||
{
|
{
|
||||||
|
/* Initialize the device structure */
|
||||||
|
|
||||||
|
priv->config = config;
|
||||||
tiva_i2c_sem_init((struct i2c_dev_s *)inst);
|
tiva_i2c_sem_init((struct i2c_dev_s *)inst);
|
||||||
|
|
||||||
|
/* Initialize the I2C hardware */
|
||||||
|
|
||||||
tiva_i2c_initialize(priv);
|
tiva_i2c_initialize(priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2003,38 +2013,43 @@ struct i2c_dev_s *up_i2cinitialize(int port)
|
|||||||
int up_i2cuninitialize(struct i2c_dev_s *dev)
|
int up_i2cuninitialize(struct i2c_dev_s *dev)
|
||||||
{
|
{
|
||||||
struct tiva_i2c_inst_s *inst = (struct tiva_i2c_inst_s *)dev;
|
struct tiva_i2c_inst_s *inst = (struct tiva_i2c_inst_s *)dev;
|
||||||
|
struct tiva_i2c_priv_s *priv ;
|
||||||
int irqs;
|
int irqs;
|
||||||
|
|
||||||
DEBUGASSERT(inst && inst->priv && inst->priv->config);
|
DEBUGASSERT(inst && inst->priv);
|
||||||
i2cvdbg("I2C%d:\n", inst->priv->config->devno);
|
priv = inst->priv;
|
||||||
|
|
||||||
|
DEBUGASSERT(priv->config && priv->refs > 0);
|
||||||
|
i2cvdbg("I2C%d: Uninitialize\n", priv->config->devno);
|
||||||
|
|
||||||
/* Decrement reference count and check for underflow */
|
/* Decrement reference count and check for underflow */
|
||||||
|
|
||||||
if (inst->priv->refs == 0)
|
|
||||||
{
|
|
||||||
return ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
irqs = irqsave();
|
irqs = irqsave();
|
||||||
|
|
||||||
if (--inst->priv->refs)
|
/* Free this instance */
|
||||||
|
|
||||||
|
kmm_free(inst);
|
||||||
|
|
||||||
|
/* Check if the reference count will decrement to zero */
|
||||||
|
|
||||||
|
if (priv->refs < 2)
|
||||||
{
|
{
|
||||||
irqrestore(irqs);
|
/* Yes.. Disable power and other HW resource (GPIO's) */
|
||||||
kmm_free(dev);
|
|
||||||
return OK;
|
tiva_i2c_uninitialize(priv);
|
||||||
|
|
||||||
|
/* Release unused resources */
|
||||||
|
|
||||||
|
tiva_i2c_sem_destroy(dev);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* No.. just decrement the number of references to the device */
|
||||||
|
|
||||||
|
priv->refs--;
|
||||||
}
|
}
|
||||||
|
|
||||||
irqrestore(irqs);
|
irqrestore(irqs);
|
||||||
|
|
||||||
/* Disable power and other HW resource (GPIO's) */
|
|
||||||
|
|
||||||
tiva_i2c_uninitialize(inst->priv);
|
|
||||||
|
|
||||||
/* Release unused resources */
|
|
||||||
|
|
||||||
tiva_i2c_sem_destroy((struct i2c_dev_s *)dev);
|
|
||||||
|
|
||||||
kmm_free(dev);
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ PIN SIGNAL(S) LanchPad Function
|
|||||||
|
|
||||||
45 PB0/T2CCP0/U1Rx GPIO, J1 pin 3
|
45 PB0/T2CCP0/U1Rx GPIO, J1 pin 3
|
||||||
46 PB1/T2CCP1/U1Tx GPIO, J1 pin 4
|
46 PB1/T2CCP1/U1Tx GPIO, J1 pin 4
|
||||||
47 PB2/I2C0SCL/T3CCP0 GPIO, J2, pin 3
|
47 PB2/I2C0SCL/T3CCP0 GPIO, J2 pin 2
|
||||||
48 PB3/I2C0SDA/T3CCP1 GPIO, J4 pin 3
|
48 PB3/I2C0SDA/T3CCP1 GPIO, J4 pin 3
|
||||||
58 PB4/AIN10/CAN0Rx/SSI2CLK/T1CCP0 GPIO, J1 pin 7
|
58 PB4/AIN10/CAN0Rx/SSI2CLK/T1CCP0 GPIO, J1 pin 7
|
||||||
57 PB5/AIN11/CAN0Tx/SSI2FSS/T1CCP1 GPIO, J1 pin 2
|
57 PB5/AIN11/CAN0Tx/SSI2FSS/T1CCP1 GPIO, J1 pin 2
|
||||||
@ -94,10 +94,12 @@ AT24 Serial EEPROM
|
|||||||
The Serial EEPROM was mounted on an external adaptor board and connected
|
The Serial EEPROM was mounted on an external adaptor board and connected
|
||||||
to the LaunchPad thusly:
|
to the LaunchPad thusly:
|
||||||
|
|
||||||
- VCC -- VCC
|
- VCC J1 pin 1 3.3V
|
||||||
- GND -- GND
|
J3 pin 1 5.0V
|
||||||
- PB2 -- SCL
|
- GND J2 pin 1 GND
|
||||||
- PB3 -- SDA
|
J3 pin 2 GND
|
||||||
|
- PB2 J2 pin 2 SCL
|
||||||
|
- PB3 J4 pin 3 SDA
|
||||||
|
|
||||||
Configuration Settings
|
Configuration Settings
|
||||||
----------------------
|
----------------------
|
||||||
|
Loading…
Reference in New Issue
Block a user